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

  1. /***
  2. *strtol.c - Contains C runtimes strtol and strtoul
  3. *
  4. *       Copyright (c) 1989-1997, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. *       strtol - convert ascii string to long signed integer
  8. *       strtoul - convert ascii 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. *strtol, strtoul(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 strtol/strtoul 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. *               strtol -- LONG_MAX or LONG_MIN
  51. *               strtoul -- ULONG_MAX
  52. *               strtol/strtoul -- 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       /* strtoul 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 strtoxl (
  70.         const char *nptr,
  71.         const char **endptr,
  72.         int ibase,
  73.         int flags
  74.         )
  75. {
  76.         const char *p;
  77.         char 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 ( isspace((int)(unsigned char)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 != '0')
  107.                         ibase = 10;
  108.                 else if (*p == 'x' || *p == '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 == '0' && (*p == 'x' || *p == '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 ( isdigit((int)(unsigned char)c) )
  129.                         digval = c - '0';
  130.                 else if ( isalpha((int)(unsigned char)c) )
  131.                         digval = toupper(c) - '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 strtol (
  194.         const char *nptr,
  195.         char **endptr,
  196.         int ibase
  197.         )
  198. {
  199.         return (long) strtoxl(nptr, endptr, ibase, 0);
  200. }
  201.  
  202. unsigned long __cdecl strtoul (
  203.         const char *nptr,
  204.         char **endptr,
  205.         int ibase
  206.         )
  207. {
  208.         return strtoxl(nptr, endptr, ibase, FL_UNSIGNED);
  209. }
  210.