2 * Copyright Neil Brown ©2020-2021 <neil@brown.name>
3 * May be distributed under terms of GPLv2 - see file:COPYING
5 * Perform numeric calculations.
7 * 'str' should hold an expression which is computed.
8 * It may can contain variables in which can comm2 should produce
9 * the contents as a string
10 * The result is passed to comm2 in decimal and hex
16 int do_calc(const char *expr, mpq_t result,
17 bool (*getvar)(const char *name, int len, mpq_t val, void *data),
20 static bool getvar(const char *name, int len, mpq_t val, void *data)
22 struct cmd_info *ci = data;
28 vnm = strnsave(ci->focus, name, len);
29 vval = comm_call_ret(strsave, ci->comm2, "get", ci->focus, 0, NULL, vnm);
32 if (do_calc(vval, val, NULL, NULL) != 0)
41 const char *formats = "xf";
43 if (!ci->str || !ci->comm2)
48 ret = do_calc(ci->str, result, getvar, (void*)ci);
51 if (mpz_cmp_si(mpq_denref(result), 1) == 0) {
52 char *buf = mpz_get_str(NULL, 10,
54 comm_call(ci->comm2, "result", ci->focus, 0, NULL, buf);
56 if (strchr(formats, 'x')) {
57 buf = mpz_get_str(NULL, 16, mpq_numref(result));
58 comm_call(ci->comm2, "hex-result", ci->focus, 0,
59 NULL, strconcat(ci->focus, "0x",buf));
62 if (strchr(formats, 'X')) {
63 buf = mpz_get_str(NULL, -16, mpq_numref(result));
64 comm_call(ci->comm2, "hex-result", ci->focus, 0,
65 NULL, strconcat(ci->focus, "0X",buf));
68 if (strchr(formats, 'o')) {
69 buf = mpz_get_str(NULL, 8, mpq_numref(result));
70 comm_call(ci->comm2, "oct-result", ci->focus, 0,
71 NULL, strconcat(ci->focus, "0o",buf));
77 buf = mpq_get_str(NULL, 10, result);
78 comm_call(ci->comm2, "frac-result", ci->focus, 0, NULL,
81 if (strchr(formats, 'f')) {
83 mpf_set_q(fl, result);
84 gmp_asprintf(&buf, "%.10Fg", fl);
86 comm_call(ci->comm2, "float-result", ci->focus,
92 comm_call(ci->comm2, "err", ci->focus, ret-1);
95 return ret == 0 ? 1 : Efail;
102 const char *expr = ci->str;
103 struct mark *m2 = ci->mark2;
104 bool hex = False, oct = False;
106 if (ci->num != NO_NUMERIC) {
107 /* e.g. from Alt-3 alt-#. Pop up a calc window */
108 struct pane *doc = call_ret(pane, "docs:byname", ci->focus,
113 doc = call_ret(pane, "doc:from-text", ci->focus,
114 0, NULL, "*Calc*", 0, NULL, "? ");
116 call("Message", ci->focus, 0, NULL,
117 "Cannot create *Calc* - sorry");
120 attr_set_str(&doc->attrs, "view-default", "view-calc");
121 p = call_ret(pane, "PopupTile", ci->focus, 0, NULL, "MD3tsa");
123 call("Message", ci->focus, 0, NULL,
124 "Cannot popup *Calc* - sorry");
127 p = home_call_ret(pane, doc, "doc:attach-view", p, 1);
129 call("doc:file", p, 1);
136 /* Try to find a WORD */
137 call("doc:WORD", ci->focus, -1, ci->mark);
138 m2 = mark_dup(ci->mark);
139 call("doc:WORD", ci->focus, 1, m2);
140 expr = call_ret(strsave, "doc:get-str", ci->focus, 0, ci->mark, NULL,
146 if (expr[0] == '#') {
149 } else if (expr[0] == '@') {
153 ret = do_calc(expr, result, NULL, NULL);
159 if (mpz_cmp_si(mpq_denref(result), 1) == 0) {
160 gmp_snprintf(buf, sizeof(buf),
161 hex ? "%#Zx" : oct ? "0o%Zo" : "%Zd",
165 mpf_set_q(fl, result);
166 gmp_snprintf(buf, sizeof(buf), "%.10Fg", fl);
169 if (!ci->mark || !m2 ||
170 call("doc:replace", ci->focus, 0, m2, buf, 0, ci->mark) <= 0)
171 call("Message", ci->focus, 0, NULL,
172 strconcat(ci->focus, expr, " -> ", buf));
174 call("Message", ci->focus, 0, NULL,
175 strconcat(ci->focus, expr, " -> error at ",
179 return ret == 0 ? 1 : Efail;
182 void edlib_init(struct pane *ed safe)
184 call_comm("global-set-command", ed, &calc,
185 0, NULL, "CalcExpr");
186 call_comm("global-set-command", ed, &calc_replace,
187 0, NULL, "interactive-cmd-calc-replace");