strto_ll.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  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. #define __USE_GNU
  36. #include <limits.h>
  37. #include <ctype.h>
  38. #if _STRTO_ERRNO
  39. #include <errno.h>
  40. #endif
  41. unsigned long long _strto_ll(const char *str, char **endptr, int base, int uflag);
  42. #if L_strto_ll
  43. /*
  44. * This is the main work fuction which handles both strtol (uflag = 0) and
  45. * strtoul (uflag = 1).
  46. */
  47. unsigned long long _strto_ll(const char *str, char **endptr, int base, int uflag)
  48. {
  49. unsigned long long number = 0;
  50. unsigned long long cutoff;
  51. char *pos = (char *) str;
  52. #if _STRTO_ENDPTR
  53. char *fail_char = (char *) str;
  54. #endif
  55. int digit, cutoff_digit;
  56. int negative;
  57. while (isspace(*pos)) { /* skip leading whitespace */
  58. ++pos;
  59. }
  60. /* handle optional sign */
  61. negative = 0;
  62. switch(*pos) {
  63. case '-': negative = 1; /* fall through to increment pos */
  64. case '+': ++pos;
  65. }
  66. if ((base == 16) && (*pos == '0')) { /* handle option prefix */
  67. ++pos;
  68. #if _STRTO_ENDPTR
  69. fail_char = pos;
  70. #endif
  71. if ((*pos == 'x') || (*pos == 'X')) {
  72. ++pos;
  73. }
  74. }
  75. if (base == 0) { /* dynamic base */
  76. base = 10; /* default is 10 */
  77. if (*pos == '0') {
  78. ++pos;
  79. base -= 2; /* now base is 8 (or 16) */
  80. #if _STRTO_ENDPTR
  81. fail_char = pos;
  82. #endif
  83. if ((*pos == 'x') || (*pos == 'X')) {
  84. base += 8; /* base is 16 */
  85. ++pos;
  86. }
  87. }
  88. }
  89. if ((base < 2) || (base > 36)) { /* illegal base */
  90. goto DONE;
  91. }
  92. cutoff_digit = ULONG_LONG_MAX % base;
  93. cutoff = ULONG_LONG_MAX / base;
  94. while (1) {
  95. digit = 40;
  96. if ((*pos >= '0') && (*pos <= '9')) {
  97. digit = (*pos - '0');
  98. } else if (*pos >= 'a') {
  99. digit = (*pos - 'a' + 10);
  100. } else if (*pos >= 'A') {
  101. digit = (*pos - 'A' + 10);
  102. } else break;
  103. if (digit >= base) {
  104. break;
  105. }
  106. ++pos;
  107. #if _STRTO_ENDPTR
  108. fail_char = pos;
  109. #endif
  110. /* adjust number, with overflow check */
  111. if ((number > cutoff)
  112. || ((number == cutoff) && (digit > cutoff_digit))) {
  113. number = ULONG_LONG_MAX;
  114. if (uflag) {
  115. negative = 0; /* since unsigned returns ULONG_LONG_MAX */
  116. }
  117. #if _STRTO_ERRNO
  118. __set_errno(ERANGE);
  119. #endif
  120. } else {
  121. number = number * base + digit;
  122. }
  123. }
  124. DONE:
  125. #if _STRTO_ENDPTR
  126. if (endptr) {
  127. *endptr = fail_char;
  128. }
  129. #endif
  130. if (negative) {
  131. if (!uflag && (number > ((unsigned long long)(-(1+LONG_LONG_MIN)))+1)) {
  132. #if _STRTO_ERRNO
  133. __set_errno(ERANGE);
  134. #endif
  135. return (unsigned long long) LONG_LONG_MIN;
  136. }
  137. return (unsigned long long)(-((long long)number));
  138. } else {
  139. if (!uflag && (number > (unsigned long long) LONG_LONG_MAX)) {
  140. #if _STRTO_ERRNO
  141. __set_errno(ERANGE);
  142. #endif
  143. return LONG_LONG_MAX;
  144. }
  145. return number;
  146. }
  147. }
  148. #endif
  149. #if L_strtoull
  150. unsigned long long strtoull(const char *str, char **endptr, int base)
  151. {
  152. return _strto_ll(str, endptr, base, 1);
  153. }
  154. #endif
  155. #if L_strtoll
  156. long long strtoll(const char *str, char **endptr, int base)
  157. {
  158. return _strto_ll(str, endptr, base, 0);
  159. }
  160. #endif
  161. #ifdef L_atoll
  162. long long atoll(const char *str)
  163. {
  164. return(_strto_ll((str),(char**)0,10,0));
  165. }
  166. #endif