intscan.c 2.6 KB

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