/* strtol 2000-10 writen by tenk * */ #define USE_ERRNO /* ANSI-C通り、値の限界値チェックをする場合 */ #ifdef USE_ERRNO #include #include #endif #include #include static signed char _strtol_chr2num[256] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, }; static unsigned long _strtol_body(char *start, char **endp, int base, int sf); unsigned long strtoul(char *start, char **endp, int base) { return (unsigned long)_strtol_body(start, endp, base, 1); } long strtol(char *start, char **endp, int base) { return (long)_strtol_body(start, endp, base, 0); } static unsigned long _strtol_body(char *start, char **endp, int base, int uf) { const char *s, *ss; unsigned char *e; unsigned long val; unsigned long v; int c, sf; #ifdef USE_ERRNO int ef; ef = 0; #endif assert(start != NULL && 0 <= base && base <= 36); s = (const char *)start; while (0 < *s && *s <= 0x20 || *s == 0x7f) s++; val = 0; sf = 1; if (*s == '-') { s++; sf = -1; } else if (*s == '+') { s++; } ss = s; if (base == 0) { if (*s == '0') { if (s[1] == 'x' || s[1] == 'X') goto BASE_16; goto BASE_8; } else { goto BASE_10; } } else if (base <= 10) { if (base == 10) { BASE_10: for (;;) { c = *s - '0'; if (c < 0 || c > 9) break; v = val * 10 + c; #ifdef USE_ERRNO ef |= (v < val); #endif val = v; s++; } } else if (base == 8) { BASE_8: for (;;) { c = *s - '0'; if (c < 0 || c > 7) break; v = (val << 3) | c; #ifdef USE_ERRNO ef |= (v < val); #endif val = v; s++; } } else { for (;;) { c = *s - '0'; if (c < 0 || c >= base) break; v = val * base + c; #ifdef USE_ERRNO ef |= (v < val); #endif val = v; s++; } } } else if (base == 16) { if (*s == '0' && (s[1] == 'x' || s[1] == 'X')) { BASE_16: s += 2; } for (;;) { #if 1 c = _strtol_chr2num[*s]; if (c < 0 || c > 15) break; v = (val << 4) + c; #ifdef USE_ERRNO ef |= (v < val); #endif val = v; s++; #else c = *s - '0'; if (c < 0) break; if (c < 10) v = (val << 4) + c; else if (c < 'A'-'0') break; else if (c <= 'F'-'0') v = (val << 4) + (c + '0' - 'A') + 10; else if (c < 'a'-'0') break; else if (c <= 'f'-'0') v = (val << 4) + (c + '0' - 'a') + 10; else break; #ifdef USE_ERRNO ef |= (v < val); #endif val = v; s++; #endif } } else if (base <= 36) { BASE_N: for (;;) { #if 1 c = _strtol_chr2num[*s]; if (c < 0 || c >= base) break; v = val * base + c; #ifdef USE_ERRNO ef |= (v < val); #endif val = v; s++; #else c = *s - '0'; if (c < 0) break; if (c < 10) v = val * base + c; else if (c < 'A'-'0') break; else if (c <= 'Z'-'0') v = val * base + (c + '0' - 'A') + 10; else if (c < 'a'-'0') break; else if (c <= 'z'-'0') v = val * base + (c + '0' - 'a') + 10; else break; #ifdef USE_ERRNO ef |= (v < val); #endif val = v; s++; #endif } } else { ; } if (s == ss) s = start; if (endp) *endp = (char *)s; #ifdef USE_ERRNO if (uf) { val = val * sf; if (ef) errno = ERANGE, val = ULONG_MAX; } else if (sf > 0) { if (ef || val > LONG_MAX) errno = ERANGE, val = LONG_MIN; } else { if (ef || val > (unsigned long)(-LONG_MIN)) errno = ERANGE, val = LONG_MIN; else val = -val; } #else val = val * sf; #endif return val; } /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ #if 0 /* お験しルーチン. 上記 strtol,strtoulをstrtol0,strtoul0にして実験 */ //#include #include // bcc32 -Ox -d (v5.5 lib) 時間 47秒 // bcc32 -Ox -d (v5.5 my) 時間 28秒 // cl /Ox /ML strtol.c kernel32.lib user32.lib winmm.lib (vc6 lib) 時間 30秒 // cl /Ox /ML strtol.c kernel32.lib user32.lib winmm.lib (vc6 my) 時間 27秒 // gcc -O3 -o strtol.exe strtol.c (mingw 2.95 lib) 時間 30秒 // gcc -O3 -o strtol.exe strtol.c (mingw 2.95 my) 時間 27秒 // _strtol_chr2num[] を使わない場合は、上記時間が 1秒遅くなるかならないか程度の差. // bcc32は付属のstrtolは、恐らく場合分けをしていないのでわ? static __inline void s_chk(long i, int base) { char buf[256]; long a; char *p; if (i < 0) { buf[0] = '-'; ltoa(-i, buf+1, base); } else { ltoa(i, buf, base); } a = strtol0(buf, &p, base); //printf("%d %s\n", i, buf); if (i != a) { printf("s:val %d %x != %x !!!\n", base,i, a); } #if 0 { char *q; long b = strtol(buf, &q, base); if (a != b) { printf("s*val %d %x != %x !!!\n", base, a, b); } } #endif } static __inline void u_chk(unsigned long i, int base) { char buf[256]; unsigned long a; char *p; ltoa(i, buf, base); a = strtoul0(buf, &p, base); if (i != a) { printf("u:val %d %x != %x !!!\n", base,i, a); } #if 0 { char *q; unsigned long b = strtoul(buf, &q, base); if (a != b) { printf("u*val %d %x != %x !!!\n", base, a, b); } } #endif } int main(void) { unsigned long i,b; int base, n; //int tim; static int bas[] = {10,16,8,2,6, 20, 36,0}; //tim = timeGetTime(); for (n = 0; bas[n]; n++) { base = bas[n]; printf("base=%d\n", base); b = 0; for (i = b-0x10000; i <= b+0x100000; i++) { s_chk(i, base); u_chk(i, base); } b = LONG_MAX; for (i = b-0x10000; i <= b+0x100000; i++) { s_chk(i, base); u_chk(i, base); } for (i = 1; i <= 0xFFF; i++) { s_chk(i*0x100000, base); u_chk(i*0x100000, base); } } //printf("時間 %d秒\n", (timeGetTime() - tim + 999) / 1000); return 0; } #endif