| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  | /* strtol - convert string representation of a number into a long integer value. */ | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  | /* Copyright (C) 1991,92,94,95,96,97,98,99,2000,2001 Free Software Foundation, Inc.
 | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  |    This file is part of GNU Bash, the Bourne Again SHell. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    Bash is free software: you can redistribute it and/or modify | 
					
						
							|  |  |  |    it under the terms of the GNU General Public License as published by | 
					
						
							|  |  |  |    the Free Software Foundation, either version 3 of the License, or | 
					
						
							|  |  |  |    (at your option) any later version. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    Bash is distributed in the hope that it will be useful, | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  |    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  |    GNU General Public License for more details. | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  |    You should have received a copy of the GNU General Public License | 
					
						
							|  |  |  |    along with Bash.  If not, see <http://www.gnu.org/licenses/>.
 | 
					
						
							|  |  |  | */ | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include <config.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #if !defined (HAVE_STRTOL)
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  | #include <chartypes.h>
 | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | #include <errno.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifndef errno
 | 
					
						
							|  |  |  | extern int errno; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifndef __set_errno
 | 
					
						
							|  |  |  | #  define __set_errno(Val) errno = (Val)
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef HAVE_LIMITS_H
 | 
					
						
							|  |  |  | #  include <limits.h>
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  | #include <typemax.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-02-19 17:11:39 +00:00
										 |  |  | #include <stdc.h>
 | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | #include <bashansi.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifndef NULL
 | 
					
						
							|  |  |  | #  define NULL 0
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  | /* Nonzero if we are defining `strtoul' or `strtoull', operating on
 | 
					
						
							|  |  |  |    unsigned integers.  */ | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | #ifndef UNSIGNED
 | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  | #  define UNSIGNED 0
 | 
					
						
							|  |  |  | #  define INT LONG int
 | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  | #  define INT unsigned LONG int
 | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #if UNSIGNED
 | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  | #  ifdef QUAD
 | 
					
						
							|  |  |  | #    define strtol strtoull
 | 
					
						
							|  |  |  | #  else
 | 
					
						
							|  |  |  | #    define strtol strtoul
 | 
					
						
							|  |  |  | #  endif
 | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | #  ifdef QUAD
 | 
					
						
							|  |  |  | #    define strtol strtoll
 | 
					
						
							|  |  |  | #  endif
 | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  | /* If QUAD is defined, we are defining `strtoll' or `strtoull',
 | 
					
						
							|  |  |  |    operating on `long long ints.  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef QUAD
 | 
					
						
							|  |  |  | #  define LONG long long
 | 
					
						
							|  |  |  | #  define STRTOL_LONG_MIN LLONG_MIN
 | 
					
						
							|  |  |  | #  define STRTOL_LONG_MAX LLONG_MAX
 | 
					
						
							|  |  |  | #  define STRTOL_ULONG_MAX ULLONG_MAX
 | 
					
						
							|  |  |  | #else	/* !QUAD */
 | 
					
						
							|  |  |  | #  define LONG long
 | 
					
						
							|  |  |  | #  define STRTOL_LONG_MIN LONG_MIN
 | 
					
						
							|  |  |  | #  define STRTOL_LONG_MAX LONG_MAX
 | 
					
						
							|  |  |  | #  define STRTOL_ULONG_MAX ULONG_MAX
 | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Convert NPTR to an `unsigned long int' or `long int' in base BASE.
 | 
					
						
							|  |  |  |    If BASE is 0 the base is determined by the presence of a leading | 
					
						
							|  |  |  |    zero, indicating octal or a leading "0x" or "0X", indicating hexadecimal. | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  |    If BASE is < 2 or > 36, it is no longer reset to 10; EINVAL is returned. | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |    If ENDPTR is not NULL, a pointer to the character after the last | 
					
						
							|  |  |  |    one converted is stored in *ENDPTR.  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  | INT | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | strtol (nptr, endptr, base) | 
					
						
							|  |  |  |      const char *nptr; | 
					
						
							|  |  |  |      char **endptr; | 
					
						
							|  |  |  |      int base; | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   int negative; | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  |   register unsigned LONG int cutoff; | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |   register unsigned int cutlim; | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  |   register unsigned LONG int i; | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |   register const char *s; | 
					
						
							|  |  |  |   register unsigned char c; | 
					
						
							|  |  |  |   const char *save, *end; | 
					
						
							|  |  |  |   int overflow; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (base < 0 || base == 1 || base > 36) | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  |     { | 
					
						
							|  |  |  |       __set_errno (EINVAL); | 
					
						
							|  |  |  |       return 0; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   save = s = nptr; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Skip white space.  */ | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  |   while (ISSPACE ((unsigned char)*s)) | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |     ++s; | 
					
						
							|  |  |  |   if (*s == '\0') | 
					
						
							|  |  |  |     goto noconv; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Check for a sign.  */ | 
					
						
							|  |  |  |   if (*s == '-' || *s == '+') | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       negative = (*s == '-'); | 
					
						
							|  |  |  |       ++s; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     negative = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  |   /* Recognize number prefix and if BASE is zero, figure it out ourselves.  */ | 
					
						
							|  |  |  |   if (*s == '0') | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       if ((base == 0 || base == 16) && TOUPPER ((unsigned char) s[1]) == 'X') | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 	  s += 2; | 
					
						
							|  |  |  | 	  base = 16; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  |       else if (base == 0) | 
					
						
							|  |  |  | 	base = 8; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   else if (base == 0) | 
					
						
							|  |  |  |     base = 10; | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   /* Save the pointer so we can check later if anything happened.  */ | 
					
						
							|  |  |  |   save = s; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   end = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  |   cutoff = STRTOL_ULONG_MAX / (unsigned LONG int) base; | 
					
						
							|  |  |  |   cutlim = STRTOL_ULONG_MAX % (unsigned LONG int) base; | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   overflow = 0; | 
					
						
							|  |  |  |   i = 0; | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  |   c = *s; | 
					
						
							|  |  |  |   if (sizeof (long int) != sizeof (LONG int)) | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  |       unsigned long int j = 0; | 
					
						
							|  |  |  |       unsigned long int jmax = ULONG_MAX / base; | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  |       for (;c != '\0'; c = *++s) | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  | 	  if (s == end) | 
					
						
							|  |  |  | 	    break; | 
					
						
							|  |  |  | 	  if (DIGIT (c)) | 
					
						
							|  |  |  | 	    c -= '0'; | 
					
						
							|  |  |  | 	  else if (ISALPHA (c)) | 
					
						
							|  |  |  | 	    c = TOUPPER (c) - 'A' + 10; | 
					
						
							|  |  |  | 	  else | 
					
						
							|  |  |  | 	    break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	  if ((int) c >= base) | 
					
						
							|  |  |  | 	    break; | 
					
						
							|  |  |  | 	  /* Note that we never can have an overflow.  */ | 
					
						
							|  |  |  | 	  else if (j >= jmax) | 
					
						
							|  |  |  | 	    { | 
					
						
							|  |  |  | 	      /* We have an overflow.  Now use the long representation.  */ | 
					
						
							|  |  |  | 	      i = (unsigned LONG int) j; | 
					
						
							|  |  |  | 	      goto use_long; | 
					
						
							|  |  |  | 	    } | 
					
						
							|  |  |  | 	  else | 
					
						
							|  |  |  | 	    j = j * (unsigned long int) base + c; | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |       i = (unsigned LONG int) j; | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  |   else | 
					
						
							|  |  |  |     for (;c != '\0'; c = *++s) | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  | 	if (s == end) | 
					
						
							|  |  |  | 	  break; | 
					
						
							|  |  |  | 	if (DIGIT (c)) | 
					
						
							|  |  |  | 	  c -= '0'; | 
					
						
							|  |  |  | 	else if (ISALPHA (c)) | 
					
						
							|  |  |  | 	  c = TOUPPER (c) - 'A' + 10; | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 	  break; | 
					
						
							|  |  |  | 	if ((int) c >= base) | 
					
						
							|  |  |  | 	  break; | 
					
						
							|  |  |  | 	/* Check for overflow.  */ | 
					
						
							|  |  |  | 	if (i > cutoff || (i == cutoff && c > cutlim)) | 
					
						
							|  |  |  | 	  overflow = 1; | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 	  { | 
					
						
							|  |  |  | 	  use_long: | 
					
						
							|  |  |  | 	    i *= (unsigned LONG int) base; | 
					
						
							|  |  |  | 	    i += c; | 
					
						
							|  |  |  | 	  } | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   /* Check if anything actually happened.  */ | 
					
						
							|  |  |  |   if (s == save) | 
					
						
							|  |  |  |     goto noconv; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Store in ENDPTR the address of one character
 | 
					
						
							|  |  |  |      past the last character we converted.  */ | 
					
						
							|  |  |  |   if (endptr != NULL) | 
					
						
							|  |  |  |     *endptr = (char *) s; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #if !UNSIGNED
 | 
					
						
							|  |  |  |   /* Check for a value that is within the range of
 | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  |      `unsigned LONG int', but outside the range of `LONG int'.  */ | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |   if (overflow == 0 | 
					
						
							|  |  |  |       && i > (negative | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  | 	      ? -((unsigned LONG int) (STRTOL_LONG_MIN + 1)) + 1 | 
					
						
							|  |  |  | 	      : (unsigned LONG int) STRTOL_LONG_MAX)) | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |     overflow = 1; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (overflow) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       __set_errno (ERANGE); | 
					
						
							|  |  |  | #if UNSIGNED
 | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  |       return STRTOL_ULONG_MAX; | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  |       return negative ? STRTOL_LONG_MIN : STRTOL_LONG_MAX; | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | #endif
 | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  |   /* Return the result of the appropriate sign.  */ | 
					
						
							|  |  |  |   return negative ? -i : i; | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | noconv: | 
					
						
							|  |  |  |   /* We must handle a special case here: the base is 0 or 16 and the
 | 
					
						
							|  |  |  |      first two characters are '0' and 'x', but the rest are no | 
					
						
							|  |  |  |      hexadecimal digits.  This is no error case.  We return 0 and | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  |      ENDPTR points to the `x`.  */ | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |   if (endptr != NULL) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  |       if (save - nptr >= 2 && TOUPPER ((unsigned char) save[-1]) == 'X' && save[-2] == '0') | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | 	*endptr = (char *) &save[-1]; | 
					
						
							|  |  |  |       else | 
					
						
							| 
									
										
										
										
											2001-04-06 19:14:31 +00:00
										 |  |  | 	/*  There was no number to convert.  */ | 
					
						
							|  |  |  | 	*endptr = (char *) nptr; | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return 0L; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #endif /* !HAVE_STRTOL */
 |