/*
* $Id: operator.c,v 1.5 2025/03/09 19:50:47 snw Exp $
* operators pattern-match, divide, multiply, add, power
*
*
* Author: Serena Willis <snw@coherent-logic.com>
* Copyright (C) 1998 MUG Deutschland
* Copyright (C) 2020, 2025 Coherent Logic Development LLC
*
*
* This file is part of FreeM.
*
* FreeM is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* FreeM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero Public License for more details.
*
* You should have received a copy of the GNU Affero Public License
* along with FreeM. If not, see <https://www.gnu.org/licenses/>.
*
* $Log: operator.c,v $
* Revision 1.5 2025/03/09 19:50:47 snw
* Second phase of REUSE compliance and header reformat
*
*
* SPDX-FileCopyrightText: (C) 2025 Coherent Logic Development LLC
* SPDX-License-Identifier: AGPL-3.0-or-later
**/
#include "mpsdef.h"
#include <stdlib.h>
#include <math.h>
int unit (char *str);
extern void cond_round (char *a, int digits); /* defined in expr.c */
#define PLUS '+'
#define MINUS '-'
#define POINT '.'
#define point (POINT-ZERO)
#define ZERO '0'
#define ONE (ZERO+1)
#define TWO (ZERO+2)
#define THREE (ZERO+3)
#define FIVE (ZERO+(NUMBASE/2))
#define NINE (ZERO+NUMBASE-1)
#define NUMBASE 10
short int
pattern (char *a, char *b) /* evaluates a ? b */
{
short levels; /* depth of stack */
register int patx; /* match stack pointer */
short notpatclass; /* pattern class negation */
char *ptrpcd[PATDEPTH], /* pointers to patcode */
*position[PATDEPTH]; /* position of matching substring */
short mincnt[PATDEPTH], /* minimum number of matches */
maxcnt[PATDEPTH], /* maximum number of matches */
actcnt[PATDEPTH]; /* actual count of matches */
short Pflag,
Pchar; /* status in pattern alternation */
short altc; /* alternation counter */
short altcnt[PATDEPTH]; /* gr.pat.alternation counters */
unsigned char gpmin[PATDEPTH][PATDEPTH][255]; /* grouped pattern minimum lengthes */
char *gp_position[PATDEPTH][PATDEPTH]; /* grouped patt.pos.of substr */
char *ptrtom; /* pointer to match code */
char patcode;
int ch;
int i;
pattrnflag = Pflag = FALSE; /* incomplete match flag */
pattrnchar = Pchar = EOL; /* incomplete match supplement */
notpatclass = FALSE; /* pattern class negation */
patx = 0;
while (*b != EOL) { /* get minimum repeat count */
mincnt[patx] = 0;
maxcnt[patx] = 255;
altcnt[patx] = (-1);
if (*b != '.') {
ch = (*b++) - '0';
while (*b >= '0' && *b <= '9') {
ch *= 10;
ch += (*b++) - '0';
}
mincnt[patx] = ch;
if (*b != '.')
maxcnt[patx] = ch;
}
/* get maximum repeat count */
if (*b == '.') {
b++;
if (*b >= '0' && *b <= '9') {
ch = (*b++) - '0';
while (*b >= '0' && *b <= '9') {
ch *= 10;
ch += (*b++) - '0';
}
maxcnt[patx] = ch;
}
}
if (maxcnt[patx] < mincnt[patx])
return '2'; /* just impossible! */
ptrpcd[patx] = b;
actcnt[patx] = 0;
position[patx] = 0;
/* scan strlit, ignore it when empty */
if (*b == '"' || *b == 'z' || (*b == '\'' && *(b + 1) == '"')) {
if (*(++b) == DELIM) {
b++;
continue;
}
while (*(++b) != DELIM) ;
b++;
} else if (*b == '(') {
i = 1;
b++;
while ((ch = *b) != EOL) {
b++;
if (ch == '"') {
while (*(++b) != DELIM) ;
}
if (ch == '(') {
i++;
continue;
}
if (ch == ')') {
i--;
if (i < 1)
break;
}
}
} else
while (*(++b) >= 'A') ;
if (++patx >= (PATDEPTH - 1))
return '3'; /* stack overflow */
}
levels = patx;
if (*(b - 1) == 'e' && mincnt[levels - 1] == 0 && maxcnt[levels - 1] == 255)
*(b - 1) = '~'; /* frequent special case: last pattern is '.E' */
mincnt[levels] = maxcnt[levels] = 1; /* sentinel, does never match */
actcnt[levels] = 0;
ptrpcd[levels] = b; /* (*b==EOL) */
patx = 0;
while (patx <= levels) {
while (actcnt[patx] < mincnt[patx]) {
actcnt[patx]++;
if (*a == EOL) {
pattrnflag = TRUE; /* incomplete match flag */
if (patx >= levels) {
pattrnchar = EOL;
return '1';
}
if (patx > 0) {
if (actcnt[patx - 1] != maxcnt[patx - 1])
return '0';
/* after alternation we are not sure about */
/* that supplement character */
if (*(ptrpcd[patx - 1]) == '(') {
pattrnchar = EOL;
return '0';
}
}
if (*(ptrpcd[patx]) == '"')
pattrnchar = *(ptrpcd[patx] + 1);
return '0';
}
for (;;)
{
/***begin section: does that char match current pattern code ***/
ptrtom = ptrpcd[patx];
ch = (*a);
for (;;)
{
patcode = (*ptrtom++);
if ((notpatclass = (patcode == '\'')))
patcode = (*ptrtom++);
switch (patcode) { /* we live in an ASCII/ISO world !! */
case 'c':
if (((ch < SP && ch >= NUL)
|| ch == DEL) != notpatclass)
goto match;
break;
case 'n':
if ((ch <= '9' && ch >= '0') != notpatclass)
goto match;
break;
case 'p':
if (((ch >= SP && ch <= '/') ||
(ch >= ':' && ch <= '@') ||
(ch >= '[' && ch <= '`') ||
(ch >= '{' && ch <= '~') ||
(ch == '\200')) != notpatclass)
goto match;
break;
case 'a':
if (((ch >= 'A' && ch <= 'Z') ||
(ch >= 'a' && ch <= 'z')) != notpatclass)
goto match;
break;
case 'l':
if ((ch >= 'a' && ch <= 'z') != notpatclass)
goto match;
break;
case 'u':
if ((ch >= 'A' && ch <= 'Z') != notpatclass)
goto match;
break;
case 'e':
if (!notpatclass)
goto match;
break;
case '"':
i = 0;
while (a[i++] == (*ptrtom++)) ;
if ((*--ptrtom) == DELIM) {
if (notpatclass)
goto nomatch;
b = ptrpcd[patx] + 1;
while (*b++ != DELIM)
a++;
goto match0;
}
if (notpatclass) {
i--;
while (*ptrtom++ != DELIM) {
if (a[i++] == EOL)
goto nomatch;
}
b = ptrpcd[patx] + 2;
while (*b++ != DELIM)
a++;
goto match0;
}
if (a[i - 1] == EOL) {
pattrnflag = TRUE;
pattrnchar = *ptrtom;
}
goto nomatch;
case '~':{
pattrnchar = EOL; /* '.E' as last pat_atom */
pattrnflag = TRUE;
return '1';
}
/* grouped pattern match */
case '(':{
char aa[256];
char bb[256];
int i1,
min,
max;
short pflag;
short pchar;
if (Pflag) {
pflag = Pflag;
pchar = Pchar;
} else {
pflag = FALSE;
pchar = EOL;
}
if (altcnt[patx] < 0) {
for (altc = 0; altc < PATDEPTH; altc++)
gpmin[patx][altc][1] = 0;
}
altcnt[patx] = 0;
alternation:;
i = 0;
i1 = 1;
while (i1) {
bb[i] = *ptrtom++;
if (bb[i] == '"') {
while ((bb[++i] = (*ptrtom++)) != DELIM) ;
}
if (bb[i] == '(')
i1++;
if (bb[i] == ')')
i1--;
if (bb[i] == ',' && i1 == 1)
i1--;
i++;
}
bb[--i] = EOL;
pminmax (bb, &min, &max);
if ((i1 = gpmin[patx][altcnt[patx]][actcnt[patx]]) < min)
gpmin[patx][altcnt[patx]][actcnt[patx]] = i1 = min;
gpmin[patx][altcnt[patx]][actcnt[patx] + 1] = 0;
/* too much charaters to get a match! */
if (i1 > max) {
if (*(ptrtom - 1) == ',') {
altcnt[patx]++;
goto alternation;
}
pattrnflag = pflag;
pattrnchar = pchar;
goto nomatch;
}
/* if number of chars too small, try anyway */
/* to get info for "incomplete" match */
for (i = 0; i < i1; i++)
if ((aa[i] = a[i]) == EOL)
break;
gp_position[patx][actcnt[patx]] = a;
for (;;)
{
aa[i] = EOL;
i1 = pattern (aa, bb);
if (i1 == '1') {
gpmin[patx][altcnt[patx]][actcnt[patx]] = i;
a += i;
goto match0;
}
if (i1 != '0')
return i1;
if (pattrnflag) {
if (pflag == FALSE)
pchar = pattrnchar;
else if (pchar != pattrnchar)
pchar = EOL;
pflag = TRUE;
}
if (!pattrnflag) {
if (*(ptrtom - 1) == ',') {
altcnt[patx]++;
goto alternation;
}
pattrnflag = pflag;
pattrnchar = pchar;
goto nomatch;
}
if (a[i] == EOL) {
Pflag = pflag;
Pchar = pchar;
if (*(ptrtom - 1) == ',') {
altcnt[patx]++;
goto alternation;
}
pattrnflag = pflag;
pattrnchar = pchar;
return '0';
}
aa[i] = a[i];
i++;
}
}
/* match one of listed characters ?1Z"string" */
case 'z':
for (;;)
{
if ((*++ptrtom) == DELIM) {
if (notpatclass)
goto match;
goto nomatch;
}
if (ch != *ptrtom) {
if (*(ptrtom + 1) == '.' && *(ptrtom + 2) == '.') {
if (ch < *ptrtom ||
(ch > *(ptrtom + 3) && *(ptrtom + 3) != DELIM)) {
ptrtom += 2;
continue;
}
} else
continue;
}
while (*++ptrtom != DELIM) ;
if (notpatclass)
goto nomatch;
goto match;
}
/* loadable matches */
case 'C':
i = 0;
while (zmc[i] != EOL) {
if (zmc[i] == ch && !notpatclass)
goto match;
i++;
}
if (notpatclass)
goto match;
break;
case 'N':
i = 0;
while (zmn[i] != EOL) {
if (zmn[i] == ch && !notpatclass)
goto match;
i++;
}
if (notpatclass)
goto match;
break;
case 'P':
i = 0;
while (zmp[i] != EOL) {
if (zmp[i] == ch && !notpatclass)
goto match;
i++;
}
if (notpatclass)
goto match;
break;
case 'A':
i = 0;
while (zmu[i] != EOL) {
if (zmu[i] == ch && !notpatclass)
goto match;
i++;
}
case 'L':
i = 0;
while (zml[i] != EOL) {
if (zml[i] == ch && !notpatclass)
goto match;
i++;
}
if (notpatclass)
goto match;
break;
case 'U':
i = 0;
while (zmu[i] != EOL) {
if (zmu[i] == ch && !notpatclass)
goto match;
i++;
}
if (notpatclass)
goto match;
break;
default:
goto nomatch;
} /* end_switch */
} /* end repeat */
/*** end section: does that char match current pattern atom ***/
nomatch:;
if (patcode == '(') {
for (altc = 0; altc <= altcnt[patx]; altc++)
gpmin[patx][altc][actcnt[patx]] = 0;
if (--actcnt[patx] > 0) {
for (altc = 0; altc <= altcnt[patx]; altc++)
gpmin[patx][altc][actcnt[patx]]++;
a = gp_position[patx][actcnt[patx]]; /* try previous patterns again */
continue;
}
}
do {
actcnt[patx] = 0;
if (--patx < 0)
return '0'; /* stack exhausted */
if (*(ptrpcd[patx]) == '(') {
if (actcnt[patx] >= maxcnt[patx]) {
++actcnt[patx];
patcode = '(';
goto nomatch;
}
}
} while (++actcnt[patx] > maxcnt[patx]);
a = position[patx]; /* try previous patterns again */
} /* end repeat */
match:;
a++;
match0:;
}
position[patx++] = a; /* pos after last match */
}
return '0';
} /* end of pattern */
/******************************************************************************/
void pminmax (char *str, int *min, int *max)
{
int mininc,
maxinc,
i,
ch;
*min = 0;
*max = 0;
mininc = 0;
maxinc = 0;
i = 0;
ch = 0;
while (str[i] != EOL) {
if (str[i] != '.') { /* scan minimum repeat count */
ch = (str[i++]) - '0';
while (str[i] >= '0' && str[i] <= '9') {
ch *= 10;
ch += (str[i++]) - '0';
}
mininc = ch;
maxinc = ch;
} else {
mininc = 0;
maxinc = 255;
}
if (str[i] == '.') { /* scan maximum repeat count */
i++;
if (str[i] >= '0' && str[i] <= '9') {
ch = (str[i++]) - '0';
while (str[i] >= '0' && str[i] <= '9') {
ch *= 10;
ch += (str[i]++) - '0';
}
} else
ch = 255;
maxinc = ch;
}
/* skip pattern codes */
if (str[i] == '"') {
int cnt;
cnt = 0;
while (str[++i] != DELIM)
cnt++;
mininc = mininc * cnt;
maxinc = maxinc * cnt;
}
if (str[i] == 'z' || str[i] == '"') {
while (str[++i] != DELIM) ;
i++;
} else if (str[i] == '(') {
char tmp[256];
char *tcur;
int tmin,
tmax,
Tmin,
Tmax,
i1;
tmin = 255;
tmax = 0;
alternation:;
i1 = 1;
tcur = tmp;
while (i1) {
ch = str[++i];
*tcur++ = ch;
if (ch == '"')
while ((*tcur++ = str[++i]) != DELIM) ;
if (ch == '(')
i1++;
if (ch == ')')
i1--;
if (ch == ',' && i1 == 1)
i1--;
}
*(--tcur) = EOL;
pminmax (tmp, &Tmin, &Tmax);
if (Tmin < tmin)
tmin = Tmin;
if (Tmax > tmax)
tmax = Tmax;
if (str[i] == ',')
goto alternation;
i++;
mininc *= tmin;
maxinc *= tmax;
} else
while (str[++i] >= 'A') ;
*min += mininc;
*max += maxinc;
}
if (*max > 255)
*max = 255;
return;
} /* end pminmax() */
/******************************************************************************/
void add (char *a, char *b) /* string arithmetic a+=b; */
{
if (b[0] == ZERO)
return;
if (a[0] == ZERO) {
stcpy (a, b);
return;
} {
long dpa, /* decimal point of 'a' */
dpb, /* decimal point of 'b' */
lena, /* length of 'a' */
lenb; /* length of 'b' */
char mi; /* minus flag */
short sign; /* sign flag if a<0<b sign=-1; */
/* if a>0>b sign=1; */
/* else sign=0; */
register int i;
register int ch;
register int j;
register int carry;
#if !defined(_AIX)
if (fp_mode) {
double fp_a;
double fp_b;
stcnv_m2c (a);
stcnv_m2c (b);
fp_a = atof (a);
fp_b = atof (b);
snprintf (a, STRLEN - 1, fp_conversion, fp_a + fp_b);
trim_decimal (a);
return;
}
#endif
/* look at the signs */
mi = 0;
sign = 0;
if (a[0] == b[0] && a[0] == MINUS) {
mi++;
a[0] = b[0] = ZERO;
} else if (a[0] == MINUS) {
sign--;
a[0] = NINE;
i = 0;
while ((ch = a[++i]) != EOL)
if (ch != POINT)
a[i] = ZERO + NINE - ch;
a[--i]++;
} else if (b[0] == MINUS) {
sign++;
b[0] = NINE;
i = 0;
while ((ch = b[++i]) != EOL)
if (ch != POINT)
b[i] = ZERO + NINE - ch;
b[--i]++;
}
/* search decimal points and length */
dpa = dpb = (-1);
i = 0;
while (a[i] != EOL) {
if (a[i] == POINT)
dpa = i;
i++;
}
lena = i;
if (dpa < 0)
dpa = i;
again:;
i = 0;
while (b[i] != EOL) {
if (b[i] == POINT)
dpb = i;
i++;
}
lenb = i;
if (dpb < 0)
dpb = i;
if (i == 1) {
if (b[0] == ONE && sign == 0 && dpa > 0) { /* frequent special case: add 1 */
i = dpa - 1;
while (++a[i] > NINE) {
a[i--] = ZERO;
if (i < 0) {
i = lena;
while (i >= 0) {
a[i + 1] = a[i];
i--;
}
a[0] = ONE;
return;
}
}
return;
}
}
/* copy additional trailing digits from b to a */
if (lenb - dpb > lena - dpa) {
j = dpa - dpb;
if (lenb + j > STRLEN) { /* round off that monster ! */
i = STRLEN - j;
if (b[i] < FIVE) {
b[i] = EOL;
lenb--;
while (b[--i] == ZERO) {
b[i] = EOL;
lenb--;
}
} else {
for (;;)
{
if (i >= dpb) {
b[i] = EOL;
lenb--;
} else
b[i] = ZERO;
if (--i < 0) {
for (i = lenb; i >= 0; i--)
b[i + 1] = b[i];
b[0] = ONE;
dpb = ++lenb;
break;
}
if ((ch = b[i]) == POINT) {
dpb = i;
continue;
}
if (ch < NINE && ch >= ZERO) {
b[i] = ++ch;
break;
}
}
}
goto again; /* look what's left from b */
}
lenb = i = lena - dpa + dpb;
j = lena;
while ((a[j++] = b[i++]) != EOL) ;
lena = (--j);
b[lenb] = EOL;
}
/* $justify a or b */
i = dpa - dpb;
if (i < 0) {
j = lena;
if ((i = (lena -= i)) > (STRLEN - 2) /*was 253*/) {
merr_raise (M75);
return;
}
ch = (sign >= 0 ? ZERO : NINE);
while (j >= 0)
a[i--] = a[j--];
while (i >= 0)
a[i--] = ch;
dpa = dpb;
} else if (i > 0) {
j = lenb;
if ((lenb = (i += lenb)) > (STRLEN - 2)/*was 253*/) {
merr_raise (M75);
return;
}
ch = (sign <= 0 ? ZERO : NINE);
while (j >= 0)
b[i--] = b[j--];
while (i >= 0)
b[i--] = ch;
dpb = dpa;
}
/* now add */
carry = 0;
for (i = lenb - 1; i >= 0; i--) {
if ((ch = a[i]) == POINT)
continue;
ch += b[i] - ZERO + carry;
if ((carry = (ch > NINE)))
ch -= NUMBASE;
a[i] = ch;
}
while (a[lena] != EOL)
lena++;
if (carry) {
if ((i = (++lena)) > (STRLEN - 2)/*was 253*/) {
merr_raise (M75);
return;
}
while (i > 0) {
a[i] = a[i - 1];
i--;
}
a[0] = ONE;
}
if (sign) {
if (a[0] == ONE) {
a[0] = ZERO;
} else {
i = 0;
carry = 0;
while ((ch = a[++i]) != EOL)
if (ch != POINT)
a[i] = ZERO + NINE - ch;
while (--i > 0) {
if (a[i] != POINT) {
if (++a[i] <= NINE)
break;
a[i] = ZERO;
}
}
mi = 1;
a[0] = ZERO;
}
while (a[mi] == ZERO) {
stcpy (&a[mi], &a[mi + 1]);
dpa--;
}
if (dpa < 0)
dpa = 0;
}
/* remove trailing zeroes */
i = dpa;
while (a[i] != EOL)
i++;
if (--i > dpa) {
while (a[i] == ZERO)
a[i--] = EOL;
}
/* remove trailing point */
if (a[i] == POINT)
a[i] = EOL;
if (mi) {
if (a[0] != ZERO) {
i = 0;
while (a[i++] != EOL) ;
while (i > 0) {
a[i] = a[i - 1];
i--;
}
}
a[0] = MINUS;
}
if (a[mi] == EOL) {
a[0] = ZERO;
a[1] = EOL;
}
return;
}
}
/******************************************************************************/
void mul (char *a, char *b) /* string arithmetic a=a*b */
{
char c[2*(STRLEN+1) /*was 512*/];
short alen,
blen,
clen,
mi,
tmpx;
register int acur;
register int bcur;
register int ccur;
register int carry;
#if !defined(_AIX)
if (fp_mode) {
double fp_a;
double fp_b;
stcnv_m2c (a);
stcnv_m2c (b);
fp_a = atof (a);
fp_b = atof (b);
snprintf (a, STRLEN - 1, fp_conversion, fp_a * fp_b);
trim_decimal (a);
return;
}
#endif
if (merr () > OK)
return; /* avoid nonsense in recursion */
/* if zero or one there's not much to do */
if (b[1] == EOL) {
if (b[0] == ZERO) {
a[0] = ZERO;
a[1] = EOL;
return;
}
if (b[0] <= ONE)
return;
if (b[0] == TWO) {
multwo:acur = 0;
while (a[++acur] != EOL) ;
mi = (a[acur - 1] == FIVE);
carry = 0;
ccur = acur;
while (acur >= 0) {
if ((bcur = a[--acur]) < ZERO)
continue;
bcur = bcur * 2 - ZERO + carry;
carry = 0;
if (bcur > NINE) {
carry = 1;
bcur -= NUMBASE;
}
a[acur] = bcur;
}
if (carry) {
acur = ccur;
if (acur > (STRLEN - 1)/*was 254*/) {
merr_raise (M75);
return;
}
while (acur >= 0) {
a[acur + 1] = a[acur];
acur--;
}
a[a[0] == MINUS] = ONE;
}
if (mi) {
if (carry)
ccur++;
acur = 0;
while (acur < ccur)
if (a[acur++] == POINT) {
a[--ccur] = EOL;
if (acur == ccur)
a[--ccur] = EOL;
return;
}
}
return;
}
}
if (a[1] == EOL) {
if (a[0] == ZERO) {
return;
}
if (a[0] <= ONE) {
stcpy (a, b);
return;
}
if (a[0] == TWO) {
stcpy (a, b);
goto multwo;
}
}
/* get length of strings and convert ASCII to decimal */
/* have a look at the signs */
if ((mi = (a[0] == MINUS))) {
a[0] = ZERO;
}
if (b[0] == MINUS) {
b[0] = ZERO;
toggle (mi);
}
carry = 0;
alen = 0;
while (a[alen] != EOL) {
a[alen] -= ZERO;
if (a[alen++] == point)
carry = alen;
}
/* append a point on the right side if there was none */
if (--carry < 0) {
carry = alen;
a[alen++] = point;
a[alen] = 0;
}
ccur = 0;
blen = 0;
while (b[blen] != EOL) {
b[blen] -= ZERO;
if (b[blen++] == point)
ccur = blen;
}
if (--ccur < 0) {
ccur = blen;
b[blen++] = point;
b[blen] = 0;
}
carry += ccur;
if (carry > (STRLEN - 3) /*was 252*/) {
a[0] = EOL;
merr_raise (M75);
return;
}
ccur = clen = alen + blen;
/* init c to zero */
while (ccur >= 0)
c[ccur--] = 0;
c[carry] = point;
bcur = blen;
clen = alen + blen - 1;
carry = 0;
while (bcur > 0) {
if (b[--bcur] == point) {
continue;
}
if (c[clen] == point)
clen--;
acur = alen;
ccur = clen--;
while (acur > 0) {
if (a[--acur] == point)
continue;
if (c[--ccur] == point)
--ccur;
tmpx = a[acur] * b[bcur] + c[ccur] + carry;
carry = tmpx / NUMBASE;
c[ccur] = tmpx % NUMBASE;
}
while (carry) {
if (c[--ccur] == point)
ccur--;
if ((c[ccur] += carry) >= NUMBASE) {
c[ccur] -= NUMBASE;
carry = 1;
} else
carry = 0;
}
}
/* copy result to a and convert it */
a[ccur = clen = acur = (alen += blen)] = EOL;
while (--ccur >= 0) {
if (c[ccur] < NUMBASE)
a[ccur] = c[ccur] + ZERO;
else
a[alen = ccur] = POINT;
}
/* oversize string */
if (acur > STRLEN) {
if (a[acur = STRLEN] >= FIVE) {
int l1;
l1 = STRLEN;
if (a[l1] >= FIVE) {
for (;;)
{
if (a[--l1] == POINT)
l1--;
if (l1 < (a[0] == MINUS)) {
for (l1 = STRLEN; l1 > 0; l1--)
a[l1] = a[l1 - 1];
a[a[0] == MINUS] = ONE;
break;
}
if ((++a[l1]) == (NINE + 1))
a[l1] = ZERO;
else
break;
}
}
}
a[acur] = EOL;
}
/* remove trailing zeroes */
if (acur >= alen) {
while (a[--acur] == ZERO)
a[acur] = EOL;
}
/* remove trailing point */
if (a[acur] == POINT)
a[acur] = EOL;
/* remove leading zeroes */
while (a[mi] == ZERO) {
acur = mi;
while ((a[acur] = a[acur + 1]) != EOL)
acur++;
}
if (a[0] == EOL) {
a[0] = ZERO;
a[1] = EOL;
mi = 0;
}
if (mi) {
if (a[0] != ZERO) {
acur = clen;
while (acur > 0) {
a[acur] = a[acur - 1];
acur--;
}
}
a[0] = MINUS;
}
return;
}
/******************************************************************************
* for a detailed description of the method for the divisions see *
* donald e.knuth 'the art of computer programming' vol.2 p.257 *
******************************************************************************/
void mdiv (char *uu, char *v, short typ) /* divide string arithmetic */
{
char q[STRLEN + 2 /*was 257*/]; /* quotient */
char u[2*(STRLEN + 1)/*was 512*/];/* intermediate result */
char vv[STRLEN +1 /*was 256*/];
short d,
d1,
k1,
m,
ulen,
vlen,
dpu,
dpv,
guess,
mi,
plus,
v1;
register long int i;
register int j;
register int k;
register int carry = 0;
#if !defined(_AIX)
if (fp_mode) {
double fp_uu;
double fp_v;
stcnv_m2c (uu);
stcnv_m2c (v);
fp_uu = atof (uu);
fp_v = atof (v);
switch (typ) {
case '/':
snprintf (uu, STRLEN - 1, fp_conversion, fp_uu / fp_v);
break;
case '\\':
snprintf (uu, STRLEN - 1, "%ld\201", (long) (fp_uu / fp_v));
break;
case '#':
snprintf (uu, STRLEN - 1, "%ld\201", (((long) fp_uu) % ((long) fp_v)));
//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));
break;
}
trim_decimal (uu);
return;
}
#endif
if (merr () > OK)
return; /* avoid nonsense in recursion */
if (uu[0] == ZERO)
return;
#ifdef NEVER
/* should be faster on DIV 2, but causes some error
* in connection with SQRT */
if (v[1] == EOL && typ == '/') {
if (v[0] == ONE)
return;
if (v[0] == TWO) {
carry = 0;
k = (-1);
k1 = (-1);
while ((i = uu[++k]) != EOL) {
if (i < ZERO) {
if (i == POINT) {
k1 = k;
if (k + zprecise < STRLEN)
uu[k + zprecise] = EOL;
}
continue;
}
if (i == EOL)
break;
if (i & 01)
j = NUMBASE;
i = (i + ZERO + carry) / 2;
carry = j;
j = 0;
uu[k] = i;
}
j = (uu[0] == MINUS);
if (uu[j] == ZERO) {
while (j < k) {
uu[j] = uu[j + 1];
j++;
}
k--;
}
if (carry && k < (STRLEN - 2) /*was 253*/) {
if (k1 < 0) {
k1 = k;
uu[k++] = POINT;
}
uu[k++] = FIVE;
uu[k] = EOL;
}
return;
}
}
#endif /* NEVER */
/* look at the signs */
stcpy (u, uu);
mi = 0;
plus = 0;
if (typ != '#') {
if (u[0] == MINUS) {
u[0] = ZERO;
mi = 1;
}
if (v[0] == MINUS) {
v[0] = ZERO;
toggle (mi);
}
} else {
stcpy (vv, v);
if (u[0] == MINUS) {
u[0] = ZERO;
plus = 1;
}
if (v[0] == MINUS) {
v[0] = ZERO;
mi = 1;
toggle (plus);
}
}
/* convert from ASCII to 'number' */
i = 0;
dpv = (-1);
k = 0;
while ((j = v[i]) != EOL) {
j -= ZERO;
if (j == point)
dpv = i;
if (j == 0)
k++;
v[i++] = j;
}
v[vlen = i] = 0;
v[i + 1] = 0;
v[i + 2] = 0;
if (v[0] != 0) {
while (i >= 0) {
v[i + 1] = v[i];
i--;
}
v[0] = 0;
dpv++;
} else {
vlen--;
}
d1 = 0;
i = 0;
dpu = (-1);
while (u[i] != EOL) {
u[i] -= ZERO;
if (u[i] == point)
dpu = i;
i++;
}
if (dpu < 0) {
u[dpu = i++] = point;
}
/* u[ulen=i]=0; u[i+1]=0; u[i+2]=0; */
ulen = i;
while (i < 512)
u[i++] = 0;
i = ulen; /* somehow that's necessary - sometimes I check why */
if (u[0] != 0) {
while (i >= 0) {
u[i + 1] = u[i];
i--;
}
u[0] = 0;
dpu++;
} else {
ulen--;
}
if ((vlen + zprecise) > STRLEN && (dpv + zprecise) < vlen)
vlen -= zprecise;
if (dpv > 0) { /* make v an integer *//* shift v */
d1 = vlen - dpv;
for (i = dpv; i < vlen; i++)
v[i] = v[i + 1];
vlen--;
/* remove leading zeroes */
while (v[1] == 0) {
for (i = 1; i <= vlen; i++)
v[i] = v[i + 1];
vlen--;
}
v[vlen + 1] = 0;
v[vlen + 2] = 0;
/* shift u */
i = dpu;
for (j = 0; j < d1; j++) {
if (i >= ulen) {
u[i + 1] = 0;
ulen++;
}
u[i] = u[i + 1];
i++;
}
u[i] = point;
dpu = i;
}
d = dpu + 1 - ulen;
if (dpv > dpu)
d += dpv - dpu;
if (typ == '/')
d += zprecise;
if ((d + ulen) > STRLEN) {
u[0] = EOL;
merr_raise (M75);
return;
}
while (d > 0) {
u[++ulen] = 0;
d--;
}
/* normalize */
if ((d = NUMBASE / (v[1] + 1)) > 1) {
i = ulen;
carry = 0;
while (i > 0) {
if (u[i] != point) {
carry += u[i] * d;
u[i] = carry % NUMBASE;
carry = carry / NUMBASE;
}
i--;
}
u[0] = carry;
i = vlen;
carry = 0;
while (i > 0) {
carry += v[i] * d;
v[i] = carry % NUMBASE;
carry = carry / NUMBASE;
i--;
}
v[0] = carry;
}
/* initialize */
j = 0;
m = ulen - vlen + 1;
if (m <= dpu)
m = dpu + 1;
for (i = 0; i <= m; q[i++] = ZERO) ;
if (typ == '#') {
m = dpu - vlen;
}
v1 = v[1];
while (j < m) {
if (u[j] != point) { /* calculate guess */
if ((k = u[j] * NUMBASE + (u[j + 1] == point ? u[j + 2] : u[j + 1])) == 0) {
j++;
continue;
}
k1 = (u[j + 1] == point || u[j + 2] == point ? u[j + 3] : u[j + 2]);
guess = (u[j] == v1 ? (NUMBASE - 1) : k / v1);
if (v[2] * guess > (k - guess * v1) * NUMBASE + k1) {
guess--;
if (v[2] * guess > (k - guess * v1) * NUMBASE + k1)
guess--;
}
/* multiply and subtract */
i = vlen;
carry = 0;
k = j + i;
if (j < dpu && k >= dpu)
k++;
while (k >= 0) {
if (u[k] == point)
k--;
if (i >= 0) {
u[k] -= v[i--] * guess + carry;
} else {
if (carry == 0)
break;
u[k] -= carry;
}
carry = 0;
while (u[k] < 0) {
u[k] += NUMBASE;
carry++;
}
k--;
}
/* test remainder / add back */
if (carry) {
guess--;
i = vlen;
carry = 0;
k = j + i;
if (j < dpu && k >= dpu)
k++;
while (k >= 0) {
if (u[k] == point)
k--;
if (i >= 0) {
u[k] += v[i--] + carry;
} else {
if (carry == 0)
break;
u[k] += carry;
}
carry = u[k] / NUMBASE;
u[k] = u[k] % NUMBASE;
k--;
}
}
q[j++] = guess + ZERO;
u[0] = 0;
} else {
q[j++] = POINT;
}
}
/* unnormalize */
if (typ != '#') {
i = 0;
while (i <= m) {
if ((u[i] = q[i]) == POINT)
dpv = i;
i++;
}
k = vlen;
k1 = dpv;
while (k-- > 0) {
while (k1 <= 0) {
for (i = (++m); i > 0; i--)
u[i] = u[i - 1];
k1++;
u[0] = ZERO;
}
u[k1] = u[k1 - 1];
u[--k1] = POINT;
dpv = k1;
}
u[m] = EOL;
/* rounding */
if (typ != '/')
u[dpv + 1] = EOL;
else {
k = dpv + zprecise;
k1 = u[k + 1] >= FIVE;
u[k + 1] = EOL;
if (k1) {
do {
if (u[k] != POINT) {
if ((carry = (u[k] == NINE)))
u[k] = ZERO;
else
u[k]++;
}
k--;
} while (carry);
}
}
} else { /* return the remainder */
carry = 0;
if (d > 1) {
for (i = 0; i <= ulen; i++) {
if (u[i] == point) {
u[i] = POINT;
dpu = i;
} else {
u[i] = (j = carry + u[i]) / d + ZERO;
carry = j % d * NUMBASE;
}
}
} else {
for (i = 0; i <= ulen; i++)
if (u[i] == point)
u[dpu = i] = POINT;
else
u[i] += ZERO;
}
u[i] = EOL;
if (d1 > 0) {
u[i + 1] = EOL;
u[i + 2] = EOL;
i = dpu;
for (j = 0; j < d1; j++) {
u[i] = u[i - 1];
i--;
}
u[i] = POINT;
}
}
/* remove trailing zeroes */
i = 0;
k = (-1);
while (u[i] != EOL) {
if (u[i] == POINT)
k = i;
i++;
}
i--;
if (k >= 0) {
while (u[i] == ZERO && i > k)
u[i--] = EOL;
}
/* remove trailing point */
if (u[i] == POINT)
u[i] = EOL;
/* remove leading zeroes */
while (u[0] == ZERO) {
i = 0;
while ((u[i] = u[i + 1]) != EOL)
i++;
}
if (u[0] == EOL) {
u[0] = ZERO;
u[1] = EOL;
mi = 0;
}
if ((mi || plus) && (u[0] != ZERO)) {
if (mi != plus) {
i = stlen (u) + 1;
do {
u[i] = u[i - 1];
i--;
} while (i > 0);
u[0] = MINUS;
}
if (plus)
add (u, vv);
}
stcpy (uu, u);
return;
} /* end div() */
/******************************************************************************/
void power (char *a, char *b) /* raise a to the b-th power */
{
char c[STRLEN + 2/*was 257*/];
char d[4*(STRLEN + 1)/*was 1024*/];/* 257 should be sufficient, but somewhere there */
/* is a memory leak resulting in wrong results */
/* with fractional powers, e.g. 2**(3/7) */
/* even a value of 513 is too small */
char e[STRLEN + 2/*was 257*/];
register long i;
register long j;
#if !defined(_AIX)
if (fp_mode) {
double fp_a;
double fp_b;
stcnv_m2c (a);
stcnv_m2c (b);
fp_a = atof (a);
fp_b = atof (b);
snprintf (a, STRLEN - 1, fp_conversion, pow (fp_a, fp_b));
trim_decimal (a);
return;
}
#endif
if (merr () > OK)
return; /* avoid nonsense in recursion */
/* if zero or one there's not much to do */
if (a[1] == EOL) {
if (a[0] == ZERO) {
if (b[1] == EOL && b[0] == ZERO)
merr_raise (M9);
return;
} /* undef */
if (a[0] == ONE)
return;
}
if (b[0] == MINUS) {
power (a, &b[1]);
if (merr () == M75) {
a[0] = ZERO;
a[1] = EOL;
merr_raise (OK);
return;
}
stcpy (c, a);
a[0] = ONE;
a[1] = EOL;
mdiv (a, c, '/');
return;
}
if (b[1] == EOL) {
switch (b[0]) {
case ZERO:
a[0] = ONE;
a[1] = EOL;
case ONE:
return;
case TWO:
stcpy (c, a);
mul (a, c);
return;
}
}
/* look for decimal point */
e[0] = EOL;
i = 0;
while (b[i] != EOL) {
if (b[i] == POINT) {
if (a[0] == MINUS) {
merr_raise (M9);
return;
} /* undefined case */
if (b[i + 1] == FIVE && b[i + 2] == EOL) { /* half-integer: extra solution */
if (i) {
stcpy (c, b);
add (b, c);
power (a, b);
if (merr () > OK) {
a[0] = ONE;
a[1] = EOL;
return;
}
}
g_sqrt (a);
return;
}
stcpy (e, &b[i]);
b[i] = EOL;
break;
}
i++;
}
stcpy (d, a);
i = intexpr (b);
if (merr () == MXNUM)
return;
/* do it with a small number of multiplications */
/* the number of multiplications is not optimum, but reasonably small */
/* see donald e. knuth "The Art of Computer Programming" Vol.II p.441 */
if (i == 0) {
a[0] = ONE;
a[1] = EOL;
} else {
j = 1;
while (j < i) {
j = j * 2;
if (j < 0) {
merr_raise (MXNUM);
return;
}
}
if (i != j)
j = j / 2;
j = j / 2;
while (j) {
stcpy (c, a);
mul (a, c);
if (i & j) {
stcpy (c, d);
mul (a, c);
}
j = j / 2;
if (merr () == MXNUM)
return;
}
if (e[0] == EOL)
return;
}
/* non integer exponent */
/* state of computation at this point: */
/* d == saved value of a */
/* a == d^^int(b); */
/* e == frac(b); */
{
char Z[STRLEN + 2/*was 257*/];
/* is fraction the inverse of an integer? */
Z[0] = ONE;
Z[1] = EOL;
stcpy (c, e);
mdiv (Z, c, '/');
i = 0;
for (;;)
{
if ((j = Z[i++]) == EOL) {
j = intexpr (Z);
break;
}
if (j != POINT)
continue;
j = intexpr (Z);
if (Z[i] == NINE)
j++;
break;
}
Z[0] = ONE;
Z[1] = EOL;
lintstr (c, j);
mdiv (Z, c, '/');
/* if integer */
if (stcmp (Z, e) == 0) {
stcpy (Z, d);
root (Z, j);
if (merr () <= OK) {
mul (a, Z);
return;
} /* on error try other method */
merr_raise (OK);
}
Z[0] = ONE;
Z[1] = EOL;
zprecise += 2;
for (;;)
{
c[0] = TWO;
c[1] = EOL;
mul (e, c);
g_sqrt (d);
if (e[0] == ONE) {
e[0] = ZERO;
numlit (e);
stcpy (c, d);
mul (Z, c);
mround (Z, zprecise);
}
if (e[0] == ZERO)
break;
i = 0;
j = (d[0] == ONE ? ZERO : NINE);
for (;;) {
++i;
if (d[i] != j && d[i] != '.')
break;
}
if (d[i] == EOL || (i > zprecise))
break;
}
zprecise -= 2;
mul (a, Z);
mround (a, zprecise + 1);
}
return;
} /* end power() */
/******************************************************************************/
void g_sqrt (char *a) /* square root */
{
register int i,
ch;
if (a[0] == ZERO)
return;
if (a[0] == MINUS) {
merr_raise (M9);
return;
}
if (merr () > OK)
return; /* avoid nonsense in recursion */
{
char tmp1[STRLEN +2 /*was 257*/],
tmp2[STRLEN +2 /*was 257*/],
XX[STRLEN +2 /*was 257*/],
XXX[STRLEN +2 /*was 257*/];
stcpy (XX, a);
/* look for good initial value */
if (a[0] > ONE || (a[0] == ONE && a[1] != POINT)) {
i = 0;
while ((ch = a[i++]) != EOL) {
if (ch == POINT)
break;
}
if ((i = (i + 1) / 2))
a[i] = EOL;
} else if (a[0] != ONE) {
a[0] = ONE;
a[1] = EOL;
}
/* "Newton's" algorithm with quadratic convergence */
zprecise++;
do {
stcpy (XXX, a);
stcpy (tmp1, XX);
stcpy (tmp2, a);
mdiv (tmp1, tmp2, '/');
if (merr () > OK)
break;
add (a, tmp1);
tmp2[0] = TWO;
tmp2[1] = EOL;
mdiv (a, tmp2, '/');
} while (comp (a, XXX));
zprecise--;
return;
}
} /* end g_sqrt() */
/******************************************************************************/
void root (char *a, long n) /* n.th root */
{
register int i,
ch;
if (a[0] == ZERO)
return;
if (a[0] == MINUS || n == 0) {
merr_raise (M9);
return;
}
if (merr () > OK)
return; /* avoid nonsense in recursion */
{
char tmp1[STRLEN +2/*was 257*/],
tmp2[STRLEN +2/*was 257*/],
XX[STRLEN +2/*was 257*/],
XXX[STRLEN +2/*was 257*/];
short again;
stcpy (XX, a);
/* look for good initial value */
if (a[0] > ONE || (a[0] == ONE && a[1] != POINT)) {
i = 0;
while ((ch = a[i++]) != EOL && ch != POINT) ;
if ((i = (i + n - 2) / n) > 0) {
a[0] = THREE;
a[i] = EOL;
}
} else if (a[0] != ONE) {
a[0] = ONE;
a[1] = EOL;
}
/* "Newton's" algorithm with quadratic convergence */
if (zprecise <= 3)
again = 0; /* speedup div with small zprec. */
else {
again = zprecise;
zprecise = 2;
}
second:;
zprecise++;
for (;;) {
stcpy (XXX, a);
lintstr (tmp1, n - 1);
stcpy (tmp2, a);
power (tmp2, tmp1);
stcpy (tmp1, XX);
mdiv (tmp1, tmp2, '/');
if (merr () > OK)
break;
lintstr (tmp2, n - 1);
mul (a, tmp2);
add (a, tmp1);
lintstr (tmp2, n);
mdiv (a, tmp2, '/');
stcpy (tmp2, a);
mdiv (XXX, tmp2, '/');
tmp2[0] = ONE;
if (zprecise <= 0)
tmp2[1] = EOL;
else {
tmp2[1] = POINT;
for (i = 2; i < zprecise; i++)
tmp2[i] = ZERO;
tmp2[i++] = FIVE;
tmp2[i] = EOL;
}
if (!comp (XXX, tmp2))
continue;
if (zprecise <= 0)
break;
tmp2[0] = POINT;
for (i = 1; i < zprecise; i++)
tmp2[i] = NINE;
tmp2[i - 1] = FIVE;
tmp2[i] = EOL;
if (comp (tmp2, XXX))
break;
}
zprecise--;
if (again) {
zprecise = again;
again = 0;
goto second;
}
return;
}
} /* end root() */
/******************************************************************************/
int numlit (char *str)
{
long j,
mi = 0,
pointx = (-1),
expflg = 0;
long val,
exp = 0L;
int result;
register int i = 0;
register int ch;
result = 0;
if (str[0] < ONE) {
if (str[0] == EOL) {
str[0] = ZERO;
str[1] = EOL;
return (0);
}
/* compact signs */
while (str[i] == PLUS || str[i] == MINUS)
if (str[i++] == MINUS)
mi++;
if ((j = (mi &= 01)))
str[0] = MINUS;
/* compact leading zeroes */
while (str[i] == ZERO)
i++;
if (i > j)
stcpy (&str[j], &str[i]);
if (str[mi] == EOL) {
str[0] = ZERO;
str[1] = EOL;
return (0);
}
i = mi;
}
while ((ch = str[i]) <= NINE && ch >= ZERO)
i++;
if ((result = unit (&str[i]))) {
if (i == mi) {
str[0] = '0';
i = 1;
}
ch = str[i] = EOL;
}
if (ch == EOL)
return (result);
if (ch == POINT) {
pointx = i++;
while ((ch = str[i]) <= NINE && ch >= ZERO)
i++;
if ((result = unit (&str[i])))
ch = str[i] = EOL;
if (ch == EOL) {
i = pointx;
goto point0;
}
}
/* check for zero mantissa */
j = 0;
while (j < i) {
if (str[j] > ZERO) {
j = (-1);
break;
}
j++;
}
if (j >= 0) {
str[0] = ZERO;
str[1] = EOL;
return (result);
}
/* search for exponent */
for (; ch != EOL; ch = str[++i]) {
if (ch <= NINE && ch >= ZERO) {
if (expflg) {
ch -= ZERO;
val = exp * NUMBASE + ch;
/* check for numeric overflow */
if (((val - ch) / NUMBASE) != exp) {
merr_raise (MXNUM);
return (0);
}
exp = val;
}
continue;
}
if (expflg) {
if (ch == MINUS) {
expflg = (-expflg);
continue;
}
if (ch == PLUS)
continue;
}
if ((result = unit (&str[i])))
ch = str[i] = EOL;
str[i] = EOL;
if (ch == 'E' || (lowerflag && ch == 'e')) {
expflg++;
continue;
}
break;
}
/* append a point at the right end */
if (expflg) {
if (pointx < 0) {
i = mi;
while (str[i] != EOL)
i++;
if (i >= (STRLEN - 1)/*was 254*/) {
str[STRLEN] = EOL;
merr_raise (M75);
return (0);
}
str[pointx = i] = POINT;
str[++i] = EOL;
}
/* if exp shift decimal point */
if (expflg > 0) {
while (exp-- > 0) {
if ((str[pointx] = str[pointx + 1]) == EOL) {
if (pointx >= (STRLEN - 1)/*was 254*/)
break;
str[pointx] = ZERO;
str[pointx + 1] = str[pointx + 2] = EOL;
}
pointx++;
}
if (pointx >= (STRLEN - 1)/*was 254*/) {
str[STRLEN] = EOL;
merr_raise (M75);
return (0);
}
str[pointx] = POINT;
} else { /* (expflg<0) */
while (exp-- > 0) {
if (--pointx < 0) {
i = pointx = 0;
while (str[i++] != EOL) ;
if (i >= (STRLEN - 1)/*was 254*/) {
merr_raise (M75);
return (0);
}
while (i-- > 0)
str[i + 1] = str[i];
str[0] = ZERO;
}
str[pointx + 1] = str[pointx];
}
str[pointx] = POINT;
}
}
if ((i = pointx) >= 0) {
point0:
while (str[++i] != EOL) ;
i--;
while (str[i] == ZERO)
str[i--] = EOL; /* remove trailing zeroes */
if (str[i] == POINT)
str[i] = EOL; /* remove trailing point */
}
if (str[mi] == EOL) {
str[0] = ZERO;
str[1] = EOL;
}
return (result);
}
/******************************************************************************/
int unit (char *str)
/**
* str is interpreted as a currency
* symbol
* return value: 1=EUR, 4=DM, ...
* 0=other */
{
char ch;
ch = str[0];
if ((ch < 'A') || (ch > 'P'))
return 0;
switch (ch) {
case 'E':
if (str[1] == 'U' && str[2] == 'R')
return 1;
if (str[1] == 'S' && str[2] == 'P')
return 5;
return 0;
case 'D':
if (str[1] == 'M')
return 4;
if (str[1] == 'E' && str[2] == 'M')
return 4;
return 0;
case 'A':
if (str[1] == 'T' && str[2] == 'S')
return 2;
return 0;
case 'B':
if (str[1] == 'F' && str[2] == 'R')
return 3;
return 0;
case 'F':
if (str[1] == 'F')
return 7;
if (str[1] == 'M' && str[2] == 'K')
return 6;
if (str[1] == 'R' && str[2] == 'F')
return 7;
return 0;
case 'I':
if (str[1] == 'E' && str[2] == 'P')
return 8;
if (str[1] == 'T' && str[2] == 'L')
return 9;
return 0;
case 'N':
if (str[1] == 'L' && str[2] == 'G')
return 10;
return 0;
case 'P':
if (str[1] == 'T' && str[2] == 'E')
return 11;
}
return 0;
}
/******************************************************************************/
long intexpr (char *str)
{
{
register int ch;
register int i = 0;
register long value;
register long newval;
short minus = FALSE;
if ((ch = str[0]) == MINUS) {
ch = str[1];
minus = TRUE;
i = 1;
}
if (ch >= ZERO && ch <= NINE) {
value = ch - ZERO;
while ((ch = str[++i]) >= ZERO && ch <= NINE) {
newval = value * NUMBASE;
if (newval < 0 || ((newval / NUMBASE) != value)) {
merr_raise (MXNUM);
return (minus ? -1 : 1);
};
newval += ((long) ch - ZERO);
if (newval < 0) {
merr_raise (MXNUM);
return (minus ? -1 : 1);
};
value = newval;
}
if (minus)
value = (-value);
if (ch == EOL)
return value;
} else if (ch != ZERO && ch != PLUS && ch != MINUS && ch != POINT)
return 0L;
}
{
register int ch;
register int i = 0;
register long value;
register long newval;
char tmp[STRLEN +2/*was 257*/];
stcpy (tmp, str);
numlit (tmp);
i = (tmp[0] == MINUS);
if (merr () == MXNUM)
return (i ? -1 : 1);
value = 0L;
while ((ch = tmp[i++]) >= ZERO && ch <= NINE) {
newval = value * NUMBASE;
if (newval < 0 || ((newval / NUMBASE) != value)) {
merr_raise (MXNUM);
value = 1;
break;
}
newval += ((long) ch - ZERO);
if (newval < 0) {
merr_raise (MXNUM);
value = 1;
break;
}
value = newval;
}
if (tmp[0] == MINUS)
value = (-value);
return value;
}
} /* end of intexpr */
/******************************************************************************/
short int tvexpr (char *str) /* str is interpreted as truth valued expression */
{
if (str[0] > ZERO && str[0] <= NINE) {
str[0] = ONE;
str[1] = EOL;
return TRUE;
}
if (str[1] == EOL) {
str[0] = ZERO;
return FALSE;
} {
register int ch;
register int i = 0;
register int pointx = FALSE;
register int sign = FALSE;
for (;;)
{
if ((ch = str[i]) > ZERO && ch <= NINE) {
str[0] = ONE;
str[1] = EOL;
return TRUE;
}
i++;
if ((ch == PLUS || ch == MINUS) && sign == FALSE)
continue;
sign = TRUE;
if (ch == ZERO)
continue;
if (ch == POINT && pointx == FALSE) {
sign = TRUE;
pointx = TRUE;
continue;
}
str[0] = ZERO;
str[1] = EOL;
return FALSE;
}
}
}
/******************************************************************************/
void m_op (char *a, char *b, short op)
{
int atyp,
btyp; /* DM/EUR currency types */
char tmp[(STRLEN + 1)/*was 256*/];
switch (op & 0177) { /* binary operators */
case '_':
if (op & 0200)
break; /* NOT_OPERAND */
if (stcat (a, b) == 0) {
merr_raise (M75);
}
return;
case '=':
if (stcmp (a, b))
*a = ZERO;
else
*a = ONE;
if (op & 0200)
toggle (*a); /* NOT_OPERAND */
a[1] = EOL;
return;
case '[':
if (*b == EOL || find (a, b))
*a = ONE;
else
*a = ZERO;
if (op & 0200)
toggle (*a); /* NOT_OPERAND */
a[1] = EOL;
return;
case ']':
if (*b == EOL) {
if (*a == EOL)
*a = ZERO;
else
*a = ONE;
}
/* frequent special case */
else if (stcmp (a, b) <= 0)
*a = ZERO;
else
*a = ONE;
if (op & 0200)
toggle (*a); /* NOT_OPERAND */
a[1] = EOL;
return;
} /* end switch */
atyp = numlit (a);
if (op == '-') {
stcpy (&tmp[1], b);
tmp[0] = '-';
op = '+';
} else
stcpy (tmp, b);
btyp = numlit (tmp);
switch (op & 0177) { /* binary operators, NOT OMITTED */
case '+':
if (op & 0200) {
merr_raise (ASSIGNER);
return;
} /* NOT_OPERAND */
#ifdef EUR2DEM
if (atyp != btyp) {
char tmp2[256];
if ((atyp == 0) && (a[0] == '0'))
atyp = btyp; /* zero is any currency */
if ((btyp == 0) && (tmp[0] == '0'))
btyp = atyp; /* zero is any currency */
if (atyp && btyp) {
if (atyp > 1) {
stcpy (tmp2, EUR2WHR[atyp]);
mul (tmp, tmp2);
}
if (btyp > 1) {
zprecise += 4;
stcpy (tmp2, EUR2WHR[btyp]);
mdiv (tmp, tmp2, '/');
zprecise -= 4;
}
} else if (atyp != btyp && typemmflag) {
merr_raise (TYPEMISMATCH);
return;
}
}
#endif /* EUR2DEM */
add (a, tmp);
plus02:
#ifdef EUR2DEM
if (atyp == 0)
break;
if (atyp != btyp)
cond_round (a, zprecise);
if (atyp)
stcat (a, WHR[atyp]);
#endif /* EUR2DEM */
break;
case '*':
if (op & 0200) {
merr_raise (ASSIGNER);
return;
} /* NOT_OPERAND */
#ifdef EUR2DEM
if (btyp && atyp == 0) {
atyp = btyp;
btyp = 0;
}
if (atyp && btyp) {
if (typemmflag) {
merr_raise (TYPEMISMATCH);
return;
}
atyp = btyp = 0;
}
#endif /* EUR2DEM */
mul (a, tmp);
#ifdef EUR2DEM
if (atyp) {
cond_round (a, zprecise);
stcat (a, WHR[atyp]);
}
#endif /* EUR2DEM */
break;
case '/':
case '\\':
case '#':
if (op & 0200) {
merr_raise (ASSIGNER);
return;
} /* NOT_OPERAND */
#ifdef EUR2DEM
if (atyp != btyp) {
char tmp2[(STRLEN + 1)/*was 256*/];
if (atyp && btyp) {
if (op == '#') {
if (atyp > 1) {
stcpy (tmp2, EUR2WHR[atyp]);
mul (tmp, tmp2);
}
if (btyp > 1) {
stcpy (tmp2, EUR2WHR[btyp]);
mdiv (tmp, tmp2, '/');
}
} else {
if (atyp > 1) {
stcpy (tmp2, EUR2WHR[atyp]);
mul (tmp, tmp2);
}
if (btyp > 1) {
stcpy (tmp2, EUR2WHR[btyp]);
mul (a, tmp2);
}
atyp = btyp = 0;
}
} else if (btyp && typemmflag && (*a != '0' || op == '#')) {
merr_raise (TYPEMISMATCH);
return;
}
} else if (op != '#')
atyp = 0;
#endif /* EUR2DEM */
if (tmp[0] == ZERO) {
merr_raise (M9);
break;
}
mdiv (a, tmp, op);
goto plus02;
case ' ':
power (a, tmp);
break; /* ' ' stands for power */
case '>':
#ifdef EUR2DEM
if (atyp != btyp) {
char tmp2[(STRLEN + 1)/*was 256*/];
if ((atyp == 0) && (a[0] == '0'))
atyp = btyp; /* zero is any currency */
if ((btyp == 0) && (tmp[0] == '0'))
btyp = atyp; /* zero is any currency */
if (atyp && btyp) {
if (atyp > 1) {
stcpy (tmp2, EUR2WHR[atyp]);
mul (tmp, tmp2);
}
if (btyp > 1) {
stcpy (tmp2, EUR2WHR[btyp]);
mul (a, tmp2);
}
cond_round (a, zprecise + 2);
cond_round (tmp, zprecise + 2);
} else if (atyp != btyp && typemmflag) {
merr_raise (TYPEMISMATCH);
return;
}
}
#endif /* EUR2DEM */
if (comp (tmp, a))
*a = ONE;
else
*a = ZERO;
if (op & 0200)
toggle (*a); /* NOT_OPERAND */
a[1] = EOL;
break;
case '<':
#ifdef EUR2DEM
if (atyp != btyp) {
char tmp2[(STRLEN + 1)/*was 256*/];
if ((atyp == 0) && (a[0] == '0'))
atyp = btyp; /* zero is any currency */
if ((btyp == 0) && (tmp[0] == '0'))
btyp = atyp; /* zero is any currency */
if (atyp && btyp) {
if (atyp > 1) {
stcpy (tmp2, EUR2WHR[atyp]);
mul (tmp, tmp2);
}
if (btyp > 1) {
stcpy (tmp2, EUR2WHR[btyp]);
mul (a, tmp2);
}
cond_round (a, zprecise + 2);
cond_round (tmp, zprecise + 2);
} else if (atyp != btyp && typemmflag) {
merr_raise (TYPEMISMATCH);
return;
}
}
#endif /* EUR2DEM */
if (comp (a, tmp))
*a = ONE;
else
*a = ZERO;
if (op & 0200)
toggle (*a); /* NOT_OPERAND */
a[1] = EOL;
break;
case '&':
if (tvexpr (a)) {
tvexpr (tmp);
*a = *tmp;
}
if (op & 0200)
toggle (*a); /* NOT_OPERAND */
a[1] = EOL;
break;
case '!':
if (tvexpr (a) == FALSE && tvexpr (tmp))
*a = ONE;
if (op & 0200)
toggle (*a); /* NOT_OPERAND */
a[1] = EOL;
break;
default:
merr_raise (ASSIGNER);
}
return;
} /* end m_op */
/******************************************************************************/
/* rounding */
/* 'a' is assumed to be a 'canonic' numeric string */
/* it is rounded to 'digits' fractional digits */
void mround (char *a, int digits)
{
int ch,
i,
pointpos,
lena;
pointpos = -1;
i = 0;
i = 0;
while (a[i] != EOL) {
if (a[i] == POINT)
pointpos = i;
i++;
}
lena = i;
if (pointpos < 0)
pointpos = i;
if ((pointpos + digits + 1) >= i)
return; /* nothing to round */
i = pointpos + digits + 1;
if (a[i] < FIVE) {
a[i] = EOL;
while (a[--i] == ZERO)
a[i] = EOL;
if (a[i] == POINT) {
a[i] = EOL;
if (i == 0 || (i == 1 && a[0] == MINUS))
a[0] = ZERO;
}
return;
}
for (;;)
{
if (i >= pointpos)
a[i] = EOL;
else
a[i] = ZERO;
if (--i < (a[0] == MINUS)) {
for (i = lena; i >= 0; i--)
a[i + 1] = a[i];
a[a[0] == '-'] = ONE;
break;
}
if ((ch = a[i]) == POINT)
continue;
if (a[i] < NINE && ch >= ZERO) {
a[i] = ++ch;
break;
}
}
return;
} /* end mround */
/* End of $Source: /home/cvsroot/freem/src/operator.c,v $ */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>