/* *strgtold.c - conversion of a string into a long double * Copyright (c) 1991-1991, Microsoft Corporation. All rights reserved. *Purpose: convert a fp constant into a 10 byte long double (IEEE format) *Revision History: * 7-17-91 GDP Initial version (ported from assembly) * 4-03-92 GDP Preserve sign of -0 * 4-30-92 GDP Now returns _ULDBL12 instead of _ULDOUBLE * 05-26-92 GWK Windbg srcs */ //#include /* for 'isdigit' macro */ #include "mathsup.h" /* local macros */ #define ISNZDIGIT(x) ((x)>='1' && (x)<='9' ) //NOTENOTE the following takes the place of the isdigit() macro // which does not work for a yet to be determined reason #define ISADIGIT(x) ((x)>='0' && (x)<='9' ) #define ISWHITE(x) ((x)==' ' || (x)=='\t' || (x)=='\n' || (x)=='\r' ) /* *unsigned int __strgtold( _ULDBL12 *pld12, * char * * pEndPtr, * char * str, * int Mult12 ) *Purpose: * converts a character string into a long double *Entry: * pld12 - pointer to the _ULDBL12 where the result should go. * pEndStr - pointer to a far pointer that will be set to the end of string. * str - pointer to the string to be converted. * Mult12 - set to non zero if the _ULDBL12 multiply should be used instead of * the long double mulitiply. *Exit: * Returns the SLD_* flags or'ed together. *Uses: *Exceptions: */ unsigned int __strgtold12(_ULDBL12 *pld12, char * *p_end_ptr, char *str, int mult12) { typedef enum { S_INIT, /* initial state */ S_EAT0L, /* eat 0's at the left of mantissa */ S_SIGNM, /* just read sign of mantissa */ S_GETL, /* get integer part of mantissa */ S_GETR, /* get decimal part of mantissa */ S_POINT, /* just found decimal point */ S_E, /* just found 'E', or 'e', etc */ S_SIGNE, /* just read sign of exponent */ S_EAT0E, /* eat 0's at the left of exponent */ S_GETE, /* get exponent */ S_END /* final state */ } state_t; /* this will accomodate the digits of the mantissa in BCD form*/ static char buf[LD_MAX_MAN_LEN1]; char *manp = buf; /* a temporary _ULDBL12 */ _ULDBL12 tmpld12; u_short man_sign = 0; /* to be ORed with result */ int exp_sign = 1; /* default sign of exponent (values: +1 or -1)*/ /* number of decimal significant mantissa digits so far*/ unsigned manlen = 0; int found_digit = 0; int overflow = 0; int underflow = 0; int pow = 0; int exp_adj = 0; /* exponent adjustment */ u_long ul0,ul1; u_short u,uexp; unsigned int result_flags = 0; state_t state = S_INIT; char c; /* the current input symbol */ char *p; /* a pointer to the next input symbol */ char *savedp; for(savedp=p=str;ISWHITE(*p);p++); /* eat up white space */ while (state != S_END) { c = *p++; switch (state) { case S_INIT: if (ISNZDIGIT(c)) { state = S_GETL; p--; } else switch (c) { case '0': state = S_EAT0L; break; case '+': state = S_SIGNM; man_sign = 0x0000; break; case '-': state = S_SIGNM; man_sign = 0x8000; break; case '.': state = S_POINT; break; default: state = S_END; p--; break; } break; case S_EAT0L: found_digit = 1; if (ISNZDIGIT(c)) { state = S_GETL; p--; } else switch (c) { case '0': state = S_EAT0L; break; case 'E': case 'e': case 'D': case 'd': state = S_E; break; case '.': state = S_GETR; break; default: state = S_END; p--; } break; case S_SIGNM: if (ISNZDIGIT(c)) { state = S_GETL; p--; } else switch (c) { case '0': state = S_EAT0L; break; case '.': state = S_POINT; break; default: state = S_END; p = savedp; } break; case S_GETL: found_digit = 1; for (;ISADIGIT(c);c=*p++) { if (manlen < LD_MAX_MAN_LEN+1){ manlen++; *manp++ = c - (char)'0'; } else exp_adj++; } switch (c) { case '.': state = S_GETR; break; case 'E': case 'e': case 'D': case 'd': state = S_E; break; default: state = S_END; p--; } break; case S_GETR: found_digit = 1; if (manlen == 0) for (;c=='0';c=*p++) exp_adj--; for(;ISADIGIT(c);c=*p++){ if (manlen < LD_MAX_MAN_LEN+1){ manlen++; *manp++ = c - (char)'0'; exp_adj--; } } switch (c){ case 'E': case 'e': case 'D': case 'd': state = S_E; break; default: state = S_END; p--; } break; case S_POINT: if (ISADIGIT(c)){ state = S_GETR; p--; } else{ state = S_END; p = savedp; } break; case S_E: savedp = p-2; /* savedp points to 'E' */ if (ISNZDIGIT(c)){ state = S_GETE; p--; } else switch (c){ case '0': state = S_EAT0E; break; case '-': state = S_SIGNE; exp_sign = -1; break; case '+': state = S_SIGNE; break; default: state = S_END; p = savedp; } break; case S_EAT0E: for(;c=='0';c=*p++); if (ISNZDIGIT(c)){ state = S_GETE; p--; } else { state = S_END; p--; } break; case S_SIGNE: if (ISNZDIGIT(c)){ state = S_GETE; p--; } else switch (c){ case '0': state = S_EAT0E; break; default: state = S_END; p = savedp; } break; case S_GETE: { long longpow=0; /* TMAX10*10 should fit in a long */ for(;ISADIGIT(c);c=*p++){ longpow = longpow*10 + (c - '0'); if (longpow > TMAX10){ longpow = TMAX10+1; /* will force overflow */ break; } } pow = (int)longpow; } for(;ISADIGIT(c);c=*p++); /* eat up remaining digits */ state = S_END; p--; break; } /* switch */ } /* while */ *p_end_ptr = p; /* set end pointer */ /* * Compute result */ if (found_digit && !overflow && !underflow) { if (manlen>LD_MAX_MAN_LEN){ if (buf[LD_MAX_MAN_LEN-1]>=5) { /* * Round mantissa to MAX_MAN_LEN digits * It's ok to round 9 to 0ah */ buf[LD_MAX_MAN_LEN-1]++; } manlen = LD_MAX_MAN_LEN; manp--; exp_adj++; } if (manlen>0) { /* * Remove trailing zero's from mantissa */ for(manp--;*manp==0;manp--) { /* there is at least one non-zero digit */ manlen--; exp_adj++; } __mtold12(buf,manlen,&tmpld12); if (exp_sign < 0) pow = -pow; pow += exp_adj; if (pow > TMAX10) overflow = 1; else if (pow < TMIN10) underflow = 1; else { __multtenpow12(&tmpld12,pow,mult12); u = *U_XT_12(&tmpld12); ul0 =*UL_MANLO_12(&tmpld12); ul1 = *UL_MANHI_12(&tmpld12); uexp = *U_EXP_12(&tmpld12); } } else { /* manlen == 0, so return 0 */ u = (u_short)0; ul0 = ul1 = uexp = 0; } } if (!found_digit) { /* return 0 */ u = (u_short)0; ul0 = ul1 = uexp = 0; result_flags |= SLD_NODIGITS; } else if (overflow) { /* return +inf or -inf */ uexp = (u_short)0x7fff; ul1 = 0x80000000; ul0 = 0; u = (u_short)0; result_flags |= SLD_OVERFLOW; } else if (underflow) { /* return 0 */ u = (u_short)0; ul0 = ul1 = uexp = 0; result_flags |= SLD_UNDERFLOW; } /* * Assemble result */ *U_XT_12(pld12) = u; *UL_MANLO_12(pld12) = ul0; *UL_MANHI_12(pld12) = ul1; *U_EXP_12(pld12) = uexp | man_sign; return result_flags; }