]> git.proxmox.com Git - mirror_edk2.git/blame - StdLib/LibC/Stdio/vfwscanf.c
StdLib: Changes needed to support XCODE5
[mirror_edk2.git] / StdLib / LibC / Stdio / vfwscanf.c
CommitLineData
dfa51bb6
DM
1/** @file\r
2 valist worker function for the wide-character fscanf.\r
3\r
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 under\r
6 the terms and conditions of the BSD License that accompanies this distribution.\r
7 The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.\r
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 * 1. Redistributions of source code must retain the above copyright\r
23 * notice, this list of conditions and the following disclaimer.\r
24 * 2. 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 * 3. All advertising materials mentioning features or use of this software\r
28 * must display the following acknowledgement:\r
29 * This product includes software developed by the University of\r
30 * California, Berkeley and its contributors.\r
31 * 4. Neither the name of the University nor the names of its contributors\r
32 * may be used to endorse or promote products derived from this software\r
33 * without specific prior written permission.\r
34 *\r
35 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND\r
36 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
37 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
38 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE\r
39 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r
40 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\r
41 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\r
42 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
43 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\r
44 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\r
45 * SUCH DAMAGE.\r
46\r
47 FreeBSD: src/lib/libc/stdio/vfwscanf.c,v 1.12 2004/05/02 20:13:29 obrien Exp\r
48 NetBSD: vfwscanf.c,v 1.2 2005/06/12 05:48:41 lukem Exp\r
49 */\r
50#include <LibConfig.h>\r
51#include <sys/EfiCdefs.h>\r
52\r
53#include "namespace.h"\r
54#include <ctype.h>\r
55#include <inttypes.h>\r
56#include <stdio.h>\r
57#include <stdlib.h>\r
58#include <stddef.h>\r
59#include <stdarg.h>\r
60#include <string.h>\r
61#include <limits.h>\r
62#include <wchar.h>\r
63#include <wctype.h>\r
64\r
65#include "reentrant.h"\r
66#include "local.h"\r
67\r
68#ifndef NO_FLOATING_POINT\r
69#include <locale.h>\r
70#endif\r
71\r
72#if defined(_MSC_VER) /* Handle Microsoft VC++ compiler specifics. */\r
73 #pragma warning ( disable : 4244 ) // Allow wint_t to wchar_t conversions\r
74 #pragma warning ( disable : 4305 ) // Allow truncation from UINT64 to void*\r
75 #pragma warning ( disable : 4701 ) // Disable false warning for local variable p near line 375\r
76#endif\r
77\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 0x01 /* l: long or double */\r
85#define LONGDBL 0x02 /* L: long double */\r
86#define SHORT 0x04 /* h: short */\r
87#define SUPPRESS 0x08 /* *: suppress assignment */\r
88#define POINTER 0x10 /* p: void * (as hex) */\r
89#define NOSKIP 0x20 /* [ or c: do not skip blanks */\r
90#define LONGLONG 0x400 /* ll: quad_t (+ deprecated q: quad) */\r
91#define INTMAXT 0x800 /* 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
dfa51bb6
DM
101#define SIGNOK 0x40 /* +/- is (still) legal */\r
102#define NDIGITS 0x80 /* no digits detected */\r
103#define PFXOK 0x100 /* 0x prefix is (still) legal */\r
104#define NZDIGITS 0x200 /* no zero digits detected */\r
2aa62f2b 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 int parsefloat(FILE *, wchar_t *, wchar_t *);\r
117\r
118#define INCCL(_c) \\r
119 (cclcompl ? (wmemchr(ccls, (_c), (size_t)(ccle - ccls)) == NULL) : \\r
120 (wmemchr(ccls, (_c), (size_t)(ccle - ccls)) != NULL))\r
121\r
122/*\r
123 * MT-safe version.\r
124 */\r
125int\r
126vfwscanf(FILE * __restrict fp, const wchar_t * __restrict fmt, va_list ap)\r
127{\r
128 int ret;\r
129\r
130 FLOCKFILE(fp);\r
131 _SET_ORIENTATION(fp, 1);\r
132 ret = __vfwscanf_unlocked(fp, fmt, ap);\r
133 FUNLOCKFILE(fp);\r
134 return (ret);\r
135}\r
136\r
137/*\r
138 * Non-MT-safe version.\r
139 */\r
140int\r
141__vfwscanf_unlocked(FILE * __restrict fp, const wchar_t * __restrict fmt, va_list ap)\r
142{\r
dfa51bb6
DM
143 wint_t c; /* character from format, or conversion */\r
144 size_t width; /* field width, or 0 */\r
145 wchar_t *p = NULL; /* points into all kinds of strings */\r
146 int n; /* handy integer */\r
147 int flags; /* flags as defined above */\r
148 wchar_t *p0; /* saves original value of p when necessary */\r
149 int nassigned; /* number of fields assigned */\r
150 int nconversions; /* number of conversions */\r
151 int nread; /* number of characters consumed from fp */\r
152 int base; /* base argument to conversion function */\r
153 wchar_t buf[BUF]; /* buffer for numeric conversions */\r
154 const wchar_t *ccls; /* character class start */\r
155 const wchar_t *ccle; /* character class end */\r
156 int cclcompl; /* ccl is complemented? */\r
157 wint_t wi; /* handy wint_t */\r
158 char *mbp; /* multibyte string pointer for %c %s %[ */\r
159 size_t nconv; /* number of bytes in mb. conversion */\r
160 char mbbuf[MB_LEN_MAX]; /* temporary mb. character buffer */\r
161 mbstate_t mbs;\r
162\r
163 static const mbstate_t initial = { 0 };\r
2aa62f2b 164 /* `basefix' is used to avoid `if' tests in the integer scanner */\r
dfa51bb6 165 static short basefix[17] =\r
2aa62f2b 166 { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };\r
167\r
dfa51bb6
DM
168 nassigned = 0;\r
169 nconversions = 0;\r
170 nread = 0;\r
171 ccls = NULL;\r
172 ccle = NULL;\r
173 base = 0;\r
174 cclcompl = 0;\r
175 mbp = NULL;\r
176\r
2aa62f2b 177 for (;;) {\r
178 c = *fmt++;\r
179 if (c == 0)\r
180 return (nassigned);\r
181 if (iswspace(c)) {\r
182 while ((c = __fgetwc_unlock(fp)) != WEOF &&\r
183 iswspace(c))\r
184 ;\r
185 if (c != WEOF)\r
186 ungetwc(c, fp);\r
187 continue;\r
188 }\r
189 if (c != '%')\r
190 goto literal;\r
191 width = 0;\r
192 flags = 0;\r
193 /*\r
194 * switch on the format. continue if done;\r
195 * break once format type is derived.\r
196 */\r
197again: c = *fmt++;\r
198 switch (c) {\r
199 case '%':\r
200literal:\r
201 if ((wi = __fgetwc_unlock(fp)) == WEOF)\r
202 goto input_failure;\r
203 if (wi != c) {\r
204 ungetwc(wi, fp);\r
d7ce7006 205 goto match_failure;\r
2aa62f2b 206 }\r
207 nread++;\r
208 continue;\r
209\r
210 case '*':\r
211 flags |= SUPPRESS;\r
212 goto again;\r
213 case 'j':\r
214 flags |= INTMAXT;\r
215 goto again;\r
216 case 'l':\r
217 if (flags & LONG) {\r
218 flags &= ~LONG;\r
219 flags |= LONGLONG;\r
220 } else\r
221 flags |= LONG;\r
222 goto again;\r
223 case 'q':\r
224 flags |= LONGLONG; /* not quite */\r
225 goto again;\r
226 case 't':\r
227 flags |= PTRDIFFT;\r
228 goto again;\r
229 case 'z':\r
230 flags |= SIZET;\r
231 goto again;\r
232 case 'L':\r
233 flags |= LONGDBL;\r
234 goto again;\r
235 case 'h':\r
236 if (flags & SHORT) {\r
237 flags &= ~SHORT;\r
238 flags |= SHORTSHORT;\r
239 } else\r
240 flags |= SHORT;\r
241 goto again;\r
242\r
243 case '0': case '1': case '2': case '3': case '4':\r
244 case '5': case '6': case '7': case '8': case '9':\r
245 width = width * 10 + c - '0';\r
246 goto again;\r
247\r
248 /*\r
249 * Conversions.\r
250 */\r
251 case 'd':\r
252 c = CT_INT;\r
253 base = 10;\r
254 break;\r
255\r
256 case 'i':\r
257 c = CT_INT;\r
258 base = 0;\r
259 break;\r
260\r
261 case 'o':\r
262 c = CT_INT;\r
263 flags |= UNSIGNED;\r
264 base = 8;\r
265 break;\r
266\r
267 case 'u':\r
268 c = CT_INT;\r
269 flags |= UNSIGNED;\r
270 base = 10;\r
271 break;\r
272\r
273 case 'X':\r
274 case 'x':\r
275 flags |= PFXOK; /* enable 0x prefixing */\r
276 c = CT_INT;\r
277 flags |= UNSIGNED;\r
278 base = 16;\r
279 break;\r
280\r
281#ifndef NO_FLOATING_POINT\r
282 //case 'A':\r
283 case 'E': case 'F': case 'G':\r
284 //case 'a':\r
285 case 'e': case 'f': case 'g':\r
286 c = CT_FLOAT;\r
287 break;\r
288#endif\r
289\r
290 case 'S':\r
291 flags |= LONG;\r
292 /* FALLTHROUGH */\r
293 case 's':\r
294 c = CT_STRING;\r
295 break;\r
296\r
297 case '[':\r
298 ccls = fmt;\r
299 if (*fmt == '^') {\r
300 cclcompl = 1;\r
301 fmt++;\r
302 } else\r
303 cclcompl = 0;\r
304 if (*fmt == ']')\r
305 fmt++;\r
306 while (*fmt != '\0' && *fmt != ']')\r
307 fmt++;\r
308 ccle = fmt;\r
309 fmt++;\r
310 flags |= NOSKIP;\r
311 c = CT_CCL;\r
312 break;\r
313\r
314 case 'C':\r
315 flags |= LONG;\r
316 /* FALLTHROUGH */\r
317 case 'c':\r
318 flags |= NOSKIP;\r
319 c = CT_CHAR;\r
320 break;\r
321\r
322 case 'p': /* pointer format is like hex */\r
323 flags |= POINTER | PFXOK;\r
324 c = CT_INT; /* assumes sizeof(uintmax_t) */\r
325 flags |= UNSIGNED; /* >= sizeof(uintptr_t) */\r
326 base = 16;\r
327 break;\r
328\r
329 case 'n':\r
330 nconversions++;\r
331 if (flags & SUPPRESS) /* ??? */\r
332 continue;\r
333 if (flags & SHORTSHORT)\r
334 *va_arg(ap, char *) = (char)nread;\r
335 else if (flags & SHORT)\r
336 *va_arg(ap, short *) = (short)nread;\r
337 else if (flags & LONG)\r
338 *va_arg(ap, long *) = (long)nread;\r
339 else if (flags & LONGLONG)\r
340 *va_arg(ap, INT64 *) = (INT64)nread; // was quad_t\r
341 else if (flags & INTMAXT)\r
342 *va_arg(ap, intmax_t *) = (intmax_t)nread;\r
343 else if (flags & SIZET)\r
344 *va_arg(ap, size_t *) = (size_t)nread;\r
345 else if (flags & PTRDIFFT)\r
346 *va_arg(ap, ptrdiff_t *) = (ptrdiff_t)nread;\r
347 else\r
348 *va_arg(ap, int *) = nread;\r
349 continue;\r
350\r
351 default:\r
352 goto match_failure;\r
353\r
354 /*\r
355 * Disgusting backwards compatibility hack. XXX\r
356 */\r
357 case '\0': /* compat */\r
358 return (EOF);\r
359 }\r
360\r
361 /*\r
362 * Consume leading white space, except for formats\r
363 * that suppress this.\r
364 */\r
365 if ((flags & NOSKIP) == 0) {\r
366 while ((wi = __fgetwc_unlock(fp)) != WEOF && iswspace(wi))\r
367 nread++;\r
368 if (wi == WEOF)\r
369 goto input_failure;\r
370 ungetwc(wi, fp);\r
371 }\r
372\r
373 /*\r
374 * Do the conversion.\r
375 */\r
376 switch (c) {\r
377\r
378 case CT_CHAR:\r
379 /* scan arbitrary characters (sets NOSKIP) */\r
380 if (width == 0)\r
381 width = 1;\r
382 if (flags & LONG) {\r
383 if (!(flags & SUPPRESS))\r
384 p = va_arg(ap, wchar_t *);\r
385 n = 0;\r
386 while (width-- != 0 &&\r
387 (wi = __fgetwc_unlock(fp)) != WEOF) {\r
388 if (!(flags & SUPPRESS))\r
389 *p++ = (wchar_t)wi;\r
390 n++;\r
391 }\r
392 if (n == 0)\r
393 goto input_failure;\r
394 nread += n;\r
395 if (!(flags & SUPPRESS))\r
396 nassigned++;\r
397 } else {\r
398 if (!(flags & SUPPRESS))\r
399 mbp = va_arg(ap, char *);\r
400 n = 0;\r
401 mbs = initial;\r
402 while (width != 0 &&\r
403 (wi = __fgetwc_unlock(fp)) != WEOF) {\r
404 if (width >= MB_CUR_MAX &&\r
405 !(flags & SUPPRESS)) {\r
406 nconv = wcrtomb(mbp, (wchar_t)wi, &mbs);\r
407 if (nconv == (size_t)-1)\r
408 goto input_failure;\r
409 } else {\r
410 nconv = wcrtomb(mbbuf, (wchar_t)wi,\r
411 &mbs);\r
412 if (nconv == (size_t)-1)\r
413 goto input_failure;\r
414 if (nconv > width) {\r
415 ungetwc(wi, fp);\r
416 break;\r
417 }\r
418 if (!(flags & SUPPRESS))\r
419 memcpy(mbp, mbbuf,\r
420 nconv);\r
421 }\r
422 if (!(flags & SUPPRESS))\r
423 mbp += nconv;\r
424 width -= nconv;\r
425 n++;\r
426 }\r
427 if (n == 0)\r
428 goto input_failure;\r
429 nread += n;\r
430 if (!(flags & SUPPRESS))\r
431 nassigned++;\r
432 }\r
433 nconversions++;\r
434 break;\r
435\r
436 case CT_CCL:\r
437 /* scan a (nonempty) character class (sets NOSKIP) */\r
438 if (width == 0)\r
439 width = (size_t)~0; /* `infinity' */\r
440 /* take only those things in the class */\r
441 if ((flags & SUPPRESS) && (flags & LONG)) {\r
442 n = 0;\r
443 while ((wi = __fgetwc_unlock(fp)) != WEOF &&\r
444 width-- != 0 && INCCL(wi))\r
445 n++;\r
446 if (wi != WEOF)\r
447 ungetwc(wi, fp);\r
448 if (n == 0)\r
449 goto match_failure;\r
450 } else if (flags & LONG) {\r
451 p0 = p = va_arg(ap, wchar_t *);\r
452 while ((wi = __fgetwc_unlock(fp)) != WEOF &&\r
453 width-- != 0 && INCCL(wi))\r
454 *p++ = (wchar_t)wi;\r
455 if (wi != WEOF)\r
456 ungetwc(wi, fp);\r
457 n = p - p0;\r
458 if (n == 0)\r
459 goto match_failure;\r
460 *p = 0;\r
461 nassigned++;\r
462 } else {\r
463 if (!(flags & SUPPRESS))\r
464 mbp = va_arg(ap, char *);\r
465 n = 0;\r
466 mbs = initial;\r
467 while ((wi = __fgetwc_unlock(fp)) != WEOF &&\r
468 width != 0 && INCCL(wi)) {\r
469 if (width >= MB_CUR_MAX &&\r
470 !(flags & SUPPRESS)) {\r
471 nconv = wcrtomb(mbp, wi, &mbs);\r
472 if (nconv == (size_t)-1)\r
473 goto input_failure;\r
474 } else {\r
475 nconv = wcrtomb(mbbuf, wi,\r
476 &mbs);\r
477 if (nconv == (size_t)-1)\r
478 goto input_failure;\r
479 if (nconv > width)\r
480 break;\r
481 if (!(flags & SUPPRESS))\r
482 memcpy(mbp, mbbuf,\r
483 nconv);\r
484 }\r
485 if (!(flags & SUPPRESS))\r
486 mbp += nconv;\r
487 width -= nconv;\r
488 n++;\r
489 }\r
490 if (wi != WEOF)\r
491 ungetwc(wi, fp);\r
492 if (!(flags & SUPPRESS)) {\r
493 *mbp = 0;\r
494 nassigned++;\r
495 }\r
496 }\r
497 nread += n;\r
498 nconversions++;\r
499 break;\r
500\r
501 case CT_STRING:\r
502 /* like CCL, but zero-length string OK, & no NOSKIP */\r
503 if (width == 0)\r
504 width = (size_t)~0;\r
505 if ((flags & SUPPRESS) && (flags & LONG)) {\r
506 while ((wi = __fgetwc_unlock(fp)) != WEOF &&\r
507 width-- != 0 &&\r
508 !iswspace(wi))\r
509 nread++;\r
510 if (wi != WEOF)\r
511 ungetwc(wi, fp);\r
512 } else if (flags & LONG) {\r
513 p0 = p = va_arg(ap, wchar_t *);\r
514 while ((wi = __fgetwc_unlock(fp)) != WEOF &&\r
515 width-- != 0 &&\r
516 !iswspace(wi)) {\r
517 *p++ = (wchar_t)wi;\r
518 nread++;\r
519 }\r
520 if (wi != WEOF)\r
521 ungetwc(wi, fp);\r
522 *p = '\0';\r
523 nassigned++;\r
524 } else {\r
525 if (!(flags & SUPPRESS))\r
526 mbp = va_arg(ap, char *);\r
527 mbs = initial;\r
528 while ((wi = __fgetwc_unlock(fp)) != WEOF &&\r
529 width != 0 &&\r
530 !iswspace(wi)) {\r
531 if (width >= MB_CUR_MAX &&\r
532 !(flags & SUPPRESS)) {\r
533 nconv = wcrtomb(mbp, wi, &mbs);\r
534 if (nconv == (size_t)-1)\r
535 goto input_failure;\r
536 } else {\r
537 nconv = wcrtomb(mbbuf, wi,\r
538 &mbs);\r
539 if (nconv == (size_t)-1)\r
540 goto input_failure;\r
541 if (nconv > width)\r
542 break;\r
543 if (!(flags & SUPPRESS))\r
544 memcpy(mbp, mbbuf,\r
545 nconv);\r
546 }\r
547 if (!(flags & SUPPRESS))\r
548 mbp += nconv;\r
549 width -= nconv;\r
550 nread++;\r
551 }\r
552 if (wi != WEOF)\r
553 ungetwc(wi, fp);\r
554 if (!(flags & SUPPRESS)) {\r
555 *mbp = 0;\r
556 nassigned++;\r
557 }\r
558 }\r
559 nconversions++;\r
560 continue;\r
561\r
562 case CT_INT:\r
563 /* scan an integer as if by the conversion function */\r
564 if (width == 0 || width > sizeof(buf) /\r
565 sizeof(*buf) - 1)\r
566 width = sizeof(buf) / sizeof(*buf) - 1;\r
567 flags |= SIGNOK | NDIGITS | NZDIGITS;\r
568 for (p = buf; width; width--) {\r
569 c = __fgetwc_unlock(fp);\r
570 /*\r
571 * Switch on the character; `goto ok'\r
572 * if we accept it as a part of number.\r
573 */\r
574 switch (c) {\r
575\r
576 /*\r
577 * The digit 0 is always legal, but is\r
578 * special. For %i conversions, if no\r
579 * digits (zero or nonzero) have been\r
580 * scanned (only signs), we will have\r
581 * base==0. In that case, we should set\r
582 * it to 8 and enable 0x prefixing.\r
583 * Also, if we have not scanned zero digits\r
584 * before this, do not turn off prefixing\r
585 * (someone else will turn it off if we\r
586 * have scanned any nonzero digits).\r
587 */\r
588 case '0':\r
589 if (base == 0) {\r
590 base = 8;\r
591 flags |= PFXOK;\r
592 }\r
593 if (flags & NZDIGITS)\r
594 flags &= ~(SIGNOK|NZDIGITS|NDIGITS);\r
595 else\r
596 flags &= ~(SIGNOK|PFXOK|NDIGITS);\r
597 goto ok;\r
598\r
599 /* 1 through 7 always legal */\r
600 case '1': case '2': case '3':\r
601 case '4': case '5': case '6': case '7':\r
602 base = basefix[base];\r
603 flags &= ~(SIGNOK | PFXOK | NDIGITS);\r
604 goto ok;\r
605\r
606 /* digits 8 and 9 ok iff decimal or hex */\r
607 case '8': case '9':\r
608 base = basefix[base];\r
609 if (base <= 8)\r
610 break; /* not legal here */\r
611 flags &= ~(SIGNOK | PFXOK | NDIGITS);\r
612 goto ok;\r
613\r
614 /* letters ok iff hex */\r
615 case 'A': case 'B': case 'C':\r
616 case 'D': case 'E': case 'F':\r
617 case 'a': case 'b': case 'c':\r
618 case 'd': case 'e': case 'f':\r
619 /* no need to fix base here */\r
620 if (base <= 10)\r
621 break; /* not legal here */\r
622 flags &= ~(SIGNOK | PFXOK | NDIGITS);\r
623 goto ok;\r
624\r
625 /* sign ok only as first character */\r
626 case '+': case '-':\r
627 if (flags & SIGNOK) {\r
628 flags &= ~SIGNOK;\r
629 flags |= HAVESIGN;\r
630 goto ok;\r
631 }\r
632 break;\r
633\r
634 /*\r
635 * x ok iff flag still set & 2nd char (or\r
636 * 3rd char if we have a sign).\r
637 */\r
638 case 'x': case 'X':\r
639 if (flags & PFXOK && p ==\r
640 buf + 1 + !!(flags & HAVESIGN)) {\r
641 base = 16; /* if %i */\r
642 flags &= ~PFXOK;\r
643 goto ok;\r
644 }\r
645 break;\r
646 }\r
647\r
648 /*\r
649 * If we got here, c is not a legal character\r
650 * for a number. Stop accumulating digits.\r
651 */\r
652 if (c != WEOF)\r
653 ungetwc(c, fp);\r
654 break;\r
655 ok:\r
656 /*\r
657 * c is legal: store it and look at the next.\r
658 */\r
659 *p++ = (wchar_t)c;\r
660 }\r
661 /*\r
662 * If we had only a sign, it is no good; push\r
663 * back the sign. If the number ends in `x',\r
664 * it was [sign] '0' 'x', so push back the x\r
665 * and treat it as [sign] '0'.\r
666 */\r
667 if (flags & NDIGITS) {\r
668 if (p > buf)\r
669 ungetwc(*--p, fp);\r
670 goto match_failure;\r
671 }\r
672 c = p[-1];\r
673 if (c == 'x' || c == 'X') {\r
674 --p;\r
675 ungetwc(c, fp);\r
676 }\r
677 if ((flags & SUPPRESS) == 0) {\r
678 uintmax_t res;\r
679\r
680 *p = 0;\r
681 if ((flags & UNSIGNED) == 0)\r
682 res = wcstoimax(buf, NULL, base);\r
683 else\r
684 res = wcstoumax(buf, NULL, base);\r
685\r
686 if (flags & POINTER) {\r
687 *va_arg(ap, void **) = (void *)res;\r
688 }\r
689 else if (flags & SHORTSHORT) {\r
690 *va_arg(ap, char *) = (char)res;\r
691 }\r
692 else if (flags & SHORT) {\r
693 *va_arg(ap, short *) = (short)res;\r
694 }\r
695 else if (flags & LONG) {\r
696 *va_arg(ap, long *) = (long)res;\r
697 }\r
698 else if (flags & LONGLONG) {\r
699 *va_arg(ap, INT64 *) = res; // was quad_t\r
700 }\r
701 else if (flags & INTMAXT) {\r
702 *va_arg(ap, intmax_t *) = res;\r
703 }\r
704 else if (flags & PTRDIFFT) {\r
705 *va_arg(ap, ptrdiff_t *) = (ptrdiff_t)res;\r
706 }\r
707 else if (flags & SIZET) {\r
708 *va_arg(ap, size_t *) = (size_t)res;\r
709 }\r
710 else {\r
711 *va_arg(ap, int *) = (int)res;\r
712 }\r
713 nassigned++;\r
714 }\r
715 nread += p - buf;\r
716 nconversions++;\r
717 break;\r
718\r
719#ifndef NO_FLOATING_POINT\r
720 case CT_FLOAT:\r
721 /* scan a floating point number as if by strtod */\r
722 if (width == 0 || width > sizeof(buf) /\r
723 sizeof(*buf) - 1)\r
724 width = sizeof(buf) / sizeof(*buf) - 1;\r
725 if ((width = parsefloat(fp, buf, buf + width)) == 0)\r
726 goto match_failure;\r
727 if ((flags & SUPPRESS) == 0) {\r
d7ce7006 728#ifdef REAL_LONG_DOUBLE_SUPPORT\r
2aa62f2b 729 if (flags & LONGDBL) {\r
730 long double res = wcstold(buf, &p);\r
731 *va_arg(ap, long double *) = res;\r
732 } else\r
733#endif\r
d7ce7006 734 if (flags & (LONG | LONGDBL)) {\r
2aa62f2b 735 double res = wcstod(buf, &p);\r
736 *va_arg(ap, double *) = res;\r
d7ce7006 737 }\r
738 else {\r
2aa62f2b 739 float res = wcstof(buf, &p);\r
740 *va_arg(ap, float *) = res;\r
2aa62f2b 741 }\r
742#ifdef DEBUG\r
743 if (p - buf != width)\r
744 abort();\r
745#endif\r
746 nassigned++;\r
747 }\r
748 nread += (int)width;\r
749 nconversions++;\r
750 break;\r
751#endif /* !NO_FLOATING_POINT */\r
752 }\r
753 }\r
754input_failure:\r
755 return (nconversions != 0 ? nassigned : EOF);\r
756match_failure:\r
757 return (nassigned);\r
758}\r
759\r
760#ifndef NO_FLOATING_POINT\r
761static int\r
762parsefloat(FILE *fp, wchar_t *buf, wchar_t *end)\r
763{\r
764 wchar_t *commit, *p;\r
765 int infnanpos = 0;\r
766 enum {\r
767 S_START, S_GOTSIGN, S_INF, S_NAN, S_MAYBEHEX,\r
768 S_DIGITS, S_FRAC, S_EXP, S_EXPDIGITS\r
769 } state = S_START;\r
770 wchar_t c;\r
771 wchar_t decpt = (wchar_t)(unsigned char)*localeconv()->decimal_point;\r
772 int gotmantdig = 0, ishex = 0;\r
773\r
774 /*\r
775 * We set commit = p whenever the string we have read so far\r
776 * constitutes a valid representation of a floating point\r
777 * number by itself. At some point, the parse will complete\r
778 * or fail, and we will ungetc() back to the last commit point.\r
779 * To ensure that the file offset gets updated properly, it is\r
780 * always necessary to read at least one character that doesn't\r
781 * match; thus, we can't short-circuit "infinity" or "nan(...)".\r
782 */\r
783 commit = buf - 1;\r
784 c = (wchar_t)WEOF;\r
785 for (p = buf; p < end; ) {\r
786 if ((wint_t)(c = __fgetwc_unlock(fp)) == WEOF)\r
787 break;\r
788reswitch:\r
789 switch (state) {\r
790 case S_START:\r
791 state = S_GOTSIGN;\r
792 if (c == '-' || c == '+')\r
793 break;\r
794 else\r
795 goto reswitch;\r
796 case S_GOTSIGN:\r
797 switch (c) {\r
798 case '0':\r
799 state = S_MAYBEHEX;\r
800 commit = p;\r
801 break;\r
802 case 'I':\r
803 case 'i':\r
804 state = S_INF;\r
805 break;\r
806 case 'N':\r
807 case 'n':\r
808 state = S_NAN;\r
809 break;\r
810 default:\r
811 state = S_DIGITS;\r
812 goto reswitch;\r
813 }\r
814 break;\r
815 case S_INF:\r
816 if (infnanpos > 6 ||\r
817 (c != "nfinity"[infnanpos] &&\r
818 c != "NFINITY"[infnanpos]))\r
819 goto parsedone;\r
820 if (infnanpos == 1 || infnanpos == 6)\r
821 commit = p; /* inf or infinity */\r
822 infnanpos++;\r
823 break;\r
824 case S_NAN:\r
825 switch (infnanpos) {\r
826 case -1: /* XXX kludge to deal with nan(...) */\r
827 goto parsedone;\r
828 case 0:\r
829 if (c != 'A' && c != 'a')\r
830 goto parsedone;\r
831 break;\r
832 case 1:\r
833 if (c != 'N' && c != 'n')\r
834 goto parsedone;\r
835 else\r
836 commit = p;\r
837 break;\r
838 case 2:\r
839 if (c != '(')\r
840 goto parsedone;\r
841 break;\r
842 default:\r
843 if (c == ')') {\r
844 commit = p;\r
845 infnanpos = -2;\r
846 } else if (!iswalnum(c) && c != '_')\r
847 goto parsedone;\r
848 break;\r
849 }\r
850 infnanpos++;\r
851 break;\r
852 case S_MAYBEHEX:\r
853 state = S_DIGITS;\r
854 if (c == 'X' || c == 'x') {\r
855 ishex = 1;\r
856 break;\r
857 } else { /* we saw a '0', but no 'x' */\r
858 gotmantdig = 1;\r
859 goto reswitch;\r
860 }\r
861 case S_DIGITS:\r
862 if ((ishex && iswxdigit(c)) || iswdigit(c))\r
863 gotmantdig = 1;\r
864 else {\r
865 state = S_FRAC;\r
866 if (c != decpt)\r
867 goto reswitch;\r
868 }\r
869 if (gotmantdig)\r
870 commit = p;\r
871 break;\r
872 case S_FRAC:\r
873 if (((c == 'E' || c == 'e') && !ishex) ||\r
874 ((c == 'P' || c == 'p') && ishex)) {\r
875 if (!gotmantdig)\r
876 goto parsedone;\r
877 else\r
878 state = S_EXP;\r
879 } else if ((ishex && iswxdigit(c)) || iswdigit(c)) {\r
880 commit = p;\r
881 gotmantdig = 1;\r
882 } else\r
883 goto parsedone;\r
884 break;\r
885 case S_EXP:\r
886 state = S_EXPDIGITS;\r
887 if (c == '-' || c == '+')\r
888 break;\r
889 else\r
890 goto reswitch;\r
891 case S_EXPDIGITS:\r
892 if (iswdigit(c))\r
893 commit = p;\r
894 else\r
895 goto parsedone;\r
896 break;\r
897 default:\r
898 abort();\r
899 }\r
900 *p++ = c;\r
901 c = (wchar_t)WEOF;\r
902 }\r
903\r
904parsedone:\r
905 if ((wint_t)c != WEOF)\r
906 ungetwc(c, fp);\r
907 while (commit < --p)\r
908 ungetwc(*p, fp);\r
909 *++commit = '\0';\r
910 return (commit - buf);\r
911}\r
912#endif\r