# strtol.c

Go to the documentation of this file.

    00001 #include <sys/cdefs.h>
    00002 //#include <limits.h>
    00003 //#include <ctype.h>
    00004 //#include <stdlib.h>
    00005
    00006 #define LONG_MIN      (-0x7fffffffL - 1)
    00007 #define LONG_MAX      0x7fffffffL
    00008
    00009
    00010
    00011 long
    00012 strtol(const char * __restrict nptr, char ** __restrict endptr, int base)
    00013 {
    00014         const char *s;
    00015         unsigned long acc;
    00016         char c = 0x0;  /* to remove warning */
    00017         unsigned long cutoff;
    00018         int neg, any, cutlim;
    00019
    00020         /*
    00021          * Skip white space and pick up leading +/- sign if any.
    00022          * If base is 0, allow 0x for hex and 0 for octal, else
    00023          * assume decimal; if base is already 16, allow 0x.
    00024          */
    00025         s = nptr;
    00026         /*
    00027         do {
    00028                 c = *s++;
    00029         } while (isspace((unsigned char)c));
    00030         */
    00031         if (c == '-') {
    00032                 neg = 1;
    00033                 c = *s++;
    00034         } else {
    00035                 neg = 0;
    00036                 if (c == '+')
    00037                         c = *s++;
    00038         }
    00039         if ((base == 0 || base == 16) &&
    00040             c == '0' && (*s == 'x' || *s == 'X')) {
    00041                 c = s[1];
    00042                 s += 2;
    00043                 base = 16;
    00044         }
    00045         if (base == 0)
    00046                 base = c == '0' ? 8 : 10;
    00047         acc = any = 0;
    00048         if (base < 2 || base > 36)
    00049                 goto noconv;
    00050
    00051         /*
    00052          * Compute the cutoff value between legal numbers and illegal
    00053          * numbers.  That is the largest legal value, divided by the
    00054          * base.  An input number that is greater than this value, if
    00055          * followed by a legal input character, is too big.  One that
    00056          * is equal to this value may be valid or not; the limit
    00057          * between valid and invalid numbers is then based on the last
    00058          * digit.  For instance, if the range for longs is
    00059          * [-2147483648..2147483647] and the input base is 10,
    00060          * cutoff will be set to 214748364 and cutlim to either
    00061          * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
    00062          * a value > 214748364, or equal but the next digit is > 7 (or 8),
    00063          * the number is too big, and we will return a range error.
    00064          *
    00065          * Set 'any' if any `digits' consumed; make it negative to indicate
    00066          * overflow.
    00067          */
    00068         cutoff = neg ? (unsigned long)-(LONG_MIN + LONG_MAX) + LONG_MAX
    00069             : LONG_MAX;
    00070         cutlim = cutoff % base;
    00071         cutoff /= base;
    00072         for ( ; ; c = *s++) {
    00073                 if (c >= '0' && c <= '9')
    00074                         c -= '0';
    00075                 else if (c >= 'A' && c <= 'Z')
    00076                         c -= 'A' - 10;
    00077                 else if (c >= 'a' && c <= 'z')
    00078                         c -= 'a' - 10;
    00079                 else
    00080                         break;
    00081                 if (c >= base)
    00082                         break;
    00083                 if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
    00084                         any = -1;
    00085                 else {
    00086                         any = 1;
    00087                         acc *= base;
    00088                         acc += c;
    00089                 }
    00090         }
    00091         if (any < 0) {
    00092                 acc = neg ? LONG_MIN : LONG_MAX;
    00093                 //errno = ERANGE;
    00094         } else if (!any) {
    00095 noconv:
    00096                 //errno = EINVAL;
    00097         cutoff = 0x0;//UBU
    00098         } else if (neg)
    00099                 acc = -acc;
    00100         if (endptr != NULL)
    00101                 *endptr = (char *)(any ? s - 1 : nptr);
    00102         return (acc);
    00103 }