123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899 |
- #include <limits.h>
- #include <errno.h>
- #include <ctype.h>
- #include "shgetc.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'<10U && x<=UINT_MAX/10-1; c=shgetc(f))
- x = x*10 + (c-'0');
- for (y=x; c-'0'<10U && y<=ULLONG_MAX/10 && 10*y<=ULLONG_MAX-(c-'0'); c=shgetc(f))
- y = y*10 + (c-'0');
- if (c-'0'>=10U) 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;
- }
- 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;
- }
|