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