vfscanf.c revision 105098
174462Salfred/*- 274462Salfred * Copyright (c) 1990, 1993 3261046Smav * The Regents of the University of California. All rights reserved. 4261046Smav * 5261046Smav * This code is derived from software contributed to Berkeley by 68858Srgrimes * Chris Torek. 7261046Smav * 8261046Smav * Redistribution and use in source and binary forms, with or without 9261046Smav * modification, are permitted provided that the following conditions 10261046Smav * are met: 11261046Smav * 1. Redistributions of source code must retain the above copyright 12261046Smav * notice, this list of conditions and the following disclaimer. 13261046Smav * 2. Redistributions in binary form must reproduce the above copyright 14261046Smav * notice, this list of conditions and the following disclaimer in the 15261046Smav * documentation and/or other materials provided with the distribution. 16261046Smav * 3. All advertising materials mentioning features or use of this software 178858Srgrimes * must display the following acknowledgement: 18261046Smav * This product includes software developed by the University of 19261046Smav * California, Berkeley and its contributors. 20261046Smav * 4. Neither the name of the University nor the names of its contributors 21261046Smav * may be used to endorse or promote products derived from this software 22261046Smav * without specific prior written permission. 23261046Smav * 24261046Smav * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25261046Smav * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26261046Smav * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27261046Smav * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28261046Smav * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 298858Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3074462Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 311903Swollman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3250473Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 331839Swollman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 341839Swollman * SUCH DAMAGE. 351839Swollman */ 361839Swollman 371839Swollman#if defined(LIBC_SCCS) && !defined(lint) 381839Swollmanstatic char sccsid[] = "@(#)vfscanf.c 8.1 (Berkeley) 6/4/93"; 391839Swollman#endif /* LIBC_SCCS and not lint */ 401839Swollman#include <sys/cdefs.h> 411839Swollman__FBSDID("$FreeBSD: head/lib/libc/stdio/vfscanf.c 105098 2002-10-14 11:18:21Z tjr $"); 421839Swollman 431839Swollman#include "namespace.h" 441839Swollman#include <ctype.h> 451839Swollman#include <inttypes.h> 461839Swollman#include <stdio.h> 471839Swollman#include <stdlib.h> 481839Swollman#include <stddef.h> 491839Swollman#include <stdarg.h> 501839Swollman#include <string.h> 511839Swollman#include <wchar.h> 521839Swollman#include <wctype.h> 531839Swollman#include "un-namespace.h" 541839Swollman 551839Swollman#include "collate.h" 561839Swollman#include "libc_private.h" 571839Swollman#include "local.h" 581839Swollman 591839Swollman#define FLOATING_POINT 601839Swollman 611839Swollman#ifdef FLOATING_POINT 621839Swollman#include <locale.h> 631839Swollman#include "floatio.h" 641839Swollman#endif 651839Swollman 661839Swollman#define BUF 513 /* Maximum length of numeric string. */ 671839Swollman 681839Swollman/* 691839Swollman * Flags used during conversion. 701839Swollman */ 711839Swollman#define LONG 0x01 /* l: long or double */ 7274462Salfred#define LONGDBL 0x02 /* L: long double */ 7374462Salfred#define SHORT 0x04 /* h: short */ 741903Swollman#define SUPPRESS 0x08 /* *: suppress assignment */ 751903Swollman#define POINTER 0x10 /* p: void * (as hex) */ 761839Swollman#define NOSKIP 0x20 /* [ or c: do not skip blanks */ 771839Swollman#define LONGLONG 0x400 /* ll: long long (+ deprecated q: quad) */ 781839Swollman#define INTMAXT 0x800 /* j: intmax_t */ 791839Swollman#define PTRDIFFT 0x1000 /* t: ptrdiff_t */ 801839Swollman#define SIZET 0x2000 /* z: size_t */ 811839Swollman#define SHORTSHORT 0x4000 /* hh: char */ 821839Swollman#define UNSIGNED 0x8000 /* %[oupxX] conversions */ 831839Swollman 841839Swollman/* 851839Swollman * The following are used in numeric conversions only: 861839Swollman * SIGNOK, NDIGITS, DPTOK, and EXPOK are for floating point; 871839Swollman * SIGNOK, NDIGITS, PFXOK, and NZDIGITS are for integral. 881839Swollman */ 891839Swollman#define SIGNOK 0x40 /* +/- is (still) legal */ 901839Swollman#define NDIGITS 0x80 /* no digits detected */ 911839Swollman 921839Swollman#define DPTOK 0x100 /* (float) decimal point is still legal */ 931839Swollman#define EXPOK 0x200 /* (float) exponent (e+3, etc) still legal */ 941839Swollman 951839Swollman#define PFXOK 0x100 /* 0x prefix is (still) legal */ 961839Swollman#define NZDIGITS 0x200 /* no zero digits detected */ 971839Swollman 981839Swollman/* 991839Swollman * Conversion types. 1001903Swollman */ 10193032Simp#define CT_CHAR 0 /* %c conversion */ 10293032Simp#define CT_CCL 1 /* %[...] conversion */ 10393032Simp#define CT_STRING 2 /* %s conversion */ 1041903Swollman#define CT_INT 3 /* %[dioupxX] conversion */ 1051903Swollman#define CT_FLOAT 4 /* %[efgEFG] conversion */ 10674462Salfred 107static const u_char *__sccl(char *, const u_char *); 108 109__weak_reference(__vfscanf, vfscanf); 110 111/* 112 * __vfscanf - MT-safe version 113 */ 114int 115__vfscanf(FILE *fp, char const *fmt0, va_list ap) 116{ 117 int ret; 118 119 FLOCKFILE(fp); 120 ret = __svfscanf(fp, fmt0, ap); 121 FUNLOCKFILE(fp); 122 return (ret); 123} 124 125/* 126 * __svfscanf - non-MT-safe version of __vfscanf 127 */ 128int 129__svfscanf(FILE *fp, const char *fmt0, va_list ap) 130{ 131 const u_char *fmt = (const u_char *)fmt0; 132 int c; /* character from format, or conversion */ 133 size_t width; /* field width, or 0 */ 134 char *p; /* points into all kinds of strings */ 135 int n; /* handy integer */ 136 int flags; /* flags as defined above */ 137 char *p0; /* saves original value of p when necessary */ 138 int nassigned; /* number of fields assigned */ 139 int nconversions; /* number of conversions */ 140 int nread; /* number of characters consumed from fp */ 141 int base; /* base argument to conversion function */ 142 char ccltab[256]; /* character class table for %[...] */ 143 char buf[BUF]; /* buffer for numeric and mb conversions */ 144 wchar_t *wcp; /* handy wide character pointer */ 145 wchar_t *wcp0; /* saves original value of wcp */ 146 mbstate_t mbs; /* multibyte conversion state */ 147 size_t nconv; /* length of multibyte sequence converted */ 148 149 /* `basefix' is used to avoid `if' tests in the integer scanner */ 150 static short basefix[17] = 151 { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }; 152#ifdef FLOATING_POINT 153 char decimal_point = localeconv()->decimal_point[0]; 154#endif 155 156 ORIENT(fp, -1); 157 158 nassigned = 0; 159 nconversions = 0; 160 nread = 0; 161 for (;;) { 162 c = *fmt++; 163 if (c == 0) 164 return (nassigned); 165 if (isspace(c)) { 166 while ((fp->_r > 0 || __srefill(fp) == 0) && isspace(*fp->_p)) 167 nread++, fp->_r--, fp->_p++; 168 continue; 169 } 170 if (c != '%') 171 goto literal; 172 width = 0; 173 flags = 0; 174 /* 175 * switch on the format. continue if done; 176 * break once format type is derived. 177 */ 178again: c = *fmt++; 179 switch (c) { 180 case '%': 181literal: 182 if (fp->_r <= 0 && __srefill(fp)) 183 goto input_failure; 184 if (*fp->_p != c) 185 goto match_failure; 186 fp->_r--, fp->_p++; 187 nread++; 188 continue; 189 190 case '*': 191 flags |= SUPPRESS; 192 goto again; 193 case 'j': 194 flags |= INTMAXT; 195 goto again; 196 case 'l': 197 if (flags & LONG) { 198 flags &= ~LONG; 199 flags |= LONGLONG; 200 } else 201 flags |= LONG; 202 goto again; 203 case 'q': 204 flags |= LONGLONG; /* not quite */ 205 goto again; 206 case 't': 207 flags |= PTRDIFFT; 208 goto again; 209 case 'z': 210 flags |= SIZET; 211 goto again; 212 case 'L': 213 flags |= LONGDBL; 214 goto again; 215 case 'h': 216 if (flags & SHORT) { 217 flags &= ~SHORT; 218 flags |= SHORTSHORT; 219 } else 220 flags |= SHORT; 221 goto again; 222 223 case '0': case '1': case '2': case '3': case '4': 224 case '5': case '6': case '7': case '8': case '9': 225 width = width * 10 + c - '0'; 226 goto again; 227 228 /* 229 * Conversions. 230 */ 231 case 'd': 232 c = CT_INT; 233 base = 10; 234 break; 235 236 case 'i': 237 c = CT_INT; 238 base = 0; 239 break; 240 241 case 'o': 242 c = CT_INT; 243 flags |= UNSIGNED; 244 base = 8; 245 break; 246 247 case 'u': 248 c = CT_INT; 249 flags |= UNSIGNED; 250 base = 10; 251 break; 252 253 case 'X': 254 case 'x': 255 flags |= PFXOK; /* enable 0x prefixing */ 256 c = CT_INT; 257 flags |= UNSIGNED; 258 base = 16; 259 break; 260 261#ifdef FLOATING_POINT 262 case 'E': case 'F': case 'G': 263 case 'e': case 'f': case 'g': 264 c = CT_FLOAT; 265 break; 266#endif 267 268 case 'S': 269 flags |= LONG; 270 /* FALLTHROUGH */ 271 case 's': 272 c = CT_STRING; 273 break; 274 275 case '[': 276 fmt = __sccl(ccltab, fmt); 277 flags |= NOSKIP; 278 c = CT_CCL; 279 break; 280 281 case 'C': 282 flags |= LONG; 283 /* FALLTHROUGH */ 284 case 'c': 285 flags |= NOSKIP; 286 c = CT_CHAR; 287 break; 288 289 case 'p': /* pointer format is like hex */ 290 flags |= POINTER | PFXOK; 291 c = CT_INT; /* assumes sizeof(uintmax_t) */ 292 flags |= UNSIGNED; /* >= sizeof(uintptr_t) */ 293 base = 16; 294 break; 295 296 case 'n': 297 nconversions++; 298 if (flags & SUPPRESS) /* ??? */ 299 continue; 300 if (flags & SHORTSHORT) 301 *va_arg(ap, char *) = nread; 302 else if (flags & SHORT) 303 *va_arg(ap, short *) = nread; 304 else if (flags & LONG) 305 *va_arg(ap, long *) = nread; 306 else if (flags & LONGLONG) 307 *va_arg(ap, long long *) = nread; 308 else if (flags & INTMAXT) 309 *va_arg(ap, intmax_t *) = nread; 310 else if (flags & SIZET) 311 *va_arg(ap, size_t *) = nread; 312 else if (flags & PTRDIFFT) 313 *va_arg(ap, ptrdiff_t *) = nread; 314 else 315 *va_arg(ap, int *) = nread; 316 continue; 317 318 default: 319 goto match_failure; 320 321 /* 322 * Disgusting backwards compatibility hack. XXX 323 */ 324 case '\0': /* compat */ 325 return (EOF); 326 } 327 328 /* 329 * We have a conversion that requires input. 330 */ 331 if (fp->_r <= 0 && __srefill(fp)) 332 goto input_failure; 333 334 /* 335 * Consume leading white space, except for formats 336 * that suppress this. 337 */ 338 if ((flags & NOSKIP) == 0) { 339 while (isspace(*fp->_p)) { 340 nread++; 341 if (--fp->_r > 0) 342 fp->_p++; 343 else if (__srefill(fp)) 344 goto input_failure; 345 } 346 /* 347 * Note that there is at least one character in 348 * the buffer, so conversions that do not set NOSKIP 349 * ca no longer result in an input failure. 350 */ 351 } 352 353 /* 354 * Do the conversion. 355 */ 356 switch (c) { 357 358 case CT_CHAR: 359 /* scan arbitrary characters (sets NOSKIP) */ 360 if (width == 0) 361 width = 1; 362 if (flags & SUPPRESS) { 363 size_t sum = 0; 364 for (;;) { 365 if ((n = fp->_r) < width) { 366 sum += n; 367 width -= n; 368 fp->_p += n; 369 if (__srefill(fp)) { 370 if (sum == 0) 371 goto input_failure; 372 break; 373 } 374 } else { 375 sum += width; 376 fp->_r -= width; 377 fp->_p += width; 378 break; 379 } 380 } 381 nread += sum; 382 } else if (flags & LONG) { 383 wcp = va_arg(ap, wchar_t *); 384 n = 0; 385 while (width != 0) { 386 if (n == MB_CUR_MAX) 387 goto input_failure; 388 buf[n++] = *fp->_p; 389 fp->_p++; 390 fp->_r--; 391 memset(&mbs, 0, sizeof(mbs)); 392 nconv = mbrtowc(wcp, buf, n, &mbs); 393 if (nconv == 0 || nconv == (size_t)-1) 394 goto input_failure; 395 if (nconv != (size_t)-2) { 396 nread += n; 397 width--; 398 wcp++; 399 n = 0; 400 } 401 if (fp->_r <= 0 && __srefill(fp)) { 402 if (n != 0) 403 goto input_failure; 404 break; 405 } 406 } 407 nassigned++; 408 } else { 409 size_t r = fread((void *)va_arg(ap, char *), 1, 410 width, fp); 411 412 if (r == 0) 413 goto input_failure; 414 nread += r; 415 nassigned++; 416 } 417 nconversions++; 418 break; 419 420 case CT_CCL: 421 /* scan a (nonempty) character class (sets NOSKIP) */ 422 if (width == 0) 423 width = (size_t)~0; /* `infinity' */ 424 /* take only those things in the class */ 425 if (flags & SUPPRESS) { 426 n = 0; 427 while (ccltab[*fp->_p]) { 428 n++, fp->_r--, fp->_p++; 429 if (--width == 0) 430 break; 431 if (fp->_r <= 0 && __srefill(fp)) { 432 if (n == 0) 433 goto input_failure; 434 break; 435 } 436 } 437 if (n == 0) 438 goto match_failure; 439 } else if (flags & LONG) { 440 wcp = wcp0 = va_arg(ap, wchar_t *); 441 n = 0; 442 while (width != 0) { 443 if (n == MB_CUR_MAX) 444 goto input_failure; 445 buf[n++] = *fp->_p; 446 fp->_p++; 447 fp->_r--; 448 memset(&mbs, 0, sizeof(mbs)); 449 nconv = mbrtowc(wcp, buf, n, &mbs); 450 if (nconv == 0 || nconv == (size_t)-1) 451 goto input_failure; 452 if (nconv != (size_t)-2) { 453 if (wctob(*wcp) != EOF && 454 !ccltab[wctob(*wcp)]) { 455 while (--n > 0) 456 __ungetc(buf[n], 457 fp); 458 break; 459 } 460 nread += n; 461 width--; 462 wcp++; 463 n = 0; 464 } 465 if (fp->_r <= 0 && __srefill(fp)) { 466 if (n != 0) 467 goto input_failure; 468 break; 469 } 470 } 471 if (n != 0) 472 goto input_failure; 473 n = wcp - wcp0; 474 if (n == 0) 475 goto match_failure; 476 *wcp = L'\0'; 477 nassigned++; 478 } else { 479 p0 = p = va_arg(ap, char *); 480 while (ccltab[*fp->_p]) { 481 fp->_r--; 482 *p++ = *fp->_p++; 483 if (--width == 0) 484 break; 485 if (fp->_r <= 0 && __srefill(fp)) { 486 if (p == p0) 487 goto input_failure; 488 break; 489 } 490 } 491 n = p - p0; 492 if (n == 0) 493 goto match_failure; 494 *p = 0; 495 nassigned++; 496 } 497 nread += n; 498 nconversions++; 499 break; 500 501 case CT_STRING: 502 /* like CCL, but zero-length string OK, & no NOSKIP */ 503 if (width == 0) 504 width = (size_t)~0; 505 if (flags & SUPPRESS) { 506 n = 0; 507 while (!isspace(*fp->_p)) { 508 n++, fp->_r--, fp->_p++; 509 if (--width == 0) 510 break; 511 if (fp->_r <= 0 && __srefill(fp)) 512 break; 513 } 514 nread += n; 515 } else if (flags & LONG) { 516 wcp = va_arg(ap, wchar_t *); 517 n = 0; 518 while (!isspace(*fp->_p) && width != 0) { 519 if (n == MB_CUR_MAX) 520 goto input_failure; 521 buf[n++] = *fp->_p; 522 fp->_p++; 523 fp->_r--; 524 memset(&mbs, 0, sizeof(mbs)); 525 nconv = mbrtowc(wcp, buf, n, &mbs); 526 if (nconv == 0 || nconv == (size_t)-1) 527 goto input_failure; 528 if (nconv != (size_t)-2) { 529 if (iswspace(*wcp)) { 530 while (--n > 0) 531 __ungetc(buf[n], 532 fp); 533 break; 534 } 535 nread += n; 536 width--; 537 wcp++; 538 n = 0; 539 } 540 if (fp->_r <= 0 && __srefill(fp)) { 541 if (n != 0) 542 goto input_failure; 543 break; 544 } 545 } 546 *wcp = L'\0'; 547 nassigned++; 548 } else { 549 p0 = p = va_arg(ap, char *); 550 while (!isspace(*fp->_p)) { 551 fp->_r--; 552 *p++ = *fp->_p++; 553 if (--width == 0) 554 break; 555 if (fp->_r <= 0 && __srefill(fp)) 556 break; 557 } 558 *p = 0; 559 nread += p - p0; 560 nassigned++; 561 } 562 nconversions++; 563 continue; 564 565 case CT_INT: 566 /* scan an integer as if by the conversion function */ 567#ifdef hardway 568 if (width == 0 || width > sizeof(buf) - 1) 569 width = sizeof(buf) - 1; 570#else 571 /* size_t is unsigned, hence this optimisation */ 572 if (--width > sizeof(buf) - 2) 573 width = sizeof(buf) - 2; 574 width++; 575#endif 576 flags |= SIGNOK | NDIGITS | NZDIGITS; 577 for (p = buf; width; width--) { 578 c = *fp->_p; 579 /* 580 * Switch on the character; `goto ok' 581 * if we accept it as a part of number. 582 */ 583 switch (c) { 584 585 /* 586 * The digit 0 is always legal, but is 587 * special. For %i conversions, if no 588 * digits (zero or nonzero) have been 589 * scanned (only signs), we will have 590 * base==0. In that case, we should set 591 * it to 8 and enable 0x prefixing. 592 * Also, if we have not scanned zero digits 593 * before this, do not turn off prefixing 594 * (someone else will turn it off if we 595 * have scanned any nonzero digits). 596 */ 597 case '0': 598 if (base == 0) { 599 base = 8; 600 flags |= PFXOK; 601 } 602 if (flags & NZDIGITS) 603 flags &= ~(SIGNOK|NZDIGITS|NDIGITS); 604 else 605 flags &= ~(SIGNOK|PFXOK|NDIGITS); 606 goto ok; 607 608 /* 1 through 7 always legal */ 609 case '1': case '2': case '3': 610 case '4': case '5': case '6': case '7': 611 base = basefix[base]; 612 flags &= ~(SIGNOK | PFXOK | NDIGITS); 613 goto ok; 614 615 /* digits 8 and 9 ok iff decimal or hex */ 616 case '8': case '9': 617 base = basefix[base]; 618 if (base <= 8) 619 break; /* not legal here */ 620 flags &= ~(SIGNOK | PFXOK | NDIGITS); 621 goto ok; 622 623 /* letters ok iff hex */ 624 case 'A': case 'B': case 'C': 625 case 'D': case 'E': case 'F': 626 case 'a': case 'b': case 'c': 627 case 'd': case 'e': case 'f': 628 /* no need to fix base here */ 629 if (base <= 10) 630 break; /* not legal here */ 631 flags &= ~(SIGNOK | PFXOK | NDIGITS); 632 goto ok; 633 634 /* sign ok only as first character */ 635 case '+': case '-': 636 if (flags & SIGNOK) { 637 flags &= ~SIGNOK; 638 goto ok; 639 } 640 break; 641 642 /* x ok iff flag still set & 2nd char */ 643 case 'x': case 'X': 644 if (flags & PFXOK && p == buf + 1) { 645 base = 16; /* if %i */ 646 flags &= ~PFXOK; 647 goto ok; 648 } 649 break; 650 } 651 652 /* 653 * If we got here, c is not a legal character 654 * for a number. Stop accumulating digits. 655 */ 656 break; 657 ok: 658 /* 659 * c is legal: store it and look at the next. 660 */ 661 *p++ = c; 662 if (--fp->_r > 0) 663 fp->_p++; 664 else if (__srefill(fp)) 665 break; /* EOF */ 666 } 667 /* 668 * If we had only a sign, it is no good; push 669 * back the sign. If the number ends in `x', 670 * it was [sign] '0' 'x', so push back the x 671 * and treat it as [sign] '0'. 672 */ 673 if (flags & NDIGITS) { 674 if (p > buf) 675 (void) __ungetc(*(u_char *)--p, fp); 676 goto match_failure; 677 } 678 c = ((u_char *)p)[-1]; 679 if (c == 'x' || c == 'X') { 680 --p; 681 (void) __ungetc(c, fp); 682 } 683 if ((flags & SUPPRESS) == 0) { 684 uintmax_t res; 685 686 *p = 0; 687 if ((flags & UNSIGNED) == 0) 688 res = strtoimax(buf, (char **)NULL, base); 689 else 690 res = strtoumax(buf, (char **)NULL, base); 691 if (flags & POINTER) 692 *va_arg(ap, void **) = 693 (void *)(uintptr_t)res; 694 else if (flags & SHORTSHORT) 695 *va_arg(ap, char *) = res; 696 else if (flags & SHORT) 697 *va_arg(ap, short *) = res; 698 else if (flags & LONG) 699 *va_arg(ap, long *) = res; 700 else if (flags & LONGLONG) 701 *va_arg(ap, long long *) = res; 702 else if (flags & INTMAXT) 703 *va_arg(ap, intmax_t *) = res; 704 else if (flags & PTRDIFFT) 705 *va_arg(ap, ptrdiff_t *) = res; 706 else if (flags & SIZET) 707 *va_arg(ap, size_t *) = res; 708 else 709 *va_arg(ap, int *) = res; 710 nassigned++; 711 } 712 nread += p - buf; 713 nconversions++; 714 break; 715 716#ifdef FLOATING_POINT 717 case CT_FLOAT: 718 /* scan a floating point number as if by strtod */ 719#ifdef hardway 720 if (width == 0 || width > sizeof(buf) - 1) 721 width = sizeof(buf) - 1; 722#else 723 /* size_t is unsigned, hence this optimisation */ 724 if (--width > sizeof(buf) - 2) 725 width = sizeof(buf) - 2; 726 width++; 727#endif 728 flags |= SIGNOK | NDIGITS | DPTOK | EXPOK; 729 for (p = buf; width; width--) { 730 c = *fp->_p; 731 /* 732 * This code mimicks the integer conversion 733 * code, but is much simpler. 734 */ 735 switch (c) { 736 737 case '0': case '1': case '2': case '3': 738 case '4': case '5': case '6': case '7': 739 case '8': case '9': 740 flags &= ~(SIGNOK | NDIGITS); 741 goto fok; 742 743 case '+': case '-': 744 if (flags & SIGNOK) { 745 flags &= ~SIGNOK; 746 goto fok; 747 } 748 break; 749 case 'e': case 'E': 750 /* no exponent without some digits */ 751 if ((flags&(NDIGITS|EXPOK)) == EXPOK) { 752 flags = 753 (flags & ~(EXPOK|DPTOK)) | 754 SIGNOK | NDIGITS; 755 goto fok; 756 } 757 break; 758 default: 759 if ((char)c == decimal_point && 760 (flags & DPTOK)) { 761 flags &= ~(SIGNOK | DPTOK); 762 goto fok; 763 } 764 break; 765 } 766 break; 767 fok: 768 *p++ = c; 769 if (--fp->_r > 0) 770 fp->_p++; 771 else if (__srefill(fp)) 772 break; /* EOF */ 773 } 774 /* 775 * If no digits, might be missing exponent digits 776 * (just give back the exponent) or might be missing 777 * regular digits, but had sign and/or decimal point. 778 */ 779 if (flags & NDIGITS) { 780 if (flags & EXPOK) { 781 /* no digits at all */ 782 while (p > buf) 783 __ungetc(*(u_char *)--p, fp); 784 goto match_failure; 785 } 786 /* just a bad exponent (e and maybe sign) */ 787 c = *(u_char *)--p; 788 if (c != 'e' && c != 'E') { 789 (void) __ungetc(c, fp);/* sign */ 790 c = *(u_char *)--p; 791 } 792 (void) __ungetc(c, fp); 793 } 794 if ((flags & SUPPRESS) == 0) { 795 double res; 796 797 *p = 0; 798 /* XXX this loses precision for long doubles. */ 799 res = strtod(buf, (char **) NULL); 800 if (flags & LONGDBL) 801 *va_arg(ap, long double *) = res; 802 else if (flags & LONG) 803 *va_arg(ap, double *) = res; 804 else 805 *va_arg(ap, float *) = res; 806 nassigned++; 807 } 808 nread += p - buf; 809 nconversions++; 810 break; 811#endif /* FLOATING_POINT */ 812 } 813 } 814input_failure: 815 return (nconversions != 0 ? nassigned : EOF); 816match_failure: 817 return (nassigned); 818} 819 820/* 821 * Fill in the given table from the scanset at the given format 822 * (just after `['). Return a pointer to the character past the 823 * closing `]'. The table has a 1 wherever characters should be 824 * considered part of the scanset. 825 */ 826static const u_char * 827__sccl(tab, fmt) 828 char *tab; 829 const u_char *fmt; 830{ 831 int c, n, v, i; 832 833 /* first `clear' the whole table */ 834 c = *fmt++; /* first char hat => negated scanset */ 835 if (c == '^') { 836 v = 1; /* default => accept */ 837 c = *fmt++; /* get new first char */ 838 } else 839 v = 0; /* default => reject */ 840 841 /* XXX: Will not work if sizeof(tab*) > sizeof(char) */ 842 (void) memset(tab, v, 256); 843 844 if (c == 0) 845 return (fmt - 1);/* format ended before closing ] */ 846 847 /* 848 * Now set the entries corresponding to the actual scanset 849 * to the opposite of the above. 850 * 851 * The first character may be ']' (or '-') without being special; 852 * the last character may be '-'. 853 */ 854 v = 1 - v; 855 for (;;) { 856 tab[c] = v; /* take character c */ 857doswitch: 858 n = *fmt++; /* and examine the next */ 859 switch (n) { 860 861 case 0: /* format ended too soon */ 862 return (fmt - 1); 863 864 case '-': 865 /* 866 * A scanset of the form 867 * [01+-] 868 * is defined as `the digit 0, the digit 1, 869 * the character +, the character -', but 870 * the effect of a scanset such as 871 * [a-zA-Z0-9] 872 * is implementation defined. The V7 Unix 873 * scanf treats `a-z' as `the letters a through 874 * z', but treats `a-a' as `the letter a, the 875 * character -, and the letter a'. 876 * 877 * For compatibility, the `-' is not considerd 878 * to define a range if the character following 879 * it is either a close bracket (required by ANSI) 880 * or is not numerically greater than the character 881 * we just stored in the table (c). 882 */ 883 n = *fmt; 884 if (n == ']' 885 || (__collate_load_error ? n < c : 886 __collate_range_cmp (n, c) < 0 887 ) 888 ) { 889 c = '-'; 890 break; /* resume the for(;;) */ 891 } 892 fmt++; 893 /* fill in the range */ 894 if (__collate_load_error) { 895 do { 896 tab[++c] = v; 897 } while (c < n); 898 } else { 899 for (i = 0; i < 256; i ++) 900 if ( __collate_range_cmp (c, i) < 0 901 && __collate_range_cmp (i, n) <= 0 902 ) 903 tab[i] = v; 904 } 905#if 1 /* XXX another disgusting compatibility hack */ 906 c = n; 907 /* 908 * Alas, the V7 Unix scanf also treats formats 909 * such as [a-c-e] as `the letters a through e'. 910 * This too is permitted by the standard.... 911 */ 912 goto doswitch; 913#else 914 c = *fmt++; 915 if (c == 0) 916 return (fmt - 1); 917 if (c == ']') 918 return (fmt); 919#endif 920 break; 921 922 case ']': /* end of scanset */ 923 return (fmt); 924 925 default: /* just another character */ 926 c = n; 927 break; 928 } 929 } 930 /* NOTREACHED */ 931} 932