1: /*
2: * $Id: operator.c,v 1.9 2025/05/05 22:52:32 snw Exp $
3: * operators pattern-match, divide, multiply, add, power
4: *
5: *
6: * Author: Serena Willis <snw@coherent-logic.com>
7: * Copyright (C) 1998 MUG Deutschland
8: * Copyright (C) 2020, 2025 Coherent Logic Development LLC
9: *
10: *
11: * This file is part of FreeM.
12: *
13: * FreeM is free software: you can redistribute it and/or modify
14: * it under the terms of the GNU Affero Public License as published by
15: * the Free Software Foundation, either version 3 of the License, or
16: * (at your option) any later version.
17: *
18: * FreeM is distributed in the hope that it will be useful,
19: * but WITHOUT ANY WARRANTY; without even the implied warranty of
20: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21: * GNU Affero Public License for more details.
22: *
23: * You should have received a copy of the GNU Affero Public License
24: * along with FreeM. If not, see <https://www.gnu.org/licenses/>.
25: *
26: * $Log: operator.c,v $
27: * Revision 1.9 2025/05/05 22:52:32 snw
28: * Make E notation error message more appropriate
29: *
30: * Revision 1.8 2025/05/05 19:34:46 snw
31: * Fix E notation code to disallow more than one minus sign after the E
32: *
33: * Revision 1.7 2025/04/10 01:24:38 snw
34: * Remove C++ style comments
35: *
36: * Revision 1.6 2025/04/09 19:52:02 snw
37: * Eliminate as many warnings as possible while building with -Wall
38: *
39: * Revision 1.5 2025/03/09 19:50:47 snw
40: * Second phase of REUSE compliance and header reformat
41: *
42: *
43: * SPDX-FileCopyrightText: (C) 2025 Coherent Logic Development LLC
44: * SPDX-License-Identifier: AGPL-3.0-or-later
45: **/
46:
47: #include "mpsdef.h"
48: #include <stdlib.h>
49: #include <math.h>
50:
51: int unit (char *str);
52: extern void cond_round (char *a, int digits); /* defined in expr.c */
53:
54:
55:
56: #define PLUS '+'
57: #define MINUS '-'
58: #define POINT '.'
59: #define point (POINT-ZERO)
60: #define ZERO '0'
61: #define ONE (ZERO+1)
62: #define TWO (ZERO+2)
63: #define THREE (ZERO+3)
64: #define FIVE (ZERO+(NUMBASE/2))
65: #define NINE (ZERO+NUMBASE-1)
66: #define NUMBASE 10
67:
68: short int
69: pattern (char *a, char *b) /* evaluates a ? b */
70: {
71: short levels; /* depth of stack */
72: register int patx; /* match stack pointer */
73: short notpatclass; /* pattern class negation */
74: char *ptrpcd[PATDEPTH], /* pointers to patcode */
75: *position[PATDEPTH]; /* position of matching substring */
76: short mincnt[PATDEPTH], /* minimum number of matches */
77: maxcnt[PATDEPTH], /* maximum number of matches */
78: actcnt[PATDEPTH]; /* actual count of matches */
79: short Pflag,
80: Pchar; /* status in pattern alternation */
81: short altc; /* alternation counter */
82: short altcnt[PATDEPTH]; /* gr.pat.alternation counters */
83:
84: unsigned char gpmin[PATDEPTH][PATDEPTH][255]; /* grouped pattern minimum lengthes */
85: char *gp_position[PATDEPTH][PATDEPTH]; /* grouped patt.pos.of substr */
86:
87: char *ptrtom; /* pointer to match code */
88: char patcode;
89: int ch;
90: int i;
91:
92: pattrnflag = Pflag = FALSE; /* incomplete match flag */
93: pattrnchar = Pchar = EOL; /* incomplete match supplement */
94: notpatclass = FALSE; /* pattern class negation */
95: patx = 0;
96: while (*b != EOL) { /* get minimum repeat count */
97: mincnt[patx] = 0;
98: maxcnt[patx] = 255;
99: altcnt[patx] = (-1);
100: if (*b != '.') {
101: ch = (*b++) - '0';
102: while (*b >= '0' && *b <= '9') {
103: ch *= 10;
104: ch += (*b++) - '0';
105: }
106: mincnt[patx] = ch;
107: if (*b != '.')
108: maxcnt[patx] = ch;
109: }
110: /* get maximum repeat count */
111: if (*b == '.') {
112: b++;
113: if (*b >= '0' && *b <= '9') {
114: ch = (*b++) - '0';
115: while (*b >= '0' && *b <= '9') {
116: ch *= 10;
117: ch += (*b++) - '0';
118: }
119: maxcnt[patx] = ch;
120: }
121: }
122: if (maxcnt[patx] < mincnt[patx])
123: return '2'; /* just impossible! */
124: ptrpcd[patx] = b;
125: actcnt[patx] = 0;
126: position[patx] = 0;
127: /* scan strlit, ignore it when empty */
128: if (*b == '"' || *b == 'z' || (*b == '\'' && *(b + 1) == '"')) {
129: if (*(++b) == DELIM) {
130: b++;
131: continue;
132: }
133: while (*(++b) != DELIM) ;
134: b++;
135: } else if (*b == '(') {
136: i = 1;
137: b++;
138: while ((ch = *b) != EOL) {
139: b++;
140: if (ch == '"') {
141: while (*(++b) != DELIM) ;
142: }
143: if (ch == '(') {
144: i++;
145: continue;
146: }
147: if (ch == ')') {
148: i--;
149: if (i < 1)
150: break;
151: }
152: }
153: } else
154: while (*(++b) >= 'A') ;
155: if (++patx >= (PATDEPTH - 1))
156: return '3'; /* stack overflow */
157: }
158: levels = patx;
159: if (*(b - 1) == 'e' && mincnt[levels - 1] == 0 && maxcnt[levels - 1] == 255)
160: *(b - 1) = '~'; /* frequent special case: last pattern is '.E' */
161: mincnt[levels] = maxcnt[levels] = 1; /* sentinel, does never match */
162: actcnt[levels] = 0;
163: ptrpcd[levels] = b; /* (*b==EOL) */
164: patx = 0;
165: while (patx <= levels) {
166: while (actcnt[patx] < mincnt[patx]) {
167: actcnt[patx]++;
168: if (*a == EOL) {
169: pattrnflag = TRUE; /* incomplete match flag */
170: if (patx >= levels) {
171: pattrnchar = EOL;
172: return '1';
173: }
174: if (patx > 0) {
175: if (actcnt[patx - 1] != maxcnt[patx - 1])
176: return '0';
177: /* after alternation we are not sure about */
178: /* that supplement character */
179: if (*(ptrpcd[patx - 1]) == '(') {
180: pattrnchar = EOL;
181: return '0';
182: }
183: }
184: if (*(ptrpcd[patx]) == '"')
185: pattrnchar = *(ptrpcd[patx] + 1);
186: return '0';
187: }
188: for (;;)
189: {
190: /***begin section: does that char match current pattern code ***/
191: ptrtom = ptrpcd[patx];
192: ch = (*a);
193: for (;;)
194: {
195: patcode = (*ptrtom++);
196: if ((notpatclass = (patcode == '\'')))
197: patcode = (*ptrtom++);
198: switch (patcode) { /* we live in an ASCII/ISO world !! */
199: case 'c':
200: if (((ch < SP && ch >= NUL)
201: || ch == DEL) != notpatclass)
202: goto match;
203: break;
204: case 'n':
205: if ((ch <= '9' && ch >= '0') != notpatclass)
206: goto match;
207: break;
208: case 'p':
209: if (((ch >= SP && ch <= '/') ||
210: (ch >= ':' && ch <= '@') ||
211: (ch >= '[' && ch <= '`') ||
212: (ch >= '{' && ch <= '~') ||
213: (ch == '\200')) != notpatclass)
214: goto match;
215: break;
216: case 'a':
217: if (((ch >= 'A' && ch <= 'Z') ||
218: (ch >= 'a' && ch <= 'z')) != notpatclass)
219: goto match;
220: break;
221: case 'l':
222: if ((ch >= 'a' && ch <= 'z') != notpatclass)
223: goto match;
224: break;
225: case 'u':
226: if ((ch >= 'A' && ch <= 'Z') != notpatclass)
227: goto match;
228: break;
229: case 'e':
230: if (!notpatclass)
231: goto match;
232: break;
233: case '"':
234: i = 0;
235: while (a[i++] == (*ptrtom++)) ;
236: if ((*--ptrtom) == DELIM) {
237: if (notpatclass)
238: goto nomatch;
239: b = ptrpcd[patx] + 1;
240: while (*b++ != DELIM)
241: a++;
242: goto match0;
243: }
244: if (notpatclass) {
245: i--;
246: while (*ptrtom++ != DELIM) {
247: if (a[i++] == EOL)
248: goto nomatch;
249: }
250: b = ptrpcd[patx] + 2;
251: while (*b++ != DELIM)
252: a++;
253: goto match0;
254: }
255: if (a[i - 1] == EOL) {
256: pattrnflag = TRUE;
257: pattrnchar = *ptrtom;
258: }
259: goto nomatch;
260:
261: case '~':{
262: pattrnchar = EOL; /* '.E' as last pat_atom */
263: pattrnflag = TRUE;
264: return '1';
265: }
266: /* grouped pattern match */
267: case '(':{
268: char aa[256];
269: char bb[256];
270: int i1,
271: min,
272: max;
273: short pflag;
274: short pchar;
275:
276: if (Pflag) {
277: pflag = Pflag;
278: pchar = Pchar;
279: } else {
280: pflag = FALSE;
281: pchar = EOL;
282: }
283: if (altcnt[patx] < 0) {
284: for (altc = 0; altc < PATDEPTH; altc++)
285: gpmin[patx][altc][1] = 0;
286: }
287: altcnt[patx] = 0;
288: alternation:;
289: i = 0;
290: i1 = 1;
291: while (i1) {
292: bb[i] = *ptrtom++;
293: if (bb[i] == '"') {
294: while ((bb[++i] = (*ptrtom++)) != DELIM) ;
295: }
296: if (bb[i] == '(')
297: i1++;
298: if (bb[i] == ')')
299: i1--;
300: if (bb[i] == ',' && i1 == 1)
301: i1--;
302: i++;
303: }
304: bb[--i] = EOL;
305: pminmax (bb, &min, &max);
306:
307: if ((i1 = gpmin[patx][altcnt[patx]][actcnt[patx]]) < min)
308: gpmin[patx][altcnt[patx]][actcnt[patx]] = i1 = min;
309: gpmin[patx][altcnt[patx]][actcnt[patx] + 1] = 0;
310: /* too much charaters to get a match! */
311: if (i1 > max) {
312: if (*(ptrtom - 1) == ',') {
313: altcnt[patx]++;
314: goto alternation;
315: }
316: pattrnflag = pflag;
317: pattrnchar = pchar;
318: goto nomatch;
319: }
320: /* if number of chars too small, try anyway */
321: /* to get info for "incomplete" match */
322: for (i = 0; i < i1; i++)
323: if ((aa[i] = a[i]) == EOL)
324: break;
325: gp_position[patx][actcnt[patx]] = a;
326:
327: for (;;)
328: {
329: aa[i] = EOL;
330: i1 = pattern (aa, bb);
331: if (i1 == '1') {
332: gpmin[patx][altcnt[patx]][actcnt[patx]] = i;
333: a += i;
334: goto match0;
335: }
336: if (i1 != '0')
337: return i1;
338: if (pattrnflag) {
339: if (pflag == FALSE)
340: pchar = pattrnchar;
341: else if (pchar != pattrnchar)
342: pchar = EOL;
343: pflag = TRUE;
344: }
345: if (!pattrnflag) {
346: if (*(ptrtom - 1) == ',') {
347: altcnt[patx]++;
348: goto alternation;
349: }
350: pattrnflag = pflag;
351: pattrnchar = pchar;
352: goto nomatch;
353: }
354: if (a[i] == EOL) {
355: Pflag = pflag;
356: Pchar = pchar;
357: if (*(ptrtom - 1) == ',') {
358: altcnt[patx]++;
359: goto alternation;
360: }
361: pattrnflag = pflag;
362: pattrnchar = pchar;
363: return '0';
364: }
365: aa[i] = a[i];
366: i++;
367: }
368: }
369: /* match one of listed characters ?1Z"string" */
370: case 'z':
371: for (;;)
372: {
373: if ((*++ptrtom) == DELIM) {
374: if (notpatclass)
375: goto match;
376: goto nomatch;
377: }
378: if (ch != *ptrtom) {
379: if (*(ptrtom + 1) == '.' && *(ptrtom + 2) == '.') {
380: if (ch < *ptrtom ||
381: (ch > *(ptrtom + 3) && *(ptrtom + 3) != DELIM)) {
382: ptrtom += 2;
383: continue;
384: }
385: } else
386: continue;
387: }
388: while (*++ptrtom != DELIM) ;
389: if (notpatclass)
390: goto nomatch;
391: goto match;
392: }
393:
394: /* loadable matches */
395: case 'C':
396: i = 0;
397: while (zmc[i] != EOL) {
398: if (zmc[i] == ch && !notpatclass)
399: goto match;
400: i++;
401: }
402: if (notpatclass)
403: goto match;
404: break;
405: case 'N':
406: i = 0;
407: while (zmn[i] != EOL) {
408: if (zmn[i] == ch && !notpatclass)
409: goto match;
410: i++;
411: }
412: if (notpatclass)
413: goto match;
414: break;
415: case 'P':
416: i = 0;
417: while (zmp[i] != EOL) {
418: if (zmp[i] == ch && !notpatclass)
419: goto match;
420: i++;
421: }
422: if (notpatclass)
423: goto match;
424: break;
425: case 'A':
426: i = 0;
427: while (zmu[i] != EOL) {
428: if (zmu[i] == ch && !notpatclass)
429: goto match;
430: i++;
431: }
432: case 'L':
433: i = 0;
434: while (zml[i] != EOL) {
435: if (zml[i] == ch && !notpatclass)
436: goto match;
437: i++;
438: }
439: if (notpatclass)
440: goto match;
441: break;
442: case 'U':
443: i = 0;
444: while (zmu[i] != EOL) {
445: if (zmu[i] == ch && !notpatclass)
446: goto match;
447: i++;
448: }
449: if (notpatclass)
450: goto match;
451: break;
452: default:
453: goto nomatch;
454: } /* end_switch */
455: } /* end repeat */
456: /*** end section: does that char match current pattern atom ***/
457: nomatch:;
458: if (patcode == '(') {
459: for (altc = 0; altc <= altcnt[patx]; altc++)
460: gpmin[patx][altc][actcnt[patx]] = 0;
461: if (--actcnt[patx] > 0) {
462: for (altc = 0; altc <= altcnt[patx]; altc++)
463: gpmin[patx][altc][actcnt[patx]]++;
464: a = gp_position[patx][actcnt[patx]]; /* try previous patterns again */
465: continue;
466: }
467: }
468: do {
469: actcnt[patx] = 0;
470: if (--patx < 0)
471: return '0'; /* stack exhausted */
472: if (*(ptrpcd[patx]) == '(') {
473: if (actcnt[patx] >= maxcnt[patx]) {
474: ++actcnt[patx];
475: patcode = '(';
476: goto nomatch;
477: }
478: }
479: } while (++actcnt[patx] > maxcnt[patx]);
480: a = position[patx]; /* try previous patterns again */
481:
482: } /* end repeat */
483: match:;
484: a++;
485: match0:;
486: }
487: position[patx++] = a; /* pos after last match */
488: }
489: return '0';
490: } /* end of pattern */
491:
492: /******************************************************************************/
493: void pminmax (char *str, int *min, int *max)
494: {
495: int mininc,
496: maxinc,
497: i,
498: ch;
499:
500: *min = 0;
501: *max = 0;
502: mininc = 0;
503: maxinc = 0;
504: i = 0;
505: ch = 0;
506: while (str[i] != EOL) {
507: if (str[i] != '.') { /* scan minimum repeat count */
508: ch = (str[i++]) - '0';
509: while (str[i] >= '0' && str[i] <= '9') {
510: ch *= 10;
511: ch += (str[i++]) - '0';
512: }
513: mininc = ch;
514: maxinc = ch;
515: } else {
516: mininc = 0;
517: maxinc = 255;
518: }
519: if (str[i] == '.') { /* scan maximum repeat count */
520: i++;
521: if (str[i] >= '0' && str[i] <= '9') {
522: ch = (str[i++]) - '0';
523: while (str[i] >= '0' && str[i] <= '9') {
524: ch *= 10;
525: ch += (str[i]++) - '0';
526: }
527: } else
528: ch = 255;
529: maxinc = ch;
530: }
531: /* skip pattern codes */
532: if (str[i] == '"') {
533: int cnt;
534:
535: cnt = 0;
536: while (str[++i] != DELIM)
537: cnt++;
538: mininc = mininc * cnt;
539: maxinc = maxinc * cnt;
540: }
541: if (str[i] == 'z' || str[i] == '"') {
542: while (str[++i] != DELIM) ;
543: i++;
544: } else if (str[i] == '(') {
545: char tmp[256];
546: char *tcur;
547: int tmin,
548: tmax,
549: Tmin,
550: Tmax,
551: i1;
552:
553: tmin = 255;
554: tmax = 0;
555: alternation:;
556: i1 = 1;
557: tcur = tmp;
558: while (i1) {
559: ch = str[++i];
560: *tcur++ = ch;
561: if (ch == '"')
562: while ((*tcur++ = str[++i]) != DELIM) ;
563: if (ch == '(')
564: i1++;
565: if (ch == ')')
566: i1--;
567: if (ch == ',' && i1 == 1)
568: i1--;
569: }
570: *(--tcur) = EOL;
571: pminmax (tmp, &Tmin, &Tmax);
572: if (Tmin < tmin)
573: tmin = Tmin;
574: if (Tmax > tmax)
575: tmax = Tmax;
576: if (str[i] == ',')
577: goto alternation;
578: i++;
579: mininc *= tmin;
580: maxinc *= tmax;
581: } else
582: while (str[++i] >= 'A') ;
583: *min += mininc;
584: *max += maxinc;
585: }
586: if (*max > 255)
587: *max = 255;
588: return;
589: } /* end pminmax() */
590: /******************************************************************************/
591: void add (char *a, char *b) /* string arithmetic a+=b; */
592: {
593:
594: if (b[0] == ZERO)
595: return;
596: if (a[0] == ZERO) {
597: stcpy (a, b);
598: return;
599: } {
600: long dpa, /* decimal point of 'a' */
601: dpb, /* decimal point of 'b' */
602: lena, /* length of 'a' */
603: lenb; /* length of 'b' */
604: char mi; /* minus flag */
605: short sign; /* sign flag if a<0<b sign=-1; */
606:
607: /* if a>0>b sign=1; */
608: /* else sign=0; */
609:
610: register int i;
611: register int ch;
612: register int j;
613: register int carry;
614:
615: #if !defined(_AIX)
616: if (fp_mode) {
617: double fp_a;
618: double fp_b;
619:
620: stcnv_m2c (a);
621: stcnv_m2c (b);
622:
623: fp_a = atof (a);
624: fp_b = atof (b);
625:
626: snprintf (a, STRLEN - 1, fp_conversion, fp_a + fp_b);
627: trim_decimal (a);
628:
629: return;
630: }
631: #endif
632:
633:
634:
635: /* look at the signs */
636: mi = 0;
637: sign = 0;
638: if (a[0] == b[0] && a[0] == MINUS) {
639: mi++;
640: a[0] = b[0] = ZERO;
641: } else if (a[0] == MINUS) {
642: sign--;
643: a[0] = NINE;
644: i = 0;
645: while ((ch = a[++i]) != EOL)
646: if (ch != POINT)
647: a[i] = ZERO + NINE - ch;
648: a[--i]++;
649: } else if (b[0] == MINUS) {
650: sign++;
651: b[0] = NINE;
652: i = 0;
653: while ((ch = b[++i]) != EOL)
654: if (ch != POINT)
655: b[i] = ZERO + NINE - ch;
656: b[--i]++;
657: }
658: /* search decimal points and length */
659: dpa = dpb = (-1);
660: i = 0;
661: while (a[i] != EOL) {
662: if (a[i] == POINT)
663: dpa = i;
664: i++;
665: }
666: lena = i;
667: if (dpa < 0)
668: dpa = i;
669: again:;
670: i = 0;
671: while (b[i] != EOL) {
672: if (b[i] == POINT)
673: dpb = i;
674: i++;
675: }
676: lenb = i;
677: if (dpb < 0)
678: dpb = i;
679: if (i == 1) {
680: if (b[0] == ONE && sign == 0 && dpa > 0) { /* frequent special case: add 1 */
681: i = dpa - 1;
682: while (++a[i] > NINE) {
683: a[i--] = ZERO;
684: if (i < 0) {
685: i = lena;
686: while (i >= 0) {
687: a[i + 1] = a[i];
688: i--;
689: }
690: a[0] = ONE;
691: return;
692: }
693: }
694: return;
695: }
696: }
697: /* copy additional trailing digits from b to a */
698: if (lenb - dpb > lena - dpa) {
699: j = dpa - dpb;
700: if (lenb + j > STRLEN) { /* round off that monster ! */
701: i = STRLEN - j;
702: if (b[i] < FIVE) {
703: b[i] = EOL;
704: lenb--;
705: while (b[--i] == ZERO) {
706: b[i] = EOL;
707: lenb--;
708: }
709: } else {
710: for (;;)
711: {
712: if (i >= dpb) {
713: b[i] = EOL;
714: lenb--;
715: } else
716: b[i] = ZERO;
717: if (--i < 0) {
718: for (i = lenb; i >= 0; i--)
719: b[i + 1] = b[i];
720: b[0] = ONE;
721: dpb = ++lenb;
722: break;
723: }
724: if ((ch = b[i]) == POINT) {
725: dpb = i;
726: continue;
727: }
728: if (ch < NINE && ch >= ZERO) {
729: b[i] = ++ch;
730: break;
731: }
732: }
733: }
734: goto again; /* look what's left from b */
735: }
736: lenb = i = lena - dpa + dpb;
737: j = lena;
738: while ((a[j++] = b[i++]) != EOL) ;
739: lena = (--j);
740: b[lenb] = EOL;
741: }
742: /* $justify a or b */
743: i = dpa - dpb;
744: if (i < 0) {
745: j = lena;
746: if ((i = (lena -= i)) > (STRLEN - 2) /*was 253*/) {
747: merr_raise (M75);
748: return;
749: }
750: ch = (sign >= 0 ? ZERO : NINE);
751: while (j >= 0)
752: a[i--] = a[j--];
753: while (i >= 0)
754: a[i--] = ch;
755: dpa = dpb;
756: } else if (i > 0) {
757: j = lenb;
758: if ((lenb = (i += lenb)) > (STRLEN - 2)/*was 253*/) {
759: merr_raise (M75);
760: return;
761: }
762: ch = (sign <= 0 ? ZERO : NINE);
763: while (j >= 0)
764: b[i--] = b[j--];
765: while (i >= 0)
766: b[i--] = ch;
767: dpb = dpa;
768: }
769: /* now add */
770: carry = 0;
771: for (i = lenb - 1; i >= 0; i--) {
772: if ((ch = a[i]) == POINT)
773: continue;
774: ch += b[i] - ZERO + carry;
775: if ((carry = (ch > NINE)))
776: ch -= NUMBASE;
777: a[i] = ch;
778: }
779: while (a[lena] != EOL)
780: lena++;
781: if (carry) {
782: if ((i = (++lena)) > (STRLEN - 2)/*was 253*/) {
783: merr_raise (M75);
784: return;
785: }
786: while (i > 0) {
787: a[i] = a[i - 1];
788: i--;
789: }
790: a[0] = ONE;
791: }
792: if (sign) {
793: if (a[0] == ONE) {
794: a[0] = ZERO;
795: } else {
796: i = 0;
797: carry = 0;
798: while ((ch = a[++i]) != EOL)
799: if (ch != POINT)
800: a[i] = ZERO + NINE - ch;
801: while (--i > 0) {
802: if (a[i] != POINT) {
803: if (++a[i] <= NINE)
804: break;
805: a[i] = ZERO;
806: }
807: }
808: mi = 1;
809: a[0] = ZERO;
810: }
811: while (a[(int) mi] == ZERO) {
812: stcpy (&a[(int) mi], &a[((int) mi) + 1]);
813: dpa--;
814: }
815: if (dpa < 0)
816: dpa = 0;
817: }
818: /* remove trailing zeroes */
819: i = dpa;
820: while (a[i] != EOL)
821: i++;
822: if (--i > dpa) {
823: while (a[i] == ZERO)
824: a[i--] = EOL;
825: }
826: /* remove trailing point */
827: if (a[i] == POINT)
828: a[i] = EOL;
829: if (mi) {
830: if (a[0] != ZERO) {
831: i = 0;
832: while (a[i++] != EOL) ;
833: while (i > 0) {
834: a[i] = a[i - 1];
835: i--;
836: }
837: }
838: a[0] = MINUS;
839: }
840: if (a[(int) mi] == EOL) {
841: a[0] = ZERO;
842: a[1] = EOL;
843: }
844: return;
845: }
846: }
847: /******************************************************************************/
848: void mul (char *a, char *b) /* string arithmetic a=a*b */
849: {
850: char c[2*(STRLEN+1) /*was 512*/];
851: short alen,
852: blen,
853: clen,
854: mi,
855: tmpx;
856: register int acur;
857: register int bcur;
858: register int ccur;
859: register int carry;
860:
861: #if !defined(_AIX)
862: if (fp_mode) {
863: double fp_a;
864: double fp_b;
865:
866: stcnv_m2c (a);
867: stcnv_m2c (b);
868:
869: fp_a = atof (a);
870: fp_b = atof (b);
871:
872: snprintf (a, STRLEN - 1, fp_conversion, fp_a * fp_b);
873: trim_decimal (a);
874:
875: return;
876: }
877: #endif
878:
879:
880: if (merr () > OK)
881: return; /* avoid nonsense in recursion */
882: /* if zero or one there's not much to do */
883: if (b[1] == EOL) {
884: if (b[0] == ZERO) {
885: a[0] = ZERO;
886: a[1] = EOL;
887: return;
888: }
889: if (b[0] <= ONE)
890: return;
891: if (b[0] == TWO) {
892: multwo:acur = 0;
893: while (a[++acur] != EOL) ;
894: mi = (a[acur - 1] == FIVE);
895: carry = 0;
896: ccur = acur;
897: while (acur >= 0) {
898: if ((bcur = a[--acur]) < ZERO)
899: continue;
900: bcur = bcur * 2 - ZERO + carry;
901: carry = 0;
902: if (bcur > NINE) {
903: carry = 1;
904: bcur -= NUMBASE;
905: }
906: a[acur] = bcur;
907: }
908: if (carry) {
909: acur = ccur;
910: if (acur > (STRLEN - 1)/*was 254*/) {
911: merr_raise (M75);
912: return;
913: }
914: while (acur >= 0) {
915: a[acur + 1] = a[acur];
916: acur--;
917: }
918: a[a[0] == MINUS] = ONE;
919: }
920: if (mi) {
921: if (carry)
922: ccur++;
923: acur = 0;
924: while (acur < ccur)
925: if (a[acur++] == POINT) {
926: a[--ccur] = EOL;
927: if (acur == ccur)
928: a[--ccur] = EOL;
929: return;
930: }
931: }
932: return;
933: }
934: }
935: if (a[1] == EOL) {
936: if (a[0] == ZERO) {
937: return;
938: }
939: if (a[0] <= ONE) {
940: stcpy (a, b);
941: return;
942: }
943: if (a[0] == TWO) {
944: stcpy (a, b);
945: goto multwo;
946: }
947: }
948: /* get length of strings and convert ASCII to decimal */
949: /* have a look at the signs */
950: if ((mi = (a[0] == MINUS))) {
951: a[0] = ZERO;
952: }
953: if (b[0] == MINUS) {
954: b[0] = ZERO;
955: toggle (mi);
956: }
957: carry = 0;
958: alen = 0;
959: while (a[alen] != EOL) {
960: a[alen] -= ZERO;
961: if (a[alen++] == point)
962: carry = alen;
963: }
964: /* append a point on the right side if there was none */
965: if (--carry < 0) {
966: carry = alen;
967: a[alen++] = point;
968: a[alen] = 0;
969: }
970: ccur = 0;
971: blen = 0;
972: while (b[blen] != EOL) {
973: b[blen] -= ZERO;
974: if (b[blen++] == point)
975: ccur = blen;
976: }
977: if (--ccur < 0) {
978: ccur = blen;
979: b[blen++] = point;
980: b[blen] = 0;
981: }
982: carry += ccur;
983: if (carry > (STRLEN - 3) /*was 252*/) {
984: a[0] = EOL;
985: merr_raise (M75);
986: return;
987: }
988: ccur = clen = alen + blen;
989: /* init c to zero */
990: while (ccur >= 0)
991: c[ccur--] = 0;
992: c[carry] = point;
993:
994: bcur = blen;
995: clen = alen + blen - 1;
996: carry = 0;
997: while (bcur > 0) {
998: if (b[--bcur] == point) {
999: continue;
1000: }
1001: if (c[clen] == point)
1002: clen--;
1003: acur = alen;
1004: ccur = clen--;
1005: while (acur > 0) {
1006: if (a[--acur] == point)
1007: continue;
1008: if (c[--ccur] == point)
1009: --ccur;
1010: tmpx = a[acur] * b[bcur] + c[ccur] + carry;
1011: carry = tmpx / NUMBASE;
1012: c[ccur] = tmpx % NUMBASE;
1013: }
1014: while (carry) {
1015: if (c[--ccur] == point)
1016: ccur--;
1017: if ((c[ccur] += carry) >= NUMBASE) {
1018: c[ccur] -= NUMBASE;
1019: carry = 1;
1020: } else
1021: carry = 0;
1022: }
1023: }
1024: /* copy result to a and convert it */
1025: a[ccur = clen = acur = (alen += blen)] = EOL;
1026: while (--ccur >= 0) {
1027: if (c[ccur] < NUMBASE)
1028: a[ccur] = c[ccur] + ZERO;
1029: else
1030: a[alen = ccur] = POINT;
1031: }
1032: /* oversize string */
1033: if (acur > STRLEN) {
1034: if (a[acur = STRLEN] >= FIVE) {
1035: int l1;
1036:
1037: l1 = STRLEN;
1038: if (a[l1] >= FIVE) {
1039: for (;;)
1040: {
1041: if (a[--l1] == POINT)
1042: l1--;
1043: if (l1 < (a[0] == MINUS)) {
1044: for (l1 = STRLEN; l1 > 0; l1--)
1045: a[l1] = a[l1 - 1];
1046: a[a[0] == MINUS] = ONE;
1047: break;
1048: }
1049: if ((++a[l1]) == (NINE + 1))
1050: a[l1] = ZERO;
1051: else
1052: break;
1053: }
1054: }
1055: }
1056: a[acur] = EOL;
1057: }
1058: /* remove trailing zeroes */
1059: if (acur >= alen) {
1060: while (a[--acur] == ZERO)
1061: a[acur] = EOL;
1062: }
1063: /* remove trailing point */
1064: if (a[acur] == POINT)
1065: a[acur] = EOL;
1066: /* remove leading zeroes */
1067: while (a[mi] == ZERO) {
1068: acur = mi;
1069: while ((a[acur] = a[acur + 1]) != EOL)
1070: acur++;
1071: }
1072: if (a[0] == EOL) {
1073: a[0] = ZERO;
1074: a[1] = EOL;
1075: mi = 0;
1076: }
1077: if (mi) {
1078: if (a[0] != ZERO) {
1079: acur = clen;
1080: while (acur > 0) {
1081: a[acur] = a[acur - 1];
1082: acur--;
1083: }
1084: }
1085: a[0] = MINUS;
1086: }
1087: return;
1088: }
1089: /******************************************************************************
1090: * for a detailed description of the method for the divisions see *
1091: * donald e.knuth 'the art of computer programming' vol.2 p.257 *
1092: ******************************************************************************/
1093: void mdiv (char *uu, char *v, short typ) /* divide string arithmetic */
1094: {
1095: char q[STRLEN + 2 /*was 257*/]; /* quotient */
1096: char u[2*(STRLEN + 1)/*was 512*/];/* intermediate result */
1097: char vv[STRLEN +1 /*was 256*/];
1098: short d,
1099: d1,
1100: k1,
1101: m,
1102: ulen,
1103: vlen,
1104: dpu,
1105: dpv,
1106: guess,
1107: mi,
1108: plus,
1109: v1;
1110: register long int i;
1111: register int j;
1112: register int k;
1113: register int carry = 0;
1114:
1115: #if !defined(_AIX)
1116: if (fp_mode) {
1117: double fp_uu;
1118: double fp_v;
1119:
1120: stcnv_m2c (uu);
1121: stcnv_m2c (v);
1122:
1123: fp_uu = atof (uu);
1124: fp_v = atof (v);
1125:
1126: switch (typ) {
1127:
1128: case '/':
1129: snprintf (uu, STRLEN - 1, fp_conversion, fp_uu / fp_v);
1130: break;
1131:
1132: case '\\':
1133: snprintf (uu, STRLEN - 1, "%ld\201", (long) (fp_uu / fp_v));
1134: break;
1135:
1136: case '#':
1137: snprintf (uu, STRLEN - 1, "%ld\201", (((long) fp_uu) % ((long) fp_v)));
1138: /*snprintf (uu, STRLEN - 1, "%ld\201", ((long) fp_uu < 0 ? (((long) fp_uu % (long) fp_v) + (long) fp_v) % (long) fp_v : (long) fp_uu % (long) fp_v)); */
1139: break;
1140: }
1141:
1142: trim_decimal (uu);
1143:
1144: return;
1145: }
1146: #endif
1147:
1148:
1149: if (merr () > OK)
1150: return; /* avoid nonsense in recursion */
1151: if (uu[0] == ZERO)
1152: return;
1153: #ifdef NEVER
1154: /* should be faster on DIV 2, but causes some error
1155: * in connection with SQRT */
1156: if (v[1] == EOL && typ == '/') {
1157: if (v[0] == ONE)
1158: return;
1159: if (v[0] == TWO) {
1160: carry = 0;
1161: k = (-1);
1162: k1 = (-1);
1163: while ((i = uu[++k]) != EOL) {
1164: if (i < ZERO) {
1165: if (i == POINT) {
1166: k1 = k;
1167: if (k + zprecise < STRLEN)
1168: uu[k + zprecise] = EOL;
1169: }
1170: continue;
1171: }
1172: if (i == EOL)
1173: break;
1174: if (i & 01)
1175: j = NUMBASE;
1176: i = (i + ZERO + carry) / 2;
1177: carry = j;
1178: j = 0;
1179: uu[k] = i;
1180: }
1181: j = (uu[0] == MINUS);
1182: if (uu[j] == ZERO) {
1183: while (j < k) {
1184: uu[j] = uu[j + 1];
1185: j++;
1186: }
1187: k--;
1188: }
1189: if (carry && k < (STRLEN - 2) /*was 253*/) {
1190: if (k1 < 0) {
1191: k1 = k;
1192: uu[k++] = POINT;
1193: }
1194: uu[k++] = FIVE;
1195: uu[k] = EOL;
1196: }
1197: return;
1198: }
1199: }
1200: #endif /* NEVER */
1201: /* look at the signs */
1202: stcpy (u, uu);
1203: mi = 0;
1204: plus = 0;
1205: if (typ != '#') {
1206: if (u[0] == MINUS) {
1207: u[0] = ZERO;
1208: mi = 1;
1209: }
1210: if (v[0] == MINUS) {
1211: v[0] = ZERO;
1212: toggle (mi);
1213: }
1214: } else {
1215: stcpy (vv, v);
1216: if (u[0] == MINUS) {
1217: u[0] = ZERO;
1218: plus = 1;
1219: }
1220: if (v[0] == MINUS) {
1221: v[0] = ZERO;
1222: mi = 1;
1223: toggle (plus);
1224: }
1225: }
1226: /* convert from ASCII to 'number' */
1227: i = 0;
1228: dpv = (-1);
1229: k = 0;
1230: while ((j = v[i]) != EOL) {
1231: j -= ZERO;
1232: if (j == point)
1233: dpv = i;
1234: if (j == 0)
1235: k++;
1236: v[i++] = j;
1237: }
1238:
1239: v[vlen = i] = 0;
1240: v[i + 1] = 0;
1241: v[i + 2] = 0;
1242: if (v[0] != 0) {
1243: while (i >= 0) {
1244: v[i + 1] = v[i];
1245: i--;
1246: }
1247: v[0] = 0;
1248: dpv++;
1249: } else {
1250: vlen--;
1251: }
1252: d1 = 0;
1253:
1254: i = 0;
1255: dpu = (-1);
1256: while (u[i] != EOL) {
1257: u[i] -= ZERO;
1258: if (u[i] == point)
1259: dpu = i;
1260: i++;
1261: }
1262: if (dpu < 0) {
1263: u[dpu = i++] = point;
1264: }
1265: /* u[ulen=i]=0; u[i+1]=0; u[i+2]=0; */
1266: ulen = i;
1267: while (i < 512)
1268: u[i++] = 0;
1269: i = ulen; /* somehow that's necessary - sometimes I check why */
1270: if (u[0] != 0) {
1271: while (i >= 0) {
1272: u[i + 1] = u[i];
1273: i--;
1274: }
1275: u[0] = 0;
1276: dpu++;
1277: } else {
1278: ulen--;
1279: }
1280: if ((vlen + zprecise) > STRLEN && (dpv + zprecise) < vlen)
1281: vlen -= zprecise;
1282:
1283: if (dpv > 0) { /* make v an integer *//* shift v */
1284: d1 = vlen - dpv;
1285: for (i = dpv; i < vlen; i++)
1286: v[i] = v[i + 1];
1287: vlen--;
1288: /* remove leading zeroes */
1289: while (v[1] == 0) {
1290: for (i = 1; i <= vlen; i++)
1291: v[i] = v[i + 1];
1292: vlen--;
1293: }
1294: v[vlen + 1] = 0;
1295: v[vlen + 2] = 0;
1296: /* shift u */
1297: i = dpu;
1298: for (j = 0; j < d1; j++) {
1299: if (i >= ulen) {
1300: u[i + 1] = 0;
1301: ulen++;
1302: }
1303: u[i] = u[i + 1];
1304: i++;
1305: }
1306: u[i] = point;
1307: dpu = i;
1308: }
1309: d = dpu + 1 - ulen;
1310: if (dpv > dpu)
1311: d += dpv - dpu;
1312: if (typ == '/')
1313: d += zprecise;
1314: if ((d + ulen) > STRLEN) {
1315: u[0] = EOL;
1316: merr_raise (M75);
1317: return;
1318: }
1319: while (d > 0) {
1320: u[++ulen] = 0;
1321: d--;
1322: }
1323: /* normalize */
1324: if ((d = NUMBASE / (v[1] + 1)) > 1) {
1325: i = ulen;
1326: carry = 0;
1327: while (i > 0) {
1328: if (u[i] != point) {
1329: carry += u[i] * d;
1330: u[i] = carry % NUMBASE;
1331: carry = carry / NUMBASE;
1332: }
1333: i--;
1334: }
1335: u[0] = carry;
1336: i = vlen;
1337: carry = 0;
1338: while (i > 0) {
1339: carry += v[i] * d;
1340: v[i] = carry % NUMBASE;
1341: carry = carry / NUMBASE;
1342: i--;
1343: }
1344: v[0] = carry;
1345: }
1346: /* initialize */
1347: j = 0;
1348: m = ulen - vlen + 1;
1349: if (m <= dpu)
1350: m = dpu + 1;
1351: for (i = 0; i <= m; q[i++] = ZERO) ;
1352: if (typ == '#') {
1353: m = dpu - vlen;
1354: }
1355: v1 = v[1];
1356:
1357: while (j < m) {
1358: if (u[j] != point) { /* calculate guess */
1359: if ((k = u[j] * NUMBASE + (u[j + 1] == point ? u[j + 2] : u[j + 1])) == 0) {
1360: j++;
1361: continue;
1362: }
1363: k1 = (u[j + 1] == point || u[j + 2] == point ? u[j + 3] : u[j + 2]);
1364: guess = (u[j] == v1 ? (NUMBASE - 1) : k / v1);
1365: if (v[2] * guess > (k - guess * v1) * NUMBASE + k1) {
1366: guess--;
1367: if (v[2] * guess > (k - guess * v1) * NUMBASE + k1)
1368: guess--;
1369: }
1370: /* multiply and subtract */
1371: i = vlen;
1372: carry = 0;
1373: k = j + i;
1374: if (j < dpu && k >= dpu)
1375: k++;
1376: while (k >= 0) {
1377: if (u[k] == point)
1378: k--;
1379: if (i >= 0) {
1380: u[k] -= v[i--] * guess + carry;
1381: } else {
1382: if (carry == 0)
1383: break;
1384: u[k] -= carry;
1385: }
1386: carry = 0;
1387: while (u[k] < 0) {
1388: u[k] += NUMBASE;
1389: carry++;
1390: }
1391: k--;
1392: }
1393: /* test remainder / add back */
1394: if (carry) {
1395: guess--;
1396: i = vlen;
1397: carry = 0;
1398: k = j + i;
1399: if (j < dpu && k >= dpu)
1400: k++;
1401: while (k >= 0) {
1402: if (u[k] == point)
1403: k--;
1404: if (i >= 0) {
1405: u[k] += v[i--] + carry;
1406: } else {
1407: if (carry == 0)
1408: break;
1409: u[k] += carry;
1410: }
1411: carry = u[k] / NUMBASE;
1412: u[k] = u[k] % NUMBASE;
1413: k--;
1414: }
1415: }
1416: q[j++] = guess + ZERO;
1417: u[0] = 0;
1418: } else {
1419: q[j++] = POINT;
1420: }
1421: }
1422: /* unnormalize */
1423: if (typ != '#') {
1424: i = 0;
1425: while (i <= m) {
1426: if ((u[i] = q[i]) == POINT)
1427: dpv = i;
1428: i++;
1429: }
1430: k = vlen;
1431: k1 = dpv;
1432: while (k-- > 0) {
1433: while (k1 <= 0) {
1434: for (i = (++m); i > 0; i--)
1435: u[i] = u[i - 1];
1436: k1++;
1437: u[0] = ZERO;
1438: }
1439: u[k1] = u[k1 - 1];
1440: u[--k1] = POINT;
1441: dpv = k1;
1442: }
1443: u[m] = EOL;
1444: /* rounding */
1445:
1446: if (typ != '/')
1447: u[dpv + 1] = EOL;
1448: else {
1449: k = dpv + zprecise;
1450: k1 = u[k + 1] >= FIVE;
1451: u[k + 1] = EOL;
1452: if (k1) {
1453: do {
1454: if (u[k] != POINT) {
1455: if ((carry = (u[k] == NINE)))
1456: u[k] = ZERO;
1457: else
1458: u[k]++;
1459: }
1460: k--;
1461: } while (carry);
1462: }
1463: }
1464: } else { /* return the remainder */
1465: carry = 0;
1466: if (d > 1) {
1467: for (i = 0; i <= ulen; i++) {
1468: if (u[i] == point) {
1469: u[i] = POINT;
1470: dpu = i;
1471: } else {
1472: u[i] = (j = carry + u[i]) / d + ZERO;
1473: carry = j % d * NUMBASE;
1474: }
1475: }
1476: } else {
1477: for (i = 0; i <= ulen; i++)
1478: if (u[i] == point)
1479: u[dpu = i] = POINT;
1480: else
1481: u[i] += ZERO;
1482: }
1483: u[i] = EOL;
1484: if (d1 > 0) {
1485: u[i + 1] = EOL;
1486: u[i + 2] = EOL;
1487: i = dpu;
1488: for (j = 0; j < d1; j++) {
1489: u[i] = u[i - 1];
1490: i--;
1491: }
1492: u[i] = POINT;
1493: }
1494: }
1495: /* remove trailing zeroes */
1496: i = 0;
1497: k = (-1);
1498: while (u[i] != EOL) {
1499: if (u[i] == POINT)
1500: k = i;
1501: i++;
1502: }
1503: i--;
1504: if (k >= 0) {
1505: while (u[i] == ZERO && i > k)
1506: u[i--] = EOL;
1507: }
1508: /* remove trailing point */
1509: if (u[i] == POINT)
1510: u[i] = EOL;
1511: /* remove leading zeroes */
1512: while (u[0] == ZERO) {
1513: i = 0;
1514: while ((u[i] = u[i + 1]) != EOL)
1515: i++;
1516: }
1517: if (u[0] == EOL) {
1518: u[0] = ZERO;
1519: u[1] = EOL;
1520: mi = 0;
1521: }
1522: if ((mi || plus) && (u[0] != ZERO)) {
1523: if (mi != plus) {
1524: i = stlen (u) + 1;
1525: do {
1526: u[i] = u[i - 1];
1527: i--;
1528: } while (i > 0);
1529: u[0] = MINUS;
1530: }
1531: if (plus)
1532: add (u, vv);
1533: }
1534: stcpy (uu, u);
1535: return;
1536: } /* end div() */
1537: /******************************************************************************/
1538: void power (char *a, char *b) /* raise a to the b-th power */
1539: {
1540: char c[STRLEN + 2/*was 257*/];
1541: char d[4*(STRLEN + 1)/*was 1024*/];/* 257 should be sufficient, but somewhere there */
1542:
1543: /* is a memory leak resulting in wrong results */
1544: /* with fractional powers, e.g. 2**(3/7) */
1545: /* even a value of 513 is too small */
1546: char e[STRLEN + 2/*was 257*/];
1547: register long i;
1548: register long j;
1549:
1550: #if !defined(_AIX)
1551: if (fp_mode) {
1552: double fp_a;
1553: double fp_b;
1554:
1555: stcnv_m2c (a);
1556: stcnv_m2c (b);
1557:
1558: fp_a = atof (a);
1559: fp_b = atof (b);
1560:
1561: snprintf (a, STRLEN - 1, fp_conversion, pow (fp_a, fp_b));
1562:
1563: trim_decimal (a);
1564:
1565: return;
1566: }
1567: #endif
1568:
1569:
1570: if (merr () > OK)
1571: return; /* avoid nonsense in recursion */
1572: /* if zero or one there's not much to do */
1573: if (a[1] == EOL) {
1574: if (a[0] == ZERO) {
1575: if (b[1] == EOL && b[0] == ZERO)
1576: merr_raise (M9);
1577: return;
1578: } /* undef */
1579: if (a[0] == ONE)
1580: return;
1581: }
1582: if (b[0] == MINUS) {
1583: power (a, &b[1]);
1584: if (merr () == M75) {
1585: a[0] = ZERO;
1586: a[1] = EOL;
1587: merr_raise (OK);
1588: return;
1589: }
1590: stcpy (c, a);
1591: a[0] = ONE;
1592: a[1] = EOL;
1593: mdiv (a, c, '/');
1594: return;
1595: }
1596: if (b[1] == EOL) {
1597: switch (b[0]) {
1598: case ZERO:
1599: a[0] = ONE;
1600: a[1] = EOL;
1601: case ONE:
1602: return;
1603: case TWO:
1604: stcpy (c, a);
1605: mul (a, c);
1606: return;
1607: }
1608: }
1609: /* look for decimal point */
1610: e[0] = EOL;
1611: i = 0;
1612: while (b[i] != EOL) {
1613: if (b[i] == POINT) {
1614: if (a[0] == MINUS) {
1615: merr_raise (M9);
1616: return;
1617: } /* undefined case */
1618: if (b[i + 1] == FIVE && b[i + 2] == EOL) { /* half-integer: extra solution */
1619: if (i) {
1620: stcpy (c, b);
1621: add (b, c);
1622: power (a, b);
1623: if (merr () > OK) {
1624: a[0] = ONE;
1625: a[1] = EOL;
1626: return;
1627: }
1628: }
1629: g_sqrt (a);
1630: return;
1631: }
1632: stcpy (e, &b[i]);
1633: b[i] = EOL;
1634: break;
1635: }
1636: i++;
1637: }
1638: stcpy (d, a);
1639: i = intexpr (b);
1640: if (merr () == MXNUM)
1641: return;
1642: /* do it with a small number of multiplications */
1643: /* the number of multiplications is not optimum, but reasonably small */
1644: /* see donald e. knuth "The Art of Computer Programming" Vol.II p.441 */
1645: if (i == 0) {
1646: a[0] = ONE;
1647: a[1] = EOL;
1648: } else {
1649: j = 1;
1650: while (j < i) {
1651: j = j * 2;
1652: if (j < 0) {
1653: merr_raise (MXNUM);
1654: return;
1655: }
1656: }
1657: if (i != j)
1658: j = j / 2;
1659: j = j / 2;
1660: while (j) {
1661: stcpy (c, a);
1662: mul (a, c);
1663: if (i & j) {
1664: stcpy (c, d);
1665: mul (a, c);
1666: }
1667: j = j / 2;
1668: if (merr () == MXNUM)
1669: return;
1670: }
1671: if (e[0] == EOL)
1672: return;
1673: }
1674: /* non integer exponent */
1675: /* state of computation at this point: */
1676: /* d == saved value of a */
1677: /* a == d^^int(b); */
1678: /* e == frac(b); */
1679: {
1680: char Z[STRLEN + 2/*was 257*/];
1681:
1682: /* is fraction the inverse of an integer? */
1683: Z[0] = ONE;
1684: Z[1] = EOL;
1685: stcpy (c, e);
1686: mdiv (Z, c, '/');
1687: i = 0;
1688: for (;;)
1689: {
1690: if ((j = Z[i++]) == EOL) {
1691: j = intexpr (Z);
1692: break;
1693: }
1694: if (j != POINT)
1695: continue;
1696: j = intexpr (Z);
1697: if (Z[i] == NINE)
1698: j++;
1699: break;
1700: }
1701: Z[0] = ONE;
1702: Z[1] = EOL;
1703: lintstr (c, j);
1704: mdiv (Z, c, '/');
1705: /* if integer */
1706:
1707: if (stcmp (Z, e) == 0) {
1708: stcpy (Z, d);
1709: root (Z, j);
1710: if (merr () <= OK) {
1711: mul (a, Z);
1712: return;
1713: } /* on error try other method */
1714: merr_raise (OK);
1715: }
1716: Z[0] = ONE;
1717: Z[1] = EOL;
1718: zprecise += 2;
1719: for (;;)
1720: {
1721: c[0] = TWO;
1722: c[1] = EOL;
1723: mul (e, c);
1724: g_sqrt (d);
1725: if (e[0] == ONE) {
1726: e[0] = ZERO;
1727: numlit (e);
1728: stcpy (c, d);
1729: mul (Z, c);
1730: mround (Z, zprecise);
1731: }
1732: if (e[0] == ZERO)
1733: break;
1734: i = 0;
1735: j = (d[0] == ONE ? ZERO : NINE);
1736: for (;;) {
1737: ++i;
1738: if (d[i] != j && d[i] != '.')
1739: break;
1740: }
1741: if (d[i] == EOL || (i > zprecise))
1742: break;
1743: }
1744: zprecise -= 2;
1745: mul (a, Z);
1746: mround (a, zprecise + 1);
1747: }
1748: return;
1749: } /* end power() */
1750: /******************************************************************************/
1751: void g_sqrt (char *a) /* square root */
1752: {
1753: register int i,
1754: ch;
1755:
1756: if (a[0] == ZERO)
1757: return;
1758: if (a[0] == MINUS) {
1759: merr_raise (M9);
1760: return;
1761: }
1762: if (merr () > OK)
1763: return; /* avoid nonsense in recursion */
1764: {
1765: char tmp1[STRLEN +2 /*was 257*/],
1766: tmp2[STRLEN +2 /*was 257*/],
1767: XX[STRLEN +2 /*was 257*/],
1768: XXX[STRLEN +2 /*was 257*/];
1769:
1770: stcpy (XX, a);
1771: /* look for good initial value */
1772: if (a[0] > ONE || (a[0] == ONE && a[1] != POINT)) {
1773: i = 0;
1774: while ((ch = a[i++]) != EOL) {
1775: if (ch == POINT)
1776: break;
1777: }
1778: if ((i = (i + 1) / 2))
1779: a[i] = EOL;
1780: } else if (a[0] != ONE) {
1781: a[0] = ONE;
1782: a[1] = EOL;
1783: }
1784: /* "Newton's" algorithm with quadratic convergence */
1785: zprecise++;
1786: do {
1787: stcpy (XXX, a);
1788: stcpy (tmp1, XX);
1789: stcpy (tmp2, a);
1790: mdiv (tmp1, tmp2, '/');
1791: if (merr () > OK)
1792: break;
1793: add (a, tmp1);
1794: tmp2[0] = TWO;
1795: tmp2[1] = EOL;
1796: mdiv (a, tmp2, '/');
1797: } while (comp (a, XXX));
1798: zprecise--;
1799: return;
1800: }
1801: } /* end g_sqrt() */
1802: /******************************************************************************/
1803: void root (char *a, long n) /* n.th root */
1804: {
1805: register int i,
1806: ch;
1807:
1808: if (a[0] == ZERO)
1809: return;
1810: if (a[0] == MINUS || n == 0) {
1811: merr_raise (M9);
1812: return;
1813: }
1814: if (merr () > OK)
1815: return; /* avoid nonsense in recursion */
1816: {
1817: char tmp1[STRLEN +2/*was 257*/],
1818: tmp2[STRLEN +2/*was 257*/],
1819: XX[STRLEN +2/*was 257*/],
1820: XXX[STRLEN +2/*was 257*/];
1821: short again;
1822:
1823: stcpy (XX, a);
1824: /* look for good initial value */
1825: if (a[0] > ONE || (a[0] == ONE && a[1] != POINT)) {
1826: i = 0;
1827: while ((ch = a[i++]) != EOL && ch != POINT) ;
1828: if ((i = (i + n - 2) / n) > 0) {
1829: a[0] = THREE;
1830: a[i] = EOL;
1831: }
1832: } else if (a[0] != ONE) {
1833: a[0] = ONE;
1834: a[1] = EOL;
1835: }
1836: /* "Newton's" algorithm with quadratic convergence */
1837:
1838: if (zprecise <= 3)
1839: again = 0; /* speedup div with small zprec. */
1840: else {
1841: again = zprecise;
1842: zprecise = 2;
1843: }
1844: second:;
1845: zprecise++;
1846: for (;;) {
1847: stcpy (XXX, a);
1848: lintstr (tmp1, n - 1);
1849: stcpy (tmp2, a);
1850: power (tmp2, tmp1);
1851: stcpy (tmp1, XX);
1852: mdiv (tmp1, tmp2, '/');
1853: if (merr () > OK)
1854: break;
1855: lintstr (tmp2, n - 1);
1856: mul (a, tmp2);
1857: add (a, tmp1);
1858: lintstr (tmp2, n);
1859: mdiv (a, tmp2, '/');
1860: stcpy (tmp2, a);
1861: mdiv (XXX, tmp2, '/');
1862: tmp2[0] = ONE;
1863: if (zprecise <= 0)
1864: tmp2[1] = EOL;
1865: else {
1866: tmp2[1] = POINT;
1867: for (i = 2; i < zprecise; i++)
1868: tmp2[i] = ZERO;
1869: tmp2[i++] = FIVE;
1870: tmp2[i] = EOL;
1871: }
1872: if (!comp (XXX, tmp2))
1873: continue;
1874: if (zprecise <= 0)
1875: break;
1876: tmp2[0] = POINT;
1877: for (i = 1; i < zprecise; i++)
1878: tmp2[i] = NINE;
1879: tmp2[i - 1] = FIVE;
1880: tmp2[i] = EOL;
1881: if (comp (tmp2, XXX))
1882: break;
1883: }
1884: zprecise--;
1885: if (again) {
1886: zprecise = again;
1887: again = 0;
1888: goto second;
1889: }
1890: return;
1891: }
1892: } /* end root() */
1893: /******************************************************************************/
1894: int numlit (char *str)
1895: {
1896: long j,
1897: mi = 0,
1898: pointx = (-1),
1899: expflg = 0;
1900: long val,
1901: exp = 0L;
1902: int result;
1903: register int i = 0;
1904: register int ch;
1905:
1906: result = 0;
1907: if (str[0] < ONE) {
1908: if (str[0] == EOL) {
1909: str[0] = ZERO;
1910: str[1] = EOL;
1911: return (0);
1912: }
1913: /* compact signs */
1914: while (str[i] == PLUS || str[i] == MINUS)
1915: if (str[i++] == MINUS)
1916: mi++;
1917: if ((j = (mi &= 01)))
1918: str[0] = MINUS;
1919: /* compact leading zeroes */
1920: while (str[i] == ZERO)
1921: i++;
1922: if (i > j)
1923: stcpy (&str[j], &str[i]);
1924: if (str[mi] == EOL) {
1925: str[0] = ZERO;
1926: str[1] = EOL;
1927: return (0);
1928: }
1929: i = mi;
1930: }
1931: while ((ch = str[i]) <= NINE && ch >= ZERO)
1932: i++;
1933: if ((result = unit (&str[i]))) {
1934: if (i == mi) {
1935: str[0] = '0';
1936: i = 1;
1937: }
1938: ch = str[i] = EOL;
1939: }
1940: if (ch == EOL)
1941: return (result);
1942: if (ch == POINT) {
1943: pointx = i++;
1944: while ((ch = str[i]) <= NINE && ch >= ZERO)
1945: i++;
1946: if ((result = unit (&str[i])))
1947: ch = str[i] = EOL;
1948: if (ch == EOL) {
1949: i = pointx;
1950: goto point0;
1951: }
1952: }
1953: /* check for zero mantissa */
1954: j = 0;
1955: while (j < i) {
1956: if (str[j] > ZERO) {
1957: j = (-1);
1958: break;
1959: }
1960: j++;
1961: }
1962: if (j >= 0) {
1963: str[0] = ZERO;
1964: str[1] = EOL;
1965: return (result);
1966: }
1967: /* search for exponent */
1968: for (; ch != EOL; ch = str[++i]) {
1969: if (ch <= NINE && ch >= ZERO) {
1970: if (expflg) {
1971: ch -= ZERO;
1972: val = exp * NUMBASE + ch;
1973: /* check for numeric overflow */
1974: if (((val - ch) / NUMBASE) != exp) {
1975: merr_raise (MXNUM);
1976: return (0);
1977: }
1978: exp = val;
1979: }
1980: continue;
1981: }
1982: if (expflg) {
1983: if (ch == MINUS) {
1984: if (str[i + 1] == '-') {
1985: merr_raise (INVEXPR);
1986: return (0);
1987: }
1988: expflg = (-expflg);
1989: continue;
1990: }
1991: if (ch == PLUS)
1992: continue;
1993: }
1994: if ((result = unit (&str[i])))
1995: ch = str[i] = EOL;
1996: str[i] = EOL;
1997: if (ch == 'E' || (lowerflag && ch == 'e')) {
1998: expflg++;
1999: continue;
2000: }
2001: break;
2002: }
2003: /* append a point at the right end */
2004: if (expflg) {
2005: if (pointx < 0) {
2006: i = mi;
2007: while (str[i] != EOL)
2008: i++;
2009: if (i >= (STRLEN - 1)/*was 254*/) {
2010: str[STRLEN] = EOL;
2011: merr_raise (M75);
2012: return (0);
2013: }
2014: str[pointx = i] = POINT;
2015: str[++i] = EOL;
2016: }
2017: /* if exp shift decimal point */
2018: if (expflg > 0) {
2019: while (exp-- > 0) {
2020: if ((str[pointx] = str[pointx + 1]) == EOL) {
2021: if (pointx >= (STRLEN - 1)/*was 254*/)
2022: break;
2023: str[pointx] = ZERO;
2024: str[pointx + 1] = str[pointx + 2] = EOL;
2025: }
2026: pointx++;
2027: }
2028: if (pointx >= (STRLEN - 1)/*was 254*/) {
2029: str[STRLEN] = EOL;
2030: merr_raise (M75);
2031: return (0);
2032: }
2033: str[pointx] = POINT;
2034: } else { /* (expflg<0) */
2035: while (exp-- > 0) {
2036: if (--pointx < 0) {
2037: i = pointx = 0;
2038: while (str[i++] != EOL) ;
2039: if (i >= (STRLEN - 1)/*was 254*/) {
2040: merr_raise (M75);
2041: return (0);
2042: }
2043: while (i-- > 0)
2044: str[i + 1] = str[i];
2045: str[0] = ZERO;
2046: }
2047: str[pointx + 1] = str[pointx];
2048: }
2049: str[pointx] = POINT;
2050: }
2051: }
2052: if ((i = pointx) >= 0) {
2053:
2054: point0:
2055:
2056: while (str[++i] != EOL) ;
2057:
2058: i--;
2059: while (str[i] == ZERO)
2060: str[i--] = EOL; /* remove trailing zeroes */
2061: if (str[i] == POINT)
2062: str[i] = EOL; /* remove trailing point */
2063: }
2064: if (str[mi] == EOL) {
2065: str[0] = ZERO;
2066: str[1] = EOL;
2067: }
2068: return (result);
2069: }
2070: /******************************************************************************/
2071: int unit (char *str)
2072: /**
2073: * str is interpreted as a currency
2074: * symbol
2075: * return value: 1=EUR, 4=DM, ...
2076: * 0=other */
2077:
2078: {
2079: char ch;
2080:
2081: ch = str[0];
2082: if ((ch < 'A') || (ch > 'P'))
2083: return 0;
2084: switch (ch) {
2085: case 'E':
2086: if (str[1] == 'U' && str[2] == 'R')
2087: return 1;
2088: if (str[1] == 'S' && str[2] == 'P')
2089: return 5;
2090: return 0;
2091: case 'D':
2092: if (str[1] == 'M')
2093: return 4;
2094: if (str[1] == 'E' && str[2] == 'M')
2095: return 4;
2096: return 0;
2097: case 'A':
2098: if (str[1] == 'T' && str[2] == 'S')
2099: return 2;
2100: return 0;
2101: case 'B':
2102: if (str[1] == 'F' && str[2] == 'R')
2103: return 3;
2104: return 0;
2105: case 'F':
2106: if (str[1] == 'F')
2107: return 7;
2108: if (str[1] == 'M' && str[2] == 'K')
2109: return 6;
2110: if (str[1] == 'R' && str[2] == 'F')
2111: return 7;
2112: return 0;
2113: case 'I':
2114: if (str[1] == 'E' && str[2] == 'P')
2115: return 8;
2116: if (str[1] == 'T' && str[2] == 'L')
2117: return 9;
2118: return 0;
2119: case 'N':
2120: if (str[1] == 'L' && str[2] == 'G')
2121: return 10;
2122: return 0;
2123: case 'P':
2124: if (str[1] == 'T' && str[2] == 'E')
2125: return 11;
2126: }
2127: return 0;
2128: }
2129: /******************************************************************************/
2130: long intexpr (char *str)
2131: {
2132: {
2133: register int ch;
2134: register int i = 0;
2135: register long value;
2136: register long newval;
2137: short minus = FALSE;
2138:
2139: if ((ch = str[0]) == MINUS) {
2140: ch = str[1];
2141: minus = TRUE;
2142: i = 1;
2143: }
2144: if (ch >= ZERO && ch <= NINE) {
2145: value = ch - ZERO;
2146: while ((ch = str[++i]) >= ZERO && ch <= NINE) {
2147: newval = value * NUMBASE;
2148: if (newval < 0 || ((newval / NUMBASE) != value)) {
2149: merr_raise (MXNUM);
2150: return (minus ? -1 : 1);
2151: };
2152: newval += ((long) ch - ZERO);
2153: if (newval < 0) {
2154: merr_raise (MXNUM);
2155: return (minus ? -1 : 1);
2156: };
2157: value = newval;
2158: }
2159: if (minus)
2160: value = (-value);
2161: if (ch == EOL)
2162: return value;
2163: } else if (ch != ZERO && ch != PLUS && ch != MINUS && ch != POINT)
2164: return 0L;
2165: }
2166: {
2167: register int ch;
2168: register int i = 0;
2169: register long value;
2170: register long newval;
2171: char tmp[STRLEN +2/*was 257*/];
2172:
2173: stcpy (tmp, str);
2174: numlit (tmp);
2175: i = (tmp[0] == MINUS);
2176: if (merr () == MXNUM)
2177: return (i ? -1 : 1);
2178: value = 0L;
2179: while ((ch = tmp[i++]) >= ZERO && ch <= NINE) {
2180: newval = value * NUMBASE;
2181: if (newval < 0 || ((newval / NUMBASE) != value)) {
2182: merr_raise (MXNUM);
2183: value = 1;
2184: break;
2185: }
2186: newval += ((long) ch - ZERO);
2187: if (newval < 0) {
2188: merr_raise (MXNUM);
2189: value = 1;
2190: break;
2191: }
2192: value = newval;
2193: }
2194: if (tmp[0] == MINUS)
2195: value = (-value);
2196: return value;
2197: }
2198: } /* end of intexpr */
2199: /******************************************************************************/
2200: short int tvexpr (char *str) /* str is interpreted as truth valued expression */
2201: {
2202: if (str[0] > ZERO && str[0] <= NINE) {
2203: str[0] = ONE;
2204: str[1] = EOL;
2205: return TRUE;
2206: }
2207: if (str[1] == EOL) {
2208: str[0] = ZERO;
2209: return FALSE;
2210: } {
2211: register int ch;
2212: register int i = 0;
2213: register int pointx = FALSE;
2214: register int sign = FALSE;
2215:
2216: for (;;)
2217: {
2218: if ((ch = str[i]) > ZERO && ch <= NINE) {
2219: str[0] = ONE;
2220: str[1] = EOL;
2221: return TRUE;
2222: }
2223: i++;
2224: if ((ch == PLUS || ch == MINUS) && sign == FALSE)
2225: continue;
2226: sign = TRUE;
2227: if (ch == ZERO)
2228: continue;
2229: if (ch == POINT && pointx == FALSE) {
2230: sign = TRUE;
2231: pointx = TRUE;
2232: continue;
2233: }
2234: str[0] = ZERO;
2235: str[1] = EOL;
2236: return FALSE;
2237: }
2238: }
2239: }
2240:
2241: /******************************************************************************/
2242: void m_op (char *a, char *b, short op)
2243: {
2244: int atyp,
2245: btyp; /* DM/EUR currency types */
2246: char tmp[(STRLEN + 1)/*was 256*/];
2247:
2248: switch (op & 0177) { /* binary operators */
2249: case '_':
2250: if (op & 0200)
2251: break; /* NOT_OPERAND */
2252: if (stcat (a, b) == 0) {
2253: merr_raise (M75);
2254: }
2255: return;
2256: case '=':
2257: if (stcmp (a, b))
2258: *a = ZERO;
2259: else
2260: *a = ONE;
2261: if (op & 0200)
2262: toggle (*a); /* NOT_OPERAND */
2263: a[1] = EOL;
2264: return;
2265: case '[':
2266: if (*b == EOL || find (a, b))
2267: *a = ONE;
2268: else
2269: *a = ZERO;
2270: if (op & 0200)
2271: toggle (*a); /* NOT_OPERAND */
2272: a[1] = EOL;
2273: return;
2274: case ']':
2275: if (*b == EOL) {
2276: if (*a == EOL)
2277: *a = ZERO;
2278: else
2279: *a = ONE;
2280: }
2281: /* frequent special case */
2282: else if (stcmp (a, b) <= 0)
2283: *a = ZERO;
2284: else
2285: *a = ONE;
2286: if (op & 0200)
2287: toggle (*a); /* NOT_OPERAND */
2288: a[1] = EOL;
2289: return;
2290: } /* end switch */
2291: atyp = numlit (a);
2292: if (op == '-') {
2293: stcpy (&tmp[1], b);
2294: tmp[0] = '-';
2295: op = '+';
2296: } else
2297: stcpy (tmp, b);
2298: btyp = numlit (tmp);
2299: switch (op & 0177) { /* binary operators, NOT OMITTED */
2300: case '+':
2301: if (op & 0200) {
2302: merr_raise (ASSIGNER);
2303: return;
2304: } /* NOT_OPERAND */
2305: #ifdef EUR2DEM
2306: if (atyp != btyp) {
2307: char tmp2[256];
2308:
2309: if ((atyp == 0) && (a[0] == '0'))
2310: atyp = btyp; /* zero is any currency */
2311: if ((btyp == 0) && (tmp[0] == '0'))
2312: btyp = atyp; /* zero is any currency */
2313: if (atyp && btyp) {
2314: if (atyp > 1) {
2315: stcpy (tmp2, EUR2WHR[atyp]);
2316: mul (tmp, tmp2);
2317: }
2318: if (btyp > 1) {
2319: zprecise += 4;
2320: stcpy (tmp2, EUR2WHR[btyp]);
2321: mdiv (tmp, tmp2, '/');
2322: zprecise -= 4;
2323: }
2324: } else if (atyp != btyp && typemmflag) {
2325: merr_raise (TYPEMISMATCH);
2326: return;
2327: }
2328: }
2329: #endif /* EUR2DEM */
2330: add (a, tmp);
2331: plus02:
2332: #ifdef EUR2DEM
2333: if (atyp == 0)
2334: break;
2335: if (atyp != btyp)
2336: cond_round (a, zprecise);
2337: if (atyp)
2338: stcat (a, WHR[atyp]);
2339: #endif /* EUR2DEM */
2340: break;
2341:
2342: case '*':
2343: if (op & 0200) {
2344: merr_raise (ASSIGNER);
2345: return;
2346: } /* NOT_OPERAND */
2347: #ifdef EUR2DEM
2348: if (btyp && atyp == 0) {
2349: atyp = btyp;
2350: btyp = 0;
2351: }
2352: if (atyp && btyp) {
2353: if (typemmflag) {
2354: merr_raise (TYPEMISMATCH);
2355: return;
2356: }
2357: atyp = btyp = 0;
2358: }
2359: #endif /* EUR2DEM */
2360: mul (a, tmp);
2361:
2362: #ifdef EUR2DEM
2363: if (atyp) {
2364: cond_round (a, zprecise);
2365: stcat (a, WHR[atyp]);
2366: }
2367: #endif /* EUR2DEM */
2368: break;
2369:
2370: case '/':
2371: case '\\':
2372: case '#':
2373:
2374: if (op & 0200) {
2375: merr_raise (ASSIGNER);
2376: return;
2377: } /* NOT_OPERAND */
2378: #ifdef EUR2DEM
2379: if (atyp != btyp) {
2380: char tmp2[(STRLEN + 1)/*was 256*/];
2381:
2382: if (atyp && btyp) {
2383: if (op == '#') {
2384: if (atyp > 1) {
2385: stcpy (tmp2, EUR2WHR[atyp]);
2386: mul (tmp, tmp2);
2387: }
2388: if (btyp > 1) {
2389: stcpy (tmp2, EUR2WHR[btyp]);
2390: mdiv (tmp, tmp2, '/');
2391: }
2392: } else {
2393: if (atyp > 1) {
2394: stcpy (tmp2, EUR2WHR[atyp]);
2395: mul (tmp, tmp2);
2396: }
2397: if (btyp > 1) {
2398: stcpy (tmp2, EUR2WHR[btyp]);
2399: mul (a, tmp2);
2400: }
2401: atyp = btyp = 0;
2402: }
2403: } else if (btyp && typemmflag && (*a != '0' || op == '#')) {
2404: merr_raise (TYPEMISMATCH);
2405: return;
2406: }
2407: } else if (op != '#')
2408: atyp = 0;
2409: #endif /* EUR2DEM */
2410: if (tmp[0] == ZERO) {
2411: merr_raise (M9);
2412: break;
2413: }
2414: mdiv (a, tmp, op);
2415: goto plus02;
2416:
2417: case ' ':
2418: power (a, tmp);
2419: break; /* ' ' stands for power */
2420:
2421: case '>':
2422:
2423: #ifdef EUR2DEM
2424: if (atyp != btyp) {
2425: char tmp2[(STRLEN + 1)/*was 256*/];
2426:
2427: if ((atyp == 0) && (a[0] == '0'))
2428: atyp = btyp; /* zero is any currency */
2429: if ((btyp == 0) && (tmp[0] == '0'))
2430: btyp = atyp; /* zero is any currency */
2431: if (atyp && btyp) {
2432: if (atyp > 1) {
2433: stcpy (tmp2, EUR2WHR[atyp]);
2434: mul (tmp, tmp2);
2435: }
2436: if (btyp > 1) {
2437: stcpy (tmp2, EUR2WHR[btyp]);
2438: mul (a, tmp2);
2439: }
2440: cond_round (a, zprecise + 2);
2441: cond_round (tmp, zprecise + 2);
2442: } else if (atyp != btyp && typemmflag) {
2443: merr_raise (TYPEMISMATCH);
2444: return;
2445: }
2446: }
2447: #endif /* EUR2DEM */
2448: if (comp (tmp, a))
2449: *a = ONE;
2450: else
2451: *a = ZERO;
2452: if (op & 0200)
2453: toggle (*a); /* NOT_OPERAND */
2454: a[1] = EOL;
2455: break;
2456:
2457: case '<':
2458:
2459: #ifdef EUR2DEM
2460: if (atyp != btyp) {
2461: char tmp2[(STRLEN + 1)/*was 256*/];
2462:
2463: if ((atyp == 0) && (a[0] == '0'))
2464: atyp = btyp; /* zero is any currency */
2465: if ((btyp == 0) && (tmp[0] == '0'))
2466: btyp = atyp; /* zero is any currency */
2467: if (atyp && btyp) {
2468: if (atyp > 1) {
2469: stcpy (tmp2, EUR2WHR[atyp]);
2470: mul (tmp, tmp2);
2471: }
2472: if (btyp > 1) {
2473: stcpy (tmp2, EUR2WHR[btyp]);
2474: mul (a, tmp2);
2475: }
2476: cond_round (a, zprecise + 2);
2477: cond_round (tmp, zprecise + 2);
2478: } else if (atyp != btyp && typemmflag) {
2479: merr_raise (TYPEMISMATCH);
2480: return;
2481: }
2482: }
2483: #endif /* EUR2DEM */
2484: if (comp (a, tmp))
2485: *a = ONE;
2486: else
2487: *a = ZERO;
2488: if (op & 0200)
2489: toggle (*a); /* NOT_OPERAND */
2490: a[1] = EOL;
2491: break;
2492:
2493: case '&':
2494:
2495: if (tvexpr (a)) {
2496: tvexpr (tmp);
2497: *a = *tmp;
2498: }
2499: if (op & 0200)
2500: toggle (*a); /* NOT_OPERAND */
2501: a[1] = EOL;
2502: break;
2503:
2504: case '!':
2505:
2506: if (tvexpr (a) == FALSE && tvexpr (tmp))
2507: *a = ONE;
2508: if (op & 0200)
2509: toggle (*a); /* NOT_OPERAND */
2510: a[1] = EOL;
2511: break;
2512:
2513: default:
2514: merr_raise (ASSIGNER);
2515:
2516: }
2517: return;
2518: } /* end m_op */
2519: /******************************************************************************/
2520: /* rounding */
2521: /* 'a' is assumed to be a 'canonic' numeric string */
2522: /* it is rounded to 'digits' fractional digits */
2523: void mround (char *a, int digits)
2524: {
2525: int ch,
2526: i,
2527: pointpos,
2528: lena;
2529:
2530: pointpos = -1;
2531: i = 0;
2532: i = 0;
2533: while (a[i] != EOL) {
2534: if (a[i] == POINT)
2535: pointpos = i;
2536: i++;
2537: }
2538: lena = i;
2539: if (pointpos < 0)
2540: pointpos = i;
2541: if ((pointpos + digits + 1) >= i)
2542: return; /* nothing to round */
2543: i = pointpos + digits + 1;
2544: if (a[i] < FIVE) {
2545: a[i] = EOL;
2546: while (a[--i] == ZERO)
2547: a[i] = EOL;
2548: if (a[i] == POINT) {
2549: a[i] = EOL;
2550: if (i == 0 || (i == 1 && a[0] == MINUS))
2551: a[0] = ZERO;
2552: }
2553: return;
2554: }
2555: for (;;)
2556: {
2557: if (i >= pointpos)
2558: a[i] = EOL;
2559: else
2560: a[i] = ZERO;
2561: if (--i < (a[0] == MINUS)) {
2562: for (i = lena; i >= 0; i--)
2563: a[i + 1] = a[i];
2564: a[a[0] == '-'] = ONE;
2565: break;
2566: }
2567: if ((ch = a[i]) == POINT)
2568: continue;
2569: if (a[i] < NINE && ch >= ZERO) {
2570: a[i] = ++ch;
2571: break;
2572: }
2573: }
2574: return;
2575: } /* end mround */
2576:
2577: /* End of $Source: /home/cvsroot/freem/src/operator.c,v $ */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>