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.

225 lines
5.6 KiB

  1. /***
  2. *wcstoq.c - Contains C runtimes wcstoi64 and wcstoui64
  3. *
  4. * Copyright (c) 1989-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. * wcstoi64 - convert ascii string to signed __int64 integer
  8. * wcstoui64- convert ascii string to unsigned __int64 integer
  9. *
  10. *Revision History:
  11. * 02-11-00 GB Module created, based on strtoq.c
  12. * 06-02-00 GB Fixed the bug for IA64_MIN value.
  13. * 08-01-00 GB Added multilangual support
  14. *
  15. *******************************************************************************/
  16. #include <cruntime.h>
  17. #include <stdlib.h>
  18. #include <limits.h>
  19. #include <errno.h>
  20. #include <ctype.h>
  21. #include <mtdll.h>
  22. int _wchartodigit(wchar_t ch);
  23. /***
  24. *wcstoq, wcstouq(nptr,endptr,ibase) - Convert ascii string to un/signed __int64.
  25. *
  26. *Purpose:
  27. * Convert an ascii string to a 64-bit __int64 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 wchar_t = '0', second wchar_t = 'x' or 'X',
  33. * use base 16.
  34. * (b) First wchar_t = '0', use base 8
  35. * (c) First wchar_t in range '1' - '9', use base 10.
  36. *
  37. * If the 'endptr' value is non-NULL, then wcstoq/wcstouq 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. * wcstoq -- _I64_MAX or _I64_MIN
  54. * wcstouq -- _UI64_MAX
  55. * wcstoq/wcstouq -- errno == ERANGE
  56. *
  57. * No digits or bad base return:
  58. * 0
  59. * endptr = nptr*
  60. *
  61. *Exceptions:
  62. * None.
  63. *******************************************************************************/
  64. /* flag values */
  65. #define FL_UNSIGNED 1 /* wcstouq called */
  66. #define FL_NEG 2 /* negative sign found */
  67. #define FL_OVERFLOW 4 /* overflow occured */
  68. #define FL_READDIGIT 8 /* we've read at least one correct digit */
  69. static unsigned __int64 __cdecl wcstoxq (
  70. const wchar_t *nptr,
  71. const wchar_t **endptr,
  72. int ibase,
  73. int flags
  74. )
  75. {
  76. const wchar_t *p;
  77. wchar_t c;
  78. unsigned __int64 number;
  79. unsigned digval;
  80. unsigned __int64 maxval;
  81. #ifdef _MT
  82. pthreadlocinfo ptloci = _getptd()->ptlocinfo;
  83. if ( ptloci != __ptlocinfo )
  84. ptloci = __updatetlocinfo();
  85. #endif
  86. p = nptr; /* p is our scanning pointer */
  87. number = 0; /* start with zero */
  88. c = *p++; /* read wchar_t */
  89. #ifdef _MT
  90. while ( __iswspace_mt(ptloci, c) )
  91. #else
  92. while ( iswspace(c) )
  93. #endif
  94. c = *p++; /* skip whitespace */
  95. if (c == '-') {
  96. flags |= FL_NEG; /* remember minus sign */
  97. c = *p++;
  98. }
  99. else if (c == '+')
  100. c = *p++; /* skip sign */
  101. if (ibase < 0 || ibase == 1 || ibase > 36) {
  102. /* bad base! */
  103. if (endptr)
  104. /* store beginning of string in endptr */
  105. *endptr = nptr;
  106. return 0L; /* return 0 */
  107. }
  108. else if (ibase == 0) {
  109. /* determine base free-lance, based on first two chars of
  110. string */
  111. if (_wchartodigit(c) != 0)
  112. ibase = 10;
  113. else if (*p == 'x' || *p == 'X')
  114. ibase = 16;
  115. else
  116. ibase = 8;
  117. }
  118. if (ibase == 16) {
  119. /* we might have 0x in front of number; remove if there */
  120. if (_wchartodigit(c) == 0 && (*p == L'x' || *p == L'X')) {
  121. ++p;
  122. c = *p++; /* advance past prefix */
  123. }
  124. }
  125. /* if our number exceeds this, we will overflow on multiply */
  126. maxval = _UI64_MAX / ibase;
  127. for (;;) { /* exit in middle of loop */
  128. /* convert c to value */
  129. if ( (digval = _wchartodigit(c)) != -1 )
  130. ;
  131. else if ( __ascii_iswalpha(c) )
  132. digval = toupper(c) - 'A' + 10;
  133. else
  134. break;
  135. if (digval >= (unsigned)ibase)
  136. break; /* exit loop if bad digit found */
  137. /* record the fact we have read one digit */
  138. flags |= FL_READDIGIT;
  139. /* we now need to compute number = number * base + digval,
  140. but we need to know if overflow occured. This requires
  141. a tricky pre-check. */
  142. if (number < maxval || (number == maxval &&
  143. (unsigned __int64)digval <= _UI64_MAX % ibase)) {
  144. /* we won't overflow, go ahead and multiply */
  145. number = number * ibase + digval;
  146. }
  147. else {
  148. /* we would have overflowed -- set the overflow flag */
  149. flags |= FL_OVERFLOW;
  150. }
  151. c = *p++; /* read next digit */
  152. }
  153. --p; /* point to place that stopped scan */
  154. if (!(flags & FL_READDIGIT)) {
  155. /* no number there; return 0 and point to beginning of
  156. string */
  157. if (endptr)
  158. /* store beginning of string in endptr later on */
  159. p = nptr;
  160. number = 0L; /* return 0 */
  161. }
  162. else if ( (flags & FL_OVERFLOW) ||
  163. ( !(flags & FL_UNSIGNED) &&
  164. ( ( (flags & FL_NEG) && (number > -_I64_MIN) ) ||
  165. ( !(flags & FL_NEG) && (number > _I64_MAX) ) ) ) )
  166. {
  167. /* overflow or signed overflow occurred */
  168. errno = ERANGE;
  169. if ( flags & FL_UNSIGNED )
  170. number = _UI64_MAX;
  171. else if ( flags & FL_NEG )
  172. number = (_I64_MIN);
  173. else
  174. number = _I64_MAX;
  175. }
  176. if (endptr != NULL)
  177. /* store pointer to wchar_t that stopped the scan */
  178. *endptr = p;
  179. if (flags & FL_NEG)
  180. /* negate result if there was a neg sign */
  181. number = (unsigned __int64)(-(__int64)number);
  182. return number; /* done. */
  183. }
  184. __int64 _CRTIMP __cdecl _wcstoi64(
  185. const wchar_t *nptr,
  186. wchar_t **endptr,
  187. int ibase
  188. )
  189. {
  190. return (__int64) wcstoxq(nptr, endptr, ibase, 0);
  191. }
  192. unsigned __int64 _CRTIMP __cdecl _wcstoui64 (
  193. const wchar_t *nptr,
  194. wchar_t **endptr,
  195. int ibase
  196. )
  197. {
  198. return wcstoxq(nptr, endptr, ibase, FL_UNSIGNED);
  199. }