Update to CVS snapshot, for testing
[alioth/jupp.git] / umath.c
1 /* $MirOS: contrib/code/jupp/umath.c,v 1.7 2017/03/19 19:19:51 tg Exp $ */
2 /*
3  *      Math
4  *      Copyright
5  *              (C) 1992 Joseph H. Allen
6  *
7  *      This file is part of JOE (Joe's Own Editor)
8  */
9 #include "config.h"
10 #include "types.h"
11
12 #include <stdio.h>
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 "utf8.h"
23 #include "charmap.h"
24 #include "w.h"
25
26 volatile sig_atomic_t merrf;
27 const unsigned char *merrt;
28
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                 sscanf((char *)ptr, "%lf", &x);
99                 while ((*ptr >= '0' && *ptr <= '9') || *ptr == '.' || *ptr == 'e' || *ptr == 'E')
100                         ++ptr;
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 double calc(BW *bw, unsigned char *s)
158 {
159         double result;
160         struct var *v;
161         BW *tbw = bw->parent->main->object;
162
163         if (math_exp) {
164                 free(math_exp);
165         }
166         math_exp = strdup((void *)s);
167
168         v = get(US "top");
169         v->val = tbw->top->line + 1;
170         v->set = 1;
171         v = get(US "lines");
172         v->val = tbw->b->eof->line + 1;
173         v->set = 1;
174         v = get(US "line");
175         v->val = tbw->cursor->line + 1;
176         v->set = 1;
177         v = get(US "col");
178         v->val = tbw->cursor->col + 1;
179         v->set = 1;
180         v = get(US "byte");
181         v->val = tbw->cursor->byte + 1;
182         v->set = 1;
183         v = get(US "height");
184         v->val = tbw->h;
185         v->set = 1;
186         v = get(US "width");
187         v->val = tbw->w;
188         v->set = 1;
189         ptr = s;
190         merrf = 0;
191       up:
192         result = expr(0, &dumb);
193         if (!merrf) {
194                 while (*ptr == ' ' || *ptr == '\t') {
195                         ++ptr;
196                 }
197                 if (*ptr == ';') {
198                         ++ptr;
199                         while (*ptr == ' ' || *ptr == '\t') {
200                                 ++ptr;
201                         }
202                         if (*ptr) {
203                                 goto up;
204                         }
205                 } else if (*ptr && !merrf) {
206                         merrf = 1;
207                         merrt = US "Extra junk after end of expr";
208                 }
209         }
210
211         if (merrf) {
212                 if (merrf == 2)
213                         merrt = US "Float point exception";
214                 joe_snprintf_1(math_res, JOE_MSGBUFSIZE,
215                     "math_error{%s}", merrt);
216         } else {
217                 joe_imaxt ires = (joe_imaxt)result;
218
219                 if ((double)ires == result) {
220                         /* representable as integer value */
221                         joe_snprintf_1(math_res, JOE_MSGBUFSIZE,
222                             "%" JOE_IMAXT "d", ires);
223                 } else {
224                         /* use float with large precision */
225                         joe_snprintf_1(math_res, JOE_MSGBUFSIZE,
226                             "%.60G", result);
227                 }
228         }
229
230         return result;
231 }
232
233 /* Main user interface */
234 static int domath(BW *bw, unsigned char *s, void *object, int *notify)
235 {
236         calc(bw, s);
237
238         if (notify) {
239                 *notify = 1;
240         }
241         if (merrf) {
242                 msgnw(bw->parent, merrt);
243                 return -1;
244         }
245         vsrm(s);
246         memcpy(msgbuf, math_res, JOE_MSGBUFSIZE);
247         if (bw->parent->watom->what != TYPETW) {
248                 binsm(bw->cursor, sz(msgbuf));
249                 pfwrd(bw->cursor, strlen((char *)msgbuf));
250                 bw->cursor->xcol = piscol(bw->cursor);
251         } else {
252                 msgnw(bw->parent, msgbuf);
253         }
254         return 0;
255 }
256
257 B *mathhist = NULL;
258
259 int umath(BW *bw)
260 {
261         joe_set_signal(SIGFPE, fperr);
262         if (wmkpw(bw->parent, US "=", &mathhist, domath, US "math", NULL, NULL, NULL, NULL, locale_map)) {
263                 return 0;
264         } else {
265                 return -1;
266         }
267 }
268
269 int umathins(BW *bw)
270 {
271         if (math_exp) {
272                 binss(bw->cursor, (void *)math_exp);
273         }
274         return 0;
275 }
276
277 int umathres(BW *bw)
278 {
279         binss(bw->cursor, (void *)math_res);
280         return 0;
281 }