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