home *** CD-ROM | disk | FTP | other *** search
/ Atari FTP / ATARI_FTP_0693.zip / ATARI_FTP_0693 / Mint / mntlib25.zoo / strtol.c < prev    next >
C/C++ Source or Header  |  1992-09-05  |  3KB  |  122 lines

  1. /* original from norbert schelenkar's stdio */
  2. /* eff hacks    ++jrb */
  3. /* conversion to ansi spec -- mj */
  4. /* 
  5.  * Base can be anything between 2 and 36 or 0.
  6.  * If not NULL then resulting *endptr points to the first
  7.  * non-accepted character.
  8.  */
  9.  
  10. #include <ctype.h>
  11. #include <errno.h>
  12. #include <limits.h>
  13. #include <stddef.h>
  14. #include <stdlib.h>
  15.  
  16. /* macro to avoid most frequent long muls on a lowly 68k */
  17. #define _BASEMUL(B, SH, X) \
  18.     ((0 != SH) ? \
  19.        ((10 == (B)) ? ((((X) << (SH)) + (X)) << 1) : ((X) << (SH))) : \
  20.        ((X) * (B))) 
  21.  
  22. long int strtol(nptr, endptr, base)
  23. register const char *nptr;
  24. char **endptr;
  25. int base;
  26. {
  27.   register short c;
  28.   long result = 0L;
  29.   long limit;
  30.   short negative = 0;
  31.   short overflow = -2; /* if this stays negative then
  32.               no conversion was performed */
  33.   short digit;
  34.   int shift;
  35.   long bottom = (long)LONG_MIN;
  36.  
  37.   if (endptr != NULL)
  38.       *endptr = (char *)nptr;
  39.  
  40.   do {             /* skip leading white space */
  41.       c = *nptr++;
  42.   } while (isspace(c));
  43.  
  44.   if (c == '+')     /* handle signs */
  45.       c = *nptr++;
  46.   else if (c == '-') {
  47.       negative = 1;
  48.       c = *nptr++;
  49.   }
  50.  
  51.   if ((base == 0) || (base == 16)) {     /* discard 0x/0X prefix if hex */
  52.       if (c == '0') {
  53.       if (*nptr == 'x' || *nptr == 'X') {
  54.               if (endptr != NULL)
  55.                   *endptr = (char *) nptr;
  56.           nptr += 1;
  57.           c = *nptr++;
  58.           base = 16;
  59.       }
  60.       }
  61.   }
  62.   if (base == 0)             /* determine base if unknown */
  63.       base = (c == '0') ? 8 : 10;    /* don't skip leading 0 if present */
  64.   else if (base < 2 || base > 36)
  65.       return result;
  66.  
  67.   /* careful with signs!! */
  68.   limit = (long)bottom/(long)base;         /* ensure no overflow */
  69.   shift = 0;
  70.   switch (base) {
  71.       case 32: shift++;
  72.       case 16: shift++;
  73.       case 8: shift++;
  74.       case 4: case 10: shift++;
  75.       case 2: shift++;
  76.       default:;
  77.   }
  78.   
  79.   do {            /* convert the number */
  80.       if (isdigit(c))
  81.       digit = c - '0';
  82.       else if (isalpha(c))
  83.       digit = c - (isupper(c) ? 'A' : 'a') + 10;
  84.       else
  85.       break;
  86.       if (digit >= base)
  87.       break;
  88.       if (0 == (overflow &= 1)) {    /* valid digit
  89.                        - some conversion performed */
  90.       if ((result < limit) ||
  91.           ((unsigned long) digit >
  92.            (unsigned long) (result = _BASEMUL(base, shift, result),
  93.                 result - bottom))) {
  94.           result = bottom;
  95.           overflow = 1;
  96.       }
  97.       else 
  98.           result -= digit;
  99.       }
  100.   } while ((c = *nptr++) != 0);
  101.  
  102.  
  103.   if (!negative) {
  104.       if (bottom == result) {
  105.       result += 1;        /* this is -(LONG_MAX) */
  106.       overflow = 1;        /* we may get LONG_MIN without overflow */
  107.       }
  108.       result = 0L - result;
  109.   }
  110.   
  111.   if (overflow > 0) {
  112.     errno = ERANGE;
  113.   }
  114.  
  115.   if ((endptr != NULL) && (overflow >= 0))     /* move *endptr if some */
  116.       *endptr = (char *) nptr - 1;               /* digits were accepted */
  117.   return result;
  118. }
  119.  
  120.  
  121.  
  122.