1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1988 AT&T */ 28 /* All Rights Reserved */ 29 30 #pragma ident "%Z%%M% %I% %E% SMI" 31 32 #include "lint.h" 33 #include <sys/types.h> 34 #include "mtlib.h" 35 #include "file64.h" 36 #include <stdio.h> 37 #include <ctype.h> 38 #include <stdarg.h> 39 #include <values.h> 40 #include <errno.h> 41 #include <stdlib.h> 42 #include <string.h> 43 #include <math.h> 44 #include <thread.h> 45 #include <synch.h> 46 #include <stdlib.h> 47 #include <fnmatch.h> 48 #include <limits.h> 49 #include <wchar.h> 50 #include <unistd.h> 51 #include "libc.h" 52 #include "stdiom.h" 53 #include "xpg6.h" 54 55 #define NCHARS (1 << BITSPERBYTE) 56 57 /* if the _IOWRT flag is set, this must be a call from sscanf */ 58 #define locgetc(cnt) (cnt += 1, (iop->_flag & _IOWRT) ? \ 59 ((*iop->_ptr == '\0') ? EOF : *iop->_ptr++) : \ 60 GETC(iop)) 61 #define locungetc(cnt, x) (cnt -= 1, (x == EOF) ? EOF : \ 62 ((iop->_flag & _IOWRT) ? *(--iop->_ptr) : \ 63 (++iop->_cnt, *(--iop->_ptr)))) 64 65 #define wlocgetc() ((iop->_flag & _IOWRT) ? \ 66 ((*iop->_ptr == '\0') ? EOF : *iop->_ptr++) : \ 67 GETC(iop)) 68 #define wlocungetc(x) ((x == EOF) ? EOF : \ 69 ((iop->_flag & _IOWRT) ? *(--iop->_ptr) : \ 70 UNGETC(x, iop))) 71 72 #define MAXARGS 30 /* max. number of args for fast positional paramters */ 73 74 /* 75 * stva_list is used to subvert C's restriction that a variable with an 76 * array type can not appear on the left hand side of an assignment operator. 77 * By putting the array inside a structure, the functionality of assigning to 78 * the whole array through a simple assignment is achieved.. 79 */ 80 typedef struct stva_list { 81 va_list ap; 82 } stva_list; 83 84 static int number(int *, int *, int, int, int, int, FILE *, va_list *); 85 static int readchar(FILE *, int *); 86 static int string(int *, int *, int, int, int, char *, FILE *, va_list *); 87 static int wstring(int *, int *, int, int, int, FILE *, va_list *); 88 static int wbrstring(int *, int *, int, int, int, FILE *, 89 unsigned char *, va_list *); 90 #ifdef _WIDE 91 static int brstring(int *, int *, int, int, int, FILE *, 92 unsigned char *, va_list *); 93 #endif 94 static int _bi_getwc(FILE *); 95 static int _bi_ungetwc(wint_t, FILE *); 96 97 #ifdef _WIDE 98 static int _mkarglst(const wchar_t *, stva_list, stva_list[]); 99 static wint_t _wd_getwc(int *, FILE *); 100 static wint_t _wd_ungetwc(int *, wchar_t, FILE *); 101 static int _watoi(wchar_t *); 102 #else /* _WIDE */ 103 static int _mkarglst(const char *, stva_list, stva_list[]); 104 #endif /* _WIDE */ 105 106 #ifndef _WIDE 107 int 108 _doscan(FILE *iop, const char *fmt, va_list va_Alist) 109 { 110 int ret; 111 rmutex_t *lk; 112 113 if (iop->_flag & _IOWRT) 114 ret = __doscan_u(iop, fmt, va_Alist, 0); 115 else { 116 FLOCKFILE(lk, iop); 117 ret = __doscan_u(iop, fmt, va_Alist, 0); 118 FUNLOCKFILE(lk); 119 } 120 return (ret); 121 } 122 #endif /* _WIDE */ 123 124 /* ARGSUSED3 */ 125 #ifdef _WIDE 126 int 127 __wdoscan_u(FILE *iop, const wchar_t *fmt, va_list va_Alist, int scflag) 128 #else /* _WIDE */ 129 int 130 __doscan_u(FILE *iop, const char *sfmt, va_list va_Alist, int scflag) 131 #endif /* _WIDE */ 132 { 133 #ifdef _WIDE 134 wchar_t ch; 135 wchar_t inchar, size; 136 int nmatch = 0, len, stow; 137 #else /* _WIDE */ 138 int ch; 139 int nmatch = 0, len, inchar, stow, size; 140 #endif /* _WIDE */ 141 142 unsigned char *bracket_str = NULL; 143 int chcount, flag_eof; 144 char tab[NCHARS]; 145 146 /* variables for postional parameters */ 147 #ifdef _WIDE 148 const wchar_t *sformat = fmt; /* save the beginning of the format */ 149 #else /* _WIDE */ 150 const unsigned char *fmt = (const unsigned char *)sfmt; 151 const char *sformat = sfmt; /* save the beginning of the format */ 152 #endif /* _WIDE */ 153 int fpos = 1; /* 1 if first postional parameter */ 154 stva_list args, /* used to step through the argument list */ 155 sargs; /* used to save the start of the argument list */ 156 stva_list arglst[MAXARGS]; 157 /* 158 * array giving the appropriate values 159 * for va_arg() to retrieve the 160 * corresponding argument: 161 * arglst[0] is the first argument 162 * arglst[1] is the second argument,etc. 163 */ 164 /* Check if readable stream */ 165 if (!(iop->_flag & (_IOREAD | _IORW))) { 166 errno = EBADF; 167 return (EOF); 168 } 169 170 /* 171 * Initialize args and sargs to the start of the argument list. 172 * We don't know any portable way to copy an arbitrary C object 173 * so we use a system-specific routine(probably a macro) from 174 * stdarg.h. (Remember that if va_list is an array, in_args will 175 * be a pointer and &in_args won't be what we would want for 176 * memcpy.) 177 */ 178 va_copy(args.ap, va_Alist); 179 180 sargs = args; 181 182 chcount = 0; flag_eof = 0; 183 184 /* 185 * **************************************************** 186 * Main loop: reads format to determine a pattern, 187 * and then goes to read input stream 188 * in attempt to match the pattern. 189 * **************************************************** 190 */ 191 for (; ; ) { 192 if ((ch = *fmt++) == '\0') { 193 return (nmatch); /* end of format */ 194 } 195 #ifdef _WIDE 196 if (iswspace(ch)) { 197 if (!flag_eof) { 198 while (iswspace(inchar = 199 _wd_getwc(&chcount, iop))) 200 ; 201 if (_wd_ungetwc(&chcount, inchar, iop) == WEOF) 202 flag_eof = 1; 203 } 204 continue; 205 } 206 if (ch != '%' || (ch = *fmt++) == '%') { 207 if ((inchar = _wd_getwc(&chcount, iop)) == ch) 208 continue; 209 if (_wd_ungetwc(&chcount, inchar, iop) != WEOF) { 210 return (nmatch); /* failed to match input */ 211 } 212 break; 213 } 214 #else /* _WIDE */ 215 if (isspace(ch)) { 216 if (!flag_eof) { 217 while (isspace(inchar = locgetc(chcount))) 218 ; 219 if (locungetc(chcount, inchar) == EOF) 220 flag_eof = 1; 221 222 } 223 continue; 224 } 225 if (ch != '%' || (ch = *fmt++) == '%') { 226 if ((inchar = locgetc(chcount)) == ch) 227 continue; 228 if (locungetc(chcount, inchar) != EOF) { 229 return (nmatch); /* failed to match input */ 230 } 231 break; 232 } 233 #endif /* _WIDE */ 234 235 charswitch: /* target of a goto 8-( */ 236 237 if (ch == '*') { 238 stow = 0; 239 ch = *fmt++; 240 } else 241 stow = 1; 242 243 #ifdef _WIDE 244 for (len = 0; ((ch >= 0) && (ch < 256) && isdigit(ch)); 245 ch = *fmt++) 246 len = len * 10 + ch - '0'; 247 #else /* _WIDE */ 248 for (len = 0; isdigit(ch); ch = *fmt++) 249 len = len * 10 + ch - '0'; 250 #endif /* _WIDE */ 251 252 if (ch == '$') { 253 /* 254 * positional parameter handling - the number 255 * specified in len gives the argument to which 256 * the next conversion should be applied. 257 * WARNING: This implementation of positional 258 * parameters assumes that the sizes of all pointer 259 * types are the same. (Code similar to that 260 * in the portable doprnt.c should be used if this 261 * assumption does not hold for a particular 262 * port.) 263 */ 264 if (fpos) { 265 if (_mkarglst(sformat, sargs, arglst) != 0) { 266 return (EOF); 267 } else { 268 fpos = 0; 269 } 270 } 271 if (len <= MAXARGS) { 272 args = arglst[len - 1]; 273 } else { 274 args = arglst[MAXARGS - 1]; 275 for (len -= MAXARGS; len > 0; len--) 276 (void) va_arg(args.ap, void *); 277 } 278 len = 0; 279 ch = *fmt++; 280 goto charswitch; 281 } 282 283 if (len == 0) 284 len = MAXINT; 285 #ifdef _WIDE 286 if ((size = ch) == 'l' || (size == 'h') || (size == 'L') || 287 (size == 'j') || (size == 't') || (size == 'z')) 288 ch = *fmt++; 289 #else /* _WIDE */ 290 if ((size = ch) == 'l' || (size == 'h') || (size == 'L') || 291 (size == 'w') || (size == 'j') || (size == 't') || 292 (size == 'z')) 293 ch = *fmt++; 294 #endif /* _WIDE */ 295 if (size == 'l' && ch == 'l') { 296 size = 'm'; /* size = 'm' if long long */ 297 ch = *fmt++; 298 } else if (size == 'h' && ch == 'h') { 299 size = 'b'; /* use size = 'b' if char */ 300 ch = *fmt++; 301 } else if ((size == 't') || (size == 'z')) { 302 size = 'l'; 303 } else if (size == 'j') { 304 #ifndef _LP64 305 /* check scflag for size of u/intmax_t (32-bit libc) */ 306 if (!(scflag & _F_INTMAX32)) 307 { 308 #endif 309 size = 'm'; 310 #ifndef _LP64 311 } 312 #endif 313 } 314 if (ch == '\0') { 315 return (EOF); /* unexpected end of format */ 316 } 317 #ifdef _WIDE 318 if (ch == '[') { 319 wchar_t c; 320 size_t len; 321 int negflg = 0; 322 wchar_t *p; 323 wchar_t *wbracket_str; 324 size_t wlen, clen; 325 326 /* p points to the address of '[' */ 327 p = (wchar_t *)fmt - 1; 328 len = 0; 329 if (*fmt == '^') { 330 len++; 331 fmt++; 332 negflg = 1; 333 } 334 if (((c = *fmt) == ']') || (c == '-')) { 335 len++; 336 fmt++; 337 } 338 while ((c = *fmt) != ']') { 339 if (c == '\0') { 340 return (EOF); /* unexpected EOF */ 341 } else { 342 len++; 343 fmt++; 344 } 345 } 346 fmt++; 347 len += 2; 348 wbracket_str = (wchar_t *) 349 malloc(sizeof (wchar_t) * (len + 1)); 350 if (wbracket_str == NULL) { 351 errno = ENOMEM; 352 return (EOF); 353 } else { 354 (void) wmemcpy(wbracket_str, 355 (const wchar_t *)p, len); 356 *(wbracket_str + len) = L'\0'; 357 if (negflg && *(wbracket_str + 1) == '^') { 358 *(wbracket_str + 1) = L'!'; 359 } 360 } 361 wlen = wcslen(wbracket_str); 362 clen = wcstombs((char *)NULL, wbracket_str, 0); 363 if (clen == (size_t)-1) { 364 free(wbracket_str); 365 return (EOF); 366 } 367 bracket_str = (unsigned char *) 368 malloc(sizeof (unsigned char) * (clen + 1)); 369 if (bracket_str == NULL) { 370 free(wbracket_str); 371 errno = ENOMEM; 372 return (EOF); 373 } 374 clen = wcstombs((char *)bracket_str, wbracket_str, 375 wlen + 1); 376 free(wbracket_str); 377 if (clen == (size_t)-1) { 378 free(bracket_str); 379 return (EOF); 380 } 381 } 382 #else /* _WIDE */ 383 if (ch == '[') { 384 if (size == 'l') { 385 int c, len, i; 386 int negflg = 0; 387 unsigned char *p; 388 389 p = (unsigned char *)(fmt - 1); 390 len = 0; 391 if (*fmt == '^') { 392 len++; 393 fmt++; 394 negflg = 1; 395 } 396 if (((c = *fmt) == ']') || (c == '-')) { 397 len++; 398 fmt++; 399 } 400 while ((c = *fmt) != ']') { 401 if (c == '\0') { 402 return (EOF); 403 } else if (isascii(c)) { 404 len++; 405 fmt++; 406 } else { 407 i = mblen((const char *)fmt, 408 MB_CUR_MAX); 409 if (i <= 0) { 410 return (EOF); 411 } else { 412 len += i; 413 fmt += i; 414 } 415 } 416 } 417 fmt++; 418 len += 2; 419 bracket_str = (unsigned char *) 420 malloc(sizeof (unsigned char) * 421 (len + 1)); 422 if (bracket_str == NULL) { 423 errno = ENOMEM; 424 return (EOF); 425 } else { 426 (void) strncpy((char *)bracket_str, 427 (const char *)p, len); 428 *(bracket_str + len) = '\0'; 429 if (negflg && 430 *(bracket_str + 1) == '^') { 431 *(bracket_str + 1) = '!'; 432 } 433 } 434 } else { 435 int t = 0; 436 int b, c, d; 437 438 if (*fmt == '^') { 439 t++; 440 fmt++; 441 } 442 (void) memset(tab, !t, NCHARS); 443 if ((c = *fmt) == ']' || c == '-') { 444 tab[c] = t; 445 fmt++; 446 } 447 448 while ((c = *fmt) != ']') { 449 if (c == '\0') { 450 return (EOF); 451 } 452 b = *(fmt - 1); 453 d = *(fmt + 1); 454 if ((c == '-') && (d != ']') && 455 (b < d)) { 456 (void) memset(&tab[b], t, 457 d - b + 1); 458 fmt += 2; 459 } else { 460 tab[c] = t; 461 fmt++; 462 } 463 } 464 fmt++; 465 } 466 } 467 #endif /* _WIDE */ 468 469 #ifdef _WIDE 470 if ((ch >= 0) && (ch < 256) && 471 isupper((int)ch)) { /* no longer documented */ 472 if (_lib_version == c_issue_4) { 473 if (size != 'm' && size != 'L') 474 size = 'l'; 475 } 476 ch = _tolower((int)ch); 477 } 478 if (ch != 'n' && !flag_eof) { 479 if (ch != 'c' && ch != 'C' && ch != '[') { 480 while (iswspace(inchar = 481 _wd_getwc(&chcount, iop))) 482 ; 483 if (_wd_ungetwc(&chcount, inchar, iop) == WEOF) 484 break; 485 486 } 487 } 488 #else /* _WIDE */ 489 if (isupper(ch)) { /* no longer documented */ 490 if (_lib_version == c_issue_4) { 491 if (size != 'm' && size != 'L') 492 size = 'l'; 493 } 494 ch = _tolower(ch); 495 } 496 if (ch != 'n' && !flag_eof) { 497 if (ch != 'c' && ch != 'C' && ch != '[') { 498 while (isspace(inchar = locgetc(chcount))) 499 ; 500 if (locungetc(chcount, inchar) == EOF) 501 break; 502 } 503 } 504 #endif /* _WIDE */ 505 506 switch (ch) { 507 case 'C': 508 case 'S': 509 case 'c': 510 case 's': 511 #ifdef _WIDE 512 if ((size == 'l') || (size == 'C') || (size == 'S')) 513 #else /* _WIDE */ 514 if ((size == 'w') || (size == 'l') || (size == 'C') || 515 (size == 'S')) 516 #endif /* _WIDE */ 517 { 518 size = wstring(&chcount, &flag_eof, stow, 519 (int)ch, len, iop, &args.ap); 520 } else { 521 size = string(&chcount, &flag_eof, stow, 522 (int)ch, len, tab, iop, &args.ap); 523 } 524 break; 525 case '[': 526 if (size == 'l') { 527 size = wbrstring(&chcount, &flag_eof, stow, 528 (int)ch, len, iop, bracket_str, 529 &args.ap); 530 free(bracket_str); 531 bracket_str = NULL; 532 } else { 533 #ifdef _WIDE 534 size = brstring(&chcount, &flag_eof, stow, 535 (int)ch, len, iop, bracket_str, 536 &args.ap); 537 free(bracket_str); 538 bracket_str = NULL; 539 #else /* _WIDE */ 540 size = string(&chcount, &flag_eof, stow, 541 ch, len, tab, iop, &args.ap); 542 #endif /* _WIDE */ 543 } 544 break; 545 546 case 'n': 547 if (stow == 0) 548 continue; 549 if (size == 'b') /* char */ 550 *va_arg(args.ap, char *) = (char)chcount; 551 else if (size == 'h') 552 *va_arg(args.ap, short *) = (short)chcount; 553 else if (size == 'l') 554 *va_arg(args.ap, long *) = (long)chcount; 555 else if (size == 'm') /* long long */ 556 *va_arg(args.ap, long long *) = 557 (long long) chcount; 558 else 559 *va_arg(args.ap, int *) = (int)chcount; 560 continue; 561 562 case 'i': 563 default: 564 size = number(&chcount, &flag_eof, stow, (int)ch, 565 len, (int)size, iop, &args.ap); 566 break; 567 } 568 if (size) 569 nmatch += stow; 570 else { 571 return ((flag_eof && !nmatch) ? EOF : nmatch); 572 } 573 continue; 574 } 575 if (bracket_str) 576 free(bracket_str); 577 return (nmatch != 0 ? nmatch : EOF); /* end of input */ 578 } 579 580 /* ****************************************************************** */ 581 /* Functions to read the input stream in an attempt to match incoming */ 582 /* data to the current pattern from the main loop of _doscan(). */ 583 /* ****************************************************************** */ 584 static int 585 number(int *chcount, int *flag_eof, int stow, int type, int len, int size, 586 FILE *iop, va_list *listp) 587 { 588 char numbuf[64]; 589 char *np = numbuf; 590 int c, base, inchar, lookahead; 591 int digitseen = 0, floater = 0, negflg = 0; 592 int lc; 593 long long lcval = 0LL; 594 595 switch (type) { 596 case 'e': 597 case 'f': 598 case 'g': 599 /* 600 * lc = 0 corresponds to c90 mode: do not recognize 601 * hexadecimal fp strings; attempt to push back 602 * all unused characters read 603 * 604 * lc = -1 corresponds to c99 mode: recognize hexa- 605 * decimal fp strings; push back at most one 606 * unused character 607 */ 608 lc = (__xpg6 & _C99SUSv3_recognize_hexfp)? -1 : 0; 609 floater = 1; 610 break; 611 612 case 'a': 613 lc = -1; 614 floater = 1; 615 break; 616 617 case 'd': 618 case 'u': 619 case 'i': 620 base = 10; 621 break; 622 case 'o': 623 base = 8; 624 break; 625 case 'p': 626 #ifdef _LP64 627 size = 'l'; /* pointers are long in LP64 */ 628 #endif /* _LP64 */ 629 /* FALLTHROUGH */ 630 case 'x': 631 base = 16; 632 break; 633 default: 634 return (0); /* unrecognized conversion character */ 635 } 636 637 if (floater != 0) { 638 /* 639 * Handle floating point with 640 * file_to_decimal. 641 */ 642 decimal_mode dm; 643 decimal_record dr; 644 fp_exception_field_type efs; 645 enum decimal_string_form form; 646 char *echar; 647 int nread; 648 char buffer[1024+1]; 649 char *nb = buffer; 650 651 if (len > 1024) 652 len = 1024; 653 file_to_decimal(&nb, len, lc, &dr, &form, &echar, iop, &nread); 654 if (lc == -1) { 655 /* 656 * In C99 mode, the entire string read has to be 657 * accepted in order to qualify as a match 658 */ 659 if (nb != buffer + nread) 660 form = invalid_form; 661 } 662 if (stow && (form != invalid_form)) { 663 #if defined(__sparc) 664 dm.rd = _QgetRD(); 665 if (size == 'L') { /* long double */ 666 if ((int)form < 0) 667 __hex_to_quadruple(&dr, dm.rd, 668 va_arg(*listp, quadruple *), 669 &efs); 670 else 671 decimal_to_quadruple( 672 va_arg(*listp, quadruple *), 673 &dm, &dr, &efs); 674 } 675 #elif defined(__i386) || defined(__amd64) 676 dm.rd = __xgetRD(); 677 if (size == 'L') { /* long double */ 678 if ((int)form < 0) 679 __hex_to_extended(&dr, dm.rd, 680 va_arg(*listp, extended *), 681 &efs); 682 else 683 decimal_to_extended( 684 va_arg(*listp, extended *), 685 &dm, &dr, &efs); 686 } 687 #else 688 #error Unknown architecture 689 #endif 690 else if (size == 'l') { /* double */ 691 if ((int)form < 0) 692 __hex_to_double(&dr, dm.rd, 693 va_arg(*listp, double *), &efs); 694 else 695 decimal_to_double( 696 va_arg(*listp, double *), 697 &dm, &dr, &efs); 698 } else { /* float */ 699 if ((int)form < 0) 700 __hex_to_single(&dr, dm.rd, 701 va_arg(*listp, single *), &efs); 702 else 703 decimal_to_single((single *) 704 va_arg(*listp, single *), 705 &dm, &dr, &efs); 706 } 707 if ((efs & (1 << fp_overflow)) != 0) { 708 errno = ERANGE; 709 } 710 if ((efs & (1 << fp_underflow)) != 0) { 711 errno = ERANGE; 712 } 713 } 714 (*chcount) += nread; /* Count characters read. */ 715 c = locgetc((*chcount)); 716 if (locungetc((*chcount), c) == EOF) 717 *flag_eof = 1; 718 return ((form == invalid_form) ? 0 : 1); 719 /* successful match if non-zero */ 720 } 721 722 switch (c = locgetc((*chcount))) { 723 case '-': 724 negflg++; 725 /* FALLTHROUGH */ 726 case '+': 727 if (--len <= 0) 728 break; 729 if ((c = locgetc((*chcount))) != '0') 730 break; 731 /* FALLTHROUGH */ 732 case '0': 733 /* 734 * If %i or %x, the characters 0x or 0X may optionally precede 735 * the sequence of letters and digits (base 16). 736 */ 737 if ((type != 'i' && type != 'x') || (len <= 1)) 738 break; 739 if (((inchar = locgetc((*chcount))) == 'x') || 740 (inchar == 'X')) { 741 lookahead = readchar(iop, chcount); 742 if (isxdigit(lookahead)) { 743 base = 16; 744 745 if (len <= 2) { 746 (void) locungetc((*chcount), lookahead); 747 /* Take into account the 'x' */ 748 len -= 1; 749 } else { 750 c = lookahead; 751 /* Take into account '0x' */ 752 len -= 2; 753 } 754 } else { 755 (void) locungetc((*chcount), lookahead); 756 (void) locungetc((*chcount), inchar); 757 } 758 } else { 759 /* inchar wans't 'x'. */ 760 (void) locungetc((*chcount), inchar); /* Put it back. */ 761 if (type == 'i') /* Only %i accepts an octal. */ 762 base = 8; 763 } 764 } 765 for (; --len >= 0; *np++ = (char)c, c = locgetc((*chcount))) { 766 if (np > numbuf + 62) { 767 errno = ERANGE; 768 return (0); 769 } 770 if (isdigit(c) || base == 16 && isxdigit(c)) { 771 int digit = c - (isdigit(c) ? '0' : 772 isupper(c) ? 'A' - 10 : 'a' - 10); 773 if (digit >= base) 774 break; 775 if (stow) 776 lcval = base * lcval + digit; 777 digitseen++; 778 continue; 779 } 780 break; 781 } 782 783 if (stow && digitseen) { 784 /* suppress possible overflow on 2's-comp negation */ 785 if (negflg && lcval != (1ULL << 63)) 786 lcval = -lcval; 787 switch (size) { 788 case 'm': 789 *va_arg(*listp, long long *) = lcval; 790 break; 791 case 'l': 792 *va_arg(*listp, long *) = (long)lcval; 793 break; 794 case 'h': 795 *va_arg(*listp, short *) = (short)lcval; 796 break; 797 case 'b': 798 *va_arg(*listp, char *) = (char)lcval; 799 break; 800 default: 801 *va_arg(*listp, int *) = (int)lcval; 802 break; 803 } 804 } 805 if (locungetc((*chcount), c) == EOF) 806 *flag_eof = 1; 807 return (digitseen); /* successful match if non-zero */ 808 } 809 810 /* Get a character. If not using sscanf and at the buffer's end */ 811 /* then do a direct read(). Characters read via readchar() */ 812 /* can be pushed back on the input stream by locungetc((*chcount),) */ 813 /* since there is padding allocated at the end of the stream buffer. */ 814 static int 815 readchar(FILE *iop, int *chcount) 816 { 817 int inchar; 818 char buf[1]; 819 820 if ((iop->_flag & _IOWRT) || (iop->_cnt != 0)) 821 inchar = locgetc((*chcount)); 822 else { 823 if (read(FILENO(iop), buf, 1) != 1) 824 return (EOF); 825 inchar = (int)buf[0]; 826 (*chcount) += 1; 827 } 828 return (inchar); 829 } 830 831 static int 832 string(int *chcount, int *flag_eof, int stow, int type, int len, char *tab, 833 FILE *iop, va_list *listp) 834 { 835 int ch; 836 char *ptr; 837 char *start; 838 839 start = ptr = stow ? va_arg(*listp, char *) : NULL; 840 if (((type == 'c') || (type == 'C')) && len == MAXINT) 841 len = 1; 842 #ifdef _WIDE 843 while ((ch = locgetc((*chcount))) != EOF && 844 !(((type == 's') || (type == 'S')) && isspace(ch))) { 845 #else /* _WIDE */ 846 while ((ch = locgetc((*chcount))) != EOF && 847 !(((type == 's') || (type == 'S')) && 848 isspace(ch) || type == '[' && tab[ch])) { 849 #endif /* _WIDE */ 850 if (stow) 851 *ptr = (char)ch; 852 ptr++; 853 if (--len <= 0) 854 break; 855 } 856 if (ch == EOF) { 857 (*flag_eof) = 1; 858 (*chcount) -= 1; 859 } else if (len > 0 && locungetc((*chcount), ch) == EOF) 860 (*flag_eof) = 1; 861 if (ptr == start) 862 return (0); /* no match */ 863 if (stow && ((type != 'c') && (type != 'C'))) 864 *ptr = '\0'; 865 return (1); /* successful match */ 866 } 867 868 /* This function initializes arglst, to contain the appropriate */ 869 /* va_list values for the first MAXARGS arguments. */ 870 /* WARNING: this code assumes that the sizes of all pointer types */ 871 /* are the same. (Code similar to that in the portable doprnt.c */ 872 /* should be used if this assumption is not true for a */ 873 /* particular port.) */ 874 875 #ifdef _WIDE 876 static int 877 _mkarglst(const wchar_t *fmt, stva_list args, stva_list arglst[]) 878 #else /* _WIDE */ 879 static int 880 _mkarglst(const char *fmt, stva_list args, stva_list arglst[]) 881 #endif /* _WIDE */ 882 { 883 #ifdef _WIDE 884 #define STRCHR wcschr 885 #define STRSPN wcsspn 886 #define ATOI(x) _watoi((wchar_t *)x) 887 #define SPNSTR1 L"01234567890" 888 #define SPNSTR2 L"# +-.0123456789hL$" 889 #else /* _WIDE */ 890 #define STRCHR strchr 891 #define STRSPN strspn 892 #define ATOI(x) atoi(x) 893 #define SPNSTR1 "01234567890" 894 #define SPNSTR2 "# +-.0123456789hL$" 895 #endif /* _WIDE */ 896 897 int maxnum, curargno; 898 size_t n; 899 900 maxnum = -1; 901 curargno = 0; 902 903 while ((fmt = STRCHR(fmt, '%')) != NULL) { 904 fmt++; /* skip % */ 905 if (*fmt == '*' || *fmt == '%') 906 continue; 907 if (fmt[n = STRSPN(fmt, SPNSTR1)] == L'$') { 908 /* convert to zero base */ 909 curargno = ATOI(fmt) - 1; 910 fmt += n + 1; 911 } 912 913 if (maxnum < curargno) 914 maxnum = curargno; 915 curargno++; /* default to next in list */ 916 917 fmt += STRSPN(fmt, SPNSTR2); 918 if (*fmt == '[') { 919 int i; 920 fmt++; /* has to be at least on item in scan list */ 921 if (*fmt == ']') { 922 fmt++; 923 } 924 while (*fmt != ']') { 925 if (*fmt == L'\0') { 926 return (-1); /* bad format */ 927 #ifdef _WIDE 928 } else { 929 fmt++; 930 } 931 #else /* _WIDE */ 932 } else if (isascii(*fmt)) { 933 fmt++; 934 } else { 935 i = mblen((const char *) 936 fmt, MB_CUR_MAX); 937 if (i <= 0) { 938 return (-1); 939 } else { 940 fmt += i; 941 } 942 } 943 #endif /* _WIDE */ 944 } 945 } 946 } 947 if (maxnum > MAXARGS) 948 maxnum = MAXARGS; 949 for (n = 0; n <= maxnum; n++) { 950 arglst[n] = args; 951 (void) va_arg(args.ap, void *); 952 } 953 return (0); 954 } 955 956 957 /* 958 * For wide character handling 959 */ 960 #ifdef _WIDE 961 static int 962 wstring(int *chcount, int *flag_eof, int stow, int type, 963 int len, FILE *iop, va_list *listp) 964 { 965 wint_t wch; 966 wchar_t *ptr; 967 wchar_t *wstart; 968 int dummy; 969 970 wstart = ptr = stow ? va_arg(*listp, wchar_t *) : NULL; 971 972 if ((type == 'c') && len == MAXINT) 973 len = 1; 974 while (((wch = _wd_getwc(chcount, iop)) != WEOF) && 975 !(type == 's' && iswspace(wch))) { 976 if (stow) 977 *ptr = wch; 978 ptr++; 979 if (--len <= 0) 980 break; 981 } 982 if (wch == WEOF) { 983 *flag_eof = 1; 984 (*chcount) -= 1; 985 } else { 986 if (len > 0 && _wd_ungetwc(chcount, wch, iop) == WEOF) 987 *flag_eof = 1; 988 } 989 if (ptr == wstart) 990 return (0); /* no match */ 991 if (stow && (type != 'c')) 992 *ptr = '\0'; 993 return (1); /* successful match */ 994 } 995 #else /* _WIDE */ 996 static int 997 wstring(int *chcount, int *flag_eof, int stow, int type, int len, FILE *iop, 998 va_list *listp) 999 { 1000 int wch; 1001 wchar_t *ptr; 1002 wchar_t *wstart; 1003 1004 wstart = ptr = stow ? va_arg(*listp, wchar_t *) : NULL; 1005 1006 if ((type == 'c') && len == MAXINT) 1007 len = 1; 1008 while (((wch = _bi_getwc(iop)) != EOF) && 1009 !(type == 's' && (isascii(wch) ? isspace(wch) : 0))) { 1010 (*chcount) += _scrwidth((wchar_t)wch); 1011 if (stow) 1012 *ptr = wch; 1013 ptr++; 1014 if (--len <= 0) 1015 break; 1016 } 1017 if (wch == EOF) { 1018 (*flag_eof) = 1; 1019 (*chcount) -= 1; 1020 } else { 1021 if (len > 0 && _bi_ungetwc(wch, iop) == EOF) 1022 (*flag_eof) = 1; 1023 } 1024 if (ptr == wstart) 1025 return (0); /* no match */ 1026 if (stow && (type != 'c')) 1027 *ptr = '\0'; 1028 return (1); /* successful match */ 1029 } 1030 #endif /* _WIDE */ 1031 1032 #ifdef _WIDE 1033 static wint_t 1034 _wd_getwc(int *chcount, FILE *iop) 1035 { 1036 wint_t wc; 1037 int len; 1038 1039 if (!(iop->_flag & _IOWRT)) { 1040 /* call from fwscanf, wscanf */ 1041 wc = __fgetwc_xpg5(iop); 1042 (*chcount)++; 1043 return (wc); 1044 } else { 1045 /* call from swscanf */ 1046 if (*iop->_ptr == '\0') 1047 return (WEOF); 1048 len = mbtowc((wchar_t *)&wc, (const char *)iop->_ptr, 1049 MB_CUR_MAX); 1050 if (len == -1) 1051 return (WEOF); 1052 iop->_ptr += len; 1053 (*chcount)++; 1054 return (wc); 1055 } 1056 } 1057 1058 static wint_t 1059 _wd_ungetwc(int *chcount, wchar_t wc, FILE *iop) 1060 { 1061 wint_t ret; 1062 int len; 1063 char mbs[MB_LEN_MAX]; 1064 1065 if (wc == WEOF) 1066 return (WEOF); 1067 1068 if (!(iop->_flag & _IOWRT)) { 1069 /* call from fwscanf, wscanf */ 1070 ret = __ungetwc_xpg5((wint_t)wc, iop); 1071 if (ret != (wint_t)wc) 1072 return (WEOF); 1073 (*chcount)--; 1074 return (ret); 1075 } else { 1076 /* call from swscanf */ 1077 len = wctomb(mbs, wc); 1078 if (len == -1) 1079 return (WEOF); 1080 iop->_ptr -= len; 1081 (*chcount)--; 1082 return ((wint_t)wc); 1083 } 1084 } 1085 1086 static int 1087 _watoi(wchar_t *fmt) 1088 { 1089 int n = 0; 1090 wchar_t ch; 1091 1092 ch = *fmt; 1093 if ((ch >= 0) && (ch < 256) && isdigit((int)ch)) { 1094 n = ch - '0'; 1095 while (((ch = *++fmt) >= 0) && (ch < 256) && 1096 isdigit((int)ch)) { 1097 n *= 10; 1098 n += ch - '0'; 1099 } 1100 } 1101 return (n); 1102 } 1103 #endif /* _WIDE */ 1104 1105 /* ARGSUSED3 */ 1106 static int 1107 wbrstring(int *chcount, int *flag_eof, int stow, int type, 1108 int len, FILE *iop, unsigned char *brstr, va_list *listp) 1109 { 1110 wint_t wch; 1111 int i; 1112 char str[MB_LEN_MAX + 1]; /* include null termination */ 1113 wchar_t *ptr, *start; 1114 #ifdef _WIDE 1115 int dummy; 1116 #endif /* _WIDE */ 1117 1118 start = ptr = stow ? va_arg(*listp, wchar_t *) : NULL; 1119 1120 #ifdef _WIDE 1121 while ((wch = _wd_getwc(&dummy, iop)) != WEOF) { 1122 #else /* _WIDE */ 1123 while ((wch = _bi_getwc(iop)) != WEOF) { 1124 #endif /* _WIDE */ 1125 i = wctomb(str, (wchar_t)wch); 1126 if (i == -1) { 1127 return (0); 1128 } 1129 str[i] = '\0'; 1130 if (fnmatch((const char *)brstr, (const char *)str, 1131 FNM_NOESCAPE)) { 1132 break; 1133 } else { 1134 if (len > 0) { 1135 #ifdef _WIDE 1136 (*chcount)++; 1137 #else /* _WIDE */ 1138 (*chcount) += _scrwidth(wch); 1139 #endif /* _WIDE */ 1140 len--; 1141 if (stow) { 1142 *ptr = wch; 1143 } 1144 ptr++; 1145 if (len <= 0) 1146 break; 1147 } else { 1148 break; 1149 } 1150 } 1151 } 1152 if (wch == WEOF) { 1153 *flag_eof = 1; 1154 } else { 1155 #ifdef _WIDE 1156 if (len > 0 && _wd_ungetwc(&dummy, wch, iop) == WEOF) 1157 #else /* _WIDE */ 1158 if (len > 0 && _bi_ungetwc(wch, iop) == WEOF) 1159 #endif /* _WIDE */ 1160 *flag_eof = 1; 1161 } 1162 if (ptr == start) 1163 return (0); /* no match */ 1164 if (stow) 1165 *ptr = L'\0'; 1166 return (1); /* successful match */ 1167 } 1168 1169 #ifdef _WIDE 1170 static int 1171 brstring(int *chcount, int *flag_eof, int stow, int type, 1172 int len, FILE *iop, unsigned char *brstr, va_list *listp) 1173 { 1174 wint_t wch; 1175 int i; 1176 char str[MB_LEN_MAX + 1]; /* include null termination */ 1177 char *ptr, *start, *p; 1178 int dummy; 1179 1180 start = ptr = stow ? va_arg(*listp, char *) : NULL; 1181 1182 while ((wch = _wd_getwc(&dummy, iop)) != WEOF) { 1183 p = str; 1184 i = wctomb(str, (wchar_t)wch); 1185 if (i == -1) { 1186 return (0); 1187 } 1188 str[i] = '\0'; 1189 if (fnmatch((const char *)brstr, (const char *)str, 1190 FNM_NOESCAPE)) { 1191 break; 1192 } else { 1193 if (len >= i) { 1194 (*chcount)++; 1195 len -= i; 1196 if (stow) { 1197 while (i-- > 0) { 1198 *ptr++ = *p++; 1199 } 1200 } else { 1201 while (i-- > 0) { 1202 ptr++; 1203 } 1204 } 1205 if (len <= 0) 1206 break; 1207 } else { 1208 break; 1209 } 1210 } 1211 } 1212 if (wch == WEOF) { 1213 *flag_eof = 1; 1214 } else { 1215 if (len > 0 && _wd_ungetwc(&dummy, wch, iop) == WEOF) 1216 *flag_eof = 1; 1217 } 1218 if (ptr == start) 1219 return (0); /* no match */ 1220 if (stow) 1221 *ptr = '\0'; 1222 return (1); /* successful match */ 1223 } 1224 #endif /* _WIDE */ 1225 1226 /* 1227 * Locally define getwc and ungetwc 1228 */ 1229 static int 1230 _bi_getwc(FILE *iop) 1231 { 1232 int c; 1233 wchar_t intcode; 1234 int i, nbytes, cur_max; 1235 char buff[MB_LEN_MAX]; 1236 1237 if ((c = wlocgetc()) == EOF) 1238 return (WEOF); 1239 1240 if (isascii(c)) /* ASCII code */ 1241 return ((wint_t)c); 1242 1243 buff[0] = (char)c; 1244 1245 cur_max = (int)MB_CUR_MAX; 1246 /* MB_CUR_MAX doen't exeed the value of MB_LEN_MAX */ 1247 /* So we use MB_CUR_MAX instead of MB_LEN_MAX for */ 1248 /* improving the performance. */ 1249 for (i = 1; i < cur_max; i++) { 1250 c = wlocgetc(); 1251 if (c == '\n') { 1252 (void) wlocungetc(c); 1253 break; 1254 } 1255 if (c == EOF) { 1256 /* this still may be a valid multibyte character */ 1257 break; 1258 } 1259 buff[i] = (char)c; 1260 } 1261 1262 if ((nbytes = mbtowc(&intcode, buff, i)) == -1) { 1263 /* 1264 * If mbtowc fails, the input was not a legal character. 1265 * ungetc all but one character. 1266 * 1267 * Note: the number of pushback characters that 1268 * ungetc() can handle must be >= (MB_LEN_MAX - 1). 1269 * In Solaris 2.x, the number of pushback 1270 * characters is 4. 1271 */ 1272 while (i-- > 1) { 1273 (void) wlocungetc((signed char)buff[i]); 1274 } 1275 errno = EILSEQ; 1276 return (WEOF); /* Illegal EUC sequence. */ 1277 } 1278 1279 while (i-- > nbytes) { 1280 /* 1281 * Note: the number of pushback characters that 1282 * ungetc() can handle must be >= (MB_LEN_MAX - 1). 1283 * In Solaris 2.x, the number of pushback 1284 * characters is 4. 1285 */ 1286 (void) wlocungetc((signed char)buff[i]); 1287 } 1288 return ((int)intcode); 1289 } 1290 1291 static int 1292 _bi_ungetwc(wint_t wc, FILE *iop) 1293 { 1294 char mbs[MB_LEN_MAX]; 1295 unsigned char *p; 1296 int n; 1297 1298 if ((wc == WEOF) || ((iop->_flag & _IOREAD) == 0)) 1299 return (WEOF); 1300 1301 n = wctomb(mbs, (wchar_t)wc); 1302 if (n <= 0) 1303 return (WEOF); 1304 1305 if (iop->_ptr <= iop->_base) { 1306 if (iop->_base == NULL) { 1307 return (WEOF); 1308 } 1309 if ((iop->_ptr == iop->_base) && (iop->_cnt == 0)) { 1310 ++iop->_ptr; 1311 } else if ((iop->_ptr - n) < (iop->_base - PUSHBACK)) { 1312 return (WEOF); 1313 } 1314 } 1315 1316 p = (unsigned char *)(mbs+n-1); /* p points the last byte */ 1317 /* if _IOWRT is set to iop->_flag, it means this is */ 1318 /* an invocation from sscanf(), and in that time we */ 1319 /* don't touch iop->_cnt. Otherwise, which means an */ 1320 /* invocation from fscanf() or scanf(), we touch iop->_cnt */ 1321 if ((iop->_flag & _IOWRT) == 0) { 1322 /* scanf() and fscanf() */ 1323 iop->_cnt += n; 1324 while (n--) { 1325 *--iop->_ptr = *(p--); 1326 } 1327 } else { 1328 /* sscanf() */ 1329 iop->_ptr -= n; 1330 } 1331 return (wc); 1332 } 1333