1 | /* $NetBSD: _strtol.h,v 1.10 2015/11/13 16:02:07 christos Exp $ */ |
2 | |
3 | /*- |
4 | * Copyright (c) 1990, 1993 |
5 | * The Regents of the University of California. All rights reserved. |
6 | * |
7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions |
9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. |
15 | * 3. Neither the name of the University nor the names of its contributors |
16 | * may be used to endorse or promote products derived from this software |
17 | * without specific prior written permission. |
18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
29 | * SUCH DAMAGE. |
30 | * |
31 | * Original version ID: |
32 | * NetBSD: src/lib/libc/locale/_wcstol.h,v 1.2 2003/08/07 16:43:03 agc Exp |
33 | */ |
34 | |
35 | /* |
36 | * function template for strtol, strtoll and strtoimax. |
37 | * |
38 | * parameters: |
39 | * _FUNCNAME : function name |
40 | * __INT : return type |
41 | * __INT_MIN : lower limit of the return type |
42 | * __INT_MAX : upper limit of the return type |
43 | */ |
44 | #if defined(_KERNEL) || defined(_STANDALONE) || defined(HAVE_NBTOOL_CONFIG_H) || defined(BCS_ONLY) |
45 | __INT |
46 | _FUNCNAME(const char *nptr, char **endptr, int base) |
47 | #else |
48 | #include <locale.h> |
49 | #include "setlocale_local.h" |
50 | #define INT_FUNCNAME_(pre, name, post) pre ## name ## post |
51 | #define INT_FUNCNAME(pre, name, post) INT_FUNCNAME_(pre, name, post) |
52 | |
53 | static __INT |
54 | INT_FUNCNAME(_int_, _FUNCNAME, _l)(const char *nptr, char **endptr, |
55 | int base, locale_t loc) |
56 | #endif |
57 | { |
58 | const char *s; |
59 | __INT acc, cutoff; |
60 | unsigned char c; |
61 | int i, neg, any, cutlim; |
62 | |
63 | _DIAGASSERT(nptr != NULL); |
64 | /* endptr may be NULL */ |
65 | |
66 | /* check base value */ |
67 | if (base && (base < 2 || base > 36)) { |
68 | #if !defined(_KERNEL) && !defined(_STANDALONE) |
69 | errno = EINVAL; |
70 | if (endptr != NULL) |
71 | /* LINTED interface specification */ |
72 | *endptr = __UNCONST(nptr); |
73 | return 0; |
74 | #else |
75 | panic("%s: invalid base %d" , __func__, base); |
76 | #endif |
77 | } |
78 | |
79 | /* |
80 | * Skip white space and pick up leading +/- sign if any. |
81 | * If base is 0, allow 0x for hex and 0 for octal, else |
82 | * assume decimal; if base is already 16, allow 0x. |
83 | */ |
84 | s = nptr; |
85 | #if defined(_KERNEL) || defined(_STANDALONE) || \ |
86 | defined(HAVE_NBTOOL_CONFIG_H) || defined(BCS_ONLY) |
87 | do { |
88 | c = *s++; |
89 | } while (isspace(c)); |
90 | #else |
91 | do { |
92 | c = *s++; |
93 | } while (isspace_l(c, loc)); |
94 | #endif |
95 | if (c == '-') { |
96 | neg = 1; |
97 | c = *s++; |
98 | } else { |
99 | neg = 0; |
100 | if (c == '+') |
101 | c = *s++; |
102 | } |
103 | if ((base == 0 || base == 16) && |
104 | c == '0' && (*s == 'x' || *s == 'X')) { |
105 | c = s[1]; |
106 | s += 2; |
107 | base = 16; |
108 | #if 0 |
109 | } else if ((base == 0 || base == 2) && |
110 | c == '0' && (*s == 'b' || *s == 'B')) { |
111 | c = s[1]; |
112 | s += 2; |
113 | base = 2; |
114 | #endif |
115 | } else if (base == 0) |
116 | base = (c == '0' ? 8 : 10); |
117 | |
118 | /* |
119 | * Compute the cutoff value between legal numbers and illegal |
120 | * numbers. That is the largest legal value, divided by the |
121 | * base. An input number that is greater than this value, if |
122 | * followed by a legal input character, is too big. One that |
123 | * is equal to this value may be valid or not; the limit |
124 | * between valid and invalid numbers is then based on the last |
125 | * digit. For instance, if the range for longs is |
126 | * [-2147483648..2147483647] and the input base is 10, |
127 | * cutoff will be set to 214748364 and cutlim to either |
128 | * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated |
129 | * a value > 214748364, or equal but the next digit is > 7 (or 8), |
130 | * the number is too big, and we will return a range error. |
131 | * |
132 | * Set any if any `digits' consumed; make it negative to indicate |
133 | * overflow. |
134 | */ |
135 | cutoff = (__INT)(neg ? __INT_MIN : __INT_MAX); |
136 | cutlim = (int)(cutoff % base); |
137 | cutoff /= base; |
138 | if (neg) { |
139 | if (cutlim > 0) { |
140 | cutlim -= base; |
141 | cutoff += 1; |
142 | } |
143 | cutlim = -cutlim; |
144 | } |
145 | for (acc = 0, any = 0;; c = *s++) { |
146 | if (c >= '0' && c <= '9') |
147 | i = c - '0'; |
148 | else if (c >= 'a' && c <= 'z') |
149 | i = (c - 'a') + 10; |
150 | else if (c >= 'A' && c <= 'Z') |
151 | i = (c - 'A') + 10; |
152 | else |
153 | break; |
154 | if (i >= base) |
155 | break; |
156 | if (any < 0) |
157 | continue; |
158 | if (neg) { |
159 | if (acc < cutoff || (acc == cutoff && i > cutlim)) { |
160 | acc = __INT_MIN; |
161 | #if !defined(_KERNEL) && !defined(_STANDALONE) |
162 | any = -1; |
163 | errno = ERANGE; |
164 | #else |
165 | any = 0; |
166 | break; |
167 | #endif |
168 | } else { |
169 | any = 1; |
170 | acc *= base; |
171 | acc -= i; |
172 | } |
173 | } else { |
174 | if (acc > cutoff || (acc == cutoff && i > cutlim)) { |
175 | acc = __INT_MAX; |
176 | #if !defined(_KERNEL) && !defined(_STANDALONE) |
177 | any = -1; |
178 | errno = ERANGE; |
179 | #else |
180 | any = 0; |
181 | break; |
182 | #endif |
183 | } else { |
184 | any = 1; |
185 | acc *= base; |
186 | acc += i; |
187 | } |
188 | } |
189 | } |
190 | if (endptr != NULL) |
191 | /* LINTED interface specification */ |
192 | *endptr = __UNCONST(any ? s - 1 : nptr); |
193 | return(acc); |
194 | } |
195 | |
196 | #if !defined(_KERNEL) && !defined(_STANDALONE) && \ |
197 | !defined(HAVE_NBTOOL_CONFIG_H) && !defined(BCS_ONLY) |
198 | __INT |
199 | _FUNCNAME(const char *nptr, char **endptr, int base) |
200 | { |
201 | return INT_FUNCNAME(_int_, _FUNCNAME, _l)(nptr, endptr, base, _current_locale()); |
202 | } |
203 | |
204 | __INT |
205 | INT_FUNCNAME(, _FUNCNAME, _l)(const char *nptr, char **endptr, int base, locale_t loc) |
206 | { |
207 | return INT_FUNCNAME(_int_, _FUNCNAME, _l)(nptr, endptr, base, loc); |
208 | } |
209 | #endif |
210 | |