/MirOS/dist/jupp/joe-3.1jupp30.tgz
[alioth/jupp.git] / umath.c
1 /* $MirOS: contrib/code/jupp/umath.c,v 1.6 2012/12/30 17:12:37 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 const unsigned char * volatile merr;
27
28 static char math_res[JOE_MSGBUFSIZE];
29 static char *math_exp;
30
31 static RETSIGTYPE fperr(int unused)
32 {
33         if (!merr) {
34                 merr = US "Float point exception";
35         }
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 {
107                         if (!merr)
108                                 merr = 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 {
140                         if (!merr)
141                                 merr = 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         merr = 0;
191       up:
192         result = expr(0, &dumb);
193         if (!merr) {
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) {
206                         merr = US "Extra junk after end of expr";
207                 }
208         }
209
210         if (merr) {
211                 joe_snprintf_1(math_res, JOE_MSGBUFSIZE,
212                     "math_error{%s}", merr);
213         } else {
214                 joe_imaxt ires = (joe_imaxt)result;
215
216                 if ((double)ires == result) {
217                         /* representable as integer value */
218                         joe_snprintf_1(math_res, JOE_MSGBUFSIZE,
219                             "%" JOE_IMAXT "d", ires);
220                 } else {
221                         /* use float with large precision */
222                         joe_snprintf_1(math_res, JOE_MSGBUFSIZE,
223                             "%.60G", result);
224                 }
225         }
226
227         return result;
228 }
229
230 /* Main user interface */
231 static int domath(BW *bw, unsigned char *s, void *object, int *notify)
232 {
233         calc(bw, s);
234
235         if (notify) {
236                 *notify = 1;
237         }
238         if (merr) {
239                 msgnw(bw->parent, merr);
240                 return -1;
241         }
242         vsrm(s);
243         memcpy(msgbuf, math_res, JOE_MSGBUFSIZE);
244         if (bw->parent->watom->what != TYPETW) {
245                 binsm(bw->cursor, sz(msgbuf));
246                 pfwrd(bw->cursor, strlen((char *)msgbuf));
247                 bw->cursor->xcol = piscol(bw->cursor);
248         } else {
249                 msgnw(bw->parent, msgbuf);
250         }
251         return 0;
252 }
253
254 B *mathhist = NULL;
255
256 int umath(BW *bw)
257 {
258         joe_set_signal(SIGFPE, fperr);
259         if (wmkpw(bw->parent, US "=", &mathhist, domath, US "math", NULL, NULL, NULL, NULL, locale_map)) {
260                 return 0;
261         } else {
262                 return -1;
263         }
264 }
265
266 int umathins(BW *bw)
267 {
268         if (math_exp) {
269                 binss(bw->cursor, (void *)math_exp);
270         }
271         return 0;
272 }
273
274 int umathres(BW *bw)
275 {
276         binss(bw->cursor, (void *)math_res);
277         return 0;
278 }