/*** *strgtold.c - conversion of a string into a long double * * Copyright (c) 1991-2001, Microsoft Corporation. All rights reserved. * *Purpose: convert a fp constant into a 10 byte long double (IEEE format) * *Revision History: * 07-17-91 GDP Initial version (ported from assembly) * 04-03-92 GDP Preserve sign of -0 * 04-30-92 GDP Now returns _LDBL12 instead of _LDOUBLE * 06-17-92 GDP Added __strgtold entry point again (68k code uses it) * 06-22-92 GDP Use scale, decpt and implicit_E for FORTRAN support * 11-06-92 GDP Made char-to-int conversions usnigned for 'isdigit' * 03-11-93 JWM Added minimal support for _INTL decimal point - one byte only! * 07-01-93 GJF Made buf[] a local array, rather than static array of * local scope (static is evil in multi-thread!). * 09-15-93 SKS Change _decimal_point to __decimal_point for CFW. * 09-06-94 CFW Remove _INTL switch. * *******************************************************************************/ #include /* for 'isdigit' macro */ #include #include /* local macros */ #define ISNZDIGIT(x) ((x)>='1' && (x)<='9' ) #define ISWHITE(x) ((x)==' ' || (x)=='\t' || (x)=='\n' || (x)=='\r' ) /**** *unsigned int __strgtold12( _LDBL12 *pld12, * char * * pEndPtr, * char * str, * int Mult12, * int scale, * int decpt, * int implicit_E) * *Purpose: * converts a character string into a 12byte long double (_LDBL12) * This has the same format as a 10byte long double plus two extra * bytes for the mantissa * *Entry: * pld12 - pointer to the _LDBL12 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 _LDBL12 multiply should be used instead of * the long double mulitiply. * scale - FORTRAN scale factor (0 for C) * decpt - FORTRAN decimal point factor (0 for C) * implicit_E - if true, E, e, D, d can be implied (FORTRAN syntax) * *Exit: * Returns the SLD_* flags or'ed together. * *Uses: * *Exceptions: * ********************************************************************************/ unsigned int __strgtold12(_LDBL12 *pld12, const char * *p_end_ptr, const char * str, int mult12, int scale, int decpt, int implicit_E) { 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 */ S_E_IMPLICIT /* check for implicit exponent */ } state_t; /* this will accomodate the digits of the mantissa in BCD form*/ char buf[LD_MAX_MAN_LEN1]; char *manp = buf; /* a temporary _LDBL12 */ _LDBL12 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 found_decpoint = 0; int found_exponent = 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 */ const char *p; /* a pointer to the next input symbol */ const 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 if (c == *__decimal_point) state = S_POINT; 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; default: state = S_END; p--; break; } break; case S_EAT0L: found_digit = 1; if (ISNZDIGIT(c)) { state = S_GETL; p--; } else if (c == *__decimal_point) state = S_GETR; else switch (c) { case '0': state = S_EAT0L; break; case 'E': case 'e': case 'D': case 'd': state = S_E; break; case '+': case '-': p--; state = S_E_IMPLICIT; break; default: state = S_END; p--; } break; case S_SIGNM: if (ISNZDIGIT(c)) { state = S_GETL; p--; } else if (c == *__decimal_point) state = S_POINT; else switch (c) { case '0': state = S_EAT0L; break; default: state = S_END; p = savedp; } break; case S_GETL: found_digit = 1; for (;isdigit((int)(unsigned char)c);c=*p++) { if (manlen < LD_MAX_MAN_LEN+1){ manlen++; *manp++ = c - (char)'0'; } else exp_adj++; } if (c == *__decimal_point) state = S_GETR; else switch (c) { case 'E': case 'e': case 'D': case 'd': state = S_E; break; case '+': case '-': p--; state = S_E_IMPLICIT; break; default: state = S_END; p--; } break; case S_GETR: found_digit = 1; found_decpoint = 1; if (manlen == 0) for (;c=='0';c=*p++) exp_adj--; for(;isdigit((int)(unsigned char)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; case '+': case '-': p--; state = S_E_IMPLICIT; break; default: state = S_END; p--; } break; case S_POINT: found_decpoint = 1; if (isdigit((int)(unsigned char)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: found_exponent = 1; 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: found_exponent = 1; { long longpow=0; /* TMAX10*10 should fit in a long */ for(;isdigit((int)(unsigned char)c);c=*p++){ longpow = longpow*10 + (c - '0'); if (longpow > TMAX10){ longpow = TMAX10+1; /* will force overflow */ break; } } pow = (int)longpow; } for(;isdigit((int)(unsigned char)c);c=*p++); /* eat up remaining digits */ state = S_END; p--; break; case S_E_IMPLICIT: if (implicit_E) { savedp = p-1; /* savedp points to whatever precedes sign */ switch (c){ case '-': state = S_SIGNE; exp_sign = -1; break; case '+': state = S_SIGNE; break; default: state = S_END; p = savedp; } } else { 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; /* new code for FORTRAN support */ if (!found_exponent) { pow += scale; } if (!found_decpoint) { pow -= decpt; } 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; } /**** *unsigned int _CALLTYPE5 __stringtold( LDOUBLE *pLd, * char * * pEndPtr, * char * str, * int Mult12 ) * *Purpose: * converts a character string into a long double * *Entry: * pLD - pointer to the long double where the result should go. * pEndStr - pointer to a 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 _LDBL12 multiply should be used instead of * the long double mulitiply. * *Exit: * Returns the SLD_* flags or'ed together. * *Uses: * *Exceptions: * ********************************************************************************/ unsigned int _CALLTYPE5 __STRINGTOLD(_LDOUBLE *pld, const char * *p_end_ptr, const char *str, int mult12) { unsigned int retflags; INTRNCVT_STATUS intrncvt; _LDBL12 ld12; retflags = __strgtold12(&ld12, p_end_ptr, str, mult12, 0, 0, 0); intrncvt = _ld12told(&ld12, pld); if (intrncvt == INTRNCVT_OVERFLOW) { retflags |= SLD_OVERFLOW; } return retflags; }