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.

242 lines
7.7 KiB

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