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 23 /* 24 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 25 * Use is subject to license terms. 26 */ 27 28 /* Copyright (c) 1988 AT&T */ 29 /* All Rights Reserved */ 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 int 66 main(int argc, char **argv) 67 { 68 wchar_t t; 69 int i, opt_end = 0; 70 int sigs[] = {SIGHUP, SIGINT, SIGPIPE, 0}; 71 72 for (i = 0; sigs[i]; ++i) { 73 if (signal(sigs[i], SIG_IGN) != SIG_IGN) 74 (void) signal(sigs[i], catchsig); 75 } 76 tempfile = mktemp(tmp_name); 77 (void) close(creat(tempfile, 0)); 78 79 (void) setlocale(LC_ALL, ""); 80 81 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 82 #define TEXT_DOMAIN "SYS_TEST" 83 #endif 84 (void) textdomain(TEXT_DOMAIN); 85 86 if ((mb_cur_max = MB_CUR_MAX) > 1) 87 wide = 1; 88 89 procnam = argv[0]; 90 getflags(&argc, &argv, &opt_end); 91 initalloc(); 92 93 setfname("-"); 94 if (argc > 1) { 95 --argc; 96 ++argv; 97 if (strcmp(argv[0], "-")) { 98 ifile[ifx] = m4open(&argv, "r", &argc); 99 setfname(argv[0]); 100 } 101 } 102 103 for (;;) { 104 token[0] = t = getchr(); 105 token[1] = EOS; 106 107 if (t == WEOF) { 108 if (ifx > 0) { 109 (void) fclose(ifile[ifx]); 110 ipflr = ipstk[--ifx]; 111 continue; 112 } 113 114 getflags(&argc, &argv, &opt_end); 115 116 if (argc <= 1) 117 /* 118 * If dowrap() has been called, the m4wrap 119 * macro has been processed, and a linked 120 * list of m4wrap strings has been created. 121 * The list starts at wrapstart. 122 */ 123 if (wrapstart) { 124 /* 125 * Now that EOF has been processed, 126 * display the m4wrap strings. 127 */ 128 showwrap(); 129 continue; 130 } else 131 break; 132 --argc; 133 ++argv; 134 135 if (ifile[ifx] != stdin) 136 (void) fclose(ifile[ifx]); 137 138 if (strcmp(argv[0], "-")) 139 ifile[ifx] = m4open(&argv, "r", &argc); 140 else 141 ifile[ifx] = stdin; 142 143 setfname(argv[0]); 144 continue; 145 } 146 147 if (is_alpha(t) || t == '_') { 148 wchar_t *tp = token+1; 149 int tlim = toksize; 150 struct nlist *macadd; /* temp variable */ 151 152 while ((*tp = getchr()) != WEOF && 153 (is_alnum(*tp) || *tp == '_')) { 154 tp++; 155 if (--tlim <= 0) 156 error2(gettext( 157 "more than %d chars in word"), 158 toksize); 159 } 160 putbak(*tp); 161 *tp = EOS; 162 163 macadd = lookup(token); 164 *Ap = (wchar_t *)macadd; 165 if (macadd->def) { 166 if ((wchar_t *)(++Ap) >= astklm) { 167 --Ap; 168 error2(gettext( 169 "more than %d items on argument stack"), 170 stksize); 171 } 172 173 if (Cp++ == NULL) 174 Cp = callst; 175 176 Cp->argp = Ap; 177 *Ap++ = op; 178 puttok(token); 179 stkchr(EOS); 180 t = getchr(); 181 putbak(t); 182 183 if (t != '(') 184 pbstr(L"()"); 185 else /* try to fix arg count */ 186 *Ap++ = op; 187 188 Cp->plev = 0; 189 } else { 190 puttok(token); 191 } 192 } else if (match(t, lquote)) { 193 int qlev = 1; 194 195 for (;;) { 196 token[0] = t = getchr(); 197 token[1] = EOS; 198 199 if (match(t, rquote)) { 200 if (--qlev > 0) 201 puttok(token); 202 else 203 break; 204 } else if (match(t, lquote)) { 205 ++qlev; 206 puttok(token); 207 } else { 208 if (t == WEOF) 209 error(gettext( 210 "EOF in quote")); 211 putchr(t); 212 } 213 } 214 } else if (match(t, lcom) && 215 ((lcom[0] != L'#' || lcom[1] != L'\0') || 216 prev_char != '$')) { 217 218 /* 219 * Don't expand commented macro (between lcom and 220 * rcom). 221 * What we know so far is that we have found the 222 * left comment char (lcom). 223 * Make sure we haven't found '#' (lcom) immediately 224 * preceded by '$' because we want to expand "$#". 225 */ 226 227 puttok(token); 228 for (;;) { 229 token[0] = t = getchr(); 230 token[1] = EOS; 231 if (match(t, rcom)) { 232 puttok(token); 233 break; 234 } else { 235 if (t == WEOF) 236 error(gettext( 237 "EOF in comment")); 238 putchr(t); 239 } 240 } 241 } else if (Cp == NULL) { 242 putchr(t); 243 } else if (t == '(') { 244 if (Cp->plev) 245 stkchr(t); 246 else { 247 /* skip white before arg */ 248 while ((t = getchr()) != WEOF && is_space(t)) 249 ; 250 251 putbak(t); 252 } 253 254 ++Cp->plev; 255 } else if (t == ')') { 256 --Cp->plev; 257 258 if (Cp->plev == 0) { 259 stkchr(EOS); 260 expand(Cp->argp, Ap-Cp->argp-1); 261 op = *Cp->argp; 262 Ap = Cp->argp-1; 263 264 if (--Cp < callst) 265 Cp = NULL; 266 } else 267 stkchr(t); 268 } else if (t == ',' && Cp->plev <= 1) { 269 stkchr(EOS); 270 *Ap = op; 271 272 if ((wchar_t *)(++Ap) >= astklm) { 273 --Ap; 274 error2(gettext( 275 "more than %d items on argument stack"), 276 stksize); 277 } 278 279 while ((t = getchr()) != WEOF && is_space(t)) 280 ; 281 282 putbak(t); 283 } else { 284 stkchr(t); 285 } 286 } 287 288 if (Cp != NULL) 289 error(gettext( 290 "EOF in argument list")); 291 292 delexit(exitstat, 1); 293 return (0); 294 } 295 296 static wchar_t * 297 inpmatch(wchar_t *s) 298 { 299 wchar_t *tp = token+1; 300 301 while (*s) { 302 *tp = getchr(); 303 304 if (*tp++ != *s++) { 305 *tp = EOS; 306 pbstr(token+1); 307 return (0); 308 } 309 } 310 311 *tp = EOS; 312 return (token); 313 } 314 315 static void 316 getflags(int *xargc, char ***xargv, int *option_end) 317 { 318 char *arg; 319 char *t; 320 wchar_t *s[3]; 321 322 while (*xargc > 1) { 323 arg = (*xargv)[1]; /* point arg to current argument */ 324 325 /* 326 * This argument is not an option if it equals "-" or if 327 * "--" has already been parsed. 328 */ 329 if (arg[0] != '-' || arg[1] == EOS || *option_end) 330 break; 331 if (arg[0] == '-' && arg[1] == '-' && arg[2] == '\0') { 332 *option_end = 1; 333 } else { 334 switch (arg[1]) { 335 case 'B': 336 chkspace(&arg, xargc, xargv); 337 bufsize = atoi(&arg[2]); 338 break; 339 case 'D': 340 initalloc(); 341 chkspace(&arg, xargc, xargv); 342 for (t = &arg[2]; *t; t++) { 343 if (*t == '=') { 344 *t++ = EOS; 345 break; 346 } 347 } 348 s[1] = str2wstr(&arg[2], 1); 349 s[2] = str2wstr(t, 1); 350 dodef(&s[0], 2); 351 free(s[1]); 352 free(s[2]); 353 break; 354 case 'H': 355 chkspace(&arg, xargc, xargv); 356 hshsize = atoi(&arg[2]); 357 break; 358 case 'S': 359 chkspace(&arg, xargc, xargv); 360 stksize = atoi(&arg[2]); 361 break; 362 case 'T': 363 chkspace(&arg, xargc, xargv); 364 toksize = atoi(&arg[2]); 365 break; 366 case 'U': 367 initalloc(); 368 chkspace(&arg, xargc, xargv); 369 s[1] = str2wstr(&arg[2], 1); 370 doundef(&s[0], 1); 371 free(s[1]); 372 break; 373 case 'e': 374 setbuf(stdout, NULL); 375 (void) signal(SIGINT, SIG_IGN); 376 break; 377 case 's': 378 /* turn on line sync */ 379 sflag = 1; 380 break; 381 default: 382 (void) fprintf(stderr, 383 gettext("%s: bad option: %s\n"), 384 procnam, arg); 385 delexit(NOT_OK, 0); 386 } 387 } /* end else not "--" */ 388 389 (*xargv)++; 390 --(*xargc); 391 } /* end while options to process */ 392 } 393 394 /* 395 * Function: chkspace 396 * 397 * If there is a space between the option and its argument, 398 * adjust argptr so that &arg[2] will point to beginning of the option argument. 399 * This will ensure that processing in getflags() will work, because &arg[2] 400 * will point to the beginning of the option argument whether or not we have 401 * a space between the option and its argument. If there is a space between 402 * the option and its argument, also adjust xargv and xargc because we are 403 * processing the next argument. 404 */ 405 static void 406 chkspace(char **argptr, int *xargc, char ***xargv) 407 { 408 if ((*argptr)[2] == EOS) { 409 /* there is a space between the option and its argument */ 410 (*xargv)++; /* look at the next argument */ 411 --(*xargc); 412 /* 413 * Adjust argptr if the option is followed by an 414 * option argument. 415 */ 416 if (*xargc > 1) { 417 *argptr = (*xargv)[1]; 418 /* point &arg[2] to beginning of option argument */ 419 *argptr -= 2; 420 } 421 } 422 } 423 424 static void 425 initalloc(void) 426 { 427 static int done = 0; 428 int t; 429 430 if (done++) 431 return; 432 433 hshtab = xcalloc(hshsize, sizeof (struct nlist *)); 434 callst = xcalloc(stksize/3+1, sizeof (struct call)); 435 Ap = argstk = xcalloc(stksize+3, sizeof (wchar_t *)); 436 ipstk[0] = ipflr = ip = ibuf = xcalloc(bufsize+1, sizeof (wchar_t)); 437 op = obuf = xcalloc(bufsize+1, sizeof (wchar_t)); 438 token = xcalloc(toksize+1, sizeof (wchar_t)); 439 440 astklm = (wchar_t *)(&argstk[stksize]); 441 ibuflm = &ibuf[bufsize]; 442 obuflm = &obuf[bufsize]; 443 toklm = &token[toksize]; 444 445 for (t = 0; barray[t].bname; ++t) { 446 wchar_t p[2] = {0, EOS}; 447 448 p[0] = builtin(t); 449 install(barray[t].bname, p, NOPUSH); 450 } 451 install(L"unix", nullstr, NOPUSH); 452 } 453 454 void 455 install(wchar_t *nam, wchar_t *val, int mode) 456 { 457 struct nlist *np; 458 wchar_t *cp; 459 int l; 460 461 if (mode == PUSH) 462 (void) lookup(nam); /* lookup sets hshval */ 463 else 464 while (undef(nam)) /* undef calls lookup */ 465 ; 466 467 np = xcalloc(1, sizeof (*np)); 468 np->name = wstrdup(nam); 469 np->next = hshtab[hshval]; 470 hshtab[hshval] = np; 471 472 cp = xcalloc((l = wcslen(val))+1, sizeof (*val)); 473 np->def = cp; 474 cp = &cp[l]; 475 476 while (*val) 477 *--cp = *val++; 478 } 479 480 struct nlist * 481 lookup(wchar_t *str) 482 { 483 wchar_t *s1; 484 struct nlist *np; 485 static struct nlist nodef; 486 487 s1 = str; 488 489 for (hshval = 0; *s1; ) 490 hshval += *s1++; 491 492 hshval %= hshsize; 493 494 for (np = hshtab[hshval]; np != NULL; np = np->next) { 495 if (*str == *np->name && wcscmp(str, np->name) == 0) 496 return (np); 497 } 498 return (&nodef); 499 } 500 501 static void 502 expand(wchar_t **a1, int c) 503 { 504 wchar_t *dp; 505 struct nlist *sp; 506 507 sp = (struct nlist *)a1[-1]; 508 509 if (sp->tflag || trace) { 510 int i; 511 512 (void) fprintf(stderr, 513 "Trace(%d): %ws", Cp-callst, a1[0]); 514 515 if (c > 0) { 516 (void) fprintf(stderr, "(%ws", chkbltin(a1[1])); 517 for (i = 2; i <= c; ++i) 518 (void) fprintf(stderr, ",%ws", chkbltin(a1[i])); 519 (void) fprintf(stderr, ")"); 520 } 521 (void) fprintf(stderr, "\n"); 522 } 523 524 dp = sp->def; 525 526 for (; *dp; ++dp) { 527 if (is_builtin(*dp)) { 528 (*barray[builtin_idx(*dp)].bfunc)(a1, c); 529 } else if (dp[1] == '$') { 530 if (is_digit(*dp)) { 531 int n; 532 if ((n = *dp-'0') <= c) 533 pbstr(a1[n]); 534 ++dp; 535 } else if (*dp == '#') { 536 pbnum((long)c); 537 ++dp; 538 } else if (*dp == '*' || *dp == '@') { 539 int i = c; 540 wchar_t **a = a1; 541 542 if (i > 0) 543 for (;;) { 544 if (*dp == '@') 545 pbstr(rquote); 546 547 pbstr(a[i--]); 548 549 if (*dp == '@') 550 pbstr(lquote); 551 552 if (i <= 0) 553 break; 554 555 pbstr(L","); 556 } 557 ++dp; 558 } else 559 putbak(*dp); 560 } else 561 putbak(*dp); 562 } 563 } 564 565 void 566 setfname(char *s) 567 { 568 if (fname[ifx]) 569 free(fname[ifx]); 570 if ((fname[ifx] = strdup(s)) == NULL) 571 error(gettext("out of storage")); 572 fline[ifx] = 1; 573 nflag = 1; 574 lnsync(stdout); 575 } 576 577 static void 578 lnsync(FILE *iop) 579 { 580 static int cline = 0; 581 static int cfile = 0; 582 583 if (!sflag || iop != stdout) 584 return; 585 586 if (nflag || ifx != cfile) { 587 nflag = 0; 588 cfile = ifx; 589 (void) fprintf(iop, "#line %d \"", cline = fline[ifx]); 590 fpath(iop); 591 (void) fprintf(iop, "\"\n"); 592 } else if (++cline != fline[ifx]) 593 (void) fprintf(iop, "#line %d\n", cline = fline[ifx]); 594 } 595 596 static void 597 fpath(FILE *iop) 598 { 599 int i; 600 601 if (fname[0] == NULL) 602 return; 603 604 (void) fprintf(iop, "%s", fname[0]); 605 606 for (i = 1; i <= ifx; ++i) 607 (void) fprintf(iop, ":%s", fname[i]); 608 } 609 610 /* ARGSUSED */ 611 static void 612 catchsig(int i) 613 { 614 (void) signal(SIGHUP, SIG_IGN); 615 (void) signal(SIGINT, SIG_IGN); 616 delexit(NOT_OK, 0); 617 } 618 619 void 620 delexit(int code, int flushio) 621 { 622 int i; 623 624 cf = stdout; 625 626 /* 627 * if (ofx != 0) { 628 * ofx = 0; 629 * code = NOT_OK; 630 * } 631 */ 632 ofx = 0; /* ensure that everything comes out */ 633 for (i = 1; i < 10; i++) 634 undiv(i, code); 635 636 tempfile[7] = 'a'; 637 (void) unlink(tempfile); 638 639 /* flush standard I/O buffers, ie: call exit() not _exit() */ 640 if (flushio) 641 exit(code); 642 643 _exit(code); 644 } 645 646 static void 647 puttok(wchar_t *tp) 648 { 649 if (Cp) { 650 while (*tp) 651 stkchr(*tp++); 652 } else if (cf) { 653 while (*tp) { 654 sputchr(*tp++, cf); 655 } 656 } 657 } 658 659 void 660 pbstr(wchar_t *str) 661 { 662 wchar_t *p; 663 664 for (p = str + wcslen(str); --p >= str; ) 665 putbak(*p); 666 } 667 668 void 669 undiv(int i, int code) 670 { 671 FILE *fp; 672 wint_t c; 673 674 if (i < 1 || i > 9 || i == ofx || !ofile[i]) 675 return; 676 677 (void) fclose(ofile[i]); 678 tempfile[7] = 'a'+i; 679 680 if (code == OK && cf) { 681 fp = xfopen(tempfile, "r"); 682 683 if (wide) { 684 while ((c = myfgetwc(fp, -1)) != WEOF) 685 sputchr((wchar_t)c, cf); 686 } else { 687 while ((c = (wint_t)getc(fp)) != WEOF) 688 sputchr((wchar_t)c, cf); 689 } 690 691 (void) fclose(fp); 692 } 693 694 (void) unlink(tempfile); 695 ofile[i] = NULL; 696 } 697 698 void 699 pbnum(long num) 700 { 701 pbnbr(num, 10, 1); 702 } 703 704 void 705 pbnbr(long nbr, int base, int len) 706 { 707 int neg = 0; 708 709 if (base <= 0) 710 return; 711 712 if (nbr < 0) 713 neg = 1; 714 else 715 nbr = -nbr; 716 717 while (nbr < 0) { 718 int i; 719 if (base > 1) { 720 i = nbr%base; 721 nbr /= base; 722 #if (-3 % 2) != -1 723 while (i > 0) { 724 i -= base; 725 ++nbr; 726 } 727 #endif 728 i = -i; 729 } else { 730 i = 1; 731 ++nbr; 732 } 733 putbak(itochr(i)); 734 --len; 735 } 736 737 while (--len >= 0) 738 putbak('0'); 739 740 if (neg) 741 putbak('-'); 742 } 743 744 static wchar_t 745 itochr(int i) 746 { 747 if (i > 9) 748 return ((wchar_t)(i-10+'A')); 749 else 750 return ((wchar_t)(i+'0')); 751 } 752 753 long 754 ctol(wchar_t *str) 755 { 756 int sign; 757 long num; 758 759 while (is_space(*str)) 760 ++str; 761 num = 0; 762 if (*str == '-') { 763 sign = -1; 764 ++str; 765 } else 766 sign = 1; 767 while (is_digit(*str)) 768 num = num*10 + *str++ - '0'; 769 return (sign * num); 770 } 771 772 int 773 min(int a, int b) 774 { 775 if (a > b) 776 return (b); 777 return (a); 778 } 779 780 FILE * 781 xfopen(char *name, char *mode) 782 { 783 FILE *fp; 784 785 if ((fp = fopen(name, mode)) == NULL) 786 error(gettext("can't open file")); 787 788 return (fp); 789 } 790 791 /* 792 * m4open 793 * 794 * Continue processing files when unable to open the given file argument. 795 */ 796 FILE * 797 m4open(char ***argvec, char *mode, int *argcnt) 798 { 799 FILE *fp; 800 char *arg; 801 802 while (*argcnt > 0) { 803 arg = (*argvec)[0]; /* point arg to current file name */ 804 if (arg[0] == '-' && arg[1] == EOS) 805 return (stdin); 806 else { 807 if ((fp = fopen(arg, mode)) == NULL) { 808 (void) fprintf(stderr, gettext( 809 "m4: cannot open %s: "), arg); 810 perror(""); 811 if (*argcnt == 1) { 812 /* last arg therefore exit */ 813 error3(); 814 } else { 815 exitstat = 1; 816 (*argvec)++; /* try next arg */ 817 (*argcnt)--; 818 } 819 } else 820 break; 821 } 822 } 823 return (fp); 824 } 825 826 void * 827 xmalloc(size_t size) 828 { 829 void *ptr; 830 831 if ((ptr = malloc(size)) == NULL) 832 error(gettext("out of storage")); 833 return (ptr); 834 } 835 836 static void * 837 xcalloc(size_t nbr, size_t size) 838 { 839 void *ptr; 840 841 ptr = xmalloc(nbr * size); 842 (void) memset(ptr, '\0', nbr * size); 843 return (ptr); 844 } 845 846 /* PRINTFLIKE1 */ 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 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