xref: /titanic_52/usr/src/boot/lib/libstand/strtol.c (revision 830d404a76dc8e6b5e01c3228d6dae8b30b98e30)
14a5d661aSToomas Soome /*-
24a5d661aSToomas Soome  * Copyright (c) 1990, 1993
34a5d661aSToomas Soome  *	The Regents of the University of California.  All rights reserved.
44a5d661aSToomas Soome  *
54a5d661aSToomas Soome  * Redistribution and use in source and binary forms, with or without
64a5d661aSToomas Soome  * modification, are permitted provided that the following conditions
74a5d661aSToomas Soome  * are met:
84a5d661aSToomas Soome  * 1. Redistributions of source code must retain the above copyright
94a5d661aSToomas Soome  *    notice, this list of conditions and the following disclaimer.
104a5d661aSToomas Soome  * 2. Redistributions in binary form must reproduce the above copyright
114a5d661aSToomas Soome  *    notice, this list of conditions and the following disclaimer in the
124a5d661aSToomas Soome  *    documentation and/or other materials provided with the distribution.
134a5d661aSToomas Soome  * 4. Neither the name of the University nor the names of its contributors
144a5d661aSToomas Soome  *    may be used to endorse or promote products derived from this software
154a5d661aSToomas Soome  *    without specific prior written permission.
164a5d661aSToomas Soome  *
174a5d661aSToomas Soome  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
184a5d661aSToomas Soome  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
194a5d661aSToomas Soome  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
204a5d661aSToomas Soome  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
214a5d661aSToomas Soome  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
224a5d661aSToomas Soome  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
234a5d661aSToomas Soome  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
244a5d661aSToomas Soome  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
254a5d661aSToomas Soome  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
264a5d661aSToomas Soome  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
274a5d661aSToomas Soome  * SUCH DAMAGE.
284a5d661aSToomas Soome  */
294a5d661aSToomas Soome 
304a5d661aSToomas Soome #include <sys/cdefs.h>
314a5d661aSToomas Soome __FBSDID("$FreeBSD$");
324a5d661aSToomas Soome 
334a5d661aSToomas Soome #if defined(LIBC_SCCS) && !defined(lint)
344a5d661aSToomas Soome static char sccsid[] = "@(#)strtol.c	8.1 (Berkeley) 6/4/93";
354a5d661aSToomas Soome #endif /* LIBC_SCCS and not lint */
364a5d661aSToomas Soome 
374a5d661aSToomas Soome #include "stand.h"
384a5d661aSToomas Soome #include <limits.h>
394a5d661aSToomas Soome 
404a5d661aSToomas Soome /*
414a5d661aSToomas Soome  * Convert a string to a long integer.
424a5d661aSToomas Soome  *
434a5d661aSToomas Soome  * Ignores `locale' stuff.  Assumes that the upper and lower case
444a5d661aSToomas Soome  * alphabets and digits are each contiguous.
454a5d661aSToomas Soome  */
464a5d661aSToomas Soome long
474a5d661aSToomas Soome strtol(nptr, endptr, base)
484a5d661aSToomas Soome 	const char *nptr;
494a5d661aSToomas Soome 	char **endptr;
504a5d661aSToomas Soome 	int base;
514a5d661aSToomas Soome {
524a5d661aSToomas Soome 	const char *s;
534a5d661aSToomas Soome 	unsigned long acc;
544a5d661aSToomas Soome 	unsigned char c;
554a5d661aSToomas Soome 	unsigned long cutoff;
564a5d661aSToomas Soome 	int neg = 0, any, cutlim;
574a5d661aSToomas Soome 
584a5d661aSToomas Soome 	/* Be sensible about NULL strings */
594a5d661aSToomas Soome 	if (nptr == NULL)
604a5d661aSToomas Soome 	    nptr = "";
614a5d661aSToomas Soome 	s = nptr;
624a5d661aSToomas Soome 
634a5d661aSToomas Soome 	/*
644a5d661aSToomas Soome 	 * Skip white space and pick up leading +/- sign if any.
654a5d661aSToomas Soome 	 * If base is 0, allow 0x for hex and 0 for octal, else
664a5d661aSToomas Soome 	 * assume decimal; if base is already 16, allow 0x.
674a5d661aSToomas Soome 	 */
684a5d661aSToomas Soome 	do {
694a5d661aSToomas Soome 		c = *s++;
704a5d661aSToomas Soome 	} while (isspace(c));
714a5d661aSToomas Soome 	if (c == '-') {
724a5d661aSToomas Soome 		neg = 1;
734a5d661aSToomas Soome 		c = *s++;
744a5d661aSToomas Soome 	} else if (c == '+')
754a5d661aSToomas Soome 		c = *s++;
764a5d661aSToomas Soome 	if ((base == 0 || base == 16) &&
774a5d661aSToomas Soome 	    c == '0' && (*s == 'x' || *s == 'X')) {
784a5d661aSToomas Soome 		c = s[1];
794a5d661aSToomas Soome 		s += 2;
804a5d661aSToomas Soome 		base = 16;
814a5d661aSToomas Soome 	}
824a5d661aSToomas Soome 	if (base == 0)
834a5d661aSToomas Soome 		base = c == '0' ? 8 : 10;
844a5d661aSToomas Soome 
854a5d661aSToomas Soome 	/*
864a5d661aSToomas Soome 	 * Compute the cutoff value between legal numbers and illegal
874a5d661aSToomas Soome 	 * numbers.  That is the largest legal value, divided by the
884a5d661aSToomas Soome 	 * base.  An input number that is greater than this value, if
894a5d661aSToomas Soome 	 * followed by a legal input character, is too big.  One that
904a5d661aSToomas Soome 	 * is equal to this value may be valid or not; the limit
914a5d661aSToomas Soome 	 * between valid and invalid numbers is then based on the last
924a5d661aSToomas Soome 	 * digit.  For instance, if the range for longs is
934a5d661aSToomas Soome 	 * [-2147483648..2147483647] and the input base is 10,
944a5d661aSToomas Soome 	 * cutoff will be set to 214748364 and cutlim to either
954a5d661aSToomas Soome 	 * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
964a5d661aSToomas Soome 	 * a value > 214748364, or equal but the next digit is > 7 (or 8),
974a5d661aSToomas Soome 	 * the number is too big, and we will return a range error.
984a5d661aSToomas Soome 	 *
994a5d661aSToomas Soome 	 * Set any if any `digits' consumed; make it negative to indicate
1004a5d661aSToomas Soome 	 * overflow.
1014a5d661aSToomas Soome 	 */
1024a5d661aSToomas Soome 	cutoff = neg ? -(unsigned long)LONG_MIN : LONG_MAX;
1034a5d661aSToomas Soome 	cutlim = cutoff % (unsigned long)base;
1044a5d661aSToomas Soome 	cutoff /= (unsigned long)base;
1054a5d661aSToomas Soome 	for (acc = 0, any = 0;; c = *s++) {
1064a5d661aSToomas Soome 		if (!isascii(c))
1074a5d661aSToomas Soome 			break;
1084a5d661aSToomas Soome 		if (isdigit(c))
1094a5d661aSToomas Soome 			c -= '0';
1104a5d661aSToomas Soome 		else if (isalpha(c))
1114a5d661aSToomas Soome 			c -= isupper(c) ? 'A' - 10 : 'a' - 10;
1124a5d661aSToomas Soome 		else
1134a5d661aSToomas Soome 			break;
1144a5d661aSToomas Soome 		if (c >= base)
1154a5d661aSToomas Soome 			break;
1164a5d661aSToomas Soome 		if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
1174a5d661aSToomas Soome 			any = -1;
1184a5d661aSToomas Soome 		else {
1194a5d661aSToomas Soome 			any = 1;
1204a5d661aSToomas Soome 			acc *= base;
1214a5d661aSToomas Soome 			acc += c;
1224a5d661aSToomas Soome 		}
1234a5d661aSToomas Soome 	}
1244a5d661aSToomas Soome 	if (any < 0) {
1254a5d661aSToomas Soome 		acc = neg ? LONG_MIN : LONG_MAX;
1264a5d661aSToomas Soome 		errno = ERANGE;
1274a5d661aSToomas Soome 	} else if (neg)
1284a5d661aSToomas Soome 		acc = -acc;
129*830d404aSToomas Soome 	if (endptr != NULL)
1304a5d661aSToomas Soome 		*endptr = (char *)(any ? s - 1 : nptr);
1314a5d661aSToomas Soome 	return (acc);
1324a5d661aSToomas Soome }
133