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