strtol.c

Go to the documentation of this file.
00001 /*
00002  * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
00003  * See the copyright notice in the ACK home directory, in the file "Copyright".
00004  */
00005 /* $Header: /opt/proj/minix/cvsroot/src/lib/ansi/strtol.c,v 1.1.1.1 2005/04/21 14:56:06 beng Exp $ */
00006 
00007 #include        <ctype.h>
00008 #include        <errno.h>
00009 #include        <limits.h>
00010 #include        <stdlib.h>
00011 
00012 static unsigned long
00013 string2long(register const char *nptr, char **endptr,
00014                         int base, int is_signed);
00015 
00016 long int
00017 strtol(register const char *nptr, char **endptr, int base)
00018 {
00019         return (signed long)string2long(nptr, endptr, base, 1);
00020 }
00021 
00022 unsigned long int
00023 strtoul(register const char *nptr, char **endptr, int base)
00024 {
00025         return (unsigned long)string2long(nptr, endptr, base, 0);
00026 }
00027 
00028 #define between(a, c, z)  ((unsigned) ((c) - (a)) <= (unsigned) ((z) - (a)))
00029 
00030 static unsigned long
00031 string2long(register const char *nptr, char ** const endptr,
00032                         int base, int is_signed)
00033 {
00034         register unsigned int v;
00035         register unsigned long val = 0;
00036         register int c;
00037         int ovfl = 0, sign = 1;
00038         const char *startnptr = nptr, *nrstart;
00039 
00040         if (endptr) *endptr = (char *)nptr;
00041         while (isspace(*nptr)) nptr++;
00042         c = *nptr;
00043 
00044         if (c == '-' || c == '+') {
00045                 if (c == '-') sign = -1;
00046                 nptr++;
00047         }
00048         nrstart = nptr;                 /* start of the number */
00049 
00050         /* When base is 0, the syntax determines the actual base */
00051         if (base == 0)
00052                 if (*nptr == '0')
00053                         if (*++nptr == 'x' || *nptr == 'X') {
00054                                 base = 16;
00055                                 nptr++;
00056                         }
00057                         else    base = 8;
00058                 else    base = 10;
00059         else if (base==16 && *nptr=='0' && (*++nptr =='x' || *nptr =='X'))
00060                 nptr++;
00061 
00062         for (;;) {
00063                 c = *nptr;
00064                 if (between('0', c, '9')) {
00065                         v = c - '0';
00066                 } else
00067                 if (between('a', c, 'z')) {
00068                         v = c - 'a' + 0xa;
00069                 } else
00070                 if (between('A', c, 'Z')) {
00071                         v = c - 'A' + 0xA;
00072                 } else {
00073                         break;
00074                 }
00075                 if (v >= base) break;
00076                 if (val > (ULONG_MAX - v) / base) ovfl++;
00077                 val = (val * base) + v;
00078                 nptr++;
00079         }
00080         if (endptr) {
00081                 if (nrstart == nptr) *endptr = (char *)startnptr;
00082                 else *endptr = (char *)nptr;
00083         }
00084 
00085         if (!ovfl) {
00086                 /* Overflow is only possible when converting a signed long. */
00087                 if (is_signed
00088                     && (   (sign < 0 && val > -(unsigned long)LONG_MIN)
00089                         || (sign > 0 && val > LONG_MAX)))
00090                     ovfl++;
00091         }
00092 
00093         if (ovfl) {
00094                 errno = ERANGE;
00095                 if (is_signed)
00096                         if (sign < 0) return LONG_MIN;
00097                         else return LONG_MAX;
00098                 else return ULONG_MAX;
00099         }
00100         return (long) sign * val;
00101 }

Generated on Fri Apr 14 22:57:25 2006 for minix by  doxygen 1.4.6