home *** CD-ROM | disk | FTP | other *** search
/ GEMini Atari / GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso / zip / mint / mntlib16.lzh / MNTLIB16 / STRTOL.C < prev    next >
C/C++ Source or Header  |  1993-08-03  |  3KB  |  116 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.  
  36.   if (endptr != NULL)
  37.       *endptr = (char *)nptr;
  38.  
  39.   while ((c = *nptr) && isspace(c))    /* skip leading white space */
  40.     nptr++;
  41.   if ((c = *nptr) == '+' || c == '-') {    /* handle signs */
  42.     negative = (c == '-');
  43.     nptr++;
  44.   }
  45.   if (base == 0) {            /* determine base if unknown */
  46.     if (*nptr == '0') {
  47.         base = 8;
  48.         nptr++;
  49.         if ((c = *nptr) == 'x' || c == 'X') {
  50.             base += base;
  51.             nptr++;
  52.         }
  53.     }
  54.     else
  55.         base = 10;
  56.   }
  57.   else
  58.   if (base == 16 && *nptr == '0') {    /* discard 0x/0X prefix if hex */
  59.     nptr++;
  60.     if ((c = *nptr == 'x') || c == 'X')
  61.         nptr++;
  62.   }
  63.   if (base < 2 || base > 36)
  64.       return result;
  65.  
  66.   /* be careful with a preprocessor and signs!! */
  67.   limit = (long)LONG_MIN/(long)base;         /* ensure no overflow */
  68.   shift = 0;
  69.   switch (base) {
  70.       case 32: shift++;
  71.       case 16: shift++;
  72.       case 8: shift++;
  73.       case 4: case 10: shift++;
  74.       case 2: shift++;
  75.       default:;
  76.   }
  77.   
  78.   nptr--;                /* convert the number */
  79.   while (c = *++nptr) {
  80.     if (isdigit(c))
  81.         digit = c - '0';
  82.     else
  83.         digit = c - (isupper(c) ? 'A' : 'a') + 10;
  84.     if (digit < 0 || digit >= base)
  85.         break;
  86.     if (0 == (overflow &= 1)) {    /* valid digit
  87.                        - some conversion performed */
  88.         if ((result < limit) ||
  89.         (digit >
  90.          ((result = _BASEMUL(base, shift, result)) - LONG_MIN))) {
  91.         result = LONG_MIN;
  92.         overflow = 1;
  93.         
  94.         }
  95.         else 
  96.         result -= digit;
  97.     }
  98.   }
  99.  
  100.   if (!negative) {
  101.       if (LONG_MIN == result) {
  102.       result += 1;        /* this is -(LONG_MAX) */
  103.       overflow = 1;        /* we may get LONG_MIN without overflow */
  104.       }
  105.       result = 0L - result;
  106.   }
  107.   
  108.   if (overflow > 0) {
  109.     errno = ERANGE;
  110.   }
  111.  
  112.   if ((endptr != NULL) && (overflow >= 0))     /* move *endptr if some */
  113.       *endptr = (char *) nptr;                  /* digits were accepted */
  114.   return result;
  115. }
  116.