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