Leaked source code of windows server 2003
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.

243 lines
8.6 KiB

  1. /***
  2. *strtol.c - Contains C runtimes strtol and strtoul
  3. *
  4. * Copyright (c) 1989-2001, 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-06-93 SKS Replace _CRTAPI* with _cdecl
  24. * 04-21-93 GJF Removed assumption that LONG_MIN == -LONG_MAX.
  25. * 05-10-93 GJF Fixed error check.
  26. * 05-20-93 GJF Nothing like taking ugly code and making prettier...
  27. * and wrong. Fixed bug introduced on 5-10.
  28. * 08-27-98 GJF Revised multithread support based on threadlocinfo
  29. * struct. Also, replaced isdigit, isalpha and toupper
  30. * macros with __ascii_isdigit, __ascii_isalpha and
  31. * __ascii_towupper macros.
  32. *
  33. *******************************************************************************/
  34. #include <cruntime.h>
  35. #include <stdlib.h>
  36. #include <limits.h>
  37. #include <errno.h>
  38. #include <ctype.h>
  39. #include <mtdll.h>
  40. /***
  41. *strtol, strtoul(nptr,endptr,ibase) - Convert ascii string to long un/signed
  42. * int.
  43. *
  44. *Purpose:
  45. * Convert an ascii string to a long 32-bit value. The base
  46. * used for the caculations is supplied by the caller. The base
  47. * must be in the range 0, 2-36. If a base of 0 is supplied, the
  48. * ascii string must be examined to determine the base of the
  49. * number:
  50. * (a) First char = '0', second char = 'x' or 'X',
  51. * use base 16.
  52. * (b) First char = '0', use base 8
  53. * (c) First char in range '1' - '9', use base 10.
  54. *
  55. * If the 'endptr' value is non-NULL, then strtol/strtoul places
  56. * a pointer to the terminating character in this value.
  57. * See ANSI standard for details
  58. *
  59. *Entry:
  60. * nptr == NEAR/FAR pointer to the start of string.
  61. * endptr == NEAR/FAR pointer to the end of the string.
  62. * ibase == integer base to use for the calculations.
  63. *
  64. * string format: [whitespace] [sign] [0] [x] [digits/letters]
  65. *
  66. *Exit:
  67. * Good return:
  68. * result
  69. *
  70. * Overflow return:
  71. * strtol -- LONG_MAX or LONG_MIN
  72. * strtoul -- ULONG_MAX
  73. * strtol/strtoul -- errno == ERANGE
  74. *
  75. * No digits or bad base return:
  76. * 0
  77. * endptr = nptr*
  78. *
  79. *Exceptions:
  80. * None.
  81. *******************************************************************************/
  82. /* flag values */
  83. #define FL_UNSIGNED 1 /* strtoul called */
  84. #define FL_NEG 2 /* negative sign found */
  85. #define FL_OVERFLOW 4 /* overflow occured */
  86. #define FL_READDIGIT 8 /* we've read at least one correct digit */
  87. static unsigned long __cdecl strtoxl (
  88. const char *nptr,
  89. const char **endptr,
  90. int ibase,
  91. int flags
  92. )
  93. {
  94. const char *p;
  95. char c;
  96. unsigned long number;
  97. unsigned digval;
  98. unsigned long maxval;
  99. #ifdef _MT
  100. pthreadlocinfo ptloci = _getptd()->ptlocinfo;
  101. if ( ptloci != __ptlocinfo )
  102. ptloci = __updatetlocinfo();
  103. #endif
  104. p = nptr; /* p is our scanning pointer */
  105. number = 0; /* start with zero */
  106. c = *p++; /* read char */
  107. #ifdef _MT
  108. while ( __isspace_mt(ptloci, (int)(unsigned char)c) )
  109. #else
  110. while ( isspace((int)(unsigned char)c) )
  111. #endif
  112. c = *p++; /* skip whitespace */
  113. if (c == '-') {
  114. flags |= FL_NEG; /* remember minus sign */
  115. c = *p++;
  116. }
  117. else if (c == '+')
  118. c = *p++; /* skip sign */
  119. if (ibase < 0 || ibase == 1 || ibase > 36) {
  120. /* bad base! */
  121. if (endptr)
  122. /* store beginning of string in endptr */
  123. *endptr = nptr;
  124. return 0L; /* return 0 */
  125. }
  126. else if (ibase == 0) {
  127. /* determine base free-lance, based on first two chars of
  128. string */
  129. if (c != '0')
  130. ibase = 10;
  131. else if (*p == 'x' || *p == 'X')
  132. ibase = 16;
  133. else
  134. ibase = 8;
  135. }
  136. if (ibase == 16) {
  137. /* we might have 0x in front of number; remove if there */
  138. if (c == '0' && (*p == 'x' || *p == 'X')) {
  139. ++p;
  140. c = *p++; /* advance past prefix */
  141. }
  142. }
  143. /* if our number exceeds this, we will overflow on multiply */
  144. maxval = ULONG_MAX / ibase;
  145. for (;;) { /* exit in middle of loop */
  146. /* convert c to value */
  147. if ( __ascii_isdigit((int)(unsigned char)c) )
  148. digval = c - '0';
  149. else if ( __ascii_isalpha((int)(unsigned char)c) )
  150. digval = __ascii_toupper(c) - 'A' + 10;
  151. else
  152. break;
  153. if (digval >= (unsigned)ibase)
  154. break; /* exit loop if bad digit found */
  155. /* record the fact we have read one digit */
  156. flags |= FL_READDIGIT;
  157. /* we now need to compute number = number * base + digval,
  158. but we need to know if overflow occured. This requires
  159. a tricky pre-check. */
  160. if (number < maxval || (number == maxval &&
  161. (unsigned long)digval <= ULONG_MAX % ibase)) {
  162. /* we won't overflow, go ahead and multiply */
  163. number = number * ibase + digval;
  164. }
  165. else {
  166. /* we would have overflowed -- set the overflow flag */
  167. flags |= FL_OVERFLOW;
  168. }
  169. c = *p++; /* read next digit */
  170. }
  171. --p; /* point to place that stopped scan */
  172. if (!(flags & FL_READDIGIT)) {
  173. /* no number there; return 0 and point to beginning of
  174. string */
  175. if (endptr)
  176. /* store beginning of string in endptr later on */
  177. p = nptr;
  178. number = 0L; /* return 0 */
  179. }
  180. else if ( (flags & FL_OVERFLOW) ||
  181. ( !(flags & FL_UNSIGNED) &&
  182. ( ( (flags & FL_NEG) && (number > -LONG_MIN) ) ||
  183. ( !(flags & FL_NEG) && (number > LONG_MAX) ) ) ) )
  184. {
  185. /* overflow or signed overflow occurred */
  186. errno = ERANGE;
  187. if ( flags & FL_UNSIGNED )
  188. number = ULONG_MAX;
  189. else if ( flags & FL_NEG )
  190. number = (unsigned long)(-LONG_MIN);
  191. else
  192. number = LONG_MAX;
  193. }
  194. if (endptr != NULL)
  195. /* store pointer to char that stopped the scan */
  196. *endptr = p;
  197. if (flags & FL_NEG)
  198. /* negate result if there was a neg sign */
  199. number = (unsigned long)(-(long)number);
  200. return number; /* done. */
  201. }
  202. long __cdecl strtol (
  203. const char *nptr,
  204. char **endptr,
  205. int ibase
  206. )
  207. {
  208. return (long) strtoxl(nptr, endptr, ibase, 0);
  209. }
  210. unsigned long __cdecl strtoul (
  211. const char *nptr,
  212. char **endptr,
  213. int ibase
  214. )
  215. {
  216. return strtoxl(nptr, endptr, ibase, FL_UNSIGNED);
  217. }