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.

209 lines
6.8 KiB

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