1 /*- 2 * Copyright (c) 1990, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Copyright (c) 2011 The FreeBSD Foundation 6 * All rights reserved. 7 * Portions of this software were developed by David Chisnall 8 * under sponsorship from the FreeBSD Foundation. 9 * 10 * This code is derived from software contributed to Berkeley by 11 * Chris Torek. 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 * 3. 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 * @(#)vfscanf.c 8.1 (Berkeley) 6/4/93 38 * $FreeBSD: head/lib/libc/stdio/vfscanf.c 249808 2013-04-23 13:33:13Z emaste $ 39 */ 40 41 42 #include "namespace.h" 43 #include <ctype.h> 44 #include <inttypes.h> 45 #include <stdio.h> 46 #include <stdlib.h> 47 #include <stddef.h> 48 #include <stdarg.h> 49 #include <string.h> 50 #include <wchar.h> 51 #include <wctype.h> 52 #include "un-namespace.h" 53 54 #include "collate.h" 55 #include "libc_private.h" 56 #include "local.h" 57 #include "xlocale_private.h" 58 59 #ifndef NO_FLOATING_POINT 60 #include <locale.h> 61 #endif 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 static const u_char *__sccl(char *, const u_char *); 101 #ifndef NO_FLOATING_POINT 102 static int parsefloat(FILE *, char *, char *, locale_t); 103 #endif 104 105 /* 106 * Conversion functions are passed a pointer to this object instead of 107 * a real parameter to indicate that the assignment-suppression (*) 108 * flag was specified. We could use a NULL pointer to indicate this, 109 * but that would mask bugs in applications that call scanf() with a 110 * NULL pointer. 111 */ 112 static const int suppress; 113 #define SUPPRESS_PTR ((void *)&suppress) 114 115 static const mbstate_t initial_mbs; 116 117 /* 118 * The following conversion functions return the number of characters consumed, 119 * or -1 on input failure. Character class conversion returns 0 on match 120 * failure. 121 */ 122 123 static __inline int 124 convert_char(FILE *fp, char * p, int width) 125 { 126 int n; 127 128 if (p == SUPPRESS_PTR) { 129 size_t sum = 0; 130 for (;;) { 131 if ((n = fp->pub._r) < width) { 132 sum += n; 133 width -= n; 134 fp->pub._p += n; 135 if (__srefill(fp)) { 136 if (sum == 0) 137 return (-1); 138 break; 139 } 140 } else { 141 sum += width; 142 fp->pub._r -= width; 143 fp->pub._p += width; 144 break; 145 } 146 } 147 return (sum); 148 } else { 149 size_t r = __fread(p, 1, width, fp); 150 151 if (r == 0) 152 return (-1); 153 return (r); 154 } 155 } 156 157 static __inline int 158 convert_wchar(FILE *fp, wchar_t *wcp, int width, locale_t locale) 159 { 160 mbstate_t mbs; 161 int n, nread; 162 wint_t wi; 163 164 mbs = initial_mbs; 165 n = 0; 166 while (width-- != 0 && 167 (wi = __fgetwc_mbs(fp, &mbs, &nread, locale)) != WEOF) { 168 if (wcp != SUPPRESS_PTR) 169 *wcp++ = (wchar_t)wi; 170 n += nread; 171 } 172 if (n == 0) 173 return (-1); 174 return (n); 175 } 176 177 static __inline int 178 convert_ccl(FILE *fp, char * p, int width, const char *ccltab) 179 { 180 char *p0; 181 int n; 182 183 if (p == SUPPRESS_PTR) { 184 n = 0; 185 while (ccltab[*fp->pub._p]) { 186 n++, fp->pub._r--, fp->pub._p++; 187 if (--width == 0) 188 break; 189 if (fp->pub._r <= 0 && __srefill(fp)) { 190 if (n == 0) 191 return (-1); 192 break; 193 } 194 } 195 } else { 196 p0 = p; 197 while (ccltab[*fp->pub._p]) { 198 fp->pub._r--; 199 *p++ = *fp->pub._p++; 200 if (--width == 0) 201 break; 202 if (fp->pub._r <= 0 && __srefill(fp)) { 203 if (p == p0) 204 return (-1); 205 break; 206 } 207 } 208 n = p - p0; 209 if (n == 0) 210 return (0); 211 *p = 0; 212 } 213 return (n); 214 } 215 216 static __inline int 217 convert_wccl(FILE *fp, wchar_t *wcp, int width, const char *ccltab, 218 locale_t locale) 219 { 220 mbstate_t mbs; 221 wint_t wi; 222 int n, nread; 223 224 mbs = initial_mbs; 225 n = 0; 226 if (wcp == SUPPRESS_PTR) { 227 while ((wi = __fgetwc_mbs(fp, &mbs, &nread, locale)) != WEOF && 228 width-- != 0 && ccltab[wctob(wi)]) 229 n += nread; 230 if (wi != WEOF) 231 __ungetwc(wi, fp, __get_locale()); 232 } else { 233 while ((wi = __fgetwc_mbs(fp, &mbs, &nread, locale)) != WEOF && 234 width-- != 0 && ccltab[wctob(wi)]) { 235 *wcp++ = (wchar_t)wi; 236 n += nread; 237 } 238 if (wi != WEOF) 239 __ungetwc(wi, fp, __get_locale()); 240 if (n == 0) 241 return (0); 242 *wcp = 0; 243 } 244 return (n); 245 } 246 247 static __inline int 248 convert_string(FILE *fp, char * p, int width) 249 { 250 char *p0; 251 int n; 252 253 if (p == SUPPRESS_PTR) { 254 n = 0; 255 while (!isspace(*fp->pub._p)) { 256 n++, fp->pub._r--, fp->pub._p++; 257 if (--width == 0) 258 break; 259 if (fp->pub._r <= 0 && __srefill(fp)) 260 break; 261 } 262 } else { 263 p0 = p; 264 while (!isspace(*fp->pub._p)) { 265 fp->pub._r--; 266 *p++ = *fp->pub._p++; 267 if (--width == 0) 268 break; 269 if (fp->pub._r <= 0 && __srefill(fp)) 270 break; 271 } 272 *p = 0; 273 n = p - p0; 274 } 275 return (n); 276 } 277 278 static __inline int 279 convert_wstring(FILE *fp, wchar_t *wcp, int width, locale_t locale) 280 { 281 mbstate_t mbs; 282 wint_t wi; 283 int n, nread; 284 285 mbs = initial_mbs; 286 n = 0; 287 if (wcp == SUPPRESS_PTR) { 288 while ((wi = __fgetwc_mbs(fp, &mbs, &nread, locale)) != WEOF && 289 width-- != 0 && !iswspace(wi)) 290 n += nread; 291 if (wi != WEOF) 292 __ungetwc(wi, fp, __get_locale()); 293 } else { 294 while ((wi = __fgetwc_mbs(fp, &mbs, &nread, locale)) != WEOF && 295 width-- != 0 && !iswspace(wi)) { 296 *wcp++ = (wchar_t)wi; 297 n += nread; 298 } 299 if (wi != WEOF) 300 __ungetwc(wi, fp, __get_locale()); 301 *wcp = '\0'; 302 } 303 return (n); 304 } 305 306 /* 307 * Read an integer, storing it in buf. The only relevant bit in the 308 * flags argument is PFXOK. 309 * 310 * Return 0 on a match failure, and the number of characters read 311 * otherwise. 312 */ 313 static __inline int 314 parseint(FILE *fp, char * __restrict buf, int width, int base, int flags) 315 { 316 /* `basefix' is used to avoid `if' tests */ 317 static const short basefix[17] = 318 { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }; 319 char *p; 320 int c; 321 322 flags |= SIGNOK | NDIGITS | NZDIGITS; 323 for (p = buf; width; width--) { 324 c = *fp->pub._p; 325 /* 326 * Switch on the character; `goto ok' if we accept it 327 * as a part of number. 328 */ 329 switch (c) { 330 331 /* 332 * The digit 0 is always legal, but is special. For 333 * %i conversions, if no digits (zero or nonzero) have 334 * been scanned (only signs), we will have base==0. 335 * In that case, we should set it to 8 and enable 0x 336 * prefixing. Also, if we have not scanned zero 337 * digits before this, do not turn off prefixing 338 * (someone else will turn it off if we have scanned 339 * any nonzero digits). 340 */ 341 case '0': 342 if (base == 0) { 343 base = 8; 344 flags |= PFXOK; 345 } 346 if (flags & NZDIGITS) 347 flags &= ~(SIGNOK|NZDIGITS|NDIGITS); 348 else 349 flags &= ~(SIGNOK|PFXOK|NDIGITS); 350 goto ok; 351 352 /* 1 through 7 always legal */ 353 case '1': case '2': case '3': 354 case '4': case '5': case '6': case '7': 355 base = basefix[base]; 356 flags &= ~(SIGNOK | PFXOK | NDIGITS); 357 goto ok; 358 359 /* digits 8 and 9 ok iff decimal or hex */ 360 case '8': case '9': 361 base = basefix[base]; 362 if (base <= 8) 363 break; /* not legal here */ 364 flags &= ~(SIGNOK | PFXOK | NDIGITS); 365 goto ok; 366 367 /* letters ok iff hex */ 368 case 'A': case 'B': case 'C': 369 case 'D': case 'E': case 'F': 370 case 'a': case 'b': case 'c': 371 case 'd': case 'e': case 'f': 372 /* no need to fix base here */ 373 if (base <= 10) 374 break; /* not legal here */ 375 flags &= ~(SIGNOK | PFXOK | NDIGITS); 376 goto ok; 377 378 /* sign ok only as first character */ 379 case '+': case '-': 380 if (flags & SIGNOK) { 381 flags &= ~SIGNOK; 382 flags |= HAVESIGN; 383 goto ok; 384 } 385 break; 386 387 /* 388 * x ok iff flag still set & 2nd char (or 3rd char if 389 * we have a sign). 390 */ 391 case 'x': case 'X': 392 if (flags & PFXOK && p == 393 buf + 1 + !!(flags & HAVESIGN)) { 394 base = 16; /* if %i */ 395 flags &= ~PFXOK; 396 goto ok; 397 } 398 break; 399 } 400 401 /* 402 * If we got here, c is not a legal character for a 403 * number. Stop accumulating digits. 404 */ 405 break; 406 ok: 407 /* 408 * c is legal: store it and look at the next. 409 */ 410 *p++ = c; 411 if (--fp->pub._r > 0) 412 fp->pub._p++; 413 else if (__srefill(fp)) 414 break; /* EOF */ 415 } 416 /* 417 * If we had only a sign, it is no good; push back the sign. 418 * If the number ends in `x', it was [sign] '0' 'x', so push 419 * back the x and treat it as [sign] '0'. 420 */ 421 if (flags & NDIGITS) { 422 if (p > buf) 423 (void) __ungetc(*(u_char *)--p, fp); 424 return (0); 425 } 426 c = ((u_char *)p)[-1]; 427 if (c == 'x' || c == 'X') { 428 --p; 429 (void) __ungetc(c, fp); 430 } 431 return (p - buf); 432 } 433 434 /* 435 * __vfscanf - MT-safe version 436 */ 437 int 438 __vfscanf(FILE *fp, char const *fmt0, va_list ap) 439 { 440 int ret; 441 442 FLOCKFILE(fp); 443 ret = __svfscanf(fp, __get_locale(), fmt0, ap); 444 FUNLOCKFILE(fp); 445 return (ret); 446 } 447 448 __weak_reference(__vfscanf, vfscanf); 449 450 int 451 vfscanf_l(FILE *fp, locale_t locale, char const *fmt0, va_list ap) 452 { 453 int ret; 454 FIX_LOCALE(locale); 455 456 FLOCKFILE(fp); 457 ret = __svfscanf(fp, locale, fmt0, ap); 458 FUNLOCKFILE(fp); 459 return (ret); 460 } 461 462 /* 463 * __svfscanf - non-MT-safe version of __vfscanf 464 */ 465 int 466 __svfscanf(FILE *fp, locale_t locale, const char *fmt0, va_list ap) 467 { 468 #define GETARG(type) ((flags & SUPPRESS) ? SUPPRESS_PTR : va_arg(ap, type)) 469 const u_char *fmt = (const u_char *)fmt0; 470 int c; /* character from format, or conversion */ 471 size_t width; /* field width, or 0 */ 472 int flags; /* flags as defined above */ 473 int nassigned; /* number of fields assigned */ 474 int nconversions; /* number of conversions */ 475 int nr; /* characters read by the current conversion */ 476 int nread; /* number of characters consumed from fp */ 477 int base; /* base argument to conversion function */ 478 char ccltab[256]; /* character class table for %[...] */ 479 char buf[BUF]; /* buffer for numeric conversions */ 480 481 ORIENT(fp, -1); 482 483 nassigned = 0; 484 nconversions = 0; 485 nread = 0; 486 for (;;) { 487 c = *fmt++; 488 if (c == 0) 489 return (nassigned); 490 if (isspace(c)) { 491 while ((fp->pub._r > 0 || __srefill(fp) == 0) && isspace(*fp->pub._p)) 492 nread++, fp->pub._r--, fp->pub._p++; 493 continue; 494 } 495 if (c != '%') 496 goto literal; 497 width = 0; 498 flags = 0; 499 /* 500 * switch on the format. continue if done; 501 * break once format type is derived. 502 */ 503 again: c = *fmt++; 504 switch (c) { 505 case '%': 506 literal: 507 if (fp->pub._r <= 0 && __srefill(fp)) 508 goto input_failure; 509 if (*fp->pub._p != c) 510 goto match_failure; 511 fp->pub._r--, fp->pub._p++; 512 nread++; 513 continue; 514 515 case '*': 516 flags |= SUPPRESS; 517 goto again; 518 case 'j': 519 flags |= INTMAXT; 520 goto again; 521 case 'l': 522 if (flags & LONG) { 523 flags &= ~LONG; 524 flags |= LONGLONG; 525 } else 526 flags |= LONG; 527 goto again; 528 case 'q': 529 flags |= LONGLONG; /* not quite */ 530 goto again; 531 case 't': 532 flags |= PTRDIFFT; 533 goto again; 534 case 'z': 535 flags |= SIZET; 536 goto again; 537 case 'L': 538 flags |= LONGDBL; 539 goto again; 540 case 'h': 541 if (flags & SHORT) { 542 flags &= ~SHORT; 543 flags |= SHORTSHORT; 544 } else 545 flags |= SHORT; 546 goto again; 547 548 case '0': case '1': case '2': case '3': case '4': 549 case '5': case '6': case '7': case '8': case '9': 550 width = width * 10 + c - '0'; 551 goto again; 552 553 /* 554 * Conversions. 555 */ 556 case 'd': 557 c = CT_INT; 558 base = 10; 559 break; 560 561 case 'i': 562 c = CT_INT; 563 base = 0; 564 break; 565 566 case 'o': 567 c = CT_INT; 568 flags |= UNSIGNED; 569 base = 8; 570 break; 571 572 case 'u': 573 c = CT_INT; 574 flags |= UNSIGNED; 575 base = 10; 576 break; 577 578 case 'X': 579 case 'x': 580 flags |= PFXOK; /* enable 0x prefixing */ 581 c = CT_INT; 582 flags |= UNSIGNED; 583 base = 16; 584 break; 585 586 #ifndef NO_FLOATING_POINT 587 case 'A': case 'E': case 'F': case 'G': 588 case 'a': case 'e': case 'f': case 'g': 589 c = CT_FLOAT; 590 break; 591 #endif 592 593 case 'S': 594 flags |= LONG; 595 /* FALLTHROUGH */ 596 case 's': 597 c = CT_STRING; 598 break; 599 600 case '[': 601 fmt = __sccl(ccltab, fmt); 602 flags |= NOSKIP; 603 c = CT_CCL; 604 break; 605 606 case 'C': 607 flags |= LONG; 608 /* FALLTHROUGH */ 609 case 'c': 610 flags |= NOSKIP; 611 c = CT_CHAR; 612 break; 613 614 case 'p': /* pointer format is like hex */ 615 flags |= POINTER | PFXOK; 616 c = CT_INT; /* assumes sizeof(uintmax_t) */ 617 flags |= UNSIGNED; /* >= sizeof(uintptr_t) */ 618 base = 16; 619 break; 620 621 case 'n': 622 if (flags & SUPPRESS) /* ??? */ 623 continue; 624 if (flags & SHORTSHORT) 625 *va_arg(ap, char *) = nread; 626 else if (flags & SHORT) 627 *va_arg(ap, short *) = nread; 628 else if (flags & LONG) 629 *va_arg(ap, long *) = nread; 630 else if (flags & LONGLONG) 631 *va_arg(ap, long long *) = nread; 632 else if (flags & INTMAXT) 633 *va_arg(ap, intmax_t *) = nread; 634 else if (flags & SIZET) 635 *va_arg(ap, size_t *) = nread; 636 else if (flags & PTRDIFFT) 637 *va_arg(ap, ptrdiff_t *) = nread; 638 else 639 *va_arg(ap, int *) = nread; 640 continue; 641 642 default: 643 goto match_failure; 644 645 /* 646 * Disgusting backwards compatibility hack. XXX 647 */ 648 case '\0': /* compat */ 649 return (EOF); 650 } 651 652 /* 653 * We have a conversion that requires input. 654 */ 655 if (fp->pub._r <= 0 && __srefill(fp)) 656 goto input_failure; 657 658 /* 659 * Consume leading white space, except for formats 660 * that suppress this. 661 */ 662 if ((flags & NOSKIP) == 0) { 663 while (isspace(*fp->pub._p)) { 664 nread++; 665 if (--fp->pub._r > 0) 666 fp->pub._p++; 667 else if (__srefill(fp)) 668 goto input_failure; 669 } 670 /* 671 * Note that there is at least one character in 672 * the buffer, so conversions that do not set NOSKIP 673 * ca no longer result in an input failure. 674 */ 675 } 676 677 /* 678 * Do the conversion. 679 */ 680 switch (c) { 681 682 case CT_CHAR: 683 /* scan arbitrary characters (sets NOSKIP) */ 684 if (width == 0) 685 width = 1; 686 if (flags & LONG) { 687 nr = convert_wchar(fp, GETARG(wchar_t *), 688 width, locale); 689 } else { 690 nr = convert_char(fp, GETARG(char *), width); 691 } 692 if (nr < 0) 693 goto input_failure; 694 break; 695 696 case CT_CCL: 697 /* scan a (nonempty) character class (sets NOSKIP) */ 698 if (width == 0) 699 width = (size_t)~0; /* `infinity' */ 700 if (flags & LONG) { 701 nr = convert_wccl(fp, GETARG(wchar_t *), width, 702 ccltab, locale); 703 } else { 704 nr = convert_ccl(fp, GETARG(char *), width, 705 ccltab); 706 } 707 if (nr <= 0) { 708 if (nr < 0) 709 goto input_failure; 710 else /* nr == 0 */ 711 goto match_failure; 712 } 713 break; 714 715 case CT_STRING: 716 /* like CCL, but zero-length string OK, & no NOSKIP */ 717 if (width == 0) 718 width = (size_t)~0; 719 if (flags & LONG) { 720 nr = convert_wstring(fp, GETARG(wchar_t *), 721 width, locale); 722 } else { 723 nr = convert_string(fp, GETARG(char *), width); 724 } 725 if (nr < 0) 726 goto input_failure; 727 break; 728 729 case CT_INT: 730 /* scan an integer as if by the conversion function */ 731 #ifdef hardway 732 if (width == 0 || width > sizeof(buf) - 1) 733 width = sizeof(buf) - 1; 734 #else 735 /* size_t is unsigned, hence this optimisation */ 736 if (--width > sizeof(buf) - 2) 737 width = sizeof(buf) - 2; 738 width++; 739 #endif 740 nr = parseint(fp, buf, width, base, flags); 741 if (nr == 0) 742 goto match_failure; 743 if ((flags & SUPPRESS) == 0) { 744 uintmax_t res; 745 746 buf[nr] = '\0'; 747 if ((flags & UNSIGNED) == 0) 748 res = strtoimax_l(buf, NULL, base, locale); 749 else 750 res = strtoumax_l(buf, NULL, base, locale); 751 if (flags & POINTER) 752 *va_arg(ap, void **) = 753 (void *)(uintptr_t)res; 754 else if (flags & SHORTSHORT) 755 *va_arg(ap, char *) = res; 756 else if (flags & SHORT) 757 *va_arg(ap, short *) = res; 758 else if (flags & LONG) 759 *va_arg(ap, long *) = res; 760 else if (flags & LONGLONG) 761 *va_arg(ap, long long *) = res; 762 else if (flags & INTMAXT) 763 *va_arg(ap, intmax_t *) = res; 764 else if (flags & PTRDIFFT) 765 *va_arg(ap, ptrdiff_t *) = res; 766 else if (flags & SIZET) 767 *va_arg(ap, size_t *) = res; 768 else 769 *va_arg(ap, int *) = res; 770 } 771 break; 772 773 #ifndef NO_FLOATING_POINT 774 case CT_FLOAT: 775 /* scan a floating point number as if by strtod */ 776 if (width == 0 || width > sizeof(buf) - 1) 777 width = sizeof(buf) - 1; 778 nr = parsefloat(fp, buf, buf + width, locale); 779 if (nr == 0) 780 goto match_failure; 781 if ((flags & SUPPRESS) == 0) { 782 if (flags & LONGDBL) { 783 long double res = strtold_l(buf, NULL, 784 locale); 785 *va_arg(ap, long double *) = res; 786 } else if (flags & LONG) { 787 double res = strtod_l(buf, NULL, 788 locale); 789 *va_arg(ap, double *) = res; 790 } else { 791 float res = strtof_l(buf, NULL, locale); 792 *va_arg(ap, float *) = res; 793 } 794 } 795 break; 796 #endif /* !NO_FLOATING_POINT */ 797 } 798 if (!(flags & SUPPRESS)) 799 nassigned++; 800 nread += nr; 801 nconversions++; 802 } 803 input_failure: 804 return (nconversions != 0 ? nassigned : EOF); 805 match_failure: 806 return (nassigned); 807 } 808 809 /* 810 * Fill in the given table from the scanset at the given format 811 * (just after `['). Return a pointer to the character past the 812 * closing `]'. The table has a 1 wherever characters should be 813 * considered part of the scanset. 814 */ 815 static const u_char * 816 __sccl(char *tab, const u_char *fmt) 817 { 818 int c, n, v, i; 819 struct xlocale_collate *table = 820 (struct xlocale_collate*)__get_locale()->components[XLC_COLLATE]; 821 822 /* first `clear' the whole table */ 823 c = *fmt++; /* first char hat => negated scanset */ 824 if (c == '^') { 825 v = 1; /* default => accept */ 826 c = *fmt++; /* get new first char */ 827 } else 828 v = 0; /* default => reject */ 829 830 /* XXX: Will not work if sizeof(tab*) > sizeof(char) */ 831 (void) memset(tab, v, 256); 832 833 if (c == 0) 834 return (fmt - 1);/* format ended before closing ] */ 835 836 /* 837 * Now set the entries corresponding to the actual scanset 838 * to the opposite of the above. 839 * 840 * The first character may be ']' (or '-') without being special; 841 * the last character may be '-'. 842 */ 843 v = 1 - v; 844 for (;;) { 845 tab[c] = v; /* take character c */ 846 doswitch: 847 n = *fmt++; /* and examine the next */ 848 switch (n) { 849 850 case 0: /* format ended too soon */ 851 return (fmt - 1); 852 853 case '-': 854 /* 855 * A scanset of the form 856 * [01+-] 857 * is defined as `the digit 0, the digit 1, 858 * the character +, the character -', but 859 * the effect of a scanset such as 860 * [a-zA-Z0-9] 861 * is implementation defined. The V7 Unix 862 * scanf treats `a-z' as `the letters a through 863 * z', but treats `a-a' as `the letter a, the 864 * character -, and the letter a'. 865 * 866 * For compatibility, the `-' is not considerd 867 * to define a range if the character following 868 * it is either a close bracket (required by ANSI) 869 * or is not numerically greater than the character 870 * we just stored in the table (c). 871 */ 872 n = *fmt; 873 if (n == ']' 874 || (table->__collate_load_error ? n < c : 875 __collate_range_cmp (table, n, c) < 0 876 ) 877 ) { 878 c = '-'; 879 break; /* resume the for(;;) */ 880 } 881 fmt++; 882 /* fill in the range */ 883 if (table->__collate_load_error) { 884 do { 885 tab[++c] = v; 886 } while (c < n); 887 } else { 888 for (i = 0; i < 256; i ++) 889 if ( __collate_range_cmp (table, c, i) < 0 890 && __collate_range_cmp (table, i, n) <= 0 891 ) 892 tab[i] = v; 893 } 894 #if 1 /* XXX another disgusting compatibility hack */ 895 c = n; 896 /* 897 * Alas, the V7 Unix scanf also treats formats 898 * such as [a-c-e] as `the letters a through e'. 899 * This too is permitted by the standard.... 900 */ 901 goto doswitch; 902 #else 903 c = *fmt++; 904 if (c == 0) 905 return (fmt - 1); 906 if (c == ']') 907 return (fmt); 908 #endif 909 break; 910 911 case ']': /* end of scanset */ 912 return (fmt); 913 914 default: /* just another character */ 915 c = n; 916 break; 917 } 918 } 919 /* NOTREACHED */ 920 } 921 922 #ifndef NO_FLOATING_POINT 923 static int 924 parsefloat(FILE *fp, char *buf, char *end, locale_t locale) 925 { 926 char *commit, *p; 927 int infnanpos = 0, decptpos = 0; 928 enum { 929 S_START, S_GOTSIGN, S_INF, S_NAN, S_DONE, S_MAYBEHEX, 930 S_DIGITS, S_DECPT, S_FRAC, S_EXP, S_EXPDIGITS 931 } state = S_START; 932 unsigned char c; 933 const char *decpt = localeconv_l(locale)->decimal_point; 934 _Bool gotmantdig = 0, ishex = 0; 935 936 /* 937 * We set commit = p whenever the string we have read so far 938 * constitutes a valid representation of a floating point 939 * number by itself. At some point, the parse will complete 940 * or fail, and we will ungetc() back to the last commit point. 941 * To ensure that the file offset gets updated properly, it is 942 * always necessary to read at least one character that doesn't 943 * match; thus, we can't short-circuit "infinity" or "nan(...)". 944 */ 945 commit = buf - 1; 946 for (p = buf; p < end; ) { 947 c = *fp->pub._p; 948 reswitch: 949 switch (state) { 950 case S_START: 951 state = S_GOTSIGN; 952 if (c == '-' || c == '+') 953 break; 954 else 955 goto reswitch; 956 case S_GOTSIGN: 957 switch (c) { 958 case '0': 959 state = S_MAYBEHEX; 960 commit = p; 961 break; 962 case 'I': 963 case 'i': 964 state = S_INF; 965 break; 966 case 'N': 967 case 'n': 968 state = S_NAN; 969 break; 970 default: 971 state = S_DIGITS; 972 goto reswitch; 973 } 974 break; 975 case S_INF: 976 if (infnanpos > 6 || 977 (c != "nfinity"[infnanpos] && 978 c != "NFINITY"[infnanpos])) 979 goto parsedone; 980 if (infnanpos == 1 || infnanpos == 6) 981 commit = p; /* inf or infinity */ 982 infnanpos++; 983 break; 984 case S_NAN: 985 switch (infnanpos) { 986 case 0: 987 if (c != 'A' && c != 'a') 988 goto parsedone; 989 break; 990 case 1: 991 if (c != 'N' && c != 'n') 992 goto parsedone; 993 else 994 commit = p; 995 break; 996 case 2: 997 if (c != '(') 998 goto parsedone; 999 break; 1000 default: 1001 if (c == ')') { 1002 commit = p; 1003 state = S_DONE; 1004 } else if (!isalnum(c) && c != '_') 1005 goto parsedone; 1006 break; 1007 } 1008 infnanpos++; 1009 break; 1010 case S_DONE: 1011 goto parsedone; 1012 case S_MAYBEHEX: 1013 state = S_DIGITS; 1014 if (c == 'X' || c == 'x') { 1015 ishex = 1; 1016 break; 1017 } else { /* we saw a '0', but no 'x' */ 1018 gotmantdig = 1; 1019 goto reswitch; 1020 } 1021 case S_DIGITS: 1022 if ((ishex && isxdigit(c)) || isdigit(c)) { 1023 gotmantdig = 1; 1024 commit = p; 1025 break; 1026 } else { 1027 state = S_DECPT; 1028 goto reswitch; 1029 } 1030 case S_DECPT: 1031 if (c == decpt[decptpos]) { 1032 if (decpt[++decptpos] == '\0') { 1033 /* We read the complete decpt seq. */ 1034 state = S_FRAC; 1035 if (gotmantdig) 1036 commit = p; 1037 } 1038 break; 1039 } else if (!decptpos) { 1040 /* We didn't read any decpt characters. */ 1041 state = S_FRAC; 1042 goto reswitch; 1043 } else { 1044 /* 1045 * We read part of a multibyte decimal point, 1046 * but the rest is invalid, so bail. 1047 */ 1048 goto parsedone; 1049 } 1050 case S_FRAC: 1051 if (((c == 'E' || c == 'e') && !ishex) || 1052 ((c == 'P' || c == 'p') && ishex)) { 1053 if (!gotmantdig) 1054 goto parsedone; 1055 else 1056 state = S_EXP; 1057 } else if ((ishex && isxdigit(c)) || isdigit(c)) { 1058 commit = p; 1059 gotmantdig = 1; 1060 } else 1061 goto parsedone; 1062 break; 1063 case S_EXP: 1064 state = S_EXPDIGITS; 1065 if (c == '-' || c == '+') 1066 break; 1067 else 1068 goto reswitch; 1069 case S_EXPDIGITS: 1070 if (isdigit(c)) 1071 commit = p; 1072 else 1073 goto parsedone; 1074 break; 1075 default: 1076 abort(); 1077 } 1078 *p++ = c; 1079 if (--fp->pub._r > 0) 1080 fp->pub._p++; 1081 else if (__srefill(fp)) 1082 break; /* EOF */ 1083 } 1084 1085 parsedone: 1086 while (commit < --p) 1087 __ungetc(*(u_char *)p, fp); 1088 *++commit = '\0'; 1089 return (commit - buf); 1090 } 1091 #endif 1092