xref: /illumos-gate/usr/src/common/util/strtoul.c (revision 28de4f3c3209c81f9a96e2019d44a0b9adcb74cb)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1988 AT&T	*/
28 /*	  All Rights Reserved	*/
29 
30 #if	defined(_KERNEL) && !defined(_BOOT)
31 #include <sys/null.h>
32 #include <sys/errno.h>
33 #else	/* _KERNEL && !_BOOT */
34 #if	!defined(_BOOT) && !defined(_KMDB) && !defined(_STANDALONE)
35 #include "lint.h"
36 #endif	/* !_BOOT && !_KMDB && !_STANDALONE */
37 #if	defined(_STANDALONE)
38 #include <sys/cdefs.h>
39 #include <stand.h>
40 #include <limits.h>
41 #else
42 #include <errno.h>
43 #include <ctype.h>
44 #include <limits.h>
45 #include <stdlib.h>
46 #endif	/* _STANDALONE */
47 #endif	/* _KERNEL && !_BOOT */
48 #include "strtolctype.h"
49 #include <sys/types.h>
50 
51 #if	defined(_KERNEL) && !defined(_BOOT)
52 int
53 ddi_strtoul(const char *str, char **nptr, int base, unsigned long *result)
54 #else	/* _KERNEL && !_BOOT */
55 unsigned long
56 strtoul(const char *str, char **nptr, int base)
57 #endif	/* _KERNEL && !_BOOT */
58 {
59 	unsigned long val;
60 	int c;
61 	int xx;
62 	int neg = 0;
63 	unsigned long multmax;
64 	const char **ptr = (const char **)nptr;
65 	const unsigned char *ustr = (const unsigned char *)str;
66 
67 	if (ptr != NULL)
68 		*ptr = (char *)ustr; /* in case no number is formed */
69 	if (base < 0 || base > MBASE || base == 1) {
70 		/* base is invalid -- should be a fatal error */
71 #if	defined(_KERNEL) && !defined(_BOOT)
72 		return (EINVAL);
73 #else	/* _KERNEL && !_BOOT */
74 		errno = EINVAL;
75 		return (0);
76 #endif	/* _KERNEL && !_BOOT */
77 	}
78 	if (!isalnum(c = *ustr)) {
79 		while (isspace(c))
80 			c = *++ustr;
81 		switch (c) {
82 		case '-':
83 			neg++;
84 			/* FALLTHROUGH */
85 		case '+':
86 			c = *++ustr;
87 		}
88 	}
89 	if (base == 0) {
90 		if (c != '0')
91 			base = 10;
92 		else if (ustr[1] == 'x' || ustr[1] == 'X')
93 			base = 16;
94 		else
95 			base = 8;
96 	}
97 	/*
98 	 * for any base > 10, the digits incrementally following
99 	 *	9 are assumed to be "abc...z" or "ABC...Z"
100 	 */
101 	if (!lisalnum(c) || (xx = DIGIT(c)) >= base) {
102 		/* no number formed */
103 #if	defined(_KERNEL) && !defined(_BOOT)
104 		return (EINVAL);
105 #else	/* _KERNEL && !_BOOT */
106 		return (0);
107 #endif	/* _KERNEL && !_BOOT */
108 	}
109 	if (base == 16 && c == '0' && (ustr[1] == 'x' || ustr[1] == 'X') &&
110 	    isxdigit(ustr[2]))
111 		c = *(ustr += 2); /* skip over leading "0x" or "0X" */
112 
113 	multmax = ULONG_MAX / (unsigned long)base;
114 	val = DIGIT(c);
115 	for (c = *++ustr; lisalnum(c) && (xx = DIGIT(c)) < base; ) {
116 		if (val > multmax)
117 			goto overflow;
118 		val *= base;
119 		if (ULONG_MAX - val < (unsigned long)xx)
120 			goto overflow;
121 		val += xx;
122 		c = *++ustr;
123 	}
124 	if (ptr != NULL)
125 		*ptr = (char *)ustr;
126 #if	defined(_KERNEL) && !defined(_BOOT)
127 	*result = neg ? -val : val;
128 	return (0);
129 #else	/* _KERNEL && !_BOOT */
130 	return (neg ? -val : val);
131 #endif	/* _KERNEL && !_BOOT */
132 
133 overflow:
134 	for (c = *++ustr; lisalnum(c) && (xx = DIGIT(c)) < base; (c = *++ustr))
135 		;
136 	if (ptr != NULL)
137 		*ptr = (char *)ustr;
138 #if	defined(_KERNEL) && !defined(_BOOT)
139 	return (ERANGE);
140 #else	/* _KERNEL && !_BOOT */
141 	errno = ERANGE;
142 	return (ULONG_MAX);
143 #endif	/* _KERNEL && !_BOOT */
144 }
145