intscan.c raw

   1  #include <limits.h>
   2  #include <errno.h>
   3  #include <ctype.h>
   4  #include "shgetc.h"
   5  
   6  /* Lookup table for digit values. -1==255>=36 -> invalid */
   7  static const unsigned char table[] = { -1,
   8  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
   9  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
  10  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
  11   0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1,
  12  -1,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,
  13  25,26,27,28,29,30,31,32,33,34,35,-1,-1,-1,-1,-1,
  14  -1,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,
  15  25,26,27,28,29,30,31,32,33,34,35,-1,-1,-1,-1,-1,
  16  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
  17  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
  18  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
  19  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
  20  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
  21  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
  22  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
  23  -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
  24  };
  25  
  26  unsigned long long __intscan(FILE *f, unsigned base, int pok, unsigned long long lim)
  27  {
  28  	const unsigned char *val = table+1;
  29  	int c, neg=0;
  30  	unsigned x;
  31  	unsigned long long y;
  32  	if (base > 36 || base == 1) {
  33  		errno = EINVAL;
  34  		return 0;
  35  	}
  36  	while (isspace((c=shgetc(f))));
  37  	if (c=='+' || c=='-') {
  38  		neg = -(c=='-');
  39  		c = shgetc(f);
  40  	}
  41  	if ((base == 0 || base == 16) && c=='0') {
  42  		c = shgetc(f);
  43  		if ((c|32)=='x') {
  44  			c = shgetc(f);
  45  			if (val[c]>=16) {
  46  				shunget(f);
  47  				if (pok) shunget(f);
  48  				else shlim(f, 0);
  49  				return 0;
  50  			}
  51  			base = 16;
  52  		} else if (base == 0) {
  53  			base = 8;
  54  		}
  55  	} else {
  56  		if (base == 0) base = 10;
  57  		if (val[c] >= base) {
  58  			shunget(f);
  59  			shlim(f, 0);
  60  			errno = EINVAL;
  61  			return 0;
  62  		}
  63  	}
  64  	if (base == 10) {
  65  		for (x=0; c-'0'<10U && x<=UINT_MAX/10-1; c=shgetc(f))
  66  			x = x*10 + (c-'0');
  67  		for (y=x; c-'0'<10U && y<=ULLONG_MAX/10 && 10*y<=ULLONG_MAX-(c-'0'); c=shgetc(f))
  68  			y = y*10 + (c-'0');
  69  		if (c-'0'>=10U) goto done;
  70  	} else if (!(base & base-1)) {
  71  		int bs = "\0\1\2\4\7\3\6\5"[(0x17*base)>>5&7];
  72  		for (x=0; val[c]<base && x<=UINT_MAX/32; c=shgetc(f))
  73  			x = x<<bs | val[c];
  74  		for (y=x; val[c]<base && y<=ULLONG_MAX>>bs; c=shgetc(f))
  75  			y = y<<bs | val[c];
  76  	} else {
  77  		for (x=0; val[c]<base && x<=UINT_MAX/36-1; c=shgetc(f))
  78  			x = x*base + val[c];
  79  		for (y=x; val[c]<base && y<=ULLONG_MAX/base && base*y<=ULLONG_MAX-val[c]; c=shgetc(f))
  80  			y = y*base + val[c];
  81  	}
  82  	if (val[c]<base) {
  83  		for (; val[c]<base; c=shgetc(f));
  84  		errno = ERANGE;
  85  		y = lim;
  86  		if (lim&1) neg = 0;
  87  	}
  88  done:
  89  	shunget(f);
  90  	if (y>=lim) {
  91  		if (!(lim&1) && !neg) {
  92  			errno = ERANGE;
  93  			return lim-1;
  94  		} else if (y>lim) {
  95  			errno = ERANGE;
  96  			return lim;
  97  		}
  98  	}
  99  	return (y^neg)-neg;
 100  }
 101