Source code of Windows XP (NT5)
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.

212 lines
5.2 KiB

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