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