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.

239 lines
7.3 KiB

  1. /***
  2. *strtoq.c - Contains C runtimes strtoq and strtouq
  3. *
  4. * Copyright (c) 1989-2001, Microsoft Corporation. All rights reserved.
  5. * Copyright (c) 1992, Digital Equipment Corporation.
  6. *
  7. *Purpose:
  8. * strtoi64 - convert ascii string to __int64 (signed) integer
  9. * strtoui64 - convert ascii string to __int64 (unsigned) integer
  10. *
  11. *Revision History:
  12. * 06-05-89 PHG Module created, based on strtol.asm
  13. * 03-06-90 GJF Fixed calling type, added #include <cruntime.h>
  14. * and fixed the copyright. Also, cleaned up the
  15. * formatting a bit.
  16. * 03-07-90 GJF Fixed compiler warnings (added const qualifier to
  17. * an arg type and local var type).
  18. * 03-23-90 GJF Made strtoxl() _CALLTYPE4.
  19. * 08-13-90 SBM Compiles cleanly with -W3
  20. * 09-27-90 GJF New-style function declarators.
  21. * 10-24-91 GJF Had to cast LONG_MAX to unsigned long in expr. to
  22. * mollify MIPS compiler.
  23. * 10-21-92 GJF Made char-to-int conversions unsigned.
  24. * 08-28-93 TVB Created strtoq.c directly from strtol.c.
  25. * 10-25-93 GJF Copied from NT SDK tree (\\orville\razzle\src\crt32).
  26. * Replaced _CRTAPI* with __cdecl. Build only for NT
  27. * SDK. Function names violate ANSI. Types and function-
  28. * ality will be superceded by __int64 support.
  29. * 02-11-00 GB Added _strtoi64 and _strtoui64 (__int64 versions for
  30. * strtol and strtoul)
  31. * 06-02-00 GB Fixed the bug for IA64_MIN value.
  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. *strtoi64, strtoui64(nptr,endptr,ibase) - Convert ascii string to __int64 un/signed
  42. * int.
  43. *
  44. *Purpose:
  45. * Convert an ascii string to a 64-bit __int64 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 strtoq/strtouq 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. * strtoi64 -- _I64_MAX or _I64_MIN
  72. * strtoui64 -- _UI64_MAX
  73. * strtoi64/strtoui64 -- 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 /* strtouq 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 __int64 __cdecl strtoxq (
  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 __int64 number;
  97. unsigned digval;
  98. unsigned __int64 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 = _UI64_MAX / ibase;
  145. for (;;) { /* exit in middle of loop */
  146. /* convert c to value */
  147. if ( isdigit((int)(unsigned char)c) )
  148. digval = c - '0';
  149. else if ( isalpha((int)(unsigned char)c) )
  150. digval = 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 __int64)digval <= _UI64_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 > -_I64_MIN) ) ||
  183. ( !(flags & FL_NEG) && (number > _I64_MAX) ) ) ) )
  184. {
  185. /* overflow or signed overflow occurred */
  186. errno = ERANGE;
  187. if ( flags & FL_UNSIGNED )
  188. number = _UI64_MAX;
  189. else if ( flags & FL_NEG )
  190. number = _I64_MIN;
  191. else
  192. number = _I64_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 __int64)(-(__int64)number);
  200. return number; /* done. */
  201. }
  202. __int64 _CRTIMP __cdecl _strtoi64(
  203. const char *nptr,
  204. char **endptr,
  205. int ibase
  206. )
  207. {
  208. return (__int64) strtoxq(nptr, endptr, ibase, 0);
  209. }
  210. unsigned __int64 _CRTIMP __cdecl _strtoui64 (
  211. const char *nptr,
  212. char **endptr,
  213. int ibase
  214. )
  215. {
  216. return strtoxq(nptr, endptr, ibase, FL_UNSIGNED);
  217. }