1 /* Copyright (C) 1991, 1992 Free Software Foundation, Inc. 2 This file is part of the GNU C Library. 3 4 The GNU C Library is free software; you can redistribute it and/or 5 modify it under the terms of the GNU Lesser General Public License as 6 published by the Free Software Foundation; either version 3 of the 7 License, or (at your option) any later version. 8 9 The GNU C Library is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 Library General Public License for more details. 13 14 You should have received a copy of the GNU Lesser General Public 15 License along with the GNU C Library; see the file COPYING.LIB. If 16 not, write to the Free Software Foundation, Inc., 17 59 Temple Place, Suite 330, Boston, MA 02111, USA. */ 18 19 #include "ansidecl.h" 20 #include <ctype.h> 21 #include <limits.h> 22 #include <stddef.h> 23 #include <stdlib.h> 24 /* errno.h is needed on SunOS 4.1.2 */ 25 #include <errno.h> 26 27 #ifndef UNSIGNED 28 #define UNSIGNED 0 29 #endif 30 31 /* Convert NPTR to an `unsigned long int' or `long int' in base BASE. 32 If BASE is 0 the base is determined by the presence of a leading 33 zero, indicating octal or a leading "0x" or "0X", indicating hexadecimal. 34 If BASE is < 2 or > 36, it is reset to 10. 35 If ENDPTR is not NULL, a pointer to the character after the last 36 one converted is stored in *ENDPTR. */ 37 #if UNSIGNED 38 unsigned long int 39 #define strtol strtoul 40 #else 41 long int 42 #endif 43 DEFUN(strtol, (nptr, endptr, base), 44 CONST char *nptr AND char **endptr AND int base) 45 { 46 int negative; 47 register unsigned long int cutoff; 48 register unsigned int cutlim; 49 register unsigned long int i; 50 register CONST char *s; 51 register unsigned char c; 52 CONST char *save; 53 int overflow; 54 55 if (base < 0 || base == 1 || base > 36) 56 base = 10; 57 58 s = nptr; 59 60 /* Skip white space. */ 61 while (isspace(*s)) 62 ++s; 63 if (*s == '\0') 64 goto noconv; 65 66 /* Check for a sign. */ 67 if (*s == '-') 68 { 69 negative = 1; 70 ++s; 71 } 72 else if (*s == '+') 73 { 74 negative = 0; 75 ++s; 76 } 77 else 78 negative = 0; 79 80 if (base == 16 && s[0] == '0' && toupper(s[1]) == 'X') 81 s += 2; 82 83 /* If BASE is zero, figure it out ourselves. */ 84 if (base == 0) 85 if (*s == '0') 86 { 87 if (toupper(s[1]) == 'X') 88 { 89 s += 2; 90 base = 16; 91 } 92 else 93 base = 8; 94 } 95 else 96 base = 10; 97 98 /* Save the pointer so we can check later if anything happened. */ 99 save = s; 100 101 cutoff = ULONG_MAX / (unsigned long int) base; 102 cutlim = ULONG_MAX % (unsigned long int) base; 103 104 overflow = 0; 105 i = 0; 106 for (c = *s; c != '\0'; c = *++s) 107 { 108 if (isdigit(c)) 109 c -= '0'; 110 else if (isalpha(c)) 111 c = toupper(c) - 'A' + 10; 112 else 113 break; 114 if (c >= base) 115 break; 116 /* Check for overflow. */ 117 if (i > cutoff || (i == cutoff && c > cutlim)) 118 overflow = 1; 119 else 120 { 121 i *= (unsigned long int) base; 122 i += c; 123 } 124 } 125 126 /* Check if anything actually happened. */ 127 if (s == save) 128 goto noconv; 129 130 /* Store in ENDPTR the address of one character 131 past the last character we converted. */ 132 if (endptr != NULL) 133 *endptr = (char *) s; 134 135 #if !UNSIGNED 136 /* Check for a value that is within the range of 137 `unsigned long int', but outside the range of `long int'. */ 138 if (i > (negative ? 139 - (unsigned long int) LONG_MIN : (unsigned long int) LONG_MAX)) 140 overflow = 1; 141 #endif 142 143 if (overflow) 144 { 145 errno = ERANGE; 146 #if UNSIGNED 147 return ULONG_MAX; 148 #else 149 return negative ? LONG_MIN : LONG_MAX; 150 #endif 151 } 152 153 /* Return the result of the appropriate sign. */ 154 return (negative ? - i : i); 155 156 noconv: 157 /* There was no number to convert. */ 158 if (endptr != NULL) 159 *endptr = (char *) nptr; 160 return 0L; 161 } 162