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