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 2002-2003 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 <signal.h> 34 #include <unistd.h> 35 #include <fcntl.h> 36 #include "m4.h" 37 38 #define match(c, s) (c == *s && (!s[1] || inpmatch(s+1))) 39 40 static char tmp_name[] = "/tmp/m4aXXXXX"; 41 static wchar_t prev_char; 42 static int mb_cur_max; 43 44 static void getflags(int *, char ***, int *); 45 static void initalloc(void); 46 static void expand(wchar_t **, int); 47 static void lnsync(FILE *); 48 static void fpath(FILE *); 49 static void puttok(wchar_t *); 50 static void error3(void); 51 static wchar_t itochr(int); 52 static wchar_t *chkbltin(wchar_t *); 53 static wchar_t *inpmatch(wchar_t *); 54 static void chkspace(char **, int *, char ***); 55 static void catchsig(int); 56 static FILE *m4open(char ***, char *, int *); 57 static void showwrap(void); 58 static void sputchr(wchar_t, FILE *); 59 static void putchr(wchar_t); 60 static void *xcalloc(size_t, size_t); 61 static wint_t myfgetwc(FILE *, int); 62 static wint_t myfputwc(wchar_t, FILE *); 63 static int myfeof(int); 64 65 main(argc, argv) 66 int argc; 67 char **argv; 68 { 69 wchar_t t; 70 int i, opt_end = 0; 71 int sigs[] = {SIGHUP, SIGINT, SIGPIPE, 0}; 72 73 for (i = 0; sigs[i]; ++i) { 74 if (signal(sigs[i], SIG_IGN) != SIG_IGN) 75 (void) signal(sigs[i], catchsig); 76 } 77 tempfile = mktemp(tmp_name); 78 (void) close(creat(tempfile, 0)); 79 80 (void) setlocale(LC_ALL, ""); 81 82 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 83 #define TEXT_DOMAIN "SYS_TEST" 84 #endif 85 (void) textdomain(TEXT_DOMAIN); 86 87 if ((mb_cur_max = MB_CUR_MAX) > 1) 88 wide = 1; 89 90 procnam = argv[0]; 91 getflags(&argc, &argv, &opt_end); 92 initalloc(); 93 94 setfname("-"); 95 if (argc > 1) { 96 --argc; 97 ++argv; 98 if (strcmp(argv[0], "-")) { 99 ifile[ifx] = m4open(&argv, "r", &argc); 100 setfname(argv[0]); 101 } 102 } 103 104 for (;;) { 105 token[0] = t = getchr(); 106 token[1] = EOS; 107 108 if (t == WEOF) { 109 if (ifx > 0) { 110 (void) fclose(ifile[ifx]); 111 ipflr = ipstk[--ifx]; 112 continue; 113 } 114 115 getflags(&argc, &argv, &opt_end); 116 117 if (argc <= 1) 118 /* 119 * If dowrap() has been called, the m4wrap 120 * macro has been processed, and a linked 121 * list of m4wrap strings has been created. 122 * The list starts at wrapstart. 123 */ 124 if (wrapstart) { 125 /* 126 * Now that EOF has been processed, 127 * display the m4wrap strings. 128 */ 129 showwrap(); 130 continue; 131 } else 132 break; 133 --argc; 134 ++argv; 135 136 if (ifile[ifx] != stdin) 137 (void) fclose(ifile[ifx]); 138 139 if (strcmp(argv[0], "-")) 140 ifile[ifx] = m4open(&argv, "r", &argc); 141 else 142 ifile[ifx] = stdin; 143 144 setfname(argv[0]); 145 continue; 146 } 147 148 if (is_alpha(t) || t == '_') { 149 wchar_t *tp = token+1; 150 int tlim = toksize; 151 struct nlist *macadd; /* temp variable */ 152 153 while ((*tp = getchr()) != WEOF && 154 (is_alnum(*tp) || *tp == '_')) { 155 tp++; 156 if (--tlim <= 0) 157 error2(gettext( 158 "more than %d chars in word"), 159 toksize); 160 } 161 putbak(*tp); 162 *tp = EOS; 163 164 macadd = lookup(token); 165 *Ap = (wchar_t *)macadd; 166 if (macadd->def) { 167 if ((wchar_t *)(++Ap) >= astklm) { 168 --Ap; 169 error2(gettext( 170 "more than %d items on argument stack"), 171 stksize); 172 } 173 174 if (Cp++ == NULL) 175 Cp = callst; 176 177 Cp->argp = Ap; 178 *Ap++ = op; 179 puttok(token); 180 stkchr(EOS); 181 t = getchr(); 182 putbak(t); 183 184 if (t != '(') 185 pbstr(L"()"); 186 else /* try to fix arg count */ 187 *Ap++ = op; 188 189 Cp->plev = 0; 190 } else { 191 puttok(token); 192 } 193 } else if (match(t, lquote)) { 194 register qlev = 1; 195 196 for (;;) { 197 token[0] = t = getchr(); 198 token[1] = EOS; 199 200 if (match(t, rquote)) { 201 if (--qlev > 0) 202 puttok(token); 203 else 204 break; 205 } else if (match(t, lquote)) { 206 ++qlev; 207 puttok(token); 208 } else { 209 if (t == WEOF) 210 error(gettext( 211 "EOF in quote")); 212 putchr(t); 213 } 214 } 215 } else if (match(t, lcom) && 216 ((lcom[0] != L'#' || lcom[1] != L'\0') || 217 prev_char != '$')) { 218 219 /* 220 * Don't expand commented macro (between lcom and 221 * rcom). 222 * What we know so far is that we have found the 223 * left comment char (lcom). 224 * Make sure we haven't found '#' (lcom) immediately 225 * preceded by '$' because we want to expand "$#". 226 */ 227 228 puttok(token); 229 for (;;) { 230 token[0] = t = getchr(); 231 token[1] = EOS; 232 if (match(t, rcom)) { 233 puttok(token); 234 break; 235 } else { 236 if (t == WEOF) 237 error(gettext( 238 "EOF in comment")); 239 putchr(t); 240 } 241 } 242 } else if (Cp == NULL) { 243 putchr(t); 244 } else if (t == '(') { 245 if (Cp->plev) 246 stkchr(t); 247 else { 248 /* skip white before arg */ 249 while ((t = getchr()) != WEOF && is_space(t)) 250 ; 251 252 putbak(t); 253 } 254 255 ++Cp->plev; 256 } else if (t == ')') { 257 --Cp->plev; 258 259 if (Cp->plev == 0) { 260 stkchr(EOS); 261 expand(Cp->argp, Ap-Cp->argp-1); 262 op = *Cp->argp; 263 Ap = Cp->argp-1; 264 265 if (--Cp < callst) 266 Cp = NULL; 267 } else 268 stkchr(t); 269 } else if (t == ',' && Cp->plev <= 1) { 270 stkchr(EOS); 271 *Ap = op; 272 273 if ((wchar_t *)(++Ap) >= astklm) { 274 --Ap; 275 error2(gettext( 276 "more than %d items on argument stack"), 277 stksize); 278 } 279 280 while ((t = getchr()) != WEOF && is_space(t)) 281 ; 282 283 putbak(t); 284 } else { 285 stkchr(t); 286 } 287 } 288 289 if (Cp != NULL) 290 error(gettext( 291 "EOF in argument list")); 292 293 delexit(exitstat, 1); 294 return (0); 295 } 296 297 static wchar_t * 298 inpmatch(wchar_t *s) 299 { 300 wchar_t *tp = token+1; 301 302 while (*s) { 303 *tp = getchr(); 304 305 if (*tp++ != *s++) { 306 *tp = EOS; 307 pbstr(token+1); 308 return (0); 309 } 310 } 311 312 *tp = EOS; 313 return (token); 314 } 315 316 static void 317 getflags(int *xargc, char ***xargv, int *option_end) 318 { 319 char *arg; 320 char *t; 321 wchar_t *s[3]; 322 323 while (*xargc > 1) { 324 arg = (*xargv)[1]; /* point arg to current argument */ 325 326 /* 327 * This argument is not an option if it equals "-" or if 328 * "--" has already been parsed. 329 */ 330 if (arg[0] != '-' || arg[1] == EOS || *option_end) 331 break; 332 if (arg[0] == '-' && arg[1] == '-' && arg[2] == '\0') { 333 *option_end = 1; 334 } else { 335 switch (arg[1]) { 336 case 'B': 337 chkspace(&arg, xargc, xargv); 338 bufsize = atoi(&arg[2]); 339 break; 340 case 'D': 341 initalloc(); 342 chkspace(&arg, xargc, xargv); 343 for (t = &arg[2]; *t; t++) { 344 if (*t == '=') { 345 *t++ = EOS; 346 break; 347 } 348 } 349 s[1] = str2wstr(&arg[2], 1); 350 s[2] = str2wstr(t, 1); 351 dodef(&s[0], 2); 352 free(s[1]); 353 free(s[2]); 354 break; 355 case 'H': 356 chkspace(&arg, xargc, xargv); 357 hshsize = atoi(&arg[2]); 358 break; 359 case 'S': 360 chkspace(&arg, xargc, xargv); 361 stksize = atoi(&arg[2]); 362 break; 363 case 'T': 364 chkspace(&arg, xargc, xargv); 365 toksize = atoi(&arg[2]); 366 break; 367 case 'U': 368 initalloc(); 369 chkspace(&arg, xargc, xargv); 370 s[1] = str2wstr(&arg[2], 1); 371 doundef(&s[0], 1); 372 free(s[1]); 373 break; 374 case 'e': 375 setbuf(stdout, NULL); 376 (void) signal(SIGINT, SIG_IGN); 377 break; 378 case 's': 379 /* turn on line sync */ 380 sflag = 1; 381 break; 382 default: 383 (void) fprintf(stderr, 384 gettext("%s: bad option: %s\n"), 385 procnam, arg); 386 delexit(NOT_OK, 0); 387 } 388 } /* end else not "--" */ 389 390 (*xargv)++; 391 --(*xargc); 392 } /* end while options to process */ 393 } 394 395 /* 396 * Function: chkspace 397 * 398 * If there is a space between the option and its argument, 399 * adjust argptr so that &arg[2] will point to beginning of the option argument. 400 * This will ensure that processing in getflags() will work, because &arg[2] 401 * will point to the beginning of the option argument whether or not we have 402 * a space between the option and its argument. If there is a space between 403 * the option and its argument, also adjust xargv and xargc because we are 404 * processing the next argument. 405 */ 406 static void 407 chkspace(char **argptr, int *xargc, char ***xargv) 408 { 409 if ((*argptr)[2] == EOS) { 410 /* there is a space between the option and its argument */ 411 (*xargv)++; /* look at the next argument */ 412 --(*xargc); 413 /* 414 * Adjust argptr if the option is followed by an 415 * option argument. 416 */ 417 if (*xargc > 1) { 418 *argptr = (*xargv)[1]; 419 /* point &arg[2] to beginning of option argument */ 420 *argptr -= 2; 421 } 422 } 423 } 424 425 static void 426 initalloc() 427 { 428 static done = 0; 429 register t; 430 431 if (done++) 432 return; 433 434 hshtab = xcalloc(hshsize, sizeof (struct nlist *)); 435 callst = xcalloc(stksize/3+1, sizeof (struct call)); 436 Ap = argstk = xcalloc(stksize+3, sizeof (wchar_t *)); 437 ipstk[0] = ipflr = ip = ibuf = xcalloc(bufsize+1, sizeof (wchar_t)); 438 op = obuf = xcalloc(bufsize+1, sizeof (wchar_t)); 439 token = xcalloc(toksize+1, sizeof (wchar_t)); 440 441 astklm = (wchar_t *)(&argstk[stksize]); 442 ibuflm = &ibuf[bufsize]; 443 obuflm = &obuf[bufsize]; 444 toklm = &token[toksize]; 445 446 for (t = 0; barray[t].bname; ++t) { 447 wchar_t p[2] = {0, EOS}; 448 449 p[0] = builtin(t); 450 install(barray[t].bname, p, NOPUSH); 451 } 452 install(L"unix", nullstr, NOPUSH); 453 } 454 455 void 456 install(wchar_t *nam, wchar_t *val, int mode) 457 { 458 register struct nlist *np; 459 wchar_t *cp; 460 int l; 461 462 if (mode == PUSH) 463 (void) lookup(nam); /* lookup sets hshval */ 464 else 465 while (undef(nam)) /* undef calls lookup */ 466 ; 467 468 np = xcalloc(1, sizeof (*np)); 469 np->name = wstrdup(nam); 470 np->next = hshtab[hshval]; 471 hshtab[hshval] = np; 472 473 cp = xcalloc((l = wcslen(val))+1, sizeof (*val)); 474 np->def = cp; 475 cp = &cp[l]; 476 477 while (*val) 478 *--cp = *val++; 479 } 480 481 struct nlist * 482 lookup(wchar_t *str) 483 { 484 wchar_t *s1; 485 register struct nlist *np; 486 static struct nlist nodef; 487 488 s1 = str; 489 490 for (hshval = 0; *s1; ) 491 hshval += *s1++; 492 493 hshval %= hshsize; 494 495 for (np = hshtab[hshval]; np != NULL; np = np->next) { 496 if (*str == *np->name && wcscmp(str, np->name) == 0) 497 return (np); 498 } 499 return (&nodef); 500 } 501 502 static void 503 expand(wchar_t **a1, int c) 504 { 505 wchar_t *dp; 506 register struct nlist *sp; 507 508 sp = (struct nlist *)a1[-1]; 509 510 if (sp->tflag || trace) { 511 int i; 512 513 (void) fprintf(stderr, 514 "Trace(%d): %ws", Cp-callst, a1[0]); 515 516 if (c > 0) { 517 (void) fprintf(stderr, "(%ws", chkbltin(a1[1])); 518 for (i = 2; i <= c; ++i) 519 (void) fprintf(stderr, ",%ws", chkbltin(a1[i])); 520 (void) fprintf(stderr, ")"); 521 } 522 (void) fprintf(stderr, "\n"); 523 } 524 525 dp = sp->def; 526 527 for (; *dp; ++dp) { 528 if (is_builtin(*dp)) { 529 (*barray[builtin_idx(*dp)].bfunc)(a1, c); 530 } else if (dp[1] == '$') { 531 if (is_digit(*dp)) { 532 register n; 533 if ((n = *dp-'0') <= c) 534 pbstr(a1[n]); 535 ++dp; 536 } else if (*dp == '#') { 537 pbnum((long)c); 538 ++dp; 539 } else if (*dp == '*' || *dp == '@') { 540 register i = c; 541 wchar_t **a = a1; 542 543 if (i > 0) 544 for (;;) { 545 if (*dp == '@') 546 pbstr(rquote); 547 548 pbstr(a[i--]); 549 550 if (*dp == '@') 551 pbstr(lquote); 552 553 if (i <= 0) 554 break; 555 556 pbstr(L","); 557 } 558 ++dp; 559 } else 560 putbak(*dp); 561 } else 562 putbak(*dp); 563 } 564 } 565 566 void 567 setfname(char *s) 568 { 569 if (fname[ifx]) 570 free(fname[ifx]); 571 if ((fname[ifx] = strdup(s)) == NULL) 572 error(gettext("out of storage")); 573 fline[ifx] = 1; 574 nflag = 1; 575 lnsync(stdout); 576 } 577 578 static void 579 lnsync(FILE *iop) 580 { 581 static int cline = 0; 582 static int cfile = 0; 583 584 if (!sflag || iop != stdout) 585 return; 586 587 if (nflag || ifx != cfile) { 588 nflag = 0; 589 cfile = ifx; 590 (void) fprintf(iop, "#line %d \"", cline = fline[ifx]); 591 fpath(iop); 592 (void) fprintf(iop, "\"\n"); 593 } else if (++cline != fline[ifx]) 594 (void) fprintf(iop, "#line %d\n", cline = fline[ifx]); 595 } 596 597 static void 598 fpath(FILE *iop) 599 { 600 register i; 601 602 if (fname[0] == NULL) 603 return; 604 605 (void) fprintf(iop, "%s", fname[0]); 606 607 for (i = 1; i <= ifx; ++i) 608 (void) fprintf(iop, ":%s", fname[i]); 609 } 610 611 /* ARGSUSED */ 612 static void 613 catchsig(int i) 614 { 615 (void) signal(SIGHUP, SIG_IGN); 616 (void) signal(SIGINT, SIG_IGN); 617 delexit(NOT_OK, 0); 618 } 619 620 void 621 delexit(int code, int flushio) 622 { 623 register i; 624 625 cf = stdout; 626 627 /* 628 * if (ofx != 0) { 629 * ofx = 0; 630 * code = NOT_OK; 631 * } 632 */ 633 ofx = 0; /* ensure that everything comes out */ 634 for (i = 1; i < 10; i++) 635 undiv(i, code); 636 637 tempfile[7] = 'a'; 638 (void) unlink(tempfile); 639 640 /* flush standard I/O buffers, ie: call exit() not _exit() */ 641 if (flushio) 642 exit(code); 643 644 _exit(code); 645 } 646 647 static void 648 puttok(wchar_t *tp) 649 { 650 if (Cp) { 651 while (*tp) 652 stkchr(*tp++); 653 } else if (cf) { 654 while (*tp) { 655 sputchr(*tp++, cf); 656 } 657 } 658 } 659 660 void 661 pbstr(wchar_t *str) 662 { 663 wchar_t *p; 664 665 for (p = str + wcslen(str); --p >= str; ) 666 putbak(*p); 667 } 668 669 void 670 undiv(int i, int code) 671 { 672 register FILE *fp; 673 wint_t c; 674 675 if (i < 1 || i > 9 || i == ofx || !ofile[i]) 676 return; 677 678 (void) fclose(ofile[i]); 679 tempfile[7] = 'a'+i; 680 681 if (code == OK && cf) { 682 fp = xfopen(tempfile, "r"); 683 684 if (wide) { 685 while ((c = myfgetwc(fp, -1)) != WEOF) 686 sputchr((wchar_t)c, cf); 687 } else { 688 while ((c = (wint_t)getc(fp)) != WEOF) 689 sputchr((wchar_t)c, cf); 690 } 691 692 (void) fclose(fp); 693 } 694 695 (void) unlink(tempfile); 696 ofile[i] = NULL; 697 } 698 699 void 700 pbnum(long num) 701 { 702 pbnbr(num, 10, 1); 703 } 704 705 void 706 pbnbr(long nbr, int base, int len) 707 { 708 register neg = 0; 709 710 if (base <= 0) 711 return; 712 713 if (nbr < 0) 714 neg = 1; 715 else 716 nbr = -nbr; 717 718 while (nbr < 0) { 719 register int i; 720 if (base > 1) { 721 i = nbr%base; 722 nbr /= base; 723 #if (-3 % 2) != -1 724 while (i > 0) { 725 i -= base; 726 ++nbr; 727 } 728 #endif 729 i = -i; 730 } else { 731 i = 1; 732 ++nbr; 733 } 734 putbak(itochr(i)); 735 --len; 736 } 737 738 while (--len >= 0) 739 putbak('0'); 740 741 if (neg) 742 putbak('-'); 743 } 744 745 static wchar_t 746 itochr(int i) 747 { 748 if (i > 9) 749 return ((wchar_t)(i-10+'A')); 750 else 751 return ((wchar_t)(i+'0')); 752 } 753 754 long 755 ctol(wchar_t *str) 756 { 757 register sign; 758 long num; 759 760 while (is_space(*str)) 761 ++str; 762 num = 0; 763 if (*str == '-') { 764 sign = -1; 765 ++str; 766 } else 767 sign = 1; 768 while (is_digit(*str)) 769 num = num*10 + *str++ - '0'; 770 return (sign * num); 771 } 772 773 int 774 min(int a, int b) 775 { 776 if (a > b) 777 return (b); 778 return (a); 779 } 780 781 FILE * 782 xfopen(char *name, char *mode) 783 { 784 FILE *fp; 785 786 if ((fp = fopen(name, mode)) == NULL) 787 error(gettext("can't open file")); 788 789 return (fp); 790 } 791 792 /* 793 * m4open 794 * 795 * Continue processing files when unable to open the given file argument. 796 */ 797 FILE * 798 m4open(char ***argvec, char *mode, int *argcnt) 799 { 800 FILE *fp; 801 char *arg; 802 803 while (*argcnt > 0) { 804 arg = (*argvec)[0]; /* point arg to current file name */ 805 if (arg[0] == '-' && arg[1] == EOS) 806 return (stdin); 807 else { 808 if ((fp = fopen(arg, mode)) == NULL) { 809 (void) fprintf(stderr, gettext( 810 "m4: cannot open %s: "), arg); 811 perror(""); 812 if (*argcnt == 1) { 813 /* last arg therefore exit */ 814 error3(); 815 } else { 816 exitstat = 1; 817 (*argvec)++; /* try next arg */ 818 (*argcnt)--; 819 } 820 } else 821 break; 822 } 823 } 824 return (fp); 825 } 826 827 void * 828 xmalloc(size_t size) 829 { 830 void *ptr; 831 832 if ((ptr = malloc(size)) == NULL) 833 error(gettext("out of storage")); 834 return (ptr); 835 } 836 837 static void * 838 xcalloc(size_t nbr, size_t size) 839 { 840 register void *ptr; 841 842 ptr = xmalloc(nbr * size); 843 (void) memset(ptr, '\0', nbr * size); 844 return (ptr); 845 } 846 847 void 848 error2(char *str, int num) 849 { 850 char buf[500]; 851 852 (void) snprintf(buf, sizeof (buf), str, num); 853 error(buf); 854 } 855 856 void 857 error(char *str) 858 { 859 (void) fprintf(stderr, "\n%s:", procnam); 860 fpath(stderr); 861 (void) fprintf(stderr, ":%d %s\n", fline[ifx], str); 862 error3(); 863 } 864 865 static void 866 error3() 867 { 868 if (Cp) { 869 register struct call *mptr; 870 871 /* fix limit */ 872 *op = EOS; 873 (Cp+1)->argp = Ap+1; 874 875 for (mptr = callst; mptr <= Cp; ++mptr) { 876 wchar_t **aptr, **lim; 877 878 aptr = mptr->argp; 879 lim = (mptr+1)->argp-1; 880 if (mptr == callst) 881 (void) fputws(*aptr, stderr); 882 ++aptr; 883 (void) fputs("(", stderr); 884 if (aptr < lim) 885 for (;;) { 886 (void) fputws(*aptr++, stderr); 887 if (aptr >= lim) 888 break; 889 (void) fputs(",", stderr); 890 } 891 } 892 while (--mptr >= callst) 893 (void) fputs(")", stderr); 894 895 (void) fputs("\n", stderr); 896 } 897 delexit(NOT_OK, 1); 898 } 899 900 static wchar_t * 901 chkbltin(wchar_t *s) 902 { 903 static wchar_t buf[24]; 904 905 if (is_builtin(*s)) { 906 (void) swprintf(buf, sizeof (buf)/sizeof (wchar_t), L"<%ls>", 907 barray[builtin_idx(*s)].bname); 908 return (buf); 909 } 910 return (s); 911 } 912 913 wchar_t 914 getchr() 915 { 916 static wchar_t C; 917 918 prev_char = C; 919 if (ip > ipflr) 920 return (*--ip); 921 if (wide) { 922 C = (wchar_t)(myfeof(ifx) ? WEOF : myfgetwc(NULL, ifx)); 923 } else { 924 C = (wchar_t)(feof(ifile[ifx]) ? 925 WEOF : (wint_t)getc(ifile[ifx])); 926 } 927 if (C == '\n') 928 fline[ifx]++; 929 return (C); 930 } 931 932 /* 933 * showwrap 934 * 935 * Loop through the list of m4wrap strings. Call pbstr() so that the 936 * string will be displayed, then delete the list entry and free the memory 937 * allocated for it. 938 */ 939 static void 940 showwrap() 941 { 942 struct Wrap *prev; 943 944 while (wrapstart) { 945 pbstr(wrapstart->wrapstr); 946 free(wrapstart->wrapstr); 947 prev = wrapstart; 948 wrapstart = wrapstart->nxt; 949 free(prev); 950 } 951 } 952 953 static void 954 sputchr(wchar_t c, FILE *f) 955 { 956 wint_t ret; 957 958 if (is_builtin(c)) 959 return; 960 if (wide) 961 ret = myfputwc(c, f); 962 else 963 ret = (wint_t)putc((int)c, f); 964 if (ret == WEOF) 965 error(gettext("output error")); 966 if (ret == '\n') 967 lnsync(f); 968 } 969 970 static void 971 putchr(wchar_t c) 972 { 973 wint_t ret; 974 975 if (Cp) 976 stkchr(c); 977 else if (cf) { 978 if (sflag) 979 sputchr(c, cf); 980 else { 981 if (is_builtin(c)) 982 return; 983 if (wide) 984 ret = myfputwc(c, cf); 985 else 986 ret = (wint_t)putc((int)c, cf); 987 if (ret == WEOF) { 988 error(gettext("output error")); 989 } 990 } 991 } 992 } 993 994 wchar_t * 995 wstrdup(wchar_t *p) 996 { 997 size_t len = wcslen(p); 998 wchar_t *ret; 999 1000 ret = xmalloc((len + 1) * sizeof (wchar_t)); 1001 (void) wcscpy(ret, p); 1002 return (ret); 1003 } 1004 1005 int 1006 wstoi(wchar_t *p) 1007 { 1008 return ((int)wcstol(p, NULL, 10)); 1009 } 1010 1011 char * 1012 wstr2str(wchar_t *from, int alloc) 1013 { 1014 static char *retbuf; 1015 static size_t bsiz; 1016 char *p, *ret; 1017 1018 if (alloc) { 1019 ret = p = xmalloc(wcslen(from) * mb_cur_max + 1); 1020 } else { 1021 while (bsiz < (wcslen(from) * mb_cur_max + 1)) { 1022 if ((p = realloc(retbuf, bsiz + 256)) == NULL) 1023 error(gettext("out of storage")); 1024 bsiz += 256; 1025 retbuf = p; 1026 } 1027 ret = p = retbuf; 1028 } 1029 1030 if (wide) { 1031 while (*from) { 1032 int len; 1033 1034 if (*from & INVALID_CHAR) { 1035 *p = (char)(*from & ~INVALID_CHAR); 1036 len = 1; 1037 } else { 1038 if ((len = wctomb(p, *from)) == -1) { 1039 *p = (char)*from; 1040 len = 1; 1041 } 1042 } 1043 p += len; 1044 from++; 1045 } 1046 } else { 1047 while (*from) 1048 *p++ = (char)*from++; 1049 } 1050 *p = '\0'; 1051 1052 return (ret); 1053 } 1054 1055 wchar_t * 1056 str2wstr(char *from, int alloc) 1057 { 1058 static wchar_t *retbuf; 1059 static size_t bsiz; 1060 wchar_t *p, *ret; 1061 1062 if (alloc) { 1063 ret = p = xmalloc((strlen(from) + 1) * sizeof (wchar_t)); 1064 } else { 1065 while (bsiz < (strlen(from) + 1)) { 1066 if ((p = realloc(retbuf, 1067 (bsiz + 256) * sizeof (wchar_t))) == NULL) { 1068 error(gettext("out of storage")); 1069 } 1070 bsiz += 256; 1071 retbuf = p; 1072 } 1073 ret = p = retbuf; 1074 } 1075 1076 if (wide) { 1077 while (*from) { 1078 int len; 1079 wchar_t wc; 1080 1081 if ((len = mbtowc(&wc, from, mb_cur_max)) <= 0) { 1082 wc = *from | INVALID_CHAR; 1083 len = 1; 1084 } 1085 *p++ = wc; 1086 from += len; 1087 } 1088 } else { 1089 while (*from) 1090 *p++ = (unsigned char) *from++; 1091 } 1092 *p = 0; 1093 1094 return (ret); 1095 } 1096 1097 static wint_t 1098 myfgetwc(FILE *fp, int idx) 1099 { 1100 int i, c, len, nb; 1101 wchar_t wc; 1102 unsigned char *buf; 1103 1104 if (fp == NULL) 1105 fp = ifile[idx]; 1106 else 1107 idx = 10; /* extra slot */ 1108 buf = ibuffer[idx].buffer; 1109 nb = ibuffer[idx].nbytes; 1110 len = 0; 1111 for (i = 1; i <= mb_cur_max; i++) { 1112 if (nb < i) { 1113 c = getc(fp); 1114 if (c == EOF) { 1115 if (nb == 0) 1116 return (WEOF); 1117 else 1118 break; 1119 } 1120 buf[nb++] = (unsigned char)c; 1121 } 1122 if ((len = mbtowc(&wc, (char *)buf, i)) >= 0) 1123 break; 1124 } 1125 if (len <= 0) { 1126 wc = buf[0] | INVALID_CHAR; 1127 len = 1; 1128 } 1129 nb -= len; 1130 if (nb > 0) { 1131 for (i = 0; i < nb; i++) 1132 buf[i] = buf[i + len]; 1133 } 1134 ibuffer[idx].nbytes = nb; 1135 return (wc); 1136 } 1137 1138 static wint_t 1139 myfputwc(wchar_t wc, FILE *fp) 1140 { 1141 if (wc & INVALID_CHAR) { 1142 wc &= ~INVALID_CHAR; 1143 return (fputc((int)wc, fp)); 1144 } 1145 return (fputwc(wc, fp)); 1146 } 1147 1148 static int 1149 myfeof(int idx) 1150 { 1151 return (ibuffer[idx].nbytes == 0 && feof(ifile[idx])); 1152 } 1153