home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / vc98 / crt / src / wcstol.c < prev    next >
C/C++ Source or Header  |  1998-06-17  |  7KB  |  210 lines

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