strto_l.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. /*
  2. * Copyright (C) 2000 Manuel Novoa III
  3. *
  4. * Notes:
  5. *
  6. * The primary objective of this implementation was minimal size.
  7. *
  8. * Note: Assumes char layout 0-9.*A-Z.*a-z for ordinals values.
  9. *
  10. * There are a couple of compile-time options below.
  11. *
  12. */
  13. /*****************************************************************************/
  14. /* OPTIONS */
  15. /*****************************************************************************/
  16. /* Set if we want errno set appropriately. */
  17. /* NOTE: Implies _STRTO_ENDPTR below */
  18. #define _STRTO_ERRNO 0
  19. /* Set if we want support for the endptr arg. */
  20. /* Implied by _STRTO_ERRNO. */
  21. #define _STRTO_ENDPTR 1
  22. /*****************************************************************************/
  23. /* Don't change anything that follows. */
  24. /*****************************************************************************/
  25. #if _STRTO_ERRNO
  26. #undef _STRTO_ENDPTR
  27. #define _STRTO_ENDPTR 1
  28. #endif
  29. /*****************************************************************************/
  30. /* Are there actually any machines where this might fail? */
  31. #if 'A' > 'a'
  32. #error ordering assumption violated : 'A' > 'a'
  33. #endif
  34. #include <stdlib.h>
  35. #include <limits.h>
  36. #include <ctype.h>
  37. #if _STRTO_ERRNO
  38. #include <errno.h>
  39. #endif
  40. unsigned long _strto_l(const char *str, char **endptr, int base, int uflag);
  41. #if L_strto_l
  42. /*
  43. * This is the main work fuction which handles both strtol (uflag = 0) and
  44. * strtoul (uflag = 1).
  45. */
  46. unsigned long _strto_l(const char *str, char **endptr, int base, int uflag)
  47. {
  48. unsigned long number = 0;
  49. unsigned long cutoff;
  50. char *pos = (char *) str;
  51. #if _STRTO_ENDPTR
  52. char *fail_char = (char *) str;
  53. #endif
  54. int digit, cutoff_digit;
  55. int negative;
  56. while (isspace(*pos)) { /* skip leading whitespace */
  57. ++pos;
  58. }
  59. /* handle optional sign */
  60. negative = 0;
  61. switch(*pos) {
  62. case '-': negative = 1; /* fall through to increment pos */
  63. case '+': ++pos;
  64. }
  65. if ((base == 16) && (*pos == '0')) { /* handle option prefix */
  66. ++pos;
  67. #if _STRTO_ENDPTR
  68. fail_char = pos;
  69. #endif
  70. if ((*pos == 'x') || (*pos == 'X')) {
  71. ++pos;
  72. }
  73. }
  74. if (base == 0) { /* dynamic base */
  75. base = 10; /* default is 10 */
  76. if (*pos == '0') {
  77. ++pos;
  78. base -= 2; /* now base is 8 (or 16) */
  79. #if _STRTO_ENDPTR
  80. fail_char = pos;
  81. #endif
  82. if ((*pos == 'x') || (*pos == 'X')) {
  83. base += 8; /* base is 16 */
  84. ++pos;
  85. }
  86. }
  87. }
  88. if ((base < 2) || (base > 36)) { /* illegal base */
  89. goto DONE;
  90. }
  91. cutoff_digit = ULONG_MAX % base;
  92. cutoff = ULONG_MAX / base;
  93. while (1) {
  94. digit = 40;
  95. if ((*pos >= '0') && (*pos <= '9')) {
  96. digit = (*pos - '0');
  97. } else if (*pos >= 'a') {
  98. digit = (*pos - 'a' + 10);
  99. } else if (*pos >= 'A') {
  100. digit = (*pos - 'A' + 10);
  101. } else break;
  102. if (digit >= base) {
  103. break;
  104. }
  105. ++pos;
  106. #if _STRTO_ENDPTR
  107. fail_char = pos;
  108. #endif
  109. /* adjust number, with overflow check */
  110. if ((number > cutoff)
  111. || ((number == cutoff) && (digit > cutoff_digit))) {
  112. number = ULONG_MAX;
  113. if (uflag) {
  114. negative = 0; /* since unsigned returns ULONG_MAX */
  115. }
  116. #if _STRTO_ERRNO
  117. __set_errno(ERANGE);
  118. #endif
  119. } else {
  120. number = number * base + digit;
  121. }
  122. }
  123. DONE:
  124. #if _STRTO_ENDPTR
  125. if (endptr) {
  126. *endptr = fail_char;
  127. }
  128. #endif
  129. if (negative) {
  130. if (!uflag && (number > ((unsigned long)(-(1+LONG_MIN)))+1)) {
  131. #if _STRTO_ERRNO
  132. __set_errno(ERANGE);
  133. #endif
  134. return (unsigned long) LONG_MIN;
  135. }
  136. return (unsigned long)(-((long)number));
  137. } else {
  138. if (!uflag && (number > (unsigned long) LONG_MAX)) {
  139. #if _STRTO_ERRNO
  140. __set_errno(ERANGE);
  141. #endif
  142. return LONG_MAX;
  143. }
  144. return number;
  145. }
  146. }
  147. #endif
  148. #if L_strtoul
  149. unsigned long strtoul(const char *str, char **endptr, int base)
  150. {
  151. return _strto_l(str, endptr, base, 1);
  152. }
  153. #endif
  154. #if L_strtol
  155. long strtol(const char *str, char **endptr, int base)
  156. {
  157. return _strto_l(str, endptr, base, 0);
  158. }
  159. #endif