Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

224 lines
5.7 KiB

4 years ago
  1. /***
  2. *strtol.c - Contains C runtimes strtol and strtoul
  3. *
  4. * Copyright (c) 1989-1993, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. * strtol - convert ascii string to long signed integer
  8. * strtoul - convert ascii string to long unsigned integer
  9. *
  10. *Revision History:
  11. * 06-05-89 PHG Module created, based on strtol.asm
  12. * 03-06-90 GJF Fixed calling type, added #include <cruntime.h>
  13. * and fixed the copyright. Also, cleaned up the
  14. * formatting a bit.
  15. * 03-07-90 GJF Fixed compiler warnings (added const qualifier to
  16. * an arg type and local var type).
  17. * 03-23-90 GJF Made strtoxl() _CALLTYPE4.
  18. * 08-13-90 SBM Compiles cleanly with -W3
  19. * 09-27-90 GJF New-style function declarators.
  20. * 10-24-91 GJF Had to cast LONG_MAX to unsigned long in expr. to
  21. * mollify MIPS compiler.
  22. * 10-21-92 GJF Made char-to-int conversions unsigned.
  23. * 04-21-93 GJF Removed assumption that LONG_MIN == -LONG_MAX.
  24. * 05-10-93 GJF Fixed error check.
  25. * 05-20-93 GJF Nothing like taking ugly code and making prettier...
  26. * and wrong. Fixed bug introduced on 5-10.
  27. *
  28. *******************************************************************************/
  29. #include <cruntime.h>
  30. #include <stdlib.h>
  31. #include <limits.h>
  32. #include <ctype.h>
  33. /***
  34. *strtol, strtoul(nptr,endptr,ibase) - Convert ascii string to long un/signed
  35. * int.
  36. *
  37. *Purpose:
  38. * Convert an ascii string to a long 32-bit value. The base
  39. * used for the caculations is supplied by the caller. The base
  40. * must be in the range 0, 2-36. If a base of 0 is supplied, the
  41. * ascii string must be examined to determine the base of the
  42. * number:
  43. * (a) First char = '0', second char = 'x' or 'X',
  44. * use base 16.
  45. * (b) First char = '0', use base 8
  46. * (c) First char in range '1' - '9', use base 10.
  47. *
  48. * If the 'endptr' value is non-NULL, then strtol/strtoul places
  49. * a pointer to the terminating character in this value.
  50. * See ANSI standard for details
  51. *
  52. *Entry:
  53. * nptr == NEAR/FAR pointer to the start of string.
  54. * endptr == NEAR/FAR pointer to the end of the string.
  55. * ibase == integer base to use for the calculations.
  56. *
  57. * string format: [whitespace] [sign] [0] [x] [digits/letters]
  58. *
  59. *Exit:
  60. * Good return:
  61. * result
  62. *
  63. * Overflow return:
  64. * strtol -- LONG_MAX or LONG_MIN
  65. * strtoul -- ULONG_MAX
  66. *
  67. * No digits or bad base return:
  68. * 0
  69. * endptr = nptr*
  70. *
  71. *Exceptions:
  72. * None.
  73. *******************************************************************************/
  74. /* flag values */
  75. #define FL_UNSIGNED 1 /* strtoul called */
  76. #define FL_NEG 2 /* negative sign found */
  77. #define FL_OVERFLOW 4 /* overflow occured */
  78. #define FL_READDIGIT 8 /* we've read at least one correct digit */
  79. static unsigned long _CRTAPI3 strtoxl (
  80. const char *nptr,
  81. const char **endptr,
  82. int ibase,
  83. int flags
  84. )
  85. {
  86. const char *p;
  87. char c;
  88. unsigned long number;
  89. unsigned digval;
  90. unsigned long maxval;
  91. p = nptr; /* p is our scanning pointer */
  92. number = 0; /* start with zero */
  93. c = *p++; /* read char */
  94. while ( isspace((int)(unsigned char)c) )
  95. c = *p++; /* skip whitespace */
  96. if (c == '-') {
  97. flags |= FL_NEG; /* remember minus sign */
  98. c = *p++;
  99. }
  100. else if (c == '+')
  101. c = *p++; /* skip sign */
  102. if (ibase < 0 || ibase == 1 || ibase > 36) {
  103. /* bad base! */
  104. if (endptr)
  105. /* store beginning of string in endptr */
  106. *endptr = nptr;
  107. return 0L; /* return 0 */
  108. }
  109. else if (ibase == 0) {
  110. /* determine base free-lance, based on first two chars of
  111. string */
  112. if (c != '0')
  113. ibase = 10;
  114. else if (*p == 'x' || *p == 'X')
  115. ibase = 16;
  116. else
  117. ibase = 8;
  118. }
  119. if (ibase == 16) {
  120. /* we might have 0x in front of number; remove if there */
  121. if (c == '0' && (*p == 'x' || *p == 'X')) {
  122. ++p;
  123. c = *p++; /* advance past prefix */
  124. }
  125. }
  126. /* if our number exceeds this, we will overflow on multiply */
  127. maxval = ULONG_MAX / ibase;
  128. for (;;) { /* exit in middle of loop */
  129. /* convert c to value */
  130. if ( isdigit((int)(unsigned char)c) )
  131. digval = c - '0';
  132. else if ( isalpha((int)(unsigned char)c) )
  133. digval = toupper(c) - 'A' + 10;
  134. else
  135. break;
  136. if (digval >= (unsigned)ibase)
  137. break; /* exit loop if bad digit found */
  138. /* record the fact we have read one digit */
  139. flags |= FL_READDIGIT;
  140. /* we now need to compute number = number * base + digval,
  141. but we need to know if overflow occured. This requires
  142. a tricky pre-check. */
  143. if (number < maxval || (number == maxval &&
  144. (unsigned long)digval <= ULONG_MAX % ibase)) {
  145. /* we won't overflow, go ahead and multiply */
  146. number = number * ibase + digval;
  147. }
  148. else {
  149. /* we would have overflowed -- set the overflow flag */
  150. flags |= FL_OVERFLOW;
  151. }
  152. c = *p++; /* read next digit */
  153. }
  154. --p; /* point to place that stopped scan */
  155. if (!(flags & FL_READDIGIT)) {
  156. /* no number there; return 0 and point to beginning of
  157. string */
  158. if (endptr)
  159. /* store beginning of string in endptr later on */
  160. p = nptr;
  161. number = 0L; /* return 0 */
  162. }
  163. else if ( (flags & FL_OVERFLOW) ||
  164. ( !(flags & FL_UNSIGNED) &&
  165. ( ( (flags & FL_NEG) && (number > -LONG_MIN) ) ||
  166. ( !(flags & FL_NEG) && (number > LONG_MAX) ) ) ) )
  167. {
  168. /* overflow or signed overflow occurred */
  169. if ( flags & FL_UNSIGNED )
  170. number = ULONG_MAX;
  171. else if ( flags & FL_NEG )
  172. number = (unsigned long)(-LONG_MIN);
  173. else
  174. number = LONG_MAX;
  175. }
  176. if (endptr != NULL)
  177. /* store pointer to char that stopped the scan */
  178. *endptr = p;
  179. if (flags & FL_NEG)
  180. /* negate result if there was a neg sign */
  181. number = (unsigned long)(-(long)number);
  182. return number; /* done. */
  183. }
  184. long _CRTAPI1 strtol (
  185. const char *nptr,
  186. char **endptr,
  187. int ibase
  188. )
  189. {
  190. return (long) strtoxl(nptr, endptr, ibase, 0);
  191. }
  192. unsigned long _CRTAPI1 strtoul (
  193. const char *nptr,
  194. char **endptr,
  195. int ibase
  196. )
  197. {
  198. return strtoxl(nptr, endptr, ibase, FL_UNSIGNED);
  199. }