/* * $Id: misc.c,v 1.5 2006-04-16 04:31:38 bacon Exp $ */ #include #ifndef XP_AWK_STAND_ALONE #include #include #endif xp_long_t xp_awk_strtolong ( const xp_char_t* str, int base, const xp_char_t** endptr) { xp_long_t n = 0; const xp_char_t* p; int digit, negative = 0; xp_assert (base < 37); p = str; while (xp_isspace(*p)) p++; while (*p != XP_CHAR('\0')) { if (*p == XP_CHAR('-')) { negative = ~negative; p++; } else if (*p == XP_CHAR('+')) p++; else break; } if (base == 0) { if (*p == XP_CHAR('0')) { p++; if (*p == XP_CHAR('x') || *p == XP_CHAR('X')) { p++; base = 16; } else if (*p == XP_CHAR('b') || *p == XP_CHAR('B')) { p++; base = 2; } else base = 8; } else base = 10; } else if (base == 16) { if (*p == XP_CHAR('0') && (*(p+1) == XP_CHAR('x') || *(p+1) == XP_CHAR('X'))) p += 2; } else if (base == 2) { if (*p == XP_CHAR('0') && (*(p+1) == XP_CHAR('b') || *(p+1) == XP_CHAR('B'))) p += 2; } while (*p != XP_CHAR('\0')) { if (*p >= XP_CHAR('0') && *p <= XP_CHAR('9')) digit = *p - XP_CHAR('0'); else if (*p >= XP_CHAR('A') && *p <= XP_CHAR('Z')) digit = *p - XP_CHAR('A') + 10; else if (*p >= XP_CHAR('a') && *p <= XP_CHAR('z')) digit = *p - XP_CHAR('a') + 10; else break; if (digit >= base) break; n = n * base + digit; p++; } if (endptr != XP_NULL) *endptr = p; return (negative)? -n: n; } /* * xp_awk_strtoreal is almost a replica of strtod. * * strtod.c -- * * Source code for the "strtod" library procedure. * * Copyright (c) 1988-1993 The Regents of the University of California. * Copyright (c) 1994 Sun Microsystems, Inc. * * Permission to use, copy, modify, and distribute this * software and its documentation for any purpose and without * fee is hereby granted, provided that the above copyright * notice appear in all copies. The University of California * makes no representations about the suitability of this * software for any purpose. It is provided "as is" without * express or implied warranty. */ #define MAX_EXPONENT 511 xp_real_t xp_awk_strtoreal (const xp_char_t* str) { /* * Table giving binary powers of 10. Entry is 10^2^i. * Used to convert decimal exponents into floating-point numbers. */ static xp_real_t powersOf10[] = { 10., 100., 1.0e4, 1.0e8, 1.0e16, 1.0e32, 1.0e64, 1.0e128, 1.0e256 }; xp_real_t fraction, dblExp, * d; const xp_char_t* p; xp_cint_t c; int exp = 0; /* Exponent read from "EX" field */ /* * Exponent that derives from the fractional part. Under normal * circumstatnces, it is the negative of the number of digits in F. * However, if I is very long, the last digits of I get dropped * (otherwise a long I with a large negative exponent could cause an * unnecessary overflow on I alone). In this case, fracExp is * incremented one for each dropped digit. */ int fracExp = 0; int mantSize; /* Number of digits in mantissa. */ int decPt; /* Number of mantissa digits BEFORE decimal point */ const xp_char_t *pExp; /* Temporarily holds location of exponent in string */ int sign = 0, expSign = 0; p = str; /* Strip off leading blanks and check for a sign */ while (xp_isspace(*p)) p++; while (*p != XP_CHAR('\0')) { if (*p == XP_CHAR('-')) { sign = ~sign; p++; } else if (*p == XP_CHAR('+')) p++; else break; } /* Count the number of digits in the mantissa (including the decimal * point), and also locate the decimal point. */ decPt = -1; for (mantSize = 0; ; mantSize++) { c = *p; if (!xp_isdigit(c)) { if ((c != XP_CHAR('.')) || (decPt >= 0)) break; decPt = mantSize; } p++; } /* * Now suck up the digits in the mantissa. Use two integers to * collect 9 digits each (this is faster than using floating-point). * If the mantissa has more than 18 digits, ignore the extras, since * they can't affect the value anyway. */ pExp = p; p -= mantSize; if (decPt < 0) { decPt = mantSize; } else { mantSize -= 1; /* One of the digits was the point */ } if (mantSize > 18) { fracExp = decPt - 18; mantSize = 18; } else { fracExp = decPt - mantSize; } if (mantSize == 0) { fraction = 0.0; p = str; goto done; } else { int frac1, frac2; frac1 = 0; for ( ; mantSize > 9; mantSize -= 1) { c = *p; p++; if (c == XP_CHAR('.')) { c = *p; p++; } frac1 = 10 * frac1 + (c - XP_CHAR('0')); } frac2 = 0; for (; mantSize > 0; mantSize -= 1) { c = *p; p++; if (c == XP_CHAR('.')) { c = *p; p++; } frac2 = 10*frac2 + (c - XP_CHAR('0')); } fraction = (1.0e9 * frac1) + frac2; } /* Skim off the exponent */ p = pExp; if ((*p == XP_CHAR('E')) || (*p == XP_CHAR('e'))) { p++; if (*p == XP_CHAR('-')) { expSign = 1; p++; } else { if (*p == XP_CHAR('+')) p++; expSign = 0; } if (!xp_isdigit(*p)) { /* p = pExp; */ goto done; } while (xp_isdigit(*p)) { exp = exp * 10 + (*p - XP_CHAR('0')); p++; } } if (expSign) exp = fracExp - exp; else exp = fracExp + exp; /* * Generate a floating-point number that represents the exponent. * Do this by processing the exponent one bit at a time to combine * many powers of 2 of 10. Then combine the exponent with the * fraction. */ if (exp < 0) { expSign = 1; exp = -exp; } else expSign = 0; if (exp > MAX_EXPONENT) exp = MAX_EXPONENT; dblExp = 1.0; for (d = powersOf10; exp != 0; exp >>= 1, d++) { if (exp & 01) dblExp *= *d; } if (expSign) fraction /= dblExp; else fraction *= dblExp; done: return (sign)? -fraction: fraction; }