/*********************************************************************** * * * This software is part of the ast package * * Copyright (c) 1985-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * * * * Information and Software Systems Research * * AT&T Research * * Florham Park NJ * * * * Glenn Fowler * * David Korn * * Phong Vo * * * ***********************************************************************/ /* * AT&T Research * Glenn Fowler * Phong Vo * * common header and implementation for * * strtol strtoul strton * strtoll strtoull strtonll * strntol strntoul strnton * strntoll strntoull strntonll * * define these macros to instantiate an implementation: * * S2I_function the function name * S2I_number the signed number type * S2I_unumber the unsigned number type * S2I_unsigned 1 for unsigned, 0 for signed * S2I_qualifier 1 for optional qualifier suffix, 0 otherwise * S2I_multiplier 1 for optional multiplier suffix, 0 otherwise * S2I_size the second argument is the input string size * * convert string to number * errno=ERANGE on overflow (LONG_MAX) or underflow (LONG_MIN) * if non-null e will point to first unrecognized char in s * if basep!=0 it points to the default base on input and * will point to the explicit base on return * a default base of 0 will determine the base from the input * a default base of 1 will determine the base from the input using bb#* * a base prefix in the string overrides *b * *b will not be set if the string has no base prefix * if m>1 and no multipler was specified then the result is multiplied by m * if m<0 then multipliers are not consumed * if a base arg or prefix is specified then multiplier is not consumed * * integer numbers are of the form: * * [sign][base][number[qualifier]][multiplier] * * base: nnn# base nnn * 0[xX] hex * 0 octal * [1-9] decimal * * number: [0-9a-zA-Z]* * * qualifier: [lL] * [uU] * [uU][lL] * [lL][uU] * [lL][lL][uU] * [uU][lL][lL] * * multiplier: . pseudo-float if m>1 * [bB] block (512) * [cC] char (1) * [gG] giga (1024*1024*1024) * [kK] kilo (1024) * [mM] mega (1024*1024) */ #include #include #include "sfhdr.h" #if !__STD_C && !defined(const) #define const #endif #ifndef ERANGE #define ERANGE EINVAL #endif #define QL 01 #define QU 02 #define S2I_umax (~((S2I_unumber)0)) #if S2I_unsigned #define S2I_type S2I_unumber #define S2I_min 0 #define S2I_max S2I_umax #else #define S2I_type S2I_number #define S2I_min (-S2I_max-1) #define S2I_max (S2I_umax>>1) #endif #if S2I_size #define S2I_valid(s) ((s)<(z)) #else #define S2I_valid(s) 1 #endif #define ADDOVER(n,c,s) ((S2I_umax-(n))<((S2I_unumber)((c)+(s)))) #define MPYOVER(n,c) (((S2I_unumber)(n))>(S2I_umax/(c))) static const S2I_unumber mm[] = { 0, S2I_umax / 1, S2I_umax / 2, S2I_umax / 3, S2I_umax / 4, S2I_umax / 5, S2I_umax / 6, S2I_umax / 7, S2I_umax / 8, S2I_umax / 9, S2I_umax / 10, S2I_umax / 11, S2I_umax / 12, S2I_umax / 13, S2I_umax / 14, S2I_umax / 15, S2I_umax / 16, S2I_umax / 17, S2I_umax / 18, S2I_umax / 19, S2I_umax / 20, S2I_umax / 21, S2I_umax / 22, S2I_umax / 23, S2I_umax / 24, S2I_umax / 25, S2I_umax / 26, S2I_umax / 27, S2I_umax / 28, S2I_umax / 29, S2I_umax / 30, S2I_umax / 31, S2I_umax / 32, S2I_umax / 33, S2I_umax / 34, S2I_umax / 35, S2I_umax / 36, S2I_umax / 37, S2I_umax / 38, S2I_umax / 39, S2I_umax / 40, S2I_umax / 41, S2I_umax / 42, S2I_umax / 43, S2I_umax / 44, S2I_umax / 45, S2I_umax / 46, S2I_umax / 47, S2I_umax / 48, S2I_umax / 49, S2I_umax / 50, S2I_umax / 51, S2I_umax / 52, S2I_umax / 53, S2I_umax / 54, S2I_umax / 55, S2I_umax / 56, S2I_umax / 57, S2I_umax / 58, S2I_umax / 59, S2I_umax / 60, S2I_umax / 61, S2I_umax / 62, S2I_umax / 63, S2I_umax / 64, }; #if defined(__EXPORT__) #define extern __EXPORT__ #endif extern S2I_type #undef extern #if S2I_size #if S2I_multiplier #if __STD_C S2I_function(const char* a, size_t size, char** e, char* basep, int m) #else S2I_function(a, size, e, basep, m) const char* a; size_t size; char** e; char* basep; int m; #endif #else #if __STD_C S2I_function(const char* a, size_t size, char** e, int base) #else S2I_function(a, size, e, base) const char* a; size_t size; char** e; int base; #endif #endif #else #if S2I_multiplier #if __STD_C S2I_function(const char* a, char** e, char* basep, int m) #else S2I_function(a, e, basep, m) const char* a; char** e; char* basep; int m; #endif #else #if __STD_C S2I_function(const char* a, char** e, int base) #else S2I_function(a, e, base) const char* a; char** e; int base; #endif #endif #endif { register unsigned char* s = (unsigned char*)a; #if S2I_size register unsigned char* z = s + size; #endif register S2I_unumber n; register S2I_unumber x; register int c; register int shift; register unsigned char* p; register unsigned char* cv; unsigned char* b; unsigned char* k; S2I_unumber v; #if S2I_multiplier register int base; #endif int negative; int overflow = 0; int decimal = 0; int thousand = 0; #if !S2I_unsigned int qualifier = 0; #endif #if S2I_multiplier base = basep ? *((unsigned char*)basep) : 0; #else if (base > 36 && base <= SF_RADIX) { static int conformance = -1; if (conformance < 0) conformance = !strcmp(astconf("CONFORMANCE", NiL, NiL), "standard"); if (conformance) base = 1; } #endif if (base && (base < 2 || base > SF_RADIX)) { errno = EINVAL; return 0; } while (S2I_valid(s) && isspace(*s)) s++; if ((negative = S2I_valid(s) && (*s == '-')) || S2I_valid(s) && *s == '+') k = ++s; else k = 0; p = s; if (!base) { if (S2I_valid(p) && (c = *p++) >= '0' && c <= '9') { n = c - '0'; if (S2I_valid(p) && (c = *p) >= '0' && c <= '9') { n = (n << 3) + (n << 1) + c - '0'; p++; } if (S2I_valid(p) && *p == '#') { if (n >= 2 && n <= 64) { k = s = p + 1; base = n; } } else if (base) base = 0; else if (S2I_valid(s) && *s == '0' && S2I_valid(s + 1)) { if ((c = *(s + 1)) == 'x' || c == 'X') { k = s += 2; base = 16; } else if (c >= '0' && c <= '7') { s++; base = 8; } } } if (!base) base = 10; else if (base < 2 || base > SF_RADIX) { errno = EINVAL; return 0; } #if S2I_multiplier else { if (basep) *basep = base; m = -1; } #endif } #if S2I_multiplier else m = -1; #endif /* * this part transcribed from sfvscanf() */ SFSETLOCALE(&decimal, &thousand); x = mm[base]; n = 0; if (base == 10) { b = s; p = 0; for (;;) { if (S2I_valid(s) && (c = *s++) >= '0' && c <= '9') { if (n > x) overflow = 1; else { n = (n << 3) + (n << 1); c -= '0'; if (ADDOVER(n, c, negative)) overflow = 1; n += c; } } else if (p && (s - p) != (3 + S2I_valid(s))) { s = p; n = v; c = 0; break; } else if (!S2I_valid(s) || c != thousand) break; else if (!p && (s - b) > 4) { if (e) *e = (char*)s - 1; if (overflow) { errno = ERANGE; #if S2I_unsigned n = S2I_max; #else n = negative ? S2I_min : S2I_max; #endif } return n; } else { p = s; v = n; } } } else { SFCVINIT(); cv = base <= 36 ? _Sfcv36 : _Sfcv64; if ((base & ~(base - 1)) == base) { #if !S2I_unsigned qualifier |= QU; #endif if (base < 8) shift = base < 4 ? 1 : 2; else if (base < 32) shift = base < 16 ? 3 : 4; else shift = base < 64 ? 5 : 6; while (S2I_valid(s) && (c = cv[*s++]) < base) { if (n > x) overflow = 1; else { n <<= shift; if (ADDOVER(n, c, negative)) overflow = 1; n += c; } } } else while (S2I_valid(s) && (c = cv[*s++]) < base) { if (n > x) overflow = 1; else { n *= base; if (ADDOVER(n, c, negative)) overflow = 1; n += c; } } c = *(s - 1); } #if S2I_qualifier /* * optional qualifier suffix */ if (S2I_valid(s) && s > (unsigned char*)(a + 1)) { base = 0; for (;;) { if (!(base & QL) && (c == 'l' || c == 'L')) { base |= QL; if (!S2I_valid(s)) break; c = *s++; if (c == 'l' || c == 'L') { if (!S2I_valid(s)) break; c = *s++; } } else if (!(base & QU) && (c == 'u' || c == 'U')) { base |= QU; #if !S2I_unsigned qualifier |= QU; #endif if (!S2I_valid(s)) break; c = *s++; } else break; } } #endif if (S2I_valid(s)) { #if S2I_multiplier /* * optional multiplier suffix */ if (m < 0 || s == (unsigned char*)(a + 1)) s--; else { switch (c) { case 'b': case 'B': shift = 9; break; case 'k': case 'K': shift = 10; break; case 'm': case 'M': shift = 20; break; case 'g': case 'G': shift = 30; break; case 't': case 'T': shift = 40; break; case 'p': case 'P': shift = 50; break; case 'e': case 'E': shift = 60; break; default: if (m <= 1) v = 0; else if (c == decimal && S2I_valid(s)) { if (MPYOVER(n, m)) overflow = 1; n *= m; v = 0; while (S2I_valid(s) && (c = *s++) >= '0' && c <= '9') v += (m /= 10) * (c - '0'); if (ADDOVER(n, v, negative)) overflow = 1; n += v; v = 0; } else v = m; s--; shift = 0; break; } if (shift) { if (S2I_valid(s)) switch (*s) { case 'b': case 'B': case 'i': case 'I': s++; break; } #if S2I_unsigned if (shift >= (sizeof(S2I_type) * CHAR_BIT)) #else if (shift >= (sizeof(S2I_type) * CHAR_BIT - 1)) #endif { v = 0; overflow = 1; } else v = ((S2I_unumber)1) << shift; } if (v) { if (MPYOVER(n, v)) overflow = 1; n *= v; } } #else s--; #endif } if (s == k) { s--; #if S2I_multiplier if (basep) *basep = 10; #endif } #if !S2I_unsigned else if (!(qualifier & QU)) { if (negative) { if (!n) { b = k; do { if (b >= s) { negative = 0; break; } } while (*b++ == '0'); } if (negative && (n - 1) > S2I_max) overflow = 1; } else if (n > S2I_max) overflow = 1; } #endif if (e) *e = (char*)s; if (overflow) { #if !S2I_unsigned if (negative) { if (x << 1) errno = ERANGE; return (S2I_type)S2I_min; } #endif errno = ERANGE; return (S2I_type)S2I_max; } return negative ? -n : n; }