blob: 13ddc02ae8bccdcd998c00b39cd7dede932d6ccb [file] [log] [blame] [raw]
/* 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