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