another update from CVS HEAD, for QA
[alioth/jupp.git] / umath.c
1 /*
2  *      Math
3  *      Copyright
4  *              (C) 1992 Joseph H. Allen
5  *
6  *      This file is part of JOE (Joe's Own Editor)
7  */
8 #include "config.h"
9 #include "types.h"
10
11 __RCSID("$MirOS: contrib/code/jupp/umath.c,v 1.24 2017/12/08 02:28:08 tg Exp $");
12
13 #include <stdlib.h>
14 #include <string.h>
15
16 #include "b.h"
17 #include "pw.h"
18 #include "umath.h"
19 #include "utils.h"
20 #include "vs.h"
21 #include "charmap.h"
22 #include "w.h"
23
24 volatile sig_atomic_t merrf;
25 const unsigned char *merrt;
26
27 #if WANT_MATH
28 static char math_res[JOE_MSGBUFSIZE];
29 static char *math_exp;
30
31 static double calc(BW *bw, unsigned char *s);
32
33 static RETSIGTYPE fperr(int unused)
34 {
35         if (!merrf)
36                 merrf = 2;
37         REINSTALL_SIGHANDLER(SIGFPE, fperr);
38 }
39
40 struct var {
41         unsigned char *name;
42         int set;
43         double val;
44         struct var *next;
45 } *vars = NULL;
46
47 static struct var *get(unsigned char *str)
48 {
49         struct var *v;
50
51         for (v = vars; v; v = v->next) {
52                 if (!strcmp(v->name, str)) {
53                         return v;
54                 }
55         }
56         v = malloc(sizeof(struct var));
57         v->set = 0;
58         v->next = vars;
59         vars = v;
60         v->name = (unsigned char *)strdup((char *)str);
61         return v;
62 }
63
64 unsigned char *ptr;
65 struct var *dumb;
66
67 static double expr(int prec, struct var **rtv)
68 {
69         double x = 0.0;
70         struct var *v = NULL;
71
72         while (*ptr == ' ' || *ptr == '\t') {
73                 ++ptr;
74         }
75         if ((*ptr >= 'a' && *ptr <= 'z') || (*ptr >= 'A' && *ptr <= 'Z')
76             || *ptr == '_') {
77                 unsigned char *s = ptr, c;
78
79                 while ((*ptr >= 'a' && *ptr <= 'z')
80                        || (*ptr >= 'A' && *ptr <= 'Z')
81                        || *ptr == '_' || (*ptr >= '0' && *ptr <= '9')) {
82                         ++ptr;
83                 }
84                 c = *ptr;
85                 *ptr = 0;
86                 v = get(s);
87                 x = v->val;
88                 *ptr = c;
89         } else if (ptr[0] == '0' && (ptr[1] | 0x20) == 'x') {
90                 unsigned long xi;
91                 void *dp;
92
93                 xi = ustol(ptr, &dp, USTOL_AUTO);
94                 x = (double)xi;
95                 ptr = dp;
96         } else if ((*ptr >= '0' && *ptr <= '9') || *ptr == '.') {
97                 char *eptr;
98
99                 x = strtod(ptr, &eptr);
100                 ptr = (unsigned char *)eptr;
101         } else if (*ptr == '(') {
102                 ++ptr;
103                 x = expr(0, &v);
104                 if (*ptr == ')')
105                         ++ptr;
106                 else if (!merrf) {
107                         merrf = 1;
108                         merrt = US "Missing )";
109                 }
110         } else if (*ptr == '-') {
111                 ++ptr;
112                 x = -expr(10, &dumb);
113         }
114  loop:
115         while (*ptr == ' ' || *ptr == '\t')
116                 ++ptr;
117         if (*ptr == '*' && 5 > prec) {
118                 ++ptr;
119                 x *= expr(5, &dumb);
120                 goto loop;
121         } else if (*ptr == '/' && 5 > prec) {
122                 ++ptr;
123                 x /= expr(5, &dumb);
124                 goto loop;
125         } else if (*ptr == '+' && 4 > prec) {
126                 ++ptr;
127                 x += expr(4, &dumb);
128                 goto loop;
129         } else if (*ptr == '-' && 4 > prec) {
130                 ++ptr;
131                 x -= expr(4, &dumb);
132                 goto loop;
133         } else if (*ptr == '=' && 2 >= prec) {
134                 ++ptr;
135                 x = expr(2, &dumb);
136                 if (v) {
137                         v->val = x;
138                         v->set = 1;
139                 } else if (!merrf) {
140                         merrf = 1;
141                         merrt = US "Left side of = is not an l-value";
142                 }
143                 goto loop;
144         }
145         *rtv = v;
146         return x;
147 }
148
149 #if defined(SIZEOF_LONG_LONG) && (SIZEOF_LONG_LONG > 0)
150 typedef long long joe_imaxt;
151 #define JOE_IMAXT "ll"
152 #else
153 typedef long joe_imaxt;
154 #define JOE_IMAXT "l"
155 #endif
156
157 static double
158 calc(BW *bw, unsigned char *s)
159 {
160         double result;
161         struct var *v;
162         BW *tbw = bw->parent->main->object.bw;
163
164         if (math_exp) {
165                 free(math_exp);
166         }
167         math_exp = strdup((void *)s);
168
169         v = get(US "top");
170         v->val = tbw->top->line + 1;
171         v->set = 1;
172         v = get(US "lines");
173         v->val = tbw->b->eof->line + 1;
174         v->set = 1;
175         v = get(US "line");
176         v->val = tbw->cursor->line + 1;
177         v->set = 1;
178         v = get(US "col");
179         v->val = tbw->cursor->col + 1;
180         v->set = 1;
181         v = get(US "byte");
182         v->val = tbw->cursor->byte + 1;
183         v->set = 1;
184         v = get(US "height");
185         v->val = tbw->h;
186         v->set = 1;
187         v = get(US "width");
188         v->val = tbw->w;
189         v->set = 1;
190         ptr = s;
191         merrf = 0;
192  up:
193         result = expr(0, &dumb);
194         if (!merrf) {
195                 while (*ptr == ' ' || *ptr == '\t') {
196                         ++ptr;
197                 }
198                 if (*ptr == ';') {
199                         ++ptr;
200                         while (*ptr == ' ' || *ptr == '\t') {
201                                 ++ptr;
202                         }
203                         if (*ptr) {
204                                 goto up;
205                         }
206                 } else if (*ptr && !merrf) {
207                         merrf = 1;
208                         merrt = US "Extra junk after end of expr";
209                 }
210         }
211
212         if (merrf) {
213                 if (merrf == 2)
214                         merrt = US "Float point exception";
215                 joe_snprintf_1(math_res, JOE_MSGBUFSIZE,
216                     "math_error{%s}", merrt);
217         } else {
218                 joe_imaxt ires = (joe_imaxt)result;
219
220                 if ((double)ires == result) {
221                         /* representable as integer value */
222                         joe_snprintf_1(math_res, JOE_MSGBUFSIZE,
223                             "%" JOE_IMAXT "d", ires);
224                 } else {
225                         /* use float with large precision */
226                         joe_snprintf_1(math_res, JOE_MSGBUFSIZE,
227                             "%.60G", result);
228                 }
229         }
230
231         return result;
232 }
233
234 /* Main user interface */
235 static int domath(BW *bw, unsigned char *s, void *object, int *notify)
236 {
237         calc(bw, s);
238         vsrm(s);
239
240         if (notify) {
241                 *notify = 1;
242         }
243         if (merrf) {
244                 msgnw(bw->parent, merrt);
245                 return -1;
246         }
247         memcpy(msgbuf, math_res, JOE_MSGBUFSIZE);
248         if (bw->parent->watom->what != TYPETW) {
249                 binsm(bw->cursor, sz(msgbuf));
250                 pfwrd(bw->cursor, strlen((char *)msgbuf));
251                 bw->cursor->xcol = piscol(bw->cursor);
252         } else {
253                 msgnw(bw->parent, msgbuf);
254         }
255         return 0;
256 }
257
258 B *mathhist = NULL;
259
260 int umath(BW *bw)
261 {
262         joe_set_signal(SIGFPE, fperr);
263         if (wmkpw(bw->parent, UC "=", &mathhist, domath, UC "Math", NULL, NULL, NULL, NULL, locale_map)) {
264                 return 0;
265         } else {
266                 return -1;
267         }
268 }
269
270 int umathins(BW *bw)
271 {
272         if (math_exp) {
273                 binss(bw->cursor, (void *)math_exp);
274         }
275         return 0;
276 }
277
278 int umathres(BW *bw)
279 {
280         binss(bw->cursor, (void *)math_res);
281         return 0;
282 }
283
284 long
285 calcl(BW *bw, unsigned char *s)
286 {
287         double rv;
288
289         rv = calc(bw, s);
290         return ((long)rv);
291 }
292 #else
293 long
294 calcl(BW *bw, unsigned char *s)
295 {
296         long rv;
297         void *cp = NULL;
298
299         rv = ustol(s, &cp, USTOL_TRIM | USTOL_EOS);
300         if (!cp) {
301                 rv = 0;
302                 merrt = US "Invalid or out-of-range number";
303                 merrf = 1;
304         }
305         return (rv);
306 }
307
308 int
309 unomath(BW *bw)
310 {
311         msgnw(bw->parent, UC "Sorry, compiled without Math");
312         return (-1);
313 }
314 #endif