1 | /* |
---|
2 | * Copyright (c) 2012-2014 ARM Ltd |
---|
3 | * All rights reserved. |
---|
4 | * |
---|
5 | * Redistribution and use in source and binary forms, with or without |
---|
6 | * modification, are permitted provided that the following conditions |
---|
7 | * are met: |
---|
8 | * 1. Redistributions of source code must retain the above copyright |
---|
9 | * notice, this list of conditions and the following disclaimer. |
---|
10 | * 2. Redistributions in binary form must reproduce the above copyright |
---|
11 | * notice, this list of conditions and the following disclaimer in the |
---|
12 | * documentation and/or other materials provided with the distribution. |
---|
13 | * 3. The name of the company may not be used to endorse or promote |
---|
14 | * products derived from this software without specific prior written |
---|
15 | * permission. |
---|
16 | * |
---|
17 | * THIS SOFTWARE IS PROVIDED BY ARM LTD ``AS IS'' AND ANY EXPRESS OR IMPLIED |
---|
18 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
---|
19 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
---|
20 | * IN NO EVENT SHALL ARM LTD BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
---|
21 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED |
---|
22 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
---|
23 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
---|
24 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
---|
25 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
---|
26 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
---|
27 | */ |
---|
28 | |
---|
29 | #include <_ansi.h> |
---|
30 | #include <reent.h> |
---|
31 | #include <newlib.h> |
---|
32 | #include <ctype.h> |
---|
33 | #include <wctype.h> |
---|
34 | #include <stdio.h> |
---|
35 | #include <stdlib.h> |
---|
36 | #include <stdint.h> |
---|
37 | #include <limits.h> |
---|
38 | #include <wchar.h> |
---|
39 | #include <string.h> |
---|
40 | #include <stdarg.h> |
---|
41 | #include <errno.h> |
---|
42 | #include "local.h" |
---|
43 | #include "../stdlib/local.h" |
---|
44 | |
---|
45 | #include "nano-vfscanf_local.h" |
---|
46 | |
---|
47 | int |
---|
48 | _scanf_chars (struct _reent *rptr, |
---|
49 | struct _scan_data_t *pdata, |
---|
50 | FILE *fp, va_list *ap) |
---|
51 | { |
---|
52 | int n; |
---|
53 | char *p; |
---|
54 | |
---|
55 | if (pdata->width == 0) |
---|
56 | pdata->width = (pdata->code == CT_CHAR) ? 1 : (size_t)~0; |
---|
57 | |
---|
58 | n = 0; |
---|
59 | if ((pdata->flags & SUPPRESS) == 0) |
---|
60 | p = GET_ARG (N, *ap, char *); |
---|
61 | |
---|
62 | /* It's impossible to have EOF when we get here. */ |
---|
63 | while ((pdata->code == CT_CHAR) |
---|
64 | || (pdata->code == CT_CCL && pdata->ccltab[*fp->_p]) |
---|
65 | || (pdata->code == CT_STRING && !isspace (*fp->_p))) |
---|
66 | { |
---|
67 | n++; |
---|
68 | if ((pdata->flags & SUPPRESS) == 0) |
---|
69 | *p++ = *fp->_p; |
---|
70 | |
---|
71 | fp->_r--, fp->_p++; |
---|
72 | if (--pdata->width == 0) |
---|
73 | break; |
---|
74 | |
---|
75 | if ((fp->_r <= 0 && pdata->pfn_refill (rptr, fp))) |
---|
76 | break; |
---|
77 | } |
---|
78 | /* For CT_CHAR, it is impossible to have input_failure(n == 0) here. |
---|
79 | For CT_CCL, it is impossible to have input_failure here. |
---|
80 | For CT_STRING, it is possible to have empty string. */ |
---|
81 | if (n == 0 && pdata->code == CT_CCL) |
---|
82 | return MATCH_FAILURE; |
---|
83 | |
---|
84 | if ((pdata->flags & SUPPRESS) == 0) |
---|
85 | { |
---|
86 | pdata->nassigned++; |
---|
87 | if (pdata->code != CT_CHAR) |
---|
88 | *p = 0; |
---|
89 | } |
---|
90 | pdata->nread += n; |
---|
91 | return 0; |
---|
92 | } |
---|
93 | int |
---|
94 | _scanf_i (struct _reent *rptr, |
---|
95 | struct _scan_data_t *pdata, |
---|
96 | FILE *fp, va_list *ap) |
---|
97 | { |
---|
98 | #define CCFN_PARAMS (struct _reent *, const char *, char **, int) |
---|
99 | /* Conversion function (strtol/strtoul). */ |
---|
100 | u_long (*ccfn)CCFN_PARAMS=0; |
---|
101 | char *p; |
---|
102 | int n; |
---|
103 | char *xdigits = "A-Fa-f8901234567]"; |
---|
104 | char *prefix_chars[3] = {"+-", "00", "xX"}; |
---|
105 | |
---|
106 | /* Scan an integer as if by strtol/strtoul. */ |
---|
107 | unsigned width_left = 0; |
---|
108 | int skips = 0; |
---|
109 | |
---|
110 | ccfn = (pdata->code == CT_INT) ? (u_long (*)CCFN_PARAMS)_strtol_r : _strtoul_r; |
---|
111 | #ifdef hardway |
---|
112 | if (pdata->width == 0 || pdata->width > BUF - 1) |
---|
113 | #else |
---|
114 | /* size_t is unsigned, hence this optimisation. */ |
---|
115 | if (pdata->width - 1 > BUF - 2) |
---|
116 | #endif |
---|
117 | { |
---|
118 | width_left = pdata->width - (BUF - 1); |
---|
119 | pdata->width = BUF - 1; |
---|
120 | } |
---|
121 | p = pdata->buf; |
---|
122 | pdata->flags |= NDIGITS | NZDIGITS | NNZDIGITS; |
---|
123 | |
---|
124 | /* Process [sign] [0] [xX] prefixes sequently. */ |
---|
125 | for (n = 0; n < 3; n++) |
---|
126 | { |
---|
127 | if (!memchr (prefix_chars[n], *fp->_p, 2)) |
---|
128 | continue; |
---|
129 | |
---|
130 | if (n == 1) |
---|
131 | { |
---|
132 | if (pdata->base == 0) |
---|
133 | { |
---|
134 | pdata->base = 8; |
---|
135 | pdata->flags |= PFXOK; |
---|
136 | } |
---|
137 | pdata->flags &= ~(NZDIGITS | NDIGITS); |
---|
138 | } |
---|
139 | else if (n == 2) |
---|
140 | { |
---|
141 | if ((pdata->flags & (PFXOK | NZDIGITS)) != PFXOK) |
---|
142 | continue; |
---|
143 | pdata->base = 16; |
---|
144 | |
---|
145 | /* We must reset the NZDIGITS and NDIGITS |
---|
146 | flags that would have been unset by seeing |
---|
147 | the zero that preceded the X or x. |
---|
148 | |
---|
149 | ??? It seems unnecessary to reset the NZDIGITS. */ |
---|
150 | pdata->flags |= NDIGITS; |
---|
151 | } |
---|
152 | if (pdata->width-- > 0) |
---|
153 | { |
---|
154 | *p++ = *fp->_p++; |
---|
155 | fp->_r--; |
---|
156 | if ((fp->_r <= 0 && pdata->pfn_refill (rptr, fp))) |
---|
157 | goto match_end; |
---|
158 | } |
---|
159 | } |
---|
160 | |
---|
161 | if (pdata->base == 0) |
---|
162 | pdata->base = 10; |
---|
163 | |
---|
164 | /* The check is un-necessary if xdigits points to exactly the string: |
---|
165 | "A-Fa-f8901234567]". The code is kept only for reading's sake. */ |
---|
166 | #if 0 |
---|
167 | if (pdata->base != 16) |
---|
168 | #endif |
---|
169 | xdigits = xdigits + 16 - pdata->base; |
---|
170 | |
---|
171 | /* Initilize ccltab according to pdata->base. */ |
---|
172 | __sccl (pdata->ccltab, (unsigned char *) xdigits); |
---|
173 | for (; pdata->width; pdata->width--) |
---|
174 | { |
---|
175 | n = *fp->_p; |
---|
176 | if (pdata->ccltab[n] == 0) |
---|
177 | break; |
---|
178 | else if (n == '0' && (pdata->flags & NNZDIGITS)) |
---|
179 | { |
---|
180 | ++skips; |
---|
181 | if (width_left) |
---|
182 | { |
---|
183 | width_left--; |
---|
184 | pdata->width++; |
---|
185 | } |
---|
186 | goto skip; |
---|
187 | } |
---|
188 | pdata->flags &= ~(NDIGITS | NNZDIGITS); |
---|
189 | /* Char is legal: store it and look at the next. */ |
---|
190 | *p++ = *fp->_p; |
---|
191 | skip: |
---|
192 | if (--fp->_r > 0) |
---|
193 | fp->_p++; |
---|
194 | else if (pdata->pfn_refill (rptr, fp)) |
---|
195 | /* "EOF". */ |
---|
196 | break; |
---|
197 | } |
---|
198 | /* If we had only a sign, it is no good; push back the sign. |
---|
199 | If the number ends in `x', it was [sign] '0' 'x', so push back |
---|
200 | the x and treat it as [sign] '0'. |
---|
201 | Use of ungetc here and below assumes ASCII encoding; we are only |
---|
202 | pushing back 7-bit characters, so casting to unsigned char is |
---|
203 | not necessary. */ |
---|
204 | match_end: |
---|
205 | if (pdata->flags & NDIGITS) |
---|
206 | { |
---|
207 | if (p > pdata->buf) |
---|
208 | pdata->pfn_ungetc (rptr, *--p, fp); /* "[-+xX]". */ |
---|
209 | |
---|
210 | if (p == pdata->buf) |
---|
211 | return MATCH_FAILURE; |
---|
212 | } |
---|
213 | if ((pdata->flags & SUPPRESS) == 0) |
---|
214 | { |
---|
215 | u_long ul; |
---|
216 | *p = 0; |
---|
217 | ul = (*ccfn) (rptr, pdata->buf, (char **) NULL, pdata->base); |
---|
218 | if (pdata->flags & POINTER) |
---|
219 | *GET_ARG (N, *ap, void **) = (void *) (uintptr_t) ul; |
---|
220 | else if (pdata->flags & SHORT) |
---|
221 | *GET_ARG (N, *ap, short *) = ul; |
---|
222 | else if (pdata->flags & LONG) |
---|
223 | *GET_ARG (N, *ap, long *) = ul; |
---|
224 | else |
---|
225 | *GET_ARG (N, *ap, int *) = ul; |
---|
226 | |
---|
227 | pdata->nassigned++; |
---|
228 | } |
---|
229 | pdata->nread += p - pdata->buf + skips; |
---|
230 | return 0; |
---|
231 | } |
---|
232 | |
---|