]> git.proxmox.com Git - mirror_edk2.git/blame - StdLib/LibC/Stdio/vfscanf.c
EmbeddedPkg: Extend NvVarStoreFormattedLib LIBRARY_CLASS
[mirror_edk2.git] / StdLib / LibC / Stdio / vfscanf.c
CommitLineData
2aa62f2b 1/** @file\r
2 Implementation of scanf internals for <stdio.h>.\r
3\r
9792ff7c 4 Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>\r
2aa62f2b 5 This program and the accompanying materials are licensed and made available\r
6 under the terms and conditions of the BSD License that accompanies this\r
7 distribution. The full text of the license may be found at\r
53e1e5c6 8 http://opensource.org/licenses/bsd-license.\r
2aa62f2b 9\r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13 Copyright (c) 1990, 1993\r
14 The Regents of the University of California. All rights reserved.\r
15\r
16 This code is derived from software contributed to Berkeley by\r
17 Chris Torek.\r
18\r
19 Redistribution and use in source and binary forms, with or without\r
20 modification, are permitted provided that the following conditions\r
21 are met:\r
22 - Redistributions of source code must retain the above copyright\r
23 notice, this list of conditions and the following disclaimer.\r
24 - Redistributions in binary form must reproduce the above copyright\r
25 notice, this list of conditions and the following disclaimer in the\r
26 documentation and/or other materials provided with the distribution.\r
27 - Neither the name of the University nor the names of its contributors\r
28 may be used to endorse or promote products derived from this software\r
29 without specific prior written permission.\r
30\r
31 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"\r
32 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
33 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
34 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE\r
35 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r
36 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r
37 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
38 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
39 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r
40 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
41 POSSIBILITY OF SUCH DAMAGE.\r
42\r
43 NetBSD: vfscanf.c,v 1.37.4.1 2007/05/07 19:49:08 pavel Exp\r
44 FreeBSD: src/lib/libc/stdio/vfscanf.c,v 1.41 2007/01/09 00:28:07 imp Exp\r
45 vfscanf.c 8.1 (Berkeley) 6/4/93\r
46**/\r
2aa62f2b 47#include <LibConfig.h>\r
48\r
49#include "namespace.h"\r
50#include <assert.h>\r
51#include <ctype.h>\r
53e1e5c6 52#include <errno.h>\r
2aa62f2b 53#include <inttypes.h>\r
54#include <stdio.h>\r
55#include <stdlib.h>\r
56#include <stddef.h>\r
57#include <stdarg.h>\r
58#include <string.h>\r
59#include <sys/types.h>\r
60#include <wchar.h>\r
61#include <wctype.h>\r
62\r
63#include "reentrant.h"\r
64#include "local.h"\r
65\r
66#ifndef NO_FLOATING_POINT\r
67#include <locale.h>\r
68#endif\r
69\r
70/*\r
f45df7a6 71 * Provide an external name for vfscanf. Note, EFI uses the normal\r
2aa62f2b 72 * namespace.h method; stdio routines explicitly use the internal name\r
73 * __svfscanf.\r
74 */\r
75#ifdef __weak_alias\r
76__weak_alias(vfscanf,__svfscanf)\r
77#endif\r
78\r
79#define BUF 513 /* Maximum length of numeric string. */\r
80\r
81/*\r
82 * Flags used during conversion.\r
83 */\r
84#define LONG 0x0001 /* l: long or double */\r
85#define LONGDBL 0x0002 /* L: long double */\r
86#define SHORT 0x0004 /* h: short */\r
87#define SUPPRESS 0x0008 /* *: suppress assignment */\r
88#define POINTER 0x0010 /* p: void * (as hex) */\r
89#define NOSKIP 0x0020 /* [ or c: do not skip blanks */\r
90#define LONGLONG 0x0400 /* ll: long long (+ deprecated q: quad) */\r
91#define INTMAXT 0x0800 /* j: intmax_t */\r
92#define PTRDIFFT 0x1000 /* t: ptrdiff_t */\r
93#define SIZET 0x2000 /* z: size_t */\r
94#define SHORTSHORT 0x4000 /* hh: char */\r
95#define UNSIGNED 0x8000 /* %[oupxX] conversions */\r
96\r
97/*\r
98 * The following are used in integral conversions only:\r
99 * SIGNOK, NDIGITS, PFXOK, and NZDIGITS\r
100 */\r
101#define SIGNOK 0x00040 /* +/- is (still) legal */\r
102#define NDIGITS 0x00080 /* no digits detected */\r
103#define PFXOK 0x00100 /* 0x prefix is (still) legal */\r
104#define NZDIGITS 0x00200 /* no zero digits detected */\r
105#define HAVESIGN 0x10000 /* sign detected */\r
106\r
107/*\r
108 * Conversion types.\r
109 */\r
110#define CT_CHAR 0 /* %c conversion */\r
111#define CT_CCL 1 /* %[...] conversion */\r
112#define CT_STRING 2 /* %s conversion */\r
113#define CT_INT 3 /* %[dioupxX] conversion */\r
114#define CT_FLOAT 4 /* %[efgEFG] conversion */\r
115\r
116static const u_char *__sccl(char *, const u_char *);\r
117#ifndef NO_FLOATING_POINT\r
118 static int parsefloat(FILE *, char *, char *);\r
119#endif\r
120\r
121int __scanfdebug = 0;\r
122\r
123#define __collate_load_error /*CONSTCOND*/0\r
124static int\r
125__collate_range_cmp(int c1, int c2)\r
126{\r
0e398dc7
OM
127 static char s1[2] = { 0 };\r
128 static char s2[2] = { 0 };\r
2aa62f2b 129\r
130 s1[0] = (char)c1;\r
131 s2[0] = (char)c2;\r
132 return strcoll(s1, s2);\r
133}\r
134\r
135\r
136/*\r
137 * __svfscanf - MT-safe version\r
138 */\r
139int\r
140__svfscanf(FILE *fp, char const *fmt0, va_list ap)\r
141{\r
142 int ret;\r
143\r
53e1e5c6 144 if(fp == NULL) {\r
145 errno = EINVAL;\r
146 return (EOF);\r
147 }\r
2aa62f2b 148 FLOCKFILE(fp);\r
149 ret = __svfscanf_unlocked(fp, fmt0, ap);\r
150 FUNLOCKFILE(fp);\r
151 return (ret);\r
152}\r
153\r
154/*\r
155 * __svfscanf_unlocked - non-MT-safe version of __svfscanf\r
156 */\r
157int\r
158__svfscanf_unlocked(FILE *fp, const char *fmt0, va_list ap)\r
159{\r
9792ff7c
OM
160 const u_char *fmt = (const u_char *)fmt0;\r
161 int c; /* character from format, or conversion */\r
162 size_t width; /* field width, or 0 */\r
163 char *p; /* points into all kinds of strings */\r
164 size_t n; /* handy size_t */\r
165 int flags; /* flags as defined above */\r
166 char *p0; /* saves original value of p when necessary */\r
167 int nassigned; /* number of fields assigned */\r
168 int nconversions; /* number of conversions */\r
169 int nread; /* number of characters consumed from fp */\r
170 int base; /* base argument to conversion function */\r
171 char ccltab[256]; /* character class table for %[...] */\r
172 char buf[BUF]; /* buffer for numeric and mb conversions */\r
173 wchar_t *wcp; /* handy wide character pointer */\r
174 size_t nconv; /* length of multibyte sequence converted */\r
175 static const mbstate_t initial = { 0 };\r
176 mbstate_t mbs;\r
2aa62f2b 177\r
178 /* `basefix' is used to avoid `if' tests in the integer scanner */\r
179 static const short basefix[17] =\r
180 { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };\r
181\r
182 _DIAGASSERT(fp != NULL);\r
183 _DIAGASSERT(fmt0 != NULL);\r
53e1e5c6 184 if(fp == NULL) {\r
185 errno = EINVAL;\r
186 return (EOF);\r
187 }\r
2aa62f2b 188\r
189 _SET_ORIENTATION(fp, -1);\r
190\r
191//Print(L"%a( %d, \"%a\", ...)\n", __func__, fp->_file, fmt0);\r
192 nassigned = 0;\r
193 nconversions = 0;\r
194 nread = 0;\r
195 base = 0;\r
196 for (;;) {\r
197 c = (unsigned char)*fmt++;\r
198 if (c == 0)\r
199 return (nassigned);\r
200 if (isspace(c)) {\r
201 while ((fp->_r > 0 || __srefill(fp) == 0) &&\r
202 isspace(*fp->_p))\r
203 nread++, fp->_r--, fp->_p++;\r
204 continue;\r
205 }\r
206//Print(L"%a: %d\n", __func__, __LINE__);\r
207 if (c != '%')\r
208 goto literal;\r
209 width = 0;\r
210 flags = 0;\r
211 /*\r
212 * switch on the format. continue if done;\r
213 * break once format type is derived.\r
214 */\r
215again: c = *fmt++;\r
216//Print(L"%a: %d\n", __func__, __LINE__);\r
217 switch (c) {\r
218 case '%':\r
219literal:\r
220//Print(L"%a: %d\n", __func__, __LINE__);\r
221 if (fp->_r <= 0 && __srefill(fp))\r
222 goto input_failure;\r
223 if (*fp->_p != c)\r
224 goto match_failure;\r
225 fp->_r--, fp->_p++;\r
226 nread++;\r
227 continue;\r
228\r
229 case '*':\r
230 flags |= SUPPRESS;\r
231 goto again;\r
232 case 'j':\r
233 flags |= INTMAXT;\r
234 goto again;\r
235 case 'l':\r
236 if (flags & LONG) {\r
237 flags &= ~LONG;\r
238 flags |= LONGLONG;\r
239 } else\r
240 flags |= LONG;\r
241 goto again;\r
242 case 'q':\r
243 flags |= LONGLONG; /* not quite */\r
244 goto again;\r
245 case 't':\r
246 flags |= PTRDIFFT;\r
247 goto again;\r
248 case 'z':\r
249 flags |= SIZET;\r
250 goto again;\r
251 case 'L':\r
252 flags |= LONGDBL;\r
253 goto again;\r
254 case 'h':\r
255 if (flags & SHORT) {\r
256 flags &= ~SHORT;\r
257 flags |= SHORTSHORT;\r
258 } else\r
259 flags |= SHORT;\r
260 goto again;\r
261\r
262 case '0': case '1': case '2': case '3': case '4':\r
263 case '5': case '6': case '7': case '8': case '9':\r
264 width = width * 10 + c - '0';\r
265 goto again;\r
266\r
267 /*\r
268 * Conversions.\r
269 */\r
270 case 'd':\r
271 c = CT_INT;\r
272 base = 10;\r
273 break;\r
274\r
275 case 'i':\r
276 c = CT_INT;\r
277 base = 0;\r
278 break;\r
279\r
280 case 'o':\r
281 c = CT_INT;\r
282 flags |= UNSIGNED;\r
283 base = 8;\r
284 break;\r
285\r
286 case 'u':\r
287 c = CT_INT;\r
288 flags |= UNSIGNED;\r
289 base = 10;\r
290 break;\r
291\r
292 case 'X':\r
293 case 'x':\r
294 flags |= PFXOK; /* enable 0x prefixing */\r
295 c = CT_INT;\r
296 flags |= UNSIGNED;\r
297 base = 16;\r
298 break;\r
299\r
300#ifndef NO_FLOATING_POINT\r
301 case 'A': case 'E': case 'F': case 'G':\r
302 case 'a': case 'e': case 'f': case 'g':\r
303 c = CT_FLOAT;\r
304 break;\r
305#endif\r
306\r
307 case 'S':\r
308 flags |= LONG;\r
309 /* FALLTHROUGH */\r
310 case 's':\r
311 c = CT_STRING;\r
312 break;\r
313\r
314 case '[':\r
315 fmt = __sccl(ccltab, fmt);\r
316 flags |= NOSKIP;\r
317 c = CT_CCL;\r
318 break;\r
319\r
320 case 'C':\r
321 flags |= LONG;\r
322 /* FALLTHROUGH */\r
323 case 'c':\r
324 flags |= NOSKIP;\r
325 c = CT_CHAR;\r
326 break;\r
327\r
328 case 'p': /* pointer format is like hex */\r
329 flags |= POINTER | PFXOK;\r
330 c = CT_INT; /* assumes sizeof(uintmax_t) */\r
331 flags |= UNSIGNED; /* >= sizeof(uintptr_t) */\r
332 base = 16;\r
333 break;\r
334\r
335 case 'n':\r
336 nconversions++;\r
337 if (flags & SUPPRESS) /* ??? */\r
338 continue;\r
339 if (flags & SHORTSHORT)\r
340 *va_arg(ap, char *) = (char)nread;\r
341 else if (flags & SHORT)\r
342 *va_arg(ap, short *) = (short)nread;\r
343 else if (flags & LONG)\r
344 *va_arg(ap, long *) = nread;\r
345 else if (flags & LONGLONG)\r
346 *va_arg(ap, long long *) = nread;\r
347 else if (flags & INTMAXT)\r
348 *va_arg(ap, intmax_t *) = nread;\r
349 else if (flags & SIZET)\r
350 *va_arg(ap, size_t *) = nread;\r
351 else if (flags & PTRDIFFT)\r
352 *va_arg(ap, ptrdiff_t *) = nread;\r
353 else\r
354 *va_arg(ap, int *) = nread;\r
355 continue;\r
356\r
357 default:\r
358 goto match_failure;\r
359\r
360 /*\r
361 * Disgusting backwards compatibility hack. XXX\r
362 */\r
363 case '\0': /* compat */\r
364 return (EOF);\r
365 }\r
366//Print(L"%a: %d\n", __func__, __LINE__);\r
367\r
368 /*\r
369 * We have a conversion that requires input.\r
370 */\r
371 if (fp->_r <= 0 && __srefill(fp))\r
372 {\r
373//Print(L"%a: %d\n", __func__, __LINE__);\r
374 goto input_failure;\r
375 }\r
376\r
377 /*\r
378 * Consume leading white space, except for formats\r
379 * that suppress this.\r
380 */\r
381 if ((flags & NOSKIP) == 0) {\r
382 while (isspace(*fp->_p)) {\r
383 nread++;\r
384 if (--fp->_r > 0)\r
385 fp->_p++;\r
386 else if (__srefill(fp))\r
387 {\r
388//Print(L"%a: %d\n", __func__, __LINE__);\r
389 goto input_failure;\r
390 }\r
391 }\r
392 /*\r
393 * Note that there is at least one character in\r
394 * the buffer, so conversions that do not set NOSKIP\r
395 * ca no longer result in an input failure.\r
396 */\r
397 }\r
398\r
399 /*\r
400 * Do the conversion.\r
401 */\r
402//Print(L"%a: %d\n", __func__, __LINE__);\r
403 switch (c) {\r
404\r
405 case CT_CHAR:\r
406 /* scan arbitrary characters (sets NOSKIP) */\r
407 if (width == 0)\r
408 width = 1;\r
409 if (flags & LONG) {\r
410 if ((flags & SUPPRESS) == 0)\r
411 wcp = va_arg(ap, wchar_t *);\r
412 else\r
413 wcp = NULL;\r
414 n = 0;\r
415 while (width != 0) {\r
416 if (n == MB_CUR_MAX) {\r
417 fp->_flags |= __SERR;\r
418 goto input_failure;\r
419 }\r
420 buf[n++] = *fp->_p;\r
421 fp->_p++;\r
422 fp->_r--;\r
423 mbs = initial;\r
424 nconv = mbrtowc(wcp, buf, n, &mbs);\r
425 if (nconv == (size_t)-1) {\r
426 fp->_flags |= __SERR;\r
427 goto input_failure;\r
428 }\r
429 if (nconv == 0 && !(flags & SUPPRESS))\r
430 *wcp = L'\0';\r
431 if (nconv != (size_t)-2) {\r
432 nread += (int)n;\r
433 width--;\r
434 if (!(flags & SUPPRESS))\r
435 wcp++;\r
436 n = 0;\r
437 }\r
438 if (fp->_r <= 0 && __srefill(fp)) {\r
439 if (n != 0) {\r
440 fp->_flags |= __SERR;\r
441 goto input_failure;\r
442 }\r
443 break;\r
444 }\r
445 }\r
446 if (!(flags & SUPPRESS))\r
447 nassigned++;\r
448 } else if (flags & SUPPRESS) {\r
449 size_t sum = 0;\r
450 for (;;) {\r
451 if ((n = fp->_r) < width) {\r
452 sum += n;\r
453 width -= n;\r
454 fp->_p += n;\r
455 if (__srefill(fp)) {\r
456 if (sum == 0)\r
457 goto input_failure;\r
458 break;\r
459 }\r
460 } else {\r
461 sum += width;\r
462 fp->_r -= (int)width;\r
463 fp->_p += width;\r
464 break;\r
465 }\r
466 }\r
467 nread += (int)sum;\r
468 } else {\r
469 size_t r = fread(va_arg(ap, char *), 1,\r
470 width, fp);\r
471\r
472 if (r == 0)\r
473 goto input_failure;\r
474 nread += (int)r;\r
475 nassigned++;\r
476 }\r
477 nconversions++;\r
478 break;\r
479\r
480 case CT_CCL:\r
481 /* scan a (nonempty) character class (sets NOSKIP) */\r
482 if (width == 0)\r
483 width = (size_t)~0; /* `infinity' */\r
484 /* take only those things in the class */\r
485 if (flags & LONG) {\r
486 wchar_t twc;\r
487 int nchars;\r
488\r
489 if ((flags & SUPPRESS) == 0)\r
490 wcp = va_arg(ap, wchar_t *);\r
491 else\r
492 wcp = &twc;\r
493 n = 0;\r
494 nchars = 0;\r
495 while (width != 0) {\r
496 if (n == MB_CUR_MAX) {\r
497 fp->_flags |= __SERR;\r
498 goto input_failure;\r
499 }\r
500 buf[n++] = *fp->_p;\r
501 fp->_p++;\r
502 fp->_r--;\r
503 mbs = initial;\r
504 nconv = mbrtowc(wcp, buf, n, &mbs);\r
505 if (nconv == (size_t)-1) {\r
506 fp->_flags |= __SERR;\r
507 goto input_failure;\r
508 }\r
509 if (nconv == 0)\r
510 *wcp = L'\0';\r
511 if (nconv != (size_t)-2) {\r
512 if (wctob(*wcp) != EOF &&\r
513 !ccltab[wctob(*wcp)]) {\r
514 while (n != 0) {\r
515 n--;\r
516 (void)ungetc(buf[n],\r
517 fp);\r
518 }\r
519 break;\r
520 }\r
521 nread += (int)n;\r
522 width--;\r
523 if (!(flags & SUPPRESS))\r
524 wcp++;\r
525 nchars++;\r
526 n = 0;\r
527 }\r
528 if (fp->_r <= 0 && __srefill(fp)) {\r
529 if (n != 0) {\r
530 fp->_flags |= __SERR;\r
531 goto input_failure;\r
532 }\r
533 break;\r
534 }\r
535 }\r
536 if (n != 0) {\r
537 fp->_flags |= __SERR;\r
538 goto input_failure;\r
539 }\r
540 n = nchars;\r
541 if (n == 0)\r
542 goto match_failure;\r
543 if (!(flags & SUPPRESS)) {\r
544 *wcp = L'\0';\r
545 nassigned++;\r
546 }\r
547 } else if (flags & SUPPRESS) {\r
548 n = 0;\r
549 while (ccltab[*fp->_p]) {\r
550 n++, fp->_r--, fp->_p++;\r
551 if (--width == 0)\r
552 break;\r
553 if (fp->_r <= 0 && __srefill(fp)) {\r
554 if (n == 0)\r
555 goto input_failure;\r
556 break;\r
557 }\r
558 }\r
559 if (n == 0)\r
560 goto match_failure;\r
561 } else {\r
562 p0 = p = va_arg(ap, char *);\r
563 while (ccltab[*fp->_p]) {\r
564 fp->_r--;\r
565 *p++ = *fp->_p++;\r
566 if (--width == 0)\r
567 break;\r
568 if (fp->_r <= 0 && __srefill(fp)) {\r
569 if (p == p0)\r
570 goto input_failure;\r
571 break;\r
572 }\r
573 }\r
574 n = p - p0;\r
575 if (n == 0)\r
576 goto match_failure;\r
577 *p = 0;\r
578 nassigned++;\r
579 }\r
580 nread += (int)n;\r
581 nconversions++;\r
582 break;\r
583\r
584 case CT_STRING:\r
585 /* like CCL, but zero-length string OK, & no NOSKIP */\r
586 if (width == 0)\r
587 width = (size_t)~0;\r
588 if (flags & LONG) {\r
589 wchar_t twc;\r
590\r
591 if ((flags & SUPPRESS) == 0)\r
592 wcp = va_arg(ap, wchar_t *);\r
593 else\r
594 wcp = &twc;\r
595 n = 0;\r
596 while (!isspace(*fp->_p) && width != 0) {\r
597 if (n == MB_CUR_MAX) {\r
598 fp->_flags |= __SERR;\r
599 goto input_failure;\r
600 }\r
601 buf[n++] = *fp->_p;\r
602 fp->_p++;\r
603 fp->_r--;\r
604 mbs = initial;\r
605 nconv = mbrtowc(wcp, buf, n, &mbs);\r
606 if (nconv == (size_t)-1) {\r
607 fp->_flags |= __SERR;\r
608 goto input_failure;\r
609 }\r
610 if (nconv == 0)\r
611 *wcp = L'\0';\r
612 if (nconv != (size_t)-2) {\r
613 if (iswspace(*wcp)) {\r
614 while (n != 0) {\r
615 n--;\r
616 (void)ungetc(buf[n],\r
617 fp);\r
618 }\r
619 break;\r
620 }\r
621 nread += (int)n;\r
622 width--;\r
623 if (!(flags & SUPPRESS))\r
624 wcp++;\r
625 n = 0;\r
626 }\r
627 if (fp->_r <= 0 && __srefill(fp)) {\r
628 if (n != 0) {\r
629 fp->_flags |= __SERR;\r
630 goto input_failure;\r
631 }\r
632 break;\r
633 }\r
634 }\r
635 if (!(flags & SUPPRESS)) {\r
636 *wcp = L'\0';\r
637 nassigned++;\r
638 }\r
639 } else if (flags & SUPPRESS) {\r
640 n = 0;\r
641 while (!isspace(*fp->_p)) {\r
642 n++, fp->_r--, fp->_p++;\r
643 if (--width == 0)\r
644 break;\r
645 if (fp->_r <= 0 && __srefill(fp))\r
646 break;\r
647 }\r
648 nread += (int)n;\r
649 } else {\r
650 p0 = p = va_arg(ap, char *);\r
651 while (!isspace(*fp->_p)) {\r
652 fp->_r--;\r
653 *p++ = *fp->_p++;\r
654 if (--width == 0)\r
655 break;\r
656 if (fp->_r <= 0 && __srefill(fp))\r
657 break;\r
658 }\r
659 *p = 0;\r
660 nread += (int)(p - p0);\r
661 nassigned++;\r
662 }\r
663 nconversions++;\r
664 continue;\r
665\r
666 case CT_INT:\r
667//Print(L"%a: %d\n", __func__, __LINE__);\r
668 /* scan an integer as if by the conversion function */\r
669#ifdef hardway\r
670 if (width == 0 || width > sizeof(buf) - 1)\r
671 width = sizeof(buf) - 1;\r
672#else\r
673 /* size_t is unsigned, hence this optimisation */\r
674 if (--width > sizeof(buf) - 2)\r
675 width = sizeof(buf) - 2;\r
676 width++;\r
677#endif\r
678 flags |= SIGNOK | NDIGITS | NZDIGITS;\r
679 for (p = buf; width; width--) {\r
680 c = *fp->_p;\r
681 /*\r
682 * Switch on the character; `goto ok'\r
683 * if we accept it as a part of number.\r
684 */\r
685 switch (c) {\r
686\r
687 /*\r
688 * The digit 0 is always legal, but is\r
689 * special. For %i conversions, if no\r
690 * digits (zero or nonzero) have been\r
691 * scanned (only signs), we will have\r
692 * base==0. In that case, we should set\r
693 * it to 8 and enable 0x prefixing.\r
694 * Also, if we have not scanned zero digits\r
695 * before this, do not turn off prefixing\r
696 * (someone else will turn it off if we\r
697 * have scanned any nonzero digits).\r
698 */\r
699 case '0':\r
700 if (base == 0) {\r
701 base = 8;\r
702 flags |= PFXOK;\r
703 }\r
704 if (flags & NZDIGITS)\r
705 flags &= ~(SIGNOK|NZDIGITS|NDIGITS);\r
706 else\r
707 flags &= ~(SIGNOK|PFXOK|NDIGITS);\r
708 goto ok;\r
709\r
710 /* 1 through 7 always legal */\r
711 case '1': case '2': case '3':\r
712 case '4': case '5': case '6': case '7':\r
713 base = basefix[base];\r
714 flags &= ~(SIGNOK | PFXOK | NDIGITS);\r
715 goto ok;\r
716\r
717 /* digits 8 and 9 ok iff decimal or hex */\r
718 case '8': case '9':\r
719 base = basefix[base];\r
720 if (base <= 8)\r
721 break; /* not legal here */\r
722 flags &= ~(SIGNOK | PFXOK | NDIGITS);\r
723 goto ok;\r
724\r
725 /* letters ok iff hex */\r
726 case 'A': case 'B': case 'C':\r
727 case 'D': case 'E': case 'F':\r
728 case 'a': case 'b': case 'c':\r
729 case 'd': case 'e': case 'f':\r
730 /* no need to fix base here */\r
731 if (base <= 10)\r
732 break; /* not legal here */\r
733 flags &= ~(SIGNOK | PFXOK | NDIGITS);\r
734 goto ok;\r
735\r
736 /* sign ok only as first character */\r
737 case '+': case '-':\r
738 if (flags & SIGNOK) {\r
739 flags &= ~SIGNOK;\r
740 flags |= HAVESIGN;\r
741 goto ok;\r
742 }\r
743 break;\r
744\r
745 /*\r
746 * x ok iff flag still set & 2nd char (or\r
747 * 3rd char if we have a sign).\r
748 */\r
749 case 'x': case 'X':\r
750 if (flags & PFXOK && p ==\r
751 buf + 1 + !!(flags & HAVESIGN)) {\r
752 base = 16; /* if %i */\r
753 flags &= ~PFXOK;\r
754 goto ok;\r
755 }\r
756 break;\r
757 }\r
758\r
759 /*\r
760 * If we got here, c is not a legal character\r
761 * for a number. Stop accumulating digits.\r
762 */\r
763 break;\r
764 ok:\r
765 /*\r
766 * c is legal: store it and look at the next.\r
767 */\r
768 *p++ = (char)c;\r
769 if (--fp->_r > 0)\r
770 fp->_p++;\r
771 else if (__srefill(fp))\r
772 break; /* EOF */\r
773 }\r
774 /*\r
775 * If we had only a sign, it is no good; push\r
776 * back the sign. If the number ends in `x',\r
777 * it was [sign] '0' 'x', so push back the x\r
778 * and treat it as [sign] '0'.\r
779 */\r
780 if (flags & NDIGITS) {\r
781 if (p > buf)\r
782 (void)ungetc(*(u_char *)--p, fp);\r
783 goto match_failure;\r
784 }\r
785 c = ((u_char *)p)[-1];\r
786 if (c == 'x' || c == 'X') {\r
787 --p;\r
788 (void)ungetc(c, fp);\r
789 }\r
790 if ((flags & SUPPRESS) == 0) {\r
791 //uintmax_t res;\r
792 // Use a union to get around the truncation warnings.\r
793 union {\r
794 uintmax_t umax;\r
795 intmax_t imax;\r
796 void *vp;\r
797 ptrdiff_t pdt;\r
798 size_t sz;\r
799 long long ll;\r
800 long lo;\r
801 int in;\r
802 short hw;\r
803 char ch;\r
804 } res;\r
805\r
806 *p = 0;\r
807 if ((flags & UNSIGNED) == 0)\r
808 res.imax = strtoimax(buf, (char **)NULL, base);\r
809 else\r
810 res.umax = strtoumax(buf, (char **)NULL, base);\r
811 if (flags & POINTER)\r
812 *va_arg(ap, void **) = res.vp;\r
813 //(void *)((uintptr_t)res);\r
814 else if (flags & SHORTSHORT)\r
815 *va_arg(ap, char *) = res.ch;\r
816 else if (flags & SHORT)\r
817 *va_arg(ap, short *) = res.hw;\r
818 else if (flags & LONG)\r
819 *va_arg(ap, long *) = res.lo;\r
820 else if (flags & LONGLONG)\r
821 *va_arg(ap, long long *) = res.ll;\r
822 else if (flags & INTMAXT)\r
823 *va_arg(ap, intmax_t *) = res.imax;\r
824 else if (flags & PTRDIFFT)\r
825 *va_arg(ap, ptrdiff_t *) = res.pdt;\r
826 //(ptrdiff_t)res;\r
827 else if (flags & SIZET)\r
828 *va_arg(ap, size_t *) = res.sz;\r
829 else\r
830 *va_arg(ap, int *) = res.in;\r
831 nassigned++;\r
832 }\r
833 nread += (int)(p - buf);\r
834 nconversions++;\r
835//Print(L"%a: %d\n", __func__, __LINE__);\r
836 break;\r
837\r
838#ifndef NO_FLOATING_POINT\r
839 case CT_FLOAT:\r
840 /* scan a floating point number as if by strtod */\r
841 if (width == 0 || width > sizeof(buf) - 1)\r
842 width = sizeof(buf) - 1;\r
843 if ((width = parsefloat(fp, buf, buf + width)) == 0)\r
844 goto match_failure;\r
845 if ((flags & SUPPRESS) == 0) {\r
846 if (flags & LONGDBL) {\r
2aa62f2b 847 long double res = strtold(buf, &p);\r
9792ff7c 848 *va_arg(ap, long double *) = res;\r
2aa62f2b 849 } else if (flags & LONG) {\r
850 double res = strtod(buf, &p);\r
851 *va_arg(ap, double *) = res;\r
852 } else {\r
853 float res = strtof(buf, &p);\r
854 *va_arg(ap, float *) = res;\r
855 }\r
856 if (__scanfdebug && p - buf != (ptrdiff_t)width)\r
857 abort();\r
858 nassigned++;\r
859 }\r
860 nread += (int)width;\r
861 nconversions++;\r
862 break;\r
863#endif /* !NO_FLOATING_POINT */\r
864 }\r
865 }\r
866input_failure:\r
867//Print(L"%a: %d\n", __func__, __LINE__);\r
868 return (nconversions != 0 ? nassigned : EOF);\r
869match_failure:\r
870 return (nassigned);\r
871}\r
872\r
873/*\r
874 * Fill in the given table from the scanset at the given format\r
875 * (just after `['). Return a pointer to the character past the\r
876 * closing `]'. The table has a 1 wherever characters should be\r
877 * considered part of the scanset.\r
878 */\r
879static const u_char *\r
880__sccl(char *tab, const u_char *fmt)\r
881{\r
882 int c, n, v, i;\r
883\r
884 _DIAGASSERT(tab != NULL);\r
885 _DIAGASSERT(fmt != NULL);\r
886 /* first `clear' the whole table */\r
887 c = *fmt++; /* first char hat => negated scanset */\r
888 if (c == '^') {\r
889 v = 1; /* default => accept */\r
890 c = *fmt++; /* get new first char */\r
891 } else\r
892 v = 0; /* default => reject */\r
893\r
894 /* XXX: Will not work if sizeof(tab*) > sizeof(char) */\r
895 (void)memset(tab, v, 256);\r
896\r
897 if (c == 0)\r
898 return (fmt - 1);/* format ended before closing ] */\r
899\r
900 /*\r
901 * Now set the entries corresponding to the actual scanset\r
902 * to the opposite of the above.\r
903 *\r
904 * The first character may be ']' (or '-') without being special;\r
905 * the last character may be '-'.\r
906 */\r
907 v = 1 - v;\r
908 for (;;) {\r
909 tab[c] = (char)v; /* take character c */\r
910doswitch:\r
911 n = *fmt++; /* and examine the next */\r
912 switch (n) {\r
913\r
914 case 0: /* format ended too soon */\r
915 return (fmt - 1);\r
916\r
917 case '-':\r
918 /*\r
919 * A scanset of the form\r
920 * [01+-]\r
921 * is defined as `the digit 0, the digit 1,\r
922 * the character +, the character -', but\r
923 * the effect of a scanset such as\r
924 * [a-zA-Z0-9]\r
925 * is implementation defined. The V7 Unix\r
926 * scanf treats `a-z' as `the letters a through\r
927 * z', but treats `a-a' as `the letter a, the\r
928 * character -, and the letter a'.\r
929 *\r
930 * For compatibility, the `-' is not considerd\r
931 * to define a range if the character following\r
932 * it is either a close bracket (required by ANSI)\r
933 * or is not numerically greater than the character\r
934 * we just stored in the table (c).\r
935 */\r
936 n = *fmt;\r
937 if (n == ']' || (__collate_load_error ? n < c :\r
938 __collate_range_cmp(n, c) < 0)) {\r
939 c = '-';\r
940 break; /* resume the for(;;) */\r
941 }\r
942 fmt++;\r
943 /* fill in the range */\r
944 if (__collate_load_error) {\r
945 do\r
946 tab[++c] = (char)v;\r
947 while (c < n);\r
948 } else {\r
949 for (i = 0; i < 256; i ++)\r
950 if (__collate_range_cmp(c, i) < 0 &&\r
951 __collate_range_cmp(i, n) <= 0)\r
952 tab[i] = (char)v;\r
953 }\r
954#if 1 /* XXX another disgusting compatibility hack */\r
955 c = n;\r
956 /*\r
957 * Alas, the V7 Unix scanf also treats formats\r
958 * such as [a-c-e] as `the letters a through e'.\r
959 * This too is permitted by the standard....\r
960 */\r
961 goto doswitch;\r
962#else\r
963 c = *fmt++;\r
964 if (c == 0)\r
965 return (fmt - 1);\r
966 if (c == ']')\r
967 return (fmt);\r
968#endif\r
969\r
970 case ']': /* end of scanset */\r
971 return (fmt);\r
972\r
973 default: /* just another character */\r
974 c = n;\r
975 break;\r
976 }\r
977 }\r
978 /* NOTREACHED */\r
979}\r
980\r
981#ifndef NO_FLOATING_POINT\r
982static int\r
983parsefloat(FILE *fp, char *buf, char *end)\r
984{\r
985 char *commit, *p;\r
986 int infnanpos = 0;\r
987 enum {\r
988 S_START, S_GOTSIGN, S_INF, S_NAN, S_MAYBEHEX,\r
989 S_DIGITS, S_FRAC, S_EXP, S_EXPDIGITS\r
990 } state = S_START;\r
991 unsigned char c;\r
992 char decpt = *localeconv()->decimal_point;\r
993 _Bool gotmantdig = 0, ishex = 0;\r
994\r
53e1e5c6 995 if(fp == NULL) {\r
996 errno = EINVAL;\r
997 return (EOF);\r
998 }\r
999\r
2aa62f2b 1000 /*\r
1001 * We set commit = p whenever the string we have read so far\r
1002 * constitutes a valid representation of a floating point\r
1003 * number by itself. At some point, the parse will complete\r
1004 * or fail, and we will ungetc() back to the last commit point.\r
1005 * To ensure that the file offset gets updated properly, it is\r
1006 * always necessary to read at least one character that doesn't\r
1007 * match; thus, we can't short-circuit "infinity" or "nan(...)".\r
1008 */\r
1009 commit = buf - 1;\r
1010 for (p = buf; p < end; ) {\r
1011 c = *fp->_p;\r
1012reswitch:\r
1013 switch (state) {\r
1014 case S_START:\r
1015 state = S_GOTSIGN;\r
1016 if (c == '-' || c == '+')\r
1017 break;\r
1018 else\r
1019 goto reswitch;\r
1020 case S_GOTSIGN:\r
1021 switch (c) {\r
1022 case '0':\r
1023 state = S_MAYBEHEX;\r
1024 commit = p;\r
1025 break;\r
1026 case 'I':\r
1027 case 'i':\r
1028 state = S_INF;\r
1029 break;\r
1030 case 'N':\r
1031 case 'n':\r
1032 state = S_NAN;\r
1033 break;\r
1034 default:\r
1035 state = S_DIGITS;\r
1036 goto reswitch;\r
1037 }\r
1038 break;\r
1039 case S_INF:\r
1040 if (infnanpos > 6 ||\r
1041 (c != "nfinity"[infnanpos] &&\r
1042 c != "NFINITY"[infnanpos]))\r
1043 goto parsedone;\r
1044 if (infnanpos == 1 || infnanpos == 6)\r
1045 commit = p; /* inf or infinity */\r
1046 infnanpos++;\r
1047 break;\r
1048 case S_NAN:\r
1049 switch (infnanpos) {\r
1050 case -1: /* XXX kludge to deal with nan(...) */\r
1051 goto parsedone;\r
1052 case 0:\r
1053 if (c != 'A' && c != 'a')\r
1054 goto parsedone;\r
1055 break;\r
1056 case 1:\r
1057 if (c != 'N' && c != 'n')\r
1058 goto parsedone;\r
1059 else\r
1060 commit = p;\r
1061 break;\r
1062 case 2:\r
1063 if (c != '(')\r
1064 goto parsedone;\r
1065 break;\r
1066 default:\r
1067 if (c == ')') {\r
1068 commit = p;\r
1069 infnanpos = -2;\r
1070 } else if (!isalnum(c) && c != '_')\r
1071 goto parsedone;\r
1072 break;\r
1073 }\r
1074 infnanpos++;\r
1075 break;\r
1076 case S_MAYBEHEX:\r
1077 state = S_DIGITS;\r
1078 if (c == 'X' || c == 'x') {\r
1079 ishex = 1;\r
1080 break;\r
1081 } else { /* we saw a '0', but no 'x' */\r
1082 gotmantdig = 1;\r
1083 goto reswitch;\r
1084 }\r
1085 case S_DIGITS:\r
1086 if ((ishex && isxdigit(c)) || isdigit(c))\r
1087 gotmantdig = 1;\r
1088 else {\r
1089 state = S_FRAC;\r
1090 if (c != decpt)\r
1091 goto reswitch;\r
1092 }\r
1093 if (gotmantdig)\r
1094 commit = p;\r
1095 break;\r
1096 case S_FRAC:\r
1097 if (((c == 'E' || c == 'e') && !ishex) ||\r
1098 ((c == 'P' || c == 'p') && ishex)) {\r
1099 if (!gotmantdig)\r
1100 goto parsedone;\r
1101 else\r
1102 state = S_EXP;\r
1103 } else if ((ishex && isxdigit(c)) || isdigit(c)) {\r
1104 commit = p;\r
1105 gotmantdig = 1;\r
1106 } else\r
1107 goto parsedone;\r
1108 break;\r
1109 case S_EXP:\r
1110 state = S_EXPDIGITS;\r
1111 if (c == '-' || c == '+')\r
1112 break;\r
1113 else\r
1114 goto reswitch;\r
1115 case S_EXPDIGITS:\r
1116 if (isdigit(c))\r
1117 commit = p;\r
1118 else\r
1119 goto parsedone;\r
1120 break;\r
1121 default:\r
1122 abort();\r
1123 }\r
1124 *p++ = c;\r
1125 if (--fp->_r > 0)\r
1126 fp->_p++;\r
1127 else if (__srefill(fp))\r
1128 break; /* EOF */\r
1129 }\r
1130\r
1131parsedone:\r
1132 while (commit < --p)\r
1133 (void)ungetc(*(u_char *)p, fp);\r
1134 *++commit = '\0';\r
1135 return (int)(commit - buf);\r
1136}\r
1137#endif\r