genericopenlibs/cstdlib/LSTDLIB/STRTOL.C
changeset 0 e4d67989cc36
equal deleted inserted replaced
-1:000000000000 0:e4d67989cc36
       
     1 /*
       
     2 FUNCTION
       
     3    <<strtol>>---string to long
       
     4    <<strtoul>>---string to unsigned long
       
     5 
       
     6 INDEX
       
     7 	strtol
       
     8 INDEX
       
     9 	_strtol_r
       
    10 
       
    11 ANSI_SYNOPSIS
       
    12 	#include <stdlib.h>
       
    13         long strtol(const char *<[s]>, char **<[ptr]>,int <[base]>);
       
    14         unsigned long strtoul(const char *<[s]>, char **<[ptr]>,
       
    15                               int <[base]>);
       
    16 
       
    17 DESCRIPTION
       
    18 The function <<strtol>> converts the string <<*<[s]>>> to
       
    19 a <<long>>. First, it breaks down the string into three parts:
       
    20 leading whitespace, which is ignored; a subject string consisting
       
    21 of characters resembling an integer in the radix specified by <[base]>;
       
    22 and a trailing portion consisting of zero or more unparseable characters,
       
    23 and always including the terminating null character. Then, it attempts
       
    24 to convert the subject string into a <<long>> and returns the
       
    25 result.
       
    26 
       
    27 If the value of <[base]> is 0, the subject string is expected to look
       
    28 like a normal C integer constant: an optional sign, a possible `<<0x>>'
       
    29 indicating a hexadecimal base, and a number. If <[base]> is between
       
    30 2 and 36, the expected form of the subject is a sequence of letters
       
    31 and digits representing an integer in the radix specified by <[base]>,
       
    32 with an optional plus or minus sign. The letters <<a>>--<<z>> (or,
       
    33 equivalently, <<A>>--<<Z>>) are used to signify values from 10 to 35;
       
    34 only letters whose ascribed values are less than <[base]> are
       
    35 permitted. If <[base]> is 16, a leading <<0x>> is permitted.
       
    36 
       
    37 The subject sequence is the longest initial sequence of the input
       
    38 string that has the expected form, starting with the first
       
    39 non-whitespace character.  If the string is empty or consists entirely
       
    40 of whitespace, or if the first non-whitespace character is not a
       
    41 permissible letter or digit, the subject string is empty.
       
    42 
       
    43 If the subject string is acceptable, and the value of <[base]> is zero,
       
    44 <<strtol>> attempts to determine the radix from the input string. A
       
    45 string with a leading <<0x>> is treated as a hexadecimal value; a string with
       
    46 a leading 0 and no <<x>> is treated as octal; all other strings are
       
    47 treated as decimal. If <[base]> is between 2 and 36, it is used as the
       
    48 conversion radix, as described above. If the subject string begins with
       
    49 a minus sign, the value is negated. Finally, a pointer to the first
       
    50 character past the converted subject string is stored in <[ptr]>, if
       
    51 <[ptr]> is not <<NULL>>.
       
    52 
       
    53 If the subject string is empty (or not in acceptable form), no conversion
       
    54 is performed and the value of <[s]> is stored in <[ptr]> (if <[ptr]> is
       
    55 not <<NULL>>).
       
    56 
       
    57 The alternate function <<_strtol_r>> is a reentrant version.  The
       
    58 extra argument <[reent]> is a pointer to a reentrancy structure.
       
    59 
       
    60 The function <<strtoul>> is similar but does not permit an optional sign
       
    61 and returns an <<unsigned long>>.
       
    62 
       
    63 RETURNS
       
    64 <<strtol>> returns the converted value, if any. If no conversion was
       
    65 made, 0 is returned.
       
    66 
       
    67 <<strtol>> returns <<LONG_MAX>> or <<LONG_MIN>> if the magnitude of
       
    68 the converted value is too large, and sets <<errno>> to <<ERANGE>>.
       
    69 
       
    70 <<strtoul>> returns <<ULONG_MAX>> if the magnitude of the converted
       
    71 value is too large, and sets <<errno>> to <<ERANGE>>.
       
    72 
       
    73 PORTABILITY
       
    74 <<strtol>> and <<strtoul>> are both ANSI.
       
    75 
       
    76 No supporting OS subroutines are required.
       
    77  */
       
    78 
       
    79 /*-
       
    80  * Copyright (c) 1990 The Regents of the University of California.
       
    81  * All rights reserved.
       
    82  *
       
    83  * Redistribution and use in source and binary forms, with or without
       
    84  * modification, are permitted provided that the following conditions
       
    85  * are met:
       
    86  * 1. Redistributions of source code must retain the above copyright
       
    87  *    notice, this list of conditions and the following disclaimer.
       
    88  * 2. Redistributions in binary form must reproduce the above copyright
       
    89  *    notice, this list of conditions and the following disclaimer in the
       
    90  *    documentation and/or other materials provided with the distribution.
       
    91  * 3. All advertising materials mentioning features or use of this software
       
    92  *    must display the following acknowledgement:
       
    93  *	This product includes software developed by the University of
       
    94  *	California, Berkeley and its contributors.
       
    95  * 4. Neither the name of the University nor the names of its contributors
       
    96  *    may be used to endorse or promote products derived from this software
       
    97  *    without specific prior written permission.
       
    98  *
       
    99  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
       
   100  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
       
   101  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
       
   102  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
       
   103  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
       
   104  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
       
   105  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
       
   106  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
       
   107  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
       
   108  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
       
   109  * SUCH DAMAGE.
       
   110  */
       
   111 
       
   112 
       
   113 #include <_ansi.h>
       
   114 #include <limits.h>
       
   115 #include <ctype.h>
       
   116 #include <errno.h>
       
   117 #include <stdlib.h>
       
   118 #include <reent.h>
       
   119 
       
   120 /*
       
   121  * Convert a string to a long integer.
       
   122  *
       
   123  * Ignores `locale' stuff.  Assumes that the upper and lower case
       
   124  * alphabets and digits are each contiguous.
       
   125  */
       
   126 static unsigned long _do_strtoX (const char *nptr, char **endptr, int base, int issigned)
       
   127 {
       
   128 	register const char *s = nptr;
       
   129 	register unsigned long acc;
       
   130 	register int c;
       
   131 	register unsigned long cutoff;
       
   132 	register int neg = 0, any, cutlim;
       
   133 	register const unsigned long long_min = (unsigned long)LONG_MIN;
       
   134 
       
   135 	/*
       
   136 	 * Skip white space and pick up leading +/- sign if any.
       
   137 	 * If base is 0, allow 0x for hex and 0 for octal, else
       
   138 	 * assume decimal; if base is already 16, allow 0x.
       
   139 	 */
       
   140 	do {
       
   141 		c = *s++;
       
   142 	} while (isspace(c));
       
   143 	
       
   144 	if ((c == '-')||(c == '+')) {
       
   145 	    issigned = 1;
       
   146 	}
       
   147 	
       
   148 	if (issigned) {
       
   149 		if (c == '-') {
       
   150 			neg = 1;
       
   151 			c = *s++;
       
   152 		} else if (c == '+')
       
   153 			c = *s++;
       
   154 	}
       
   155 	if ((base == 0 || base == 16) &&
       
   156 	    c == '0' && (*s == 'x' || *s == 'X')) {
       
   157 		c = s[1];
       
   158 		s += 2;
       
   159 		base = 16;
       
   160 	}
       
   161 	if (base == 0)
       
   162 		base = c == '0' ? 8 : 10;
       
   163 
       
   164 	/*
       
   165 	 * Compute the cutoff value between legal numbers and illegal
       
   166 	 * numbers.  That is the largest legal value, divided by the
       
   167 	 * base.  An input number that is greater than this value, if
       
   168 	 * followed by a legal input character, is too big.  One that
       
   169 	 * is equal to this value may be valid or not; the limit
       
   170 	 * between valid and invalid numbers is then based on the last
       
   171 	 * digit.  For instance, if the range for longs is
       
   172 	 * [-2147483648..2147483647] and the input base is 10,
       
   173 	 * cutoff will be set to 214748364 and cutlim to either
       
   174 	 * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
       
   175 	 * a value > 214748364, or equal but the next digit is > 7 (or 8),
       
   176 	 * the number is too big, and we will return a range error.
       
   177 	 *
       
   178 	 * Set any if any `digits' consumed; make it negative to indicate
       
   179 	 * overflow.
       
   180 	 */
       
   181 	if (issigned)
       
   182 		cutoff = neg ? long_min : LONG_MAX;
       
   183 	else
       
   184 		cutoff = ULONG_MAX;
       
   185 	cutlim = cutoff % (unsigned long)base;
       
   186 	cutoff = cutoff / (unsigned long)base;
       
   187 	for (acc = 0, any = 0;; c = *s++) {
       
   188 		if (isdigit(c))
       
   189 			c -= '0';
       
   190 		else if (isalpha(c))
       
   191 			c -= isupper(c) ? 'A' - 10 : 'a' - 10;
       
   192 		else
       
   193 			break;
       
   194 		if (c >= base)
       
   195 			break;
       
   196 		if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
       
   197 			any = -1;
       
   198 		else {
       
   199 			any = 1;
       
   200 			acc *= base;
       
   201 			acc += c;
       
   202 		}
       
   203 	}
       
   204 	if (any < 0) {
       
   205 		if (issigned)
       
   206 			acc = neg ? LONG_MIN : LONG_MAX;
       
   207 		else
       
   208 			acc = ULONG_MAX;
       
   209 		errno = ERANGE;
       
   210 	} else if (neg)
       
   211 		acc = (unsigned long)(-(long)acc);
       
   212 	if (endptr != 0)
       
   213 		*endptr = (char *) (any ? s - 1 : nptr);
       
   214 	return (acc);
       
   215 }
       
   216 
       
   217 /**
       
   218 Convert string to unsigned long integer.
       
   219 Parses string interpreting its content as an integer value 
       
   220 until a character that can not be interpreted is found,
       
   221 and returns an unsigned long value.
       
   222 @return The converted unsigned long value from the input string.
       
   223 If an error occurs or no conversion can be made 0 is returned.
       
   224 @param s String representing an integer number. 
       
   225 @param ptr Address of a pointer.
       
   226 This is filled by the function with the address where scan has ended. 
       
   227 Serves to determine where there is the first non-numerical character in the string. 
       
   228 @param base Numeral radix in which the number to be interpreted. 
       
   229 Must be 0 or be between 2 and 36. If it is 0 the radix of the string is determined 
       
   230 by the initial characters of the string:
       
   231 */
       
   232 EXPORT_C unsigned long strtoul (const char *s, char **ptr, int base)
       
   233 	{
       
   234 	return _do_strtoX (s, ptr, base, 0);
       
   235 	}
       
   236 
       
   237 /**
       
   238 Convert string to long integer.
       
   239 @return The converted long int value from the input string.
       
   240 If an error occurs or no conversion can be made 0 is returned.
       
   241 @param s String representing an integer number. 
       
   242 @param ptr Address of a pointer. 
       
   243 This is filled by the function with the address where scan has ended. 
       
   244 @param base Numeral radix in which the number to be interpreted. 
       
   245 Must be 0 or be between 2 and 36. If it is 0 the radix of the string 
       
   246 is determined by the initial characters of the string
       
   247 */
       
   248 EXPORT_C long strtol (const char *s, char **ptr, int base)
       
   249 	{
       
   250 	return (long)_do_strtoX (s, ptr, base, 1);
       
   251 	}
       
   252 
       
   253 /**
       
   254 Convert string to integer.
       
   255 Parses string interpreting its content as a number and returns an int value.
       
   256 @return   The converted integer value of the input string.
       
   257 On overflow the result is undefined.
       
   258 If an error occurs 0 is returned.
       
   259 @param s String representing an integer number. 
       
   260 */
       
   261 EXPORT_C int atoi (const char *s)
       
   262 	{
       
   263 	return (int) _do_strtoX (s, NULL, 10, 1);
       
   264 	}