1 /*-
2 * Copyright (c) 1990 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms are permitted
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * and/or other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley. The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16 */
17
18 #define _DEFAULT_SOURCE
19 #include <_ansi.h>
20 #include <newlib.h>
21 #include <ctype.h>
22 #include <wctype.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <stdint.h>
26 #include <limits.h>
27 #include <wchar.h>
28 #include <string.h>
29 #include <stdarg.h>
30 #include <errno.h>
31 #include "local.h"
32 #include "../stdlib/local.h"
33 #include "nano-vfscanf_local.h"
34
35 #ifdef FLOATING_POINT
36 int
_scanf_float(struct _reent * rptr,struct _scan_data_t * pdata,FILE * fp,va_list * ap)37 _scanf_float (struct _reent *rptr,
38 struct _scan_data_t *pdata,
39 FILE *fp, va_list *ap)
40 {
41 int c;
42 char *p;
43 float *flp;
44 _LONG_DOUBLE *ldp;
45
46 /* Scan a floating point number as if by strtod. */
47 /* This code used to assume that the number of digits is reasonable.
48 However, ANSI / ISO C makes no such stipulation; we have to get
49 exact results even when there is an unreasonable amount of leading
50 zeroes. */
51 long leading_zeroes = 0;
52 long zeroes, exp_adjust;
53 char *exp_start = NULL;
54 unsigned width_left = 0;
55 char nancount = 0;
56 char infcount = 0;
57 #ifdef hardway
58 if (pdata->width == 0 || pdata->width > BUF - 1)
59 #else
60 /* size_t is unsigned, hence this optimisation. */
61 if (pdata->width - 1 > BUF - 2)
62 #endif
63 {
64 width_left = pdata->width - (BUF - 1);
65 pdata->width = BUF - 1;
66 }
67 pdata->flags |= SIGNOK | NDIGITS | DPTOK | EXPOK;
68 zeroes = 0;
69 exp_adjust = 0;
70 for (p = pdata->buf; pdata->width; )
71 {
72 c = *fp->_p;
73 /* This code mimicks the integer conversion code,
74 but is much simpler. */
75 switch (c)
76 {
77 case '0':
78 if (pdata->flags & NDIGITS)
79 {
80 pdata->flags &= ~SIGNOK;
81 zeroes++;
82 if (width_left)
83 {
84 width_left--;
85 pdata->width++;
86 }
87 goto fskip;
88 }
89 /* Fall through. */
90 case '1':
91 case '2':
92 case '3':
93 case '4':
94 case '5':
95 case '6':
96 case '7':
97 case '8':
98 case '9':
99 if (nancount + infcount == 0)
100 {
101 pdata->flags &= ~(SIGNOK | NDIGITS);
102 goto fok;
103 }
104 break;
105
106 case '+':
107 case '-':
108 if (pdata->flags & SIGNOK)
109 {
110 pdata->flags &= ~SIGNOK;
111 goto fok;
112 }
113 break;
114 case 'n':
115 case 'N':
116 if (nancount == 0 && zeroes == 0
117 && (pdata->flags & (NDIGITS | DPTOK | EXPOK)) ==
118 (NDIGITS | DPTOK | EXPOK))
119 {
120 pdata->flags &= ~(SIGNOK | DPTOK | EXPOK | NDIGITS);
121 nancount = 1;
122 goto fok;
123 }
124 if (nancount == 2)
125 {
126 nancount = 3;
127 goto fok;
128 }
129 if (infcount == 1 || infcount == 4)
130 {
131 infcount++;
132 goto fok;
133 }
134 break;
135 case 'a':
136 case 'A':
137 if (nancount == 1)
138 {
139 nancount = 2;
140 goto fok;
141 }
142 break;
143 case 'i':
144 case 'I':
145 if (infcount == 0 && zeroes == 0
146 && (pdata->flags & (NDIGITS | DPTOK | EXPOK)) ==
147 (NDIGITS | DPTOK | EXPOK))
148 {
149 pdata->flags &= ~(SIGNOK | DPTOK | EXPOK | NDIGITS);
150 infcount = 1;
151 goto fok;
152 }
153 if (infcount == 3 || infcount == 5)
154 {
155 infcount++;
156 goto fok;
157 }
158 break;
159 case 'f':
160 case 'F':
161 if (infcount == 2)
162 {
163 infcount = 3;
164 goto fok;
165 }
166 break;
167 case 't':
168 case 'T':
169 if (infcount == 6)
170 {
171 infcount = 7;
172 goto fok;
173 }
174 break;
175 case 'y':
176 case 'Y':
177 if (infcount == 7)
178 {
179 infcount = 8;
180 goto fok;
181 }
182 break;
183 case '.':
184 if (pdata->flags & DPTOK)
185 {
186 pdata->flags &= ~(SIGNOK | DPTOK);
187 leading_zeroes = zeroes;
188 goto fok;
189 }
190 break;
191 case 'e':
192 case 'E':
193 /* No exponent without some digits. */
194 if ((pdata->flags & (NDIGITS | EXPOK)) == EXPOK
195 || ((pdata->flags & EXPOK) && zeroes))
196 {
197 if (! (pdata->flags & DPTOK))
198 {
199 exp_adjust = zeroes - leading_zeroes;
200 exp_start = p;
201 }
202 pdata->flags =
203 (pdata->flags & ~(EXPOK | DPTOK)) | SIGNOK | NDIGITS;
204 zeroes = 0;
205 goto fok;
206 }
207 break;
208 }
209 break;
210 fok:
211 *p++ = c;
212 fskip:
213 pdata->width--;
214 ++pdata->nread;
215 if (--fp->_r > 0)
216 fp->_p++;
217 else if (pdata->pfn_refill (rptr, fp))
218 /* "EOF". */
219 break;
220 }
221 if (zeroes)
222 pdata->flags &= ~NDIGITS;
223 /* We may have a 'N' or possibly even [sign] 'N' 'a' as the
224 start of 'NaN', only to run out of chars before it was
225 complete (or having encountered a non-matching char). So
226 check here if we have an outstanding nancount, and if so
227 put back the chars we did swallow and treat as a failed
228 match.
229
230 FIXME - we still don't handle NAN([0xdigits]). */
231 if (nancount - 1U < 2U)
232 {
233 /* "nancount && nancount < 3". */
234 /* Newlib's ungetc works even if we called __srefill in
235 the middle of a partial parse, but POSIX does not
236 guarantee that in all implementations of ungetc. */
237 while (p > pdata->buf)
238 {
239 pdata->pfn_ungetc (rptr, *--p, fp); /* "[-+nNaA]". */
240 --pdata->nread;
241 }
242 return MATCH_FAILURE;
243 }
244 /* Likewise for 'inf' and 'infinity'. But be careful that
245 'infinite' consumes only 3 characters, leaving the stream
246 at the second 'i'. */
247 if (infcount - 1U < 7U)
248 {
249 /* "infcount && infcount < 8". */
250 if (infcount >= 3) /* valid 'inf', but short of 'infinity'. */
251 while (infcount-- > 3)
252 {
253 pdata->pfn_ungetc (rptr, *--p, fp); /* "[iInNtT]". */
254 --pdata->nread;
255 }
256 else
257 {
258 while (p > pdata->buf)
259 {
260 pdata->pfn_ungetc (rptr, *--p, fp); /* "[-+iInN]". */
261 --pdata->nread;
262 }
263 return MATCH_FAILURE;
264 }
265 }
266 /* If no digits, might be missing exponent digits
267 (just give back the exponent) or might be missing
268 regular digits, but had sign and/or decimal point. */
269 if (pdata->flags & NDIGITS)
270 {
271 if (pdata->flags & EXPOK)
272 {
273 /* No digits at all. */
274 while (p > pdata->buf)
275 {
276 pdata->pfn_ungetc (rptr, *--p, fp); /* "[-+.]". */
277 --pdata->nread;
278 }
279 return MATCH_FAILURE;
280 }
281 /* Just a bad exponent (e and maybe sign). */
282 c = *--p;
283 --pdata->nread;
284 if (c != 'e' && c != 'E')
285 {
286 pdata->pfn_ungetc (rptr, c, fp); /* "[-+]". */
287 c = *--p;
288 --pdata->nread;
289 }
290 pdata->pfn_ungetc (rptr, c, fp); /* "[eE]". */
291 }
292 if ((pdata->flags & SUPPRESS) == 0)
293 {
294 double fp;
295 long new_exp = 0;
296
297 *p = 0;
298 if ((pdata->flags & (DPTOK | EXPOK)) == EXPOK)
299 {
300 exp_adjust = zeroes - leading_zeroes;
301 new_exp = -exp_adjust;
302 exp_start = p;
303 }
304 else if (exp_adjust)
305 new_exp = strtol ((exp_start + 1), NULL, 10) - exp_adjust;
306
307 if (exp_adjust)
308 {
309 /* If there might not be enough space for the new exponent,
310 truncate some trailing digits to make room. */
311 if (exp_start >= pdata->buf + BUF - MAX_LONG_LEN)
312 exp_start = pdata->buf + BUF - MAX_LONG_LEN - 1;
313 sprintf (exp_start, "e%ld", new_exp);
314 }
315
316 /* Current strtold routine is markedly slower than
317 strtod. Only use it if we have a long double
318 result. */
319 fp = strtod (pdata->buf, NULL);
320
321 /* Do not support long double. */
322 if (pdata->flags & LONG)
323 *GET_ARG (N, *ap, double *) = fp;
324 else if (pdata->flags & LONGDBL)
325 {
326 ldp = GET_ARG (N, *ap, _LONG_DOUBLE *);
327 *ldp = fp;
328 }
329 else
330 {
331 flp = GET_ARG (N, *ap, float *);
332 if (isnan (fp))
333 *flp = nanf ("");
334 else
335 *flp = fp;
336 }
337 pdata->nassigned++;
338 }
339 return 0;
340 }
341 #endif
342
343