1 /* $NetBSD: vfscanf.c,v 1.43 2012/03/15 18:22:30 christos 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.43 2012/03/15 18:22:30 christos 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 size_t 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 size_t 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 *) = (char)nread; 329 else if (flags & SHORT) 330 *va_arg(ap, short *) = (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 *) = (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 _DIAGASSERT(__type_fit(int, 443 fp->_r - width)); 444 fp->_r -= (int)width; 445 fp->_p += width; 446 break; 447 } 448 } 449 nread += sum; 450 } else { 451 size_t r = fread(va_arg(ap, char *), 1, 452 width, fp); 453 454 if (r == 0) 455 goto input_failure; 456 nread += r; 457 nassigned++; 458 } 459 nconversions++; 460 break; 461 462 case CT_CCL: 463 /* scan a (nonempty) character class (sets NOSKIP) */ 464 if (width == 0) 465 width = (size_t)~0; /* `infinity' */ 466 /* take only those things in the class */ 467 if (flags & LONG) { 468 wchar_t twc; 469 int nchars; 470 471 if ((flags & SUPPRESS) == 0) 472 wcp = va_arg(ap, wchar_t *); 473 else 474 wcp = &twc; 475 n = 0; 476 nchars = 0; 477 while (width != 0) { 478 if (n == MB_CUR_MAX) { 479 fp->_flags |= __SERR; 480 goto input_failure; 481 } 482 buf[n++] = *fp->_p; 483 fp->_p++; 484 fp->_r--; 485 mbs = initial; 486 nconv = mbrtowc(wcp, buf, n, &mbs); 487 if (nconv == (size_t)-1) { 488 fp->_flags |= __SERR; 489 goto input_failure; 490 } 491 if (nconv == 0) 492 *wcp = L'\0'; 493 if (nconv != (size_t)-2) { 494 if (wctob(*wcp) != EOF && 495 !ccltab[wctob(*wcp)]) { 496 while (n != 0) { 497 n--; 498 (void)ungetc(buf[n], 499 fp); 500 } 501 break; 502 } 503 nread += n; 504 width--; 505 if (!(flags & SUPPRESS)) 506 wcp++; 507 nchars++; 508 n = 0; 509 } 510 if (fp->_r <= 0 && __srefill(fp)) { 511 if (n != 0) { 512 fp->_flags |= __SERR; 513 goto input_failure; 514 } 515 break; 516 } 517 } 518 if (n != 0) { 519 fp->_flags |= __SERR; 520 goto input_failure; 521 } 522 n = nchars; 523 if (n == 0) 524 goto match_failure; 525 if (!(flags & SUPPRESS)) { 526 *wcp = L'\0'; 527 nassigned++; 528 } 529 } else if (flags & SUPPRESS) { 530 n = 0; 531 while (ccltab[*fp->_p]) { 532 n++, fp->_r--, fp->_p++; 533 if (--width == 0) 534 break; 535 if (fp->_r <= 0 && __srefill(fp)) { 536 if (n == 0) 537 goto input_failure; 538 break; 539 } 540 } 541 if (n == 0) 542 goto match_failure; 543 } else { 544 p0 = p = va_arg(ap, char *); 545 while (ccltab[*fp->_p]) { 546 fp->_r--; 547 *p++ = *fp->_p++; 548 if (--width == 0) 549 break; 550 if (fp->_r <= 0 && __srefill(fp)) { 551 if (p == p0) 552 goto input_failure; 553 break; 554 } 555 } 556 n = p - p0; 557 if (n == 0) 558 goto match_failure; 559 *p = 0; 560 nassigned++; 561 } 562 nread += n; 563 nconversions++; 564 break; 565 566 case CT_STRING: 567 /* like CCL, but zero-length string OK, & no NOSKIP */ 568 if (width == 0) 569 width = (size_t)~0; 570 if (flags & LONG) { 571 wchar_t twc; 572 573 if ((flags & SUPPRESS) == 0) 574 wcp = va_arg(ap, wchar_t *); 575 else 576 wcp = &twc; 577 n = 0; 578 while (!isspace(*fp->_p) && width != 0) { 579 if (n == MB_CUR_MAX) { 580 fp->_flags |= __SERR; 581 goto input_failure; 582 } 583 buf[n++] = *fp->_p; 584 fp->_p++; 585 fp->_r--; 586 mbs = initial; 587 nconv = mbrtowc(wcp, buf, n, &mbs); 588 if (nconv == (size_t)-1) { 589 fp->_flags |= __SERR; 590 goto input_failure; 591 } 592 if (nconv == 0) 593 *wcp = L'\0'; 594 if (nconv != (size_t)-2) { 595 if (iswspace(*wcp)) { 596 while (n != 0) { 597 n--; 598 (void)ungetc(buf[n], 599 fp); 600 } 601 break; 602 } 603 nread += n; 604 width--; 605 if (!(flags & SUPPRESS)) 606 wcp++; 607 n = 0; 608 } 609 if (fp->_r <= 0 && __srefill(fp)) { 610 if (n != 0) { 611 fp->_flags |= __SERR; 612 goto input_failure; 613 } 614 break; 615 } 616 } 617 if (!(flags & SUPPRESS)) { 618 *wcp = L'\0'; 619 nassigned++; 620 } 621 } else if (flags & SUPPRESS) { 622 n = 0; 623 while (!isspace(*fp->_p)) { 624 n++, fp->_r--, fp->_p++; 625 if (--width == 0) 626 break; 627 if (fp->_r <= 0 && __srefill(fp)) 628 break; 629 } 630 nread += n; 631 } else { 632 p0 = p = va_arg(ap, char *); 633 while (!isspace(*fp->_p)) { 634 fp->_r--; 635 *p++ = *fp->_p++; 636 if (--width == 0) 637 break; 638 if (fp->_r <= 0 && __srefill(fp)) 639 break; 640 } 641 *p = 0; 642 nread += p - p0; 643 nassigned++; 644 } 645 nconversions++; 646 continue; 647 648 case CT_INT: 649 /* scan an integer as if by the conversion function */ 650 #ifdef hardway 651 if (width == 0 || width > sizeof(buf) - 1) 652 width = sizeof(buf) - 1; 653 #else 654 /* size_t is unsigned, hence this optimisation */ 655 if (--width > sizeof(buf) - 2) 656 width = sizeof(buf) - 2; 657 width++; 658 #endif 659 flags |= SIGNOK | NDIGITS | NZDIGITS; 660 for (p = buf; width; width--) { 661 c = *fp->_p; 662 /* 663 * Switch on the character; `goto ok' 664 * if we accept it as a part of number. 665 */ 666 switch (c) { 667 668 /* 669 * The digit 0 is always legal, but is 670 * special. For %i conversions, if no 671 * digits (zero or nonzero) have been 672 * scanned (only signs), we will have 673 * base==0. In that case, we should set 674 * it to 8 and enable 0x prefixing. 675 * Also, if we have not scanned zero digits 676 * before this, do not turn off prefixing 677 * (someone else will turn it off if we 678 * have scanned any nonzero digits). 679 */ 680 case '0': 681 if (base == 0) { 682 base = 8; 683 flags |= PFXOK; 684 } 685 if (flags & NZDIGITS) 686 flags &= ~(SIGNOK|NZDIGITS|NDIGITS); 687 else 688 flags &= ~(SIGNOK|PFXOK|NDIGITS); 689 goto ok; 690 691 /* 1 through 7 always legal */ 692 case '1': case '2': case '3': 693 case '4': case '5': case '6': case '7': 694 base = basefix[base]; 695 flags &= ~(SIGNOK | PFXOK | NDIGITS); 696 goto ok; 697 698 /* digits 8 and 9 ok iff decimal or hex */ 699 case '8': case '9': 700 base = basefix[base]; 701 if (base <= 8) 702 break; /* not legal here */ 703 flags &= ~(SIGNOK | PFXOK | NDIGITS); 704 goto ok; 705 706 /* letters ok iff hex */ 707 case 'A': case 'B': case 'C': 708 case 'D': case 'E': case 'F': 709 case 'a': case 'b': case 'c': 710 case 'd': case 'e': case 'f': 711 /* no need to fix base here */ 712 if (base <= 10) 713 break; /* not legal here */ 714 flags &= ~(SIGNOK | PFXOK | NDIGITS); 715 goto ok; 716 717 /* sign ok only as first character */ 718 case '+': case '-': 719 if (flags & SIGNOK) { 720 flags &= ~SIGNOK; 721 flags |= HAVESIGN; 722 goto ok; 723 } 724 break; 725 726 /* 727 * x ok iff flag still set & 2nd char (or 728 * 3rd char if we have a sign). 729 */ 730 case 'x': case 'X': 731 if (flags & PFXOK && p == 732 buf + 1 + !!(flags & HAVESIGN)) { 733 base = 16; /* if %i */ 734 flags &= ~PFXOK; 735 goto ok; 736 } 737 break; 738 } 739 740 /* 741 * If we got here, c is not a legal character 742 * for a number. Stop accumulating digits. 743 */ 744 break; 745 ok: 746 /* 747 * c is legal: store it and look at the next. 748 */ 749 *p++ = c; 750 if (--fp->_r > 0) 751 fp->_p++; 752 else if (__srefill(fp)) 753 break; /* EOF */ 754 } 755 /* 756 * If we had only a sign, it is no good; push 757 * back the sign. If the number ends in `x', 758 * it was [sign] '0' 'x', so push back the x 759 * and treat it as [sign] '0'. 760 */ 761 if (flags & NDIGITS) { 762 if (p > buf) 763 (void)ungetc(*(u_char *)--p, fp); 764 goto match_failure; 765 } 766 c = ((u_char *)p)[-1]; 767 if (c == 'x' || c == 'X') { 768 --p; 769 (void)ungetc(c, fp); 770 } 771 if ((flags & SUPPRESS) == 0) { 772 uintmax_t res; 773 774 *p = 0; 775 if ((flags & UNSIGNED) == 0) 776 res = strtoimax(buf, (char **)NULL, base); 777 else 778 res = strtoumax(buf, (char **)NULL, base); 779 if (flags & POINTER) 780 *va_arg(ap, void **) = 781 (void *)(uintptr_t)res; 782 else if (flags & SHORTSHORT) 783 *va_arg(ap, char *) = (char)res; 784 else if (flags & SHORT) 785 *va_arg(ap, short *) = (short)res; 786 else if (flags & LONG) 787 *va_arg(ap, long *) = (long)res; 788 else if (flags & LONGLONG) 789 *va_arg(ap, long long *) = res; 790 else if (flags & INTMAXT) 791 *va_arg(ap, intmax_t *) = res; 792 else if (flags & PTRDIFFT) 793 *va_arg(ap, ptrdiff_t *) = 794 (ptrdiff_t)res; 795 else if (flags & SIZET) 796 *va_arg(ap, size_t *) = (size_t)res; 797 else 798 *va_arg(ap, int *) = (int)res; 799 nassigned++; 800 } 801 nread += p - buf; 802 nconversions++; 803 break; 804 805 #ifndef NO_FLOATING_POINT 806 case CT_FLOAT: 807 /* scan a floating point number as if by strtod */ 808 if (width == 0 || width > sizeof(buf) - 1) 809 width = sizeof(buf) - 1; 810 if ((width = parsefloat(fp, buf, buf + width)) == 0) 811 goto match_failure; 812 if ((flags & SUPPRESS) == 0) { 813 if (flags & LONGDBL) { 814 long double res = strtold(buf, &p); 815 *va_arg(ap, long double *) = res; 816 } else if (flags & LONG) { 817 double res = strtod(buf, &p); 818 *va_arg(ap, double *) = res; 819 } else { 820 float res = strtof(buf, &p); 821 *va_arg(ap, float *) = res; 822 } 823 if (__scanfdebug && (size_t)(p - buf) != width) 824 abort(); 825 nassigned++; 826 } 827 nread += width; 828 nconversions++; 829 break; 830 #endif /* !NO_FLOATING_POINT */ 831 } 832 } 833 input_failure: 834 return nconversions != 0 ? nassigned : EOF; 835 match_failure: 836 return nassigned; 837 } 838 839 /* 840 * Fill in the given table from the scanset at the given format 841 * (just after `['). Return a pointer to the character past the 842 * closing `]'. The table has a 1 wherever characters should be 843 * considered part of the scanset. 844 */ 845 static const u_char * 846 __sccl(char *tab, 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 size_t 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