Back to index

cell-binutils  2.17cvs20070401
strtol.c
Go to the documentation of this file.
00001 /*-
00002  * Copyright (c) 1990 The Regents of the University of California.
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. [rescinded 22 July 1999]
00014  * 4. Neither the name of the University nor the names of its contributors
00015  *    may be used to endorse or promote products derived from this software
00016  *    without specific prior written permission.
00017  *
00018  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00019  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00020  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00021  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00022  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00023  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00024  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00025  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00026  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00027  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00028  * SUCH DAMAGE.
00029  */
00030 
00031 /*
00032 
00033 @deftypefn Supplemental {long int} strtol (const char *@var{string}, char **@var{endptr}, int @var{base})
00034 @deftypefnx Supplemental {unsigned long int} strtoul (const char *@var{string}, char **@var{endptr}, int @var{base})
00035 
00036 The @code{strtol} function converts the string in @var{string} to a
00037 long integer value according to the given @var{base}, which must be
00038 between 2 and 36 inclusive, or be the special value 0.  If @var{base}
00039 is 0, @code{strtol} will look for the prefixes @code{0} and @code{0x}
00040 to indicate bases 8 and 16, respectively, else default to base 10.
00041 When the base is 16 (either explicitly or implicitly), a prefix of
00042 @code{0x} is allowed.  The handling of @var{endptr} is as that of
00043 @code{strtod} above.  The @code{strtoul} function is the same, except
00044 that the converted value is unsigned.
00045 
00046 @end deftypefn
00047 
00048 */
00049 
00050 #ifdef HAVE_CONFIG_H
00051 #include "config.h"
00052 #endif
00053 #ifdef HAVE_LIMITS_H
00054 #include <limits.h>
00055 #endif
00056 #ifdef HAVE_SYS_PARAM_H
00057 #include <sys/param.h>
00058 #endif
00059 #include <errno.h>
00060 #ifdef NEED_DECLARATION_ERRNO
00061 extern int errno;
00062 #endif
00063 #include "safe-ctype.h"
00064 
00065 /* FIXME: It'd be nice to configure around these, but the include files are too
00066    painful.  These macros should at least be more portable than hardwired hex
00067    constants. */
00068 
00069 #ifndef ULONG_MAX
00070 #define       ULONG_MAX     ((unsigned long)(~0L))             /* 0xFFFFFFFF */
00071 #endif
00072 
00073 #ifndef LONG_MAX
00074 #define       LONG_MAX      ((long)(ULONG_MAX >> 1))    /* 0x7FFFFFFF */
00075 #endif
00076 
00077 #ifndef LONG_MIN
00078 #define       LONG_MIN      ((long)(~LONG_MAX))         /* 0x80000000 */
00079 #endif
00080 
00081 /*
00082  * Convert a string to a long integer.
00083  *
00084  * Ignores `locale' stuff.  Assumes that the upper and lower case
00085  * alphabets and digits are each contiguous.
00086  */
00087 long
00088 strtol(const char *nptr, char **endptr, register int base)
00089 {
00090        register const char *s = nptr;
00091        register unsigned long acc;
00092        register int c;
00093        register unsigned long cutoff;
00094        register int neg = 0, any, cutlim;
00095 
00096        /*
00097         * Skip white space and pick up leading +/- sign if any.
00098         * If base is 0, allow 0x for hex and 0 for octal, else
00099         * assume decimal; if base is already 16, allow 0x.
00100         */
00101        do {
00102               c = *s++;
00103        } while (ISSPACE(c));
00104        if (c == '-') {
00105               neg = 1;
00106               c = *s++;
00107        } else if (c == '+')
00108               c = *s++;
00109        if ((base == 0 || base == 16) &&
00110            c == '0' && (*s == 'x' || *s == 'X')) {
00111               c = s[1];
00112               s += 2;
00113               base = 16;
00114        }
00115        if (base == 0)
00116               base = c == '0' ? 8 : 10;
00117 
00118        /*
00119         * Compute the cutoff value between legal numbers and illegal
00120         * numbers.  That is the largest legal value, divided by the
00121         * base.  An input number that is greater than this value, if
00122         * followed by a legal input character, is too big.  One that
00123         * is equal to this value may be valid or not; the limit
00124         * between valid and invalid numbers is then based on the last
00125         * digit.  For instance, if the range for longs is
00126         * [-2147483648..2147483647] and the input base is 10,
00127         * cutoff will be set to 214748364 and cutlim to either
00128         * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
00129         * a value > 214748364, or equal but the next digit is > 7 (or 8),
00130         * the number is too big, and we will return a range error.
00131         *
00132         * Set any if any `digits' consumed; make it negative to indicate
00133         * overflow.
00134         */
00135        cutoff = neg ? -(unsigned long)LONG_MIN : LONG_MAX;
00136        cutlim = cutoff % (unsigned long)base;
00137        cutoff /= (unsigned long)base;
00138        for (acc = 0, any = 0;; c = *s++) {
00139               if (ISDIGIT(c))
00140                      c -= '0';
00141               else if (ISALPHA(c))
00142                      c -= ISUPPER(c) ? 'A' - 10 : 'a' - 10;
00143               else
00144                      break;
00145               if (c >= base)
00146                      break;
00147               if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
00148                      any = -1;
00149               else {
00150                      any = 1;
00151                      acc *= base;
00152                      acc += c;
00153               }
00154        }
00155        if (any < 0) {
00156               acc = neg ? LONG_MIN : LONG_MAX;
00157               errno = ERANGE;
00158        } else if (neg)
00159               acc = -acc;
00160        if (endptr != 0)
00161               *endptr = (char *) (any ? s - 1 : nptr);
00162        return (acc);
00163 }