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