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 #define _DEFAULT_SOURCE
30 #include <ctype.h>
31 #include <wctype.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <stdint.h>
35 #include <limits.h>
36 #include <wchar.h>
37 #include <string.h>
38 #include <stdarg.h>
39 #include <errno.h>
40 #include "local.h"
41 #include "../stdlib/local.h"
42
43 #include "nano-vfscanf_local.h"
44
45 int
_scanf_chars(struct _scan_data_t * pdata,FILE * fp,va_list * ap)46 _scanf_chars (
47 struct _scan_data_t *pdata,
48 FILE *fp, va_list *ap)
49 {
50 int n;
51 char *p;
52
53 if (pdata->width == 0)
54 pdata->width = (pdata->code == CT_CHAR) ? 1 : (size_t)~0;
55
56 n = 0;
57 if ((pdata->flags & SUPPRESS) == 0)
58 p = GET_ARG (N, *ap, char *);
59
60 /* It's impossible to have EOF when we get here. */
61 while ((pdata->code == CT_CHAR)
62 || (pdata->code == CT_CCL && pdata->ccltab[*fp->_p])
63 || (pdata->code == CT_STRING && !isspace (*fp->_p)))
64 {
65 n++;
66 if ((pdata->flags & SUPPRESS) == 0)
67 *p++ = *fp->_p;
68
69 fp->_r--, fp->_p++;
70 if (--pdata->width == 0)
71 break;
72
73 if ((fp->_r <= 0 && pdata->pfn_refill (fp)))
74 break;
75 }
76 /* For CT_CHAR, it is impossible to have input_failure(n == 0) here.
77 For CT_CCL, it is impossible to have input_failure here.
78 For CT_STRING, it is possible to have empty string. */
79 if (n == 0 && pdata->code == CT_CCL)
80 return MATCH_FAILURE;
81
82 if ((pdata->flags & SUPPRESS) == 0)
83 {
84 pdata->nassigned++;
85 if (pdata->code != CT_CHAR)
86 *p = 0;
87 }
88 pdata->nread += n;
89 return 0;
90 }
91 int
_scanf_i(struct _scan_data_t * pdata,FILE * fp,va_list * ap)92 _scanf_i (
93 struct _scan_data_t *pdata,
94 FILE *fp, va_list *ap)
95 {
96 #define CCFN_PARAMS (const char *, char **, int)
97 /* Conversion function (strtol/strtoul). */
98 u_long (*ccfn)CCFN_PARAMS=0;
99 char *p;
100 int n;
101 char *xdigits = "A-Fa-f8901234567]";
102 char *prefix_chars[3] = {"+-", "00", "xX"};
103
104 /* Scan an integer as if by strtol/strtoul. */
105 unsigned width_left = 0;
106 int skips = 0;
107
108 ccfn = (pdata->code == CT_INT) ? (u_long (*)CCFN_PARAMS)strtol : strtoul;
109 #ifdef hardway
110 if (pdata->width == 0 || pdata->width > BUF - 1)
111 #else
112 /* size_t is unsigned, hence this optimisation. */
113 if (pdata->width - 1 > BUF - 2)
114 #endif
115 {
116 width_left = pdata->width - (BUF - 1);
117 pdata->width = BUF - 1;
118 }
119 p = pdata->buf;
120 pdata->flags |= NDIGITS | NZDIGITS | NNZDIGITS;
121
122 /* Process [sign] [0] [xX] prefixes sequently. */
123 for (n = 0; n < 3; n++)
124 {
125 if (!memchr (prefix_chars[n], *fp->_p, 2))
126 continue;
127
128 if (n == 1)
129 {
130 if (pdata->base == 0)
131 {
132 pdata->base = 8;
133 pdata->flags |= PFXOK;
134 }
135 pdata->flags &= ~(NZDIGITS | NDIGITS);
136 }
137 else if (n == 2)
138 {
139 if ((pdata->flags & (PFXOK | NZDIGITS)) != PFXOK)
140 continue;
141 pdata->base = 16;
142
143 /* We must reset the NZDIGITS and NDIGITS
144 flags that would have been unset by seeing
145 the zero that preceded the X or x.
146
147 ??? It seems unnecessary to reset the NZDIGITS. */
148 pdata->flags |= NDIGITS;
149 }
150 if (pdata->width-- > 0)
151 {
152 *p++ = *fp->_p++;
153 fp->_r--;
154 if ((fp->_r <= 0 && pdata->pfn_refill (fp)))
155 goto match_end;
156 }
157 }
158
159 if (pdata->base == 0)
160 pdata->base = 10;
161
162 /* The check is un-necessary if xdigits points to exactly the string:
163 "A-Fa-f8901234567]". The code is kept only for reading's sake. */
164 #if 0
165 if (pdata->base != 16)
166 #endif
167 xdigits = xdigits + 16 - pdata->base;
168
169 /* Initilize ccltab according to pdata->base. */
170 __sccl (pdata->ccltab, (unsigned char *) xdigits);
171 for (; pdata->width; pdata->width--)
172 {
173 n = *fp->_p;
174 if (pdata->ccltab[n] == 0)
175 break;
176 else if (n == '0' && (pdata->flags & NNZDIGITS))
177 {
178 ++skips;
179 if (width_left)
180 {
181 width_left--;
182 pdata->width++;
183 }
184 goto skip;
185 }
186 pdata->flags &= ~(NDIGITS | NNZDIGITS);
187 /* Char is legal: store it and look at the next. */
188 *p++ = *fp->_p;
189 skip:
190 if (--fp->_r > 0)
191 fp->_p++;
192 else if (pdata->pfn_refill (fp))
193 /* "EOF". */
194 break;
195 }
196 /* If we had only a sign, it is no good; push back the sign.
197 If the number ends in `x', it was [sign] '0' 'x', so push back
198 the x and treat it as [sign] '0'.
199 Use of ungetc here and below assumes ASCII encoding; we are only
200 pushing back 7-bit characters, so casting to unsigned char is
201 not necessary. */
202 match_end:
203 if (pdata->flags & NDIGITS)
204 {
205 if (p > pdata->buf)
206 pdata->pfn_ungetc (*--p, fp); /* "[-+xX]". */
207
208 if (p == pdata->buf)
209 return MATCH_FAILURE;
210 }
211 if ((pdata->flags & SUPPRESS) == 0)
212 {
213 u_long ul;
214 *p = 0;
215 ul = (*ccfn) (pdata->buf, (char **) NULL, pdata->base);
216 if (pdata->flags & POINTER)
217 *GET_ARG (N, *ap, void **) = (void *) (uintptr_t) ul;
218 else if (pdata->flags & SHORT)
219 *GET_ARG (N, *ap, short *) = ul;
220 else if (pdata->flags & LONG)
221 *GET_ARG (N, *ap, long *) = ul;
222 else
223 *GET_ARG (N, *ap, int *) = ul;
224
225 pdata->nassigned++;
226 }
227 pdata->nread += p - pdata->buf + skips;
228 return 0;
229 }
230
231