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