blob: 122c1ccfaf550afe5e3d60f27b570e05b547220b [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 UNSIGNED
#define SIGN unsigned
#define strtoll strtoull
#else
#define SIGN signed
#define F(X) (ULONG_MAX / X)
static const unsigned long int jmax_tab[] = {
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)
};
#undef F
#endif
SIGN long long int strtoll(const char *nptr, char **endptr, int base) {
int negative;
register unsigned long 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;
overflow = 0;
i = 0;
c = *s;
{
unsigned long int j = 0;
unsigned long int jmax = jmax_tab[base - 2];
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;
else if(j >= jmax) {
i = j;
i *= base;
i += c;
} else {
j = j * base + c;
}
} while((c = *++s));
i = j;
}
if(s == save) goto noconv;
if(endptr) *endptr = (char *) s;
#ifndef UNSIGNED
if(!overflow && i > (negative ?
-((unsigned long long int)(LONG_LONG_MIN + 1)) + 1 : (unsigned long long int)LONG_LONG_MAX)) {
overflow = 1;
}
#endif
if(__builtin_expect(overflow, 0)) {
errno = ERANGE;
#ifdef UNSIGNED
return ULONG_LONG_MAX;
#else
return negative ? LONG_LONG_MIN : LONG_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 "strtoll.c"
#endif