home *** CD-ROM | disk | FTP | other *** search
- /*
- * File: rconv.c
- * Contents: cvcset, cvint, cvnum, cvpos, cvreal, cvstr, mkint,
- * makereal, mksubs, strprc
- */
-
- #include <math.h>
- #include "../h/config.h"
- #include "../h/rt.h"
- #include "rproto.h"
-
- /*
- * Prototypes.
- */
-
- hidden int cstos Params((int *cs,dptr dp,char *s));
- hidden int itos Params((long num,dptr dp,char *s));
- hidden int ston Params((char *s,dptr dp));
-
- #ifndef LargeInts
- hidden int radix Params((int sign,int r,char *s,dptr dp));
- #endif /* LargeInts */
-
- #ifdef StrInvoke
- extern struct pstrnm pntab[];
- #endif /* StrInvoke */
-
- #include <ctype.h>
-
- #if !EBCDIC
- #define tonum(c) (isdigit(c) ? (c)-'0' : 10+(((c)|(040))-'a'))
- #endif /* !EBCDIC */
-
- /*
- * cvcset(dp, cs, csbuf) - convert dp to a cset and
- * make cs point to it, using csbuf as a buffer if necessary.
- */
-
- int cvcset(dp, cs, csbuf)
- register dptr dp;
- int **cs, *csbuf;
- {
- register char *s;
- register word l;
- char sbuf[MaxCvtLen];
-
- if (dp->dword == D_Cset) {
- *cs = BlkLoc(*dp)->cset.bits;
- return T_Cset;
- }
-
- if (cvstr(dp, sbuf) == CvtFail)
- return CvtFail;
-
- for (l = 0; l < CsetSize; l++)
- csbuf[l] = 0;
-
- s = StrLoc(*dp);
- l = StrLen(*dp);
- while (l--) {
- Setb(ToAscii(*s), csbuf);
- s++;
- }
- *cs = csbuf;
- return T_Cset;
- }
-
- /*
- * cvint - convert the value represented by dp into an integer and write
- * the value into the location referenced by i. cvint returns the type or
- * CvtFail depending on the outcome of the conversion.
- */
-
- int cvint(dp)
- register dptr dp;
- {
- /*
- * Use cvnum to attempt the conversion into "result".
- */
- switch (cvnum(dp)) {
-
- case T_Integer:
- return T_Integer;
-
- #ifdef LargeInts
- case T_Bignum:
- /*
- * Bignum, not in the range of an integer. Fail as we do
- * for large reals.
- */
- return CvtFail;
- #endif /* LargeInts */
-
- case T_Real:
- /*
- * The value converted into a real number. If it's not in the
- * range of an integer, fail, otherwise convert the real value
- * into an integer.
- */
- if (BlkLoc(*dp)->realblk.realval > MaxLong ||
- BlkLoc(*dp)->realblk.realval < MinLong)
- return CvtFail;
- dp->dword = D_Integer;
- IntVal(*dp) = (long)BlkLoc(*dp)->realblk.realval;
- return T_Integer;
-
- default:
- return CvtFail;
- }
- }
-
- /*
- * cvnum - convert the value represented by d into a numeric quantity
- * in place. The value returned is the type or CvtFail.
- */
-
- int cvnum(dp)
- register dptr dp;
- {
- static char sbuf[MaxCvtLen];
- struct descrip cstring;
-
- cstring = *dp; /* placed outside "if" to avoid Lattice 3.21 code gen bug */
- if (Qual(*dp)) {
- qtos(&cstring, sbuf);
- return ston(StrLoc(cstring), dp);
- }
-
- switch (Type(*dp)) {
-
- case T_Integer:
-
- #ifdef LargeInts
- case T_Bignum:
- #endif /* LargeInts */
-
- case T_Real:
- return Type(*dp);
-
- default:
- /*
- * Try to convert the value to a string and
- * then try to convert the string to an integer.
- */
- if (cvstr(dp, sbuf) == CvtFail)
- return CvtFail;
- return ston(StrLoc(*dp), dp);
- }
- }
-
- /*
- * ston - convert a string to a numeric quantity if possible.
- */
- static int ston(s, dp)
- register char *s;
- dptr dp;
- {
- register int c;
- int realflag = 0; /* indicates a real number */
- char msign = '+'; /* sign of mantissa */
- char esign = '+'; /* sign of exponent */
- double mantissa = 0; /* scaled mantissa with no fractional part */
- long lresult = 0; /* integer result */
- int scale = 0; /* number of decimal places to shift mantissa */
- int digits = 0; /* total number of digits seen */
- int sdigits = 0; /* number of significant digits seen */
- int exponent = 0; /* exponent part of real number */
- double fiveto; /* holds 5^scale */
- double power; /* holds successive squares of 5 to compute fiveto */
- int err_no;
- char *ssave; /* holds original ptr for bigradix */
-
- c = *s++;
-
- /*
- * Skip leading white space.
- */
- while (isspace(c))
- c = *s++;
-
- /*
- * Check for sign.
- */
- if (c == '+' || c == '-') {
- msign = c;
- c = *s++;
- }
-
- ssave = s - 1; /* set pointer to beginning of digits in case it's needed */
-
- /*
- * Get integer part of mantissa.
- */
- while (isdigit(c)) {
- digits++;
- if (mantissa < Big) {
- mantissa = mantissa * 10 + (c - '0');
- lresult = lresult * 10 + (c - '0');
- if (mantissa > 0.0)
- sdigits++;
- }
- else
- scale++;
- c = *s++;
- }
-
- /*
- * Check for based integer.
- */
- if (c == 'r' || c == 'R')
-
- #ifdef LargeInts
- return bigradix(msign, (int)mantissa, s, dp);
- #else /* LargeInts */
- return radix(msign, (int)mantissa, s, dp);
- #endif /* LargeInts */
-
- /*
- * Get fractional part of mantissa.
- */
- if (c == '.') {
- realflag++;
- c = *s++;
- while (isdigit(c)) {
- digits++;
- if (mantissa < Big) {
- mantissa = mantissa * 10 + (c - '0');
- lresult = lresult * 10 + (c - '0');
- scale--;
- if (mantissa > 0.0)
- sdigits++;
- }
- c = *s++;
- }
- }
-
- /*
- * Check that at least one digit has been seen so far.
- */
- if (digits == 0)
- return CvtFail;
-
- /*
- * Get exponent part.
- */
- if (c == 'e' || c == 'E') {
- realflag++;
- c = *s++;
- if (c == '+' || c == '-') {
- esign = c;
- c = *s++;
- }
- if (!isdigit(c))
- return CvtFail;
- while (isdigit(c)) {
- exponent = exponent * 10 + (c - '0');
- c = *s++;
- }
- scale += (esign == '+') ? exponent : -exponent;
- }
-
- /*
- * Skip trailing white space.
- */
- while (isspace(c))
- c = *s++;
-
- /*
- * Check that entire string has been consumed.
- */
- if (c != '\0')
- return CvtFail;
-
- /*
- * Test for integer.
- */
- if (!realflag && !scale && mantissa >= MinLong && mantissa <= MaxLong) {
- dp->dword = D_Integer;
- IntVal(*dp) = (msign == '+' ? lresult : -lresult);
- return T_Integer;
- }
-
- #ifdef LargeInts
- /*
- * Test for bignum.
- */
- if (!realflag)
- return bigradix(msign, 10, ssave, dp);
- #endif /* LargeInts */
-
- if (!realflag)
- return CvtFail; /* don't promote to real if integer format */
-
- /*
- * Rough tests for overflow and underflow.
- */
- if (sdigits + scale > LogHuge)
- return CvtFail;
-
- if (sdigits + scale < -LogHuge) {
- makereal(0.0, dp);
- return T_Real;
- }
-
- /*
- * Put the number together by multiplying the mantissa by 5^scale and
- * then using ldexp() to multiply by 2^scale.
- */
-
- exponent = (scale > 0)? scale : -scale;
- fiveto = 1.0;
- power = 5.0;
- for (;;) {
- if (exponent & 01)
- fiveto *= power;
- exponent >>= 1;
- if (exponent == 0)
- break;
- power *= power;
- }
- if (scale > 0)
- mantissa *= fiveto;
- else
- mantissa /= fiveto;
-
- err_no = 0;
- mantissa = ldexp(mantissa, scale);
- if (err_no > 0 && mantissa > 0)
- /*
- * ldexp caused overflow.
- */
- return CvtFail;
-
- if (msign == '-')
- mantissa = -mantissa;
- makereal(mantissa, dp);
- return T_Real;
- }
-
- #ifndef LargeInts
- /*
- * radix - convert string s in radix r into an integer in *dp. sign
- * will be either '+' or '-'.
- */
- static int radix(sign, r, s, dp)
- int sign;
- register int r;
- register char *s;
- dptr dp;
- {
- register int c;
- long num;
-
- if (r < 2 || r > 36)
- return CvtFail;
- c = *s++;
- num = 0L;
- while (isalnum(c)) {
- c = tonum(c);
- if (c >= r)
- return CvtFail;
- num = num * r + c;
- c = *s++;
- }
-
- while (isspace(c))
- c = *s++;
-
- if (c != '\0')
- return CvtFail;
-
- dp->dword = D_Integer;
- dp->vword.integr = (sign == '+' ? num : -num);
-
- return T_Integer;
- }
- #endif /* LargeInts */
-
- /*
- * cvpos - convert position to strictly positive position
- * given length.
- */
-
- word cvpos(pos, len)
- long pos;
- register long len;
- {
- register word p;
-
- /*
- * Make sure the position is in the range of an int. (?)
- */
- if ((long)(p = pos) != pos)
- return CvtFail;
- /*
- * Make sure the position is within range.
- */
- if (p < -len || p > len + 1)
- return CvtFail;
- /*
- * If the position is greater than zero, just return it. Otherwise,
- * convert the zero/negative position.
- */
- if (pos > 0)
- return p;
- return (len + p + 1);
- }
-
- /*
- * cvreal - convert to real in place.
- */
-
- int cvreal(dp)
- register dptr dp;
- {
- /*
- * Use cvnum to classify the value. Cast integers into reals and
- * fail if the value is non-numeric.
- */
- switch (cvnum(dp)) {
-
- case T_Integer:
- makereal((double)IntVal(*dp), dp);
- return T_Real;
-
- #ifdef LargeInts
- case T_Bignum:
- makereal(bigtoreal(dp), dp);
- return T_Real;
- #endif /* LargeInts */
-
- case T_Real:
- return T_Real;
-
- default:
- return CvtFail;
- }
- }
-
- /*
- * cvstr(dp,s) - convert dp (in place) into a string, using s as buffer
- * if necessary. cvstr returns CvtFail if the conversion fails, Cvt if dp
- * wasn't a string but was converted into one, and NoCvt if dp was already
- * a string. When a string conversion takes place, sbuf gets the
- * resulting string.
- */
-
- int cvstr(dp, sbuf)
- register dptr dp;
- char *sbuf;
- {
- double rres;
-
- if (Qual(*dp))
- return NoCvt; /* It is already a string */
-
- switch (Type(*dp)) {
- /*
- * For types that can be converted into strings, call the
- * appropriate conversion routine and return its result.
- * Note that the conversion routines change the descriptor
- * pointed to by dp.
- */
- case T_Integer:
- return itos((long)IntVal(*dp), dp, sbuf);
-
- #ifdef LargeInts
- case T_Bignum:
- return bigtos(dp, dp);
- #endif /* LargeInts */
-
- case T_Real:
- GetReal(dp,rres);
- return rtos(rres, dp, sbuf);
-
- case T_Cset:
- return cstos(BlkLoc(*dp)->cset.bits, dp, sbuf);
-
- default:
- /*
- * The value cannot be converted to a string.
- */
- return CvtFail;
- }
- }
-
- /*
- * itos - convert the integer num into a string using s as a buffer and
- * making q a descriptor for the resulting string.
- */
-
- static int itos(num, dp, s)
- long num;
- dptr dp;
- char *s;
- {
- register char *p;
- long ival;
- static char *maxneg = MaxNegInt;
-
- p = s + MaxCvtLen - 1;
- ival = num;
-
- *p = '\0';
- if (num >= 0L)
- do {
- *--p = ival % 10L + '0';
- ival /= 10L;
- } while (ival != 0L);
- else {
- if (ival == -ival) { /* max negative value */
- p -= strlen (maxneg);
- sprintf (p, "%s", maxneg);
- }
- else {
- ival = -ival;
- do {
- *--p = '0' + (ival % 10L);
- ival /= 10L;
- } while (ival != 0L);
- *--p = '-';
- }
- }
-
- StrLen(*dp) = s + MaxCvtLen - 1 - p;
- StrLoc(*dp) = p;
- return Cvt;
- }
-
- /*
- * rtos - convert the real number n into a string using s as a buffer and
- * making a descriptor for the resulting string.
- */
- int rtos(n, dp, s)
- double n;
- dptr dp;
- char *s;
- {
-
- s++; /* leave room for leading zero */
- /*
- * The following code is operating-system dependent [@rconv.01]. Convert real
- * number to string.
- *
- * If IconGcvt is defined, icon_gcvt() is actually called, due to a #define
- * in config.h.
- */
-
- #if PORT
- gcvt(n, Precision, s);
- Deliberate Syntax Error
- #endif /* PORT */
-
- #if AMIGA || ARM || ATARI_ST || MSDOS || UNIX || VMS
- gcvt(n, Precision, s);
- #endif /* AMIGA || ATARI_ST || ... */
-
- #if VM || MVS
- #if SASC
- sprintf(s,"%.*g", Precision, n);
- {
- char *ep = strstr(s, "e+");
- if (ep) memmove(ep+1, ep+2, strlen(ep+2)+1);
- }
- #else /* SASC */
- gcvt(n, Precision, s);
- #endif /* SASC */
- #endif /* MVS || VM */
-
-
- #if HIGHC_386
- sprintf(s,"%.*g", Precision, n);
- #endif /* HIGHC_386 */
-
- #if MACINTOSH
- sprintf(s,"%20g",n);
- #endif /* MACINTOSH */
-
- /*
- * End of operating-system specific code.
- */
-
- /*
- * Now clean up possible messes.
- */
- while (*s == ' ') /* delete leading blanks */
- s++;
- if (*s == '.') { /* prefix 0 t0 to initial period */
- s--;
- *s = '0';
- }
- else if (strcmp(s, "-0.0") == 0) /* negative zero */
- s++;
- else if (!index(s, '.') && !index(s,'e') && !index(s,'E'))
- strcat(s, ".0"); /* if no decimal point or exp. */
- if (s[strlen(s) - 1] == '.') /* if decimal point is at the end ... */
- strcat(s, "0");
- StrLen(*dp) = strlen(s);
- StrLoc(*dp) = s;
- return Cvt;
- }
-
- /*
- * cstos - convert the cset bit array pointed at by cs into a string using
- * s as a buffer and making a descriptor for the resulting string.
- */
-
- static int cstos(cs, dp, s)
- int *cs;
- dptr dp;
- char *s;
- {
- register unsigned int w;
- register int j, i;
- register char *p;
-
- p = s;
- for (i = 0; i < CsetSize; i++) {
- if (cs[i])
- for (j=i*IntBits, w=cs[i]; w; j++, w >>= 1)
- if (w & 01)
- *p++ = FromAscii((char)j);
- }
- *p = '\0';
-
- StrLen(*dp) = p - s;
- StrLoc(*dp) = s;
- return Cvt;
- }
-
- /*
- * makereal(r, dp) - make a real number descriptor and associated block
- * for r and place it in *dp.
- */
-
- int makereal(r, dp)
- double r;
- register dptr dp;
- {
-
- if (blkreq((uword)sizeof(struct b_real)) == Error)
- return Error;
- dp->dword = D_Real;
- BlkLoc(*dp) = (union block *)alcreal(r);
- return Success;
- }
-
- /*
- * mksubs - form a substring. var is a descriptor for the string from
- * which the substring is to be formed. var may be a variable. val
- * is a dereferenced version of var. The descriptor for the resulting
- * substring is placed in *result. The substring starts at position
- * i and extends for j characters.
- */
-
- novalue mksubs(var, val, i, j, result)
- register dptr var, val, result;
- word i, j;
- {
-
- if (!Var(*var)) {
- /*
- * var isn't a variable, just form a descriptor that points into
- * the string named by val.
- */
- StrLen(*result) = j;
- StrLoc(*result) = StrLoc(*val) + i - 1;
- return;
- }
-
- if ((var)->dword == D_Tvsubs) {
- /*
- * If var is a substring trapped variable,
- * adjust the position and make var the substrung string.
- */
- i += BlkLoc(*var)->tvsubs.sspos - 1;
- var = &BlkLoc(*var)->tvsubs.ssvar;
- }
-
- /*
- * Make a substring trapped variable by passing the buck to alcsubs.
- */
- result->dword = D_Tvsubs;
- BlkLoc(*result) = (union block *) alcsubs(j, i, var);
- return;
- }
-
- /*
- * strprc - Convert the qualified string named by *dp into a procedure
- * descriptor if possible. n is the number of arguments that the desired
- * procedure has. n is only used when the name of the procedure is
- * non-alphabetic (hence, an operator).
- *
- */
- int strprc(dp, n)
- dptr dp;
- word n;
- {
-
- #ifndef StrInvoke
- return CvtFail;
- #else /* StrInvoke */
-
- dptr np, gp;
- struct pstrnm *p;
- char *s;
- int i;
- word ns;
-
- /*
- * Look in global name list first.
- */
- np = gnames; gp = globals;
- while (gp < eglobals) {
- if (!lexcmp(np++,dp))
- if (BlkLoc(*gp)->proc.title == T_Proc) {
- StrLen(*dp) = D_Proc; /* really type field */
- BlkLoc(*dp) = BlkLoc(*gp);
- return T_Proc;
- }
- gp++;
- }
-
- /*
- * The name is not a global, see if it is a function or an operator.
- */
- s = StrLoc(*dp);
- if (StrLen(*dp) > MaxCvtLen) /* can't be that big */
- return CvtFail;
- i = (int)StrLen(*dp);
- for (p = pntab; p->pstrep; p++)
- /*
- * Compare the desired name with each standard procedure/operator
- * name.
- */
- if (strlen(p->pstrep) == i && strncmp(s,p->pstrep,i) == 0) {
- if (isalpha(*s)) {
- /*
- * The names are the same and s starts with an alphabetic,
- * so it's the one being looked for; return it.
- */
- StrLen(*dp) = D_Proc;
- BlkLoc(*dp) = (union block *) p->pblock;
- return T_Proc;
- }
- if ((ns = p->pblock->nstatic) < 0)
- ns = -ns;
- else
- ns = abs((int)p->pblock->nparam);
- if (n == ns) {
- StrLen(*dp) = D_Proc; /* really type field */
- BlkLoc(*dp) = (union block *)p->pblock;
- return T_Proc;
- }
- }
- return CvtFail;
- #endif /* StrInvoke */
-
- }
-