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