wcstol.c revision 1.1 1 1.1 yamt /* $NetBSD: wcstol.c,v 1.1 2001/09/27 16:30:36 yamt Exp $ */
2 1.1 yamt /* $Citrus: xpg4dl/FreeBSD/lib/libc/locale/wcstol.c,v 1.2 2001/09/21 16:11:41 yamt Exp $ */
3 1.1 yamt
4 1.1 yamt /*-
5 1.1 yamt * Copyright (c) 1990, 1993
6 1.1 yamt * The Regents of the University of California. All rights reserved.
7 1.1 yamt *
8 1.1 yamt * Redistribution and use in source and binary forms, with or without
9 1.1 yamt * modification, are permitted provided that the following conditions
10 1.1 yamt * are met:
11 1.1 yamt * 1. Redistributions of source code must retain the above copyright
12 1.1 yamt * notice, this list of conditions and the following disclaimer.
13 1.1 yamt * 2. Redistributions in binary form must reproduce the above copyright
14 1.1 yamt * notice, this list of conditions and the following disclaimer in the
15 1.1 yamt * documentation and/or other materials provided with the distribution.
16 1.1 yamt * 3. All advertising materials mentioning features or use of this software
17 1.1 yamt * must display the following acknowledgement:
18 1.1 yamt * This product includes software developed by the University of
19 1.1 yamt * California, Berkeley and its contributors.
20 1.1 yamt * 4. Neither the name of the University nor the names of its contributors
21 1.1 yamt * may be used to endorse or promote products derived from this software
22 1.1 yamt * without specific prior written permission.
23 1.1 yamt *
24 1.1 yamt * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 1.1 yamt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 1.1 yamt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 1.1 yamt * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 1.1 yamt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 1.1 yamt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 1.1 yamt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 1.1 yamt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 1.1 yamt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 1.1 yamt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 1.1 yamt * SUCH DAMAGE.
35 1.1 yamt */
36 1.1 yamt
37 1.1 yamt #include <sys/cdefs.h>
38 1.1 yamt #if defined(LIBC_SCCS) && !defined(lint)
39 1.1 yamt #if 0
40 1.1 yamt static char sccsid[] = "@(#)strtol.c 8.1 (Berkeley) 6/4/93";
41 1.1 yamt #else
42 1.1 yamt __RCSID("$NetBSD: wcstol.c,v 1.1 2001/09/27 16:30:36 yamt Exp $");
43 1.1 yamt #endif
44 1.1 yamt #endif /* LIBC_SCCS and not lint */
45 1.1 yamt
46 1.1 yamt #include <assert.h>
47 1.1 yamt #include <ctype.h>
48 1.1 yamt #include <errno.h>
49 1.1 yamt #include <limits.h>
50 1.1 yamt #include <stdlib.h>
51 1.1 yamt #include <wchar.h>
52 1.1 yamt #include <wctype.h>
53 1.1 yamt
54 1.1 yamt #include "__wctoint.h"
55 1.1 yamt
56 1.1 yamt /*
57 1.1 yamt * Convert a wide-char string to a long integer.
58 1.1 yamt */
59 1.1 yamt long
60 1.1 yamt wcstol(nptr, endptr, base)
61 1.1 yamt const wchar_t *nptr;
62 1.1 yamt wchar_t **endptr;
63 1.1 yamt int base;
64 1.1 yamt {
65 1.1 yamt const wchar_t *s;
66 1.1 yamt long acc, cutoff;
67 1.1 yamt wint_t wc;
68 1.1 yamt int i;
69 1.1 yamt int neg, any, cutlim;
70 1.1 yamt
71 1.1 yamt _DIAGASSERT(nptr != NULL);
72 1.1 yamt /* endptr may be NULL */
73 1.1 yamt
74 1.1 yamt /* check base value */
75 1.1 yamt if (base && (base < 2 || base > 36)) {
76 1.1 yamt errno = EINVAL;
77 1.1 yamt return 0;
78 1.1 yamt }
79 1.1 yamt
80 1.1 yamt /*
81 1.1 yamt * Skip white space and pick up leading +/- sign if any.
82 1.1 yamt * If base is 0, allow 0x for hex and 0 for octal, else
83 1.1 yamt * assume decimal; if base is already 16, allow 0x.
84 1.1 yamt */
85 1.1 yamt s = nptr;
86 1.1 yamt do {
87 1.1 yamt wc = (wchar_t) *s++;
88 1.1 yamt } while (iswspace(wc));
89 1.1 yamt if (wc == L'-') {
90 1.1 yamt neg = 1;
91 1.1 yamt wc = *s++;
92 1.1 yamt } else {
93 1.1 yamt neg = 0;
94 1.1 yamt if (wc == L'+')
95 1.1 yamt wc = *s++;
96 1.1 yamt }
97 1.1 yamt if ((base == 0 || base == 16) &&
98 1.1 yamt wc == L'0' && (*s == L'x' || *s == L'X')) {
99 1.1 yamt wc = s[1];
100 1.1 yamt s += 2;
101 1.1 yamt base = 16;
102 1.1 yamt }
103 1.1 yamt if (base == 0)
104 1.1 yamt base = wc == '0' ? 8 : 10;
105 1.1 yamt
106 1.1 yamt /*
107 1.1 yamt * Compute the cutoff value between legal numbers and illegal
108 1.1 yamt * numbers. That is the largest legal value, divided by the
109 1.1 yamt * base. An input number that is greater than this value, if
110 1.1 yamt * followed by a legal input character, is too big. One that
111 1.1 yamt * is equal to this value may be valid or not; the limit
112 1.1 yamt * between valid and invalid numbers is then based on the last
113 1.1 yamt * digit. For instance, if the range for longs is
114 1.1 yamt * [-2147483648..2147483647] and the input base is 10,
115 1.1 yamt * cutoff will be set to 214748364 and cutlim to either
116 1.1 yamt * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
117 1.1 yamt * a value > 214748364, or equal but the next digit is > 7 (or 8),
118 1.1 yamt * the number is too big, and we will return a range error.
119 1.1 yamt *
120 1.1 yamt * Set any if any `digits' consumed; make it negative to indicate
121 1.1 yamt * overflow.
122 1.1 yamt */
123 1.1 yamt cutoff = neg ? LONG_MIN : LONG_MAX;
124 1.1 yamt cutlim = (int)(cutoff % base);
125 1.1 yamt cutoff /= base;
126 1.1 yamt if (neg) {
127 1.1 yamt if (cutlim > 0) {
128 1.1 yamt cutlim -= base;
129 1.1 yamt cutoff += 1;
130 1.1 yamt }
131 1.1 yamt cutlim = -cutlim;
132 1.1 yamt }
133 1.1 yamt for (acc = 0, any = 0;; wc = (wchar_t) *s++) {
134 1.1 yamt i = __wctoint(wc);
135 1.1 yamt if (i == -1)
136 1.1 yamt break;
137 1.1 yamt if (i >= base)
138 1.1 yamt break;
139 1.1 yamt if (any < 0)
140 1.1 yamt continue;
141 1.1 yamt if (neg) {
142 1.1 yamt if (acc < cutoff || (acc == cutoff && i > cutlim)) {
143 1.1 yamt any = -1;
144 1.1 yamt acc = LONG_MIN;
145 1.1 yamt errno = ERANGE;
146 1.1 yamt } else {
147 1.1 yamt any = 1;
148 1.1 yamt acc *= base;
149 1.1 yamt acc -= i;
150 1.1 yamt }
151 1.1 yamt } else {
152 1.1 yamt if (acc > cutoff || (acc == cutoff && i > cutlim)) {
153 1.1 yamt any = -1;
154 1.1 yamt acc = LONG_MAX;
155 1.1 yamt errno = ERANGE;
156 1.1 yamt } else {
157 1.1 yamt any = 1;
158 1.1 yamt acc *= base;
159 1.1 yamt acc += i;
160 1.1 yamt }
161 1.1 yamt }
162 1.1 yamt }
163 1.1 yamt if (endptr != 0)
164 1.1 yamt /* LINTED interface specification */
165 1.1 yamt *endptr = (wchar_t *)(any ? s - 1 : nptr);
166 1.1 yamt return (acc);
167 1.1 yamt }
168