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