| /* A part of the Native C Library for Windows NT |
| Copyright 2007-2015 PC GO Ld. |
| |
| This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. |
| */ |
| |
| #include <stdlib.h> |
| #include <errno.h> |
| #include <ctype.h> |
| #include <limits.h> |
| |
| /* |
| #ifdef _LONGLONG |
| #define RETURN_TYPE long long int |
| #else |
| #define RETURN_TYPE long int |
| #endif |
| */ |
| |
| #ifdef UNSIGNED |
| #define SIGN unsigned |
| #define strtol strtoul |
| #else |
| #define SIGN signed |
| |
| #define DEF(TYPE, NAME) \ |
| static const TYPE NAME[] = { \ |
| F(2), F(3), F(4), F(5), F(6), F(7), F(8), F(9), F(10), \ |
| F(11), F(12), F(13), F(14), F(15), F(16), F(17), F(18), F(19), F(20), \ |
| F(21), F(22), F(23), F(24), F(25), F(26), F(27), F(28), F(29), F(30), \ |
| F(31), F(32), F(33), F(34), F(35), F(36) \ |
| } |
| |
| #define F(X) (ULONG_MAX / X) |
| DEF(unsigned long int, cutoff_tab); |
| #undef F |
| |
| #define F(X) (ULONG_MAX % X) |
| DEF(unsigned char, cutlim_tab); |
| #undef F |
| #endif |
| |
| //static const unsigned long int |
| |
| SIGN long int strtol(const char *nptr, char **endptr, int base) { |
| int negative; |
| register unsigned long int cutoff; |
| register unsigned int cutlim; |
| //register unsigned RETURN_TYPE i; |
| register unsigned long int i; |
| register const char *s; |
| register unsigned char c; |
| const char *save, *end; |
| int overflow; |
| |
| if(base < 0 || base == 1 || base > 36) { |
| errno = EINVAL; |
| return 0; |
| } |
| |
| save = s = nptr; |
| while(isspace(*s)) s++; |
| if(__builtin_expect(!*s, 0)) goto noconv; |
| |
| negative = 0; |
| if(*s == '-') { |
| negative = 1; |
| s++; |
| } else if(*s == '+') s++; |
| |
| if(*s == '0') { |
| if(tolower(s[1]) == 'x' && ((base == 0 && (base = 16)) || base == 16)) { |
| s += 2; |
| } else if(base == 0) base = 8; |
| } else if(base == 0) base = 10; |
| |
| save = s; |
| |
| end = NULL; |
| |
| cutoff = cutoff_tab[base - 2]; |
| cutlim = cutlim_tab[base - 2]; |
| |
| overflow = 0; |
| i = 0; |
| c = *s; |
| |
| if(c) do { |
| if(s == end) break; |
| if(c >= '0' && c <= '9') c -= '0'; |
| else if(isalpha(c)) c = toupper(c) - 'A' + 10; |
| else break; |
| if((int)c >= base) break; |
| if(i > cutoff || (i == cutoff && c > cutlim)) overflow = 1; |
| else { |
| i *= base; |
| i += c; |
| } |
| } while((c = *++s)); |
| |
| if(s == save) goto noconv; |
| if(endptr) *endptr = (char *) s; |
| |
| #ifndef UNSIGNED |
| if(!overflow && i > (negative ? |
| -((unsigned long int)(LONG_MIN + 1)) + 1 : (unsigned long int)LONG_MAX)) { |
| overflow = 1; |
| } |
| #endif |
| |
| if(__builtin_expect(overflow, 0)) { |
| errno = ERANGE; |
| #ifdef UNSIGNED |
| return ULONG_MAX; |
| #else |
| return negative ? LONG_MIN : LONG_MAX; |
| #endif |
| } |
| return negative ? -i : i; |
| |
| noconv: |
| if(endptr) { |
| if(save - nptr >= 2 && tolower(save[-1]) == 'x' && save[-2] == '0') { |
| *endptr = (char *)(save - 1); |
| } else { |
| *endptr = (char *) nptr; |
| } |
| } |
| return 0; |
| } |
| |
| #ifndef UNSIGNED |
| #define UNSIGNED |
| #undef SIGN |
| #include "strtol.c" |
| #endif |