blob: 947620a776b40ccd3a0e5e2dd3d06e0f46885da1 [file] [log] [blame]
#include "shgetc.h"
#include <ctype.h>
#include <errno.h>
#include <limits.h>
/* Lookup table for digit values. -1==255>=36 -> invalid */
static const unsigned char table[] = {
-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, 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,
};
unsigned long long __intscan(FILE* f, unsigned base, int pok, unsigned long long lim) {
const unsigned char* val = table + 1;
int c, neg = 0;
unsigned x;
unsigned long long y;
if (base > 36) {
errno = EINVAL;
return 0;
}
while (isspace((c = shgetc(f))))
;
if (c == '+' || c == '-') {
neg = -(c == '-');
c = shgetc(f);
}
if ((base == 0 || base == 16) && c == '0') {
c = shgetc(f);
if ((c | 32) == 'x') {
c = shgetc(f);
if (val[c] >= 16) {
shunget(f);
if (pok)
shunget(f);
else
shlim(f, 0);
return 0;
}
base = 16;
} else if (base == 0) {
base = 8;
}
} else {
if (base == 0)
base = 10;
if (val[c] >= base) {
shunget(f);
shlim(f, 0);
errno = EINVAL;
return 0;
}
}
if (base == 10) {
for (x = 0; c >= '0' && c <= '9' && x <= UINT_MAX / 10 - 1; c = shgetc(f))
x = x * 10 + (c - '0');
for (y = x; c >= '0' && c <= '9' && y <= ULLONG_MAX / 10 && 10 * y <= ULLONG_MAX - (c - '0');
c = shgetc(f))
y = y * 10 + (c - '0');
if (c < '0' || c > '9')
goto done;
} else if (!(base & (base - 1))) {
int bs = "\0\1\2\4\7\3\6\5"[(0x17 * base) >> 5 & 7];
for (x = 0; val[c] < base && x <= UINT_MAX / 32; c = shgetc(f))
x = x << bs | val[c];
for (y = x; val[c] < base && y <= ULLONG_MAX >> bs; c = shgetc(f))
y = y << bs | val[c];
} else {
for (x = 0; val[c] < base && x <= UINT_MAX / 36 - 1; c = shgetc(f))
x = x * base + val[c];
for (y = x; val[c] < base && y <= ULLONG_MAX / base && base * y <= ULLONG_MAX - val[c];
c = shgetc(f))
y = y * base + val[c];
}
if (val[c] < base) {
for (; val[c] < base; c = shgetc(f))
;
errno = ERANGE;
y = lim;
if (lim & 1)
neg = 0;
}
done:
shunget(f);
if (y >= lim) {
if (!(lim & 1) && !neg) {
errno = ERANGE;
return lim - 1;
} else if (y > lim) {
errno = ERANGE;
return lim;
}
}
return (y ^ neg) - neg;
}