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