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