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