1 /* $OpenBSD: vfscanf.c,v 1.34 2016/10/30 05:07:06 jsg Exp $ */ 2 /*- 3 * Copyright (c) 1990, 1993 4 * The Regents of the University of California. All rights reserved. 5 * 6 * This code is derived from software contributed to Berkeley by 7 * Chris Torek. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #include <ctype.h> 35 #include <wctype.h> 36 #include <inttypes.h> 37 #include <stdarg.h> 38 #include <stddef.h> 39 #include <stdio.h> 40 #include <stdlib.h> 41 #include <string.h> 42 #include "local.h" 43 44 #ifdef FLOATING_POINT 45 #include <float.h> 46 #include "floatio.h" 47 #endif 48 49 #define BUF 513 /* Maximum length of numeric string. */ 50 51 /* 52 * Flags used during conversion. 53 */ 54 #define LONG 0x00001 /* l: long or double */ 55 #define LONGDBL 0x00002 /* L: long double */ 56 #define SHORT 0x00004 /* h: short */ 57 #define SHORTSHORT 0x00008 /* hh: 8 bit integer */ 58 #define LLONG 0x00010 /* ll: long long (+ deprecated q: quad) */ 59 #define POINTER 0x00020 /* p: void * (as hex) */ 60 #define SIZEINT 0x00040 /* z: (signed) size_t */ 61 #define MAXINT 0x00080 /* j: intmax_t */ 62 #define PTRINT 0x00100 /* t: ptrdiff_t */ 63 #define NOSKIP 0x00200 /* [ or c: do not skip blanks */ 64 #define SUPPRESS 0x00400 /* *: suppress assignment */ 65 #define UNSIGNED 0x00800 /* %[oupxX] conversions */ 66 67 /* 68 * The following are used in numeric conversions only: 69 * SIGNOK, HAVESIGN, NDIGITS, DPTOK, and EXPOK are for floating point; 70 * SIGNOK, HAVESIGN, NDIGITS, PFXOK, and NZDIGITS are for integral. 71 */ 72 #define SIGNOK 0x01000 /* +/- is (still) legal */ 73 #define HAVESIGN 0x02000 /* sign detected */ 74 #define NDIGITS 0x04000 /* no digits detected */ 75 76 #define DPTOK 0x08000 /* (float) decimal point is still legal */ 77 #define EXPOK 0x10000 /* (float) exponent (e+3, etc) still legal */ 78 79 #define PFXOK 0x08000 /* 0x prefix is (still) legal */ 80 #define NZDIGITS 0x10000 /* no zero digits detected */ 81 82 /* 83 * Conversion types. 84 */ 85 #define CT_CHAR 0 /* %c conversion */ 86 #define CT_CCL 1 /* %[...] conversion */ 87 #define CT_STRING 2 /* %s conversion */ 88 #define CT_INT 3 /* integer, i.e., strtoimax or strtoumax */ 89 #define CT_FLOAT 4 /* floating, i.e., strtod */ 90 91 #define u_char unsigned char 92 #define u_long unsigned long 93 94 static u_char *__sccl(char *, u_char *); 95 96 /* 97 * Internal, unlocked version of vfscanf 98 */ 99 int 100 __svfscanf(FILE *fp, const char *fmt0, __va_list ap) 101 { 102 u_char *fmt = (u_char *)fmt0; 103 int c; /* character from format, or conversion */ 104 size_t width; /* field width, or 0 */ 105 char *p; /* points into all kinds of strings */ 106 int n; /* handy integer */ 107 int flags; /* flags as defined above */ 108 char *p0; /* saves original value of p when necessary */ 109 int nassigned; /* number of fields assigned */ 110 int nread; /* number of characters consumed from fp */ 111 int base; /* base argument to strtoimax/strtouimax */ 112 char ccltab[256]; /* character class table for %[...] */ 113 char buf[BUF]; /* buffer for numeric conversions */ 114 #ifdef SCANF_WIDE_CHAR 115 wchar_t *wcp; /* handy wide character pointer */ 116 size_t nconv; /* length of multibyte sequence converted */ 117 mbstate_t mbs; 118 #endif 119 120 /* `basefix' is used to avoid `if' tests in the integer scanner */ 121 static short basefix[17] = 122 { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }; 123 124 _SET_ORIENTATION(fp, -1); 125 126 nassigned = 0; 127 nread = 0; 128 base = 0; /* XXX just to keep gcc happy */ 129 for (;;) { 130 c = *fmt++; 131 if (c == 0) 132 return (nassigned); 133 if (isspace(c)) { 134 while ((fp->_r > 0 || __srefill(fp) == 0) && 135 isspace(*fp->_p)) 136 nread++, fp->_r--, fp->_p++; 137 continue; 138 } 139 if (c != '%') 140 goto literal; 141 width = 0; 142 flags = 0; 143 /* 144 * switch on the format. continue if done; 145 * break once format type is derived. 146 */ 147 again: c = *fmt++; 148 switch (c) { 149 case '%': 150 literal: 151 if (fp->_r <= 0 && __srefill(fp)) 152 goto input_failure; 153 if (*fp->_p != c) 154 goto match_failure; 155 fp->_r--, fp->_p++; 156 nread++; 157 continue; 158 159 case '*': 160 flags |= SUPPRESS; 161 goto again; 162 case 'j': 163 flags |= MAXINT; 164 goto again; 165 case 'L': 166 flags |= LONGDBL; 167 goto again; 168 case 'h': 169 if (*fmt == 'h') { 170 fmt++; 171 flags |= SHORTSHORT; 172 } else { 173 flags |= SHORT; 174 } 175 goto again; 176 case 'l': 177 if (*fmt == 'l') { 178 fmt++; 179 flags |= LLONG; 180 } else { 181 flags |= LONG; 182 } 183 goto again; 184 case 'q': 185 flags |= LLONG; /* deprecated */ 186 goto again; 187 case 't': 188 flags |= PTRINT; 189 goto again; 190 case 'z': 191 flags |= SIZEINT; 192 goto again; 193 194 case '0': case '1': case '2': case '3': case '4': 195 case '5': case '6': case '7': case '8': case '9': 196 width = width * 10 + c - '0'; 197 goto again; 198 199 /* 200 * Conversions. 201 * Those marked `compat' are for 4.[123]BSD compatibility. 202 * 203 * (According to ANSI, E and X formats are supposed 204 * to the same as e and x. Sorry about that.) 205 */ 206 case 'D': /* compat */ 207 flags |= LONG; 208 /* FALLTHROUGH */ 209 case 'd': 210 c = CT_INT; 211 base = 10; 212 break; 213 214 case 'i': 215 c = CT_INT; 216 base = 0; 217 break; 218 219 case 'O': /* compat */ 220 flags |= LONG; 221 /* FALLTHROUGH */ 222 case 'o': 223 c = CT_INT; 224 flags |= UNSIGNED; 225 base = 8; 226 break; 227 228 case 'u': 229 c = CT_INT; 230 flags |= UNSIGNED; 231 base = 10; 232 break; 233 234 case 'X': 235 case 'x': 236 flags |= PFXOK; /* enable 0x prefixing */ 237 c = CT_INT; 238 flags |= UNSIGNED; 239 base = 16; 240 break; 241 242 #ifdef FLOATING_POINT 243 case 'e': case 'E': 244 case 'f': case 'F': 245 case 'g': case 'G': 246 case 'a': case 'A': 247 c = CT_FLOAT; 248 break; 249 #endif 250 251 case 's': 252 c = CT_STRING; 253 break; 254 255 case '[': 256 fmt = __sccl(ccltab, fmt); 257 flags |= NOSKIP; 258 c = CT_CCL; 259 break; 260 261 case 'c': 262 flags |= NOSKIP; 263 c = CT_CHAR; 264 break; 265 266 case 'p': /* pointer format is like hex */ 267 flags |= POINTER | PFXOK; 268 c = CT_INT; 269 flags |= UNSIGNED; 270 base = 16; 271 break; 272 273 case 'n': 274 if (flags & SUPPRESS) 275 continue; 276 if (flags & SHORTSHORT) 277 *va_arg(ap, signed char *) = nread; 278 else if (flags & SHORT) 279 *va_arg(ap, short *) = nread; 280 else if (flags & LONG) 281 *va_arg(ap, long *) = nread; 282 else if (flags & SIZEINT) 283 *va_arg(ap, ssize_t *) = nread; 284 else if (flags & PTRINT) 285 *va_arg(ap, ptrdiff_t *) = nread; 286 else if (flags & LLONG) 287 *va_arg(ap, long long *) = nread; 288 else if (flags & MAXINT) 289 *va_arg(ap, intmax_t *) = nread; 290 else 291 *va_arg(ap, int *) = nread; 292 continue; 293 294 /* 295 * Disgusting backwards compatibility hacks. XXX 296 */ 297 case '\0': /* compat */ 298 return (EOF); 299 300 default: /* compat */ 301 if (isupper(c)) 302 flags |= LONG; 303 c = CT_INT; 304 base = 10; 305 break; 306 } 307 308 /* 309 * We have a conversion that requires input. 310 */ 311 if (fp->_r <= 0 && __srefill(fp)) 312 goto input_failure; 313 314 /* 315 * Consume leading white space, except for formats 316 * that suppress this. 317 */ 318 if ((flags & NOSKIP) == 0) { 319 while (isspace(*fp->_p)) { 320 nread++; 321 if (--fp->_r > 0) 322 fp->_p++; 323 else if (__srefill(fp)) 324 goto input_failure; 325 } 326 /* 327 * Note that there is at least one character in 328 * the buffer, so conversions that do not set NOSKIP 329 * ca no longer result in an input failure. 330 */ 331 } 332 333 /* 334 * Do the conversion. 335 */ 336 switch (c) { 337 338 case CT_CHAR: 339 /* scan arbitrary characters (sets NOSKIP) */ 340 if (width == 0) 341 width = 1; 342 #ifdef SCANF_WIDE_CHAR 343 if (flags & LONG) { 344 if ((flags & SUPPRESS) == 0) 345 wcp = va_arg(ap, wchar_t *); 346 else 347 wcp = NULL; 348 n = 0; 349 while (width != 0) { 350 if (n == MB_CUR_MAX) { 351 fp->_flags |= __SERR; 352 goto input_failure; 353 } 354 buf[n++] = *fp->_p; 355 fp->_p++; 356 fp->_r--; 357 bzero(&mbs, sizeof(mbs)); 358 nconv = mbrtowc(wcp, buf, n, &mbs); 359 if (nconv == (size_t)-1) { 360 fp->_flags |= __SERR; 361 goto input_failure; 362 } 363 if (nconv == 0 && !(flags & SUPPRESS)) 364 *wcp = L'\0'; 365 if (nconv != (size_t)-2) { 366 nread += n; 367 width--; 368 if (!(flags & SUPPRESS)) 369 wcp++; 370 n = 0; 371 } 372 if (fp->_r <= 0 && __srefill(fp)) { 373 if (n != 0) { 374 fp->_flags |= __SERR; 375 goto input_failure; 376 } 377 break; 378 } 379 } 380 if (!(flags & SUPPRESS)) 381 nassigned++; 382 } else 383 #endif /* SCANF_WIDE_CHAR */ 384 if (flags & SUPPRESS) { 385 size_t sum = 0; 386 for (;;) { 387 if ((n = fp->_r) < width) { 388 sum += n; 389 width -= n; 390 fp->_p += n; 391 if (__srefill(fp)) { 392 if (sum == 0) 393 goto input_failure; 394 break; 395 } 396 } else { 397 sum += width; 398 fp->_r -= width; 399 fp->_p += width; 400 break; 401 } 402 } 403 nread += sum; 404 } else { 405 size_t r = fread(va_arg(ap, char *), 1, 406 width, fp); 407 408 if (r == 0) 409 goto input_failure; 410 nread += r; 411 nassigned++; 412 } 413 break; 414 415 case CT_CCL: 416 /* scan a (nonempty) character class (sets NOSKIP) */ 417 if (width == 0) 418 width = (size_t)~0; /* `infinity' */ 419 #ifdef SCANF_WIDE_CHAR 420 /* take only those things in the class */ 421 if (flags & LONG) { 422 wchar_t twc; 423 int nchars; 424 425 if ((flags & SUPPRESS) == 0) 426 wcp = va_arg(ap, wchar_t *); 427 else 428 wcp = &twc; 429 n = 0; 430 nchars = 0; 431 while (width != 0) { 432 if (n == MB_CUR_MAX) { 433 fp->_flags |= __SERR; 434 goto input_failure; 435 } 436 buf[n++] = *fp->_p; 437 fp->_p++; 438 fp->_r--; 439 bzero(&mbs, sizeof(mbs)); 440 nconv = mbrtowc(wcp, buf, n, &mbs); 441 if (nconv == (size_t)-1) { 442 fp->_flags |= __SERR; 443 goto input_failure; 444 } 445 if (nconv == 0) 446 *wcp = L'\0'; 447 if (nconv != (size_t)-2) { 448 if (wctob(*wcp) != EOF && 449 !ccltab[wctob(*wcp)]) { 450 while (n != 0) { 451 n--; 452 ungetc(buf[n], 453 fp); 454 } 455 break; 456 } 457 nread += n; 458 width--; 459 if (!(flags & SUPPRESS)) 460 wcp++; 461 nchars++; 462 n = 0; 463 } 464 if (fp->_r <= 0 && __srefill(fp)) { 465 if (n != 0) { 466 fp->_flags |= __SERR; 467 goto input_failure; 468 } 469 break; 470 } 471 } 472 if (n != 0) { 473 fp->_flags |= __SERR; 474 goto input_failure; 475 } 476 n = nchars; 477 if (n == 0) 478 goto match_failure; 479 if (!(flags & SUPPRESS)) { 480 *wcp = L'\0'; 481 nassigned++; 482 } 483 } else 484 #endif /* SCANF_WIDE_CHAR */ 485 /* take only those things in the class */ 486 if (flags & SUPPRESS) { 487 n = 0; 488 while (ccltab[*fp->_p]) { 489 n++, fp->_r--, fp->_p++; 490 if (--width == 0) 491 break; 492 if (fp->_r <= 0 && __srefill(fp)) { 493 if (n == 0) 494 goto input_failure; 495 break; 496 } 497 } 498 if (n == 0) 499 goto match_failure; 500 } else { 501 p0 = p = va_arg(ap, char *); 502 while (ccltab[*fp->_p]) { 503 fp->_r--; 504 *p++ = *fp->_p++; 505 if (--width == 0) 506 break; 507 if (fp->_r <= 0 && __srefill(fp)) { 508 if (p == p0) 509 goto input_failure; 510 break; 511 } 512 } 513 n = p - p0; 514 if (n == 0) 515 goto match_failure; 516 *p = '\0'; 517 nassigned++; 518 } 519 nread += n; 520 break; 521 522 case CT_STRING: 523 /* like CCL, but zero-length string OK, & no NOSKIP */ 524 if (width == 0) 525 width = (size_t)~0; 526 #ifdef SCANF_WIDE_CHAR 527 if (flags & LONG) { 528 wchar_t twc; 529 530 if ((flags & SUPPRESS) == 0) 531 wcp = va_arg(ap, wchar_t *); 532 else 533 wcp = &twc; 534 n = 0; 535 while (!isspace(*fp->_p) && width != 0) { 536 if (n == MB_CUR_MAX) { 537 fp->_flags |= __SERR; 538 goto input_failure; 539 } 540 buf[n++] = *fp->_p; 541 fp->_p++; 542 fp->_r--; 543 bzero(&mbs, sizeof(mbs)); 544 nconv = mbrtowc(wcp, buf, n, &mbs); 545 if (nconv == (size_t)-1) { 546 fp->_flags |= __SERR; 547 goto input_failure; 548 } 549 if (nconv == 0) 550 *wcp = L'\0'; 551 if (nconv != (size_t)-2) { 552 if (iswspace(*wcp)) { 553 while (n != 0) { 554 n--; 555 ungetc(buf[n], 556 fp); 557 } 558 break; 559 } 560 nread += n; 561 width--; 562 if (!(flags & SUPPRESS)) 563 wcp++; 564 n = 0; 565 } 566 if (fp->_r <= 0 && __srefill(fp)) { 567 if (n != 0) { 568 fp->_flags |= __SERR; 569 goto input_failure; 570 } 571 break; 572 } 573 } 574 if (!(flags & SUPPRESS)) { 575 *wcp = L'\0'; 576 nassigned++; 577 } 578 } else 579 #endif /* SCANF_WIDE_CHAR */ 580 if (flags & SUPPRESS) { 581 n = 0; 582 while (!isspace(*fp->_p)) { 583 n++, fp->_r--, fp->_p++; 584 if (--width == 0) 585 break; 586 if (fp->_r <= 0 && __srefill(fp)) 587 break; 588 } 589 nread += n; 590 } else { 591 p0 = p = va_arg(ap, char *); 592 while (!isspace(*fp->_p)) { 593 fp->_r--; 594 *p++ = *fp->_p++; 595 if (--width == 0) 596 break; 597 if (fp->_r <= 0 && __srefill(fp)) 598 break; 599 } 600 *p = '\0'; 601 nread += p - p0; 602 nassigned++; 603 } 604 continue; 605 606 case CT_INT: 607 /* scan an integer as if by strtoimax/strtoumax */ 608 #ifdef hardway 609 if (width == 0 || width > sizeof(buf) - 1) 610 width = sizeof(buf) - 1; 611 #else 612 /* size_t is unsigned, hence this optimisation */ 613 if (--width > sizeof(buf) - 2) 614 width = sizeof(buf) - 2; 615 width++; 616 #endif 617 flags |= SIGNOK | NDIGITS | NZDIGITS; 618 for (p = buf; width; width--) { 619 c = *fp->_p; 620 /* 621 * Switch on the character; `goto ok' 622 * if we accept it as a part of number. 623 */ 624 switch (c) { 625 626 /* 627 * The digit 0 is always legal, but is 628 * special. For %i conversions, if no 629 * digits (zero or nonzero) have been 630 * scanned (only signs), we will have 631 * base==0. In that case, we should set 632 * it to 8 and enable 0x prefixing. 633 * Also, if we have not scanned zero digits 634 * before this, do not turn off prefixing 635 * (someone else will turn it off if we 636 * have scanned any nonzero digits). 637 */ 638 case '0': 639 if (base == 0) { 640 base = 8; 641 flags |= PFXOK; 642 } 643 if (flags & NZDIGITS) 644 flags &= ~(SIGNOK|NZDIGITS|NDIGITS); 645 else 646 flags &= ~(SIGNOK|PFXOK|NDIGITS); 647 goto ok; 648 649 /* 1 through 7 always legal */ 650 case '1': case '2': case '3': 651 case '4': case '5': case '6': case '7': 652 base = basefix[base]; 653 flags &= ~(SIGNOK | PFXOK | NDIGITS); 654 goto ok; 655 656 /* digits 8 and 9 ok iff decimal or hex */ 657 case '8': case '9': 658 base = basefix[base]; 659 if (base <= 8) 660 break; /* not legal here */ 661 flags &= ~(SIGNOK | PFXOK | NDIGITS); 662 goto ok; 663 664 /* letters ok iff hex */ 665 case 'A': case 'B': case 'C': 666 case 'D': case 'E': case 'F': 667 case 'a': case 'b': case 'c': 668 case 'd': case 'e': case 'f': 669 /* no need to fix base here */ 670 if (base <= 10) 671 break; /* not legal here */ 672 flags &= ~(SIGNOK | PFXOK | NDIGITS); 673 goto ok; 674 675 /* sign ok only as first character */ 676 case '+': case '-': 677 if (flags & SIGNOK) { 678 flags &= ~SIGNOK; 679 flags |= HAVESIGN; 680 goto ok; 681 } 682 break; 683 684 /* 685 * x ok iff flag still set and 2nd char (or 686 * 3rd char if we have a sign). 687 */ 688 case 'x': case 'X': 689 if ((flags & PFXOK) && p == 690 buf + 1 + !!(flags & HAVESIGN)) { 691 base = 16; /* if %i */ 692 flags &= ~PFXOK; 693 goto ok; 694 } 695 break; 696 } 697 698 /* 699 * If we got here, c is not a legal character 700 * for a number. Stop accumulating digits. 701 */ 702 break; 703 ok: 704 /* 705 * c is legal: store it and look at the next. 706 */ 707 *p++ = c; 708 if (--fp->_r > 0) 709 fp->_p++; 710 else if (__srefill(fp)) 711 break; /* EOF */ 712 } 713 /* 714 * If we had only a sign, it is no good; push 715 * back the sign. If the number ends in `x', 716 * it was [sign] '0' 'x', so push back the x 717 * and treat it as [sign] '0'. 718 */ 719 if (flags & NDIGITS) { 720 if (p > buf) 721 (void) ungetc(*(u_char *)--p, fp); 722 goto match_failure; 723 } 724 c = ((u_char *)p)[-1]; 725 if (c == 'x' || c == 'X') { 726 --p; 727 (void) ungetc(c, fp); 728 } 729 if ((flags & SUPPRESS) == 0) { 730 uintmax_t res; 731 732 *p = '\0'; 733 if (flags & UNSIGNED) 734 res = strtoumax(buf, NULL, base); 735 else 736 res = strtoimax(buf, NULL, base); 737 if (flags & POINTER) 738 *va_arg(ap, void **) = 739 (void *)(uintptr_t)res; 740 else if (flags & MAXINT) 741 *va_arg(ap, intmax_t *) = res; 742 else if (flags & LLONG) 743 *va_arg(ap, long long *) = res; 744 else if (flags & SIZEINT) 745 *va_arg(ap, ssize_t *) = res; 746 else if (flags & PTRINT) 747 *va_arg(ap, ptrdiff_t *) = res; 748 else if (flags & LONG) 749 *va_arg(ap, long *) = res; 750 else if (flags & SHORT) 751 *va_arg(ap, short *) = res; 752 else if (flags & SHORTSHORT) 753 *va_arg(ap, signed char *) = res; 754 else 755 *va_arg(ap, int *) = res; 756 nassigned++; 757 } 758 nread += p - buf; 759 break; 760 761 #ifdef FLOATING_POINT 762 case CT_FLOAT: 763 /* scan a floating point number as if by strtod */ 764 #ifdef hardway 765 if (width == 0 || width > sizeof(buf) - 1) 766 width = sizeof(buf) - 1; 767 #else 768 /* size_t is unsigned, hence this optimisation */ 769 if (--width > sizeof(buf) - 2) 770 width = sizeof(buf) - 2; 771 width++; 772 #endif 773 flags |= SIGNOK | NDIGITS | DPTOK | EXPOK; 774 for (p = buf; width; width--) { 775 c = *fp->_p; 776 /* 777 * This code mimicks the integer conversion 778 * code, but is much simpler. 779 */ 780 switch (c) { 781 782 case '0': case '1': case '2': case '3': 783 case '4': case '5': case '6': case '7': 784 case '8': case '9': 785 flags &= ~(SIGNOK | NDIGITS); 786 goto fok; 787 788 case '+': case '-': 789 if (flags & SIGNOK) { 790 flags &= ~SIGNOK; 791 goto fok; 792 } 793 break; 794 case '.': 795 if (flags & DPTOK) { 796 flags &= ~(SIGNOK | DPTOK); 797 goto fok; 798 } 799 break; 800 case 'e': case 'E': 801 /* no exponent without some digits */ 802 if ((flags&(NDIGITS|EXPOK)) == EXPOK) { 803 flags = 804 (flags & ~(EXPOK|DPTOK)) | 805 SIGNOK | NDIGITS; 806 goto fok; 807 } 808 break; 809 } 810 break; 811 fok: 812 *p++ = c; 813 if (--fp->_r > 0) 814 fp->_p++; 815 else if (__srefill(fp)) 816 break; /* EOF */ 817 } 818 /* 819 * If no digits, might be missing exponent digits 820 * (just give back the exponent) or might be missing 821 * regular digits, but had sign and/or decimal point. 822 */ 823 if (flags & NDIGITS) { 824 if (flags & EXPOK) { 825 /* no digits at all */ 826 while (p > buf) 827 ungetc(*(u_char *)--p, fp); 828 goto match_failure; 829 } 830 /* just a bad exponent (e and maybe sign) */ 831 c = *(u_char *)--p; 832 if (c != 'e' && c != 'E') { 833 (void) ungetc(c, fp);/* sign */ 834 c = *(u_char *)--p; 835 } 836 (void) ungetc(c, fp); 837 } 838 if ((flags & SUPPRESS) == 0) { 839 *p = '\0'; 840 if (flags & LONGDBL) { 841 long double res = strtold(buf, 842 (char **)NULL); 843 *va_arg(ap, long double *) = res; 844 } else if (flags & LONG) { 845 double res = strtod(buf, (char **)NULL); 846 *va_arg(ap, double *) = res; 847 } else { 848 float res = strtof(buf, (char **)NULL); 849 *va_arg(ap, float *) = res; 850 } 851 nassigned++; 852 } 853 nread += p - buf; 854 break; 855 #endif /* FLOATING_POINT */ 856 } 857 } 858 input_failure: 859 if (nassigned == 0) 860 nassigned = -1; 861 match_failure: 862 return (nassigned); 863 } 864 865 /* 866 * Fill in the given table from the scanset at the given format 867 * (just after `['). Return a pointer to the character past the 868 * closing `]'. The table has a 1 wherever characters should be 869 * considered part of the scanset. 870 */ 871 static u_char * 872 __sccl(char *tab, u_char *fmt) 873 { 874 int c, n, v; 875 876 /* first `clear' the whole table */ 877 c = *fmt++; /* first char hat => negated scanset */ 878 if (c == '^') { 879 v = 1; /* default => accept */ 880 c = *fmt++; /* get new first char */ 881 } else 882 v = 0; /* default => reject */ 883 /* should probably use memset here */ 884 for (n = 0; n < 256; n++) 885 tab[n] = v; 886 if (c == 0) 887 return (fmt - 1);/* format ended before closing ] */ 888 889 /* 890 * Now set the entries corresponding to the actual scanset 891 * to the opposite of the above. 892 * 893 * The first character may be ']' (or '-') without being special; 894 * the last character may be '-'. 895 */ 896 v = 1 - v; 897 for (;;) { 898 tab[c] = v; /* take character c */ 899 doswitch: 900 n = *fmt++; /* and examine the next */ 901 switch (n) { 902 903 case 0: /* format ended too soon */ 904 return (fmt - 1); 905 906 case '-': 907 /* 908 * A scanset of the form 909 * [01+-] 910 * is defined as `the digit 0, the digit 1, 911 * the character +, the character -', but 912 * the effect of a scanset such as 913 * [a-zA-Z0-9] 914 * is implementation defined. The V7 Unix 915 * scanf treats `a-z' as `the letters a through 916 * z', but treats `a-a' as `the letter a, the 917 * character -, and the letter a'. 918 * 919 * For compatibility, the `-' is not considerd 920 * to define a range if the character following 921 * it is either a close bracket (required by ANSI) 922 * or is not numerically greater than the character 923 * we just stored in the table (c). 924 */ 925 n = *fmt; 926 if (n == ']' || n < c) { 927 c = '-'; 928 break; /* resume the for(;;) */ 929 } 930 fmt++; 931 do { /* fill in the range */ 932 tab[++c] = v; 933 } while (c < n); 934 #if 1 /* XXX another disgusting compatibility hack */ 935 /* 936 * Alas, the V7 Unix scanf also treats formats 937 * such as [a-c-e] as `the letters a through e'. 938 * This too is permitted by the standard.... 939 */ 940 goto doswitch; 941 #else 942 c = *fmt++; 943 if (c == 0) 944 return (fmt - 1); 945 if (c == ']') 946 return (fmt); 947 #endif 948 break; 949 950 case ']': /* end of scanset */ 951 return (fmt); 952 953 default: /* just another character */ 954 c = n; 955 break; 956 } 957 } 958 /* NOTREACHED */ 959 } 960 961 int 962 vfscanf(FILE *fp, const char *fmt0, __va_list ap) 963 { 964 int r; 965 966 FLOCKFILE(fp); 967 r = __svfscanf(fp, fmt0, ap); 968 FUNLOCKFILE(fp); 969 return (r); 970 } 971 DEF_STRONG(vfscanf); 972