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
main(int argc,char ** argv)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 *
inpmatch(wchar_t * s)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
getflags(int * xargc,char *** xargv,int * option_end)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
chkspace(char ** argptr,int * xargc,char *** xargv)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
initalloc(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
install(wchar_t * nam,wchar_t * val,int mode)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 *
lookup(wchar_t * str)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
expand(wchar_t ** a1,int c)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
setfname(char * s)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
lnsync(FILE * iop)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
fpath(FILE * iop)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
catchsig(int i)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
delexit(int code,int flushio)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
puttok(wchar_t * tp)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
pbstr(wchar_t * str)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
undiv(int i,int code)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
pbnum(long num)721 pbnum(long num)
722 {
723 pbnbr(num, 10, 1);
724 }
725
726 void
pbnbr(long nbr,int base,int len)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
itochr(int i)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
ctol(wchar_t * str)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
min(int a,int b)795 min(int a, int b)
796 {
797 if (a > b)
798 return (b);
799 return (a);
800 }
801
802 FILE *
xfopen(char * name,char * mode)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 *
m4open(char *** argvec,char * mode,int * argcnt)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 *
xmalloc(size_t size)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 *
xcalloc(size_t nbr,size_t size)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
error2(char * str,int num)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
error(char * str)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
error3()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 *
chkbltin(wchar_t * s)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
getchr()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
showwrap()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
sputchr(wchar_t c,FILE * f)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
putchr(wchar_t c)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 *
wstrdup(wchar_t * p)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
wstoi(wchar_t * p)1028 wstoi(wchar_t *p)
1029 {
1030 return ((int)wcstol(p, NULL, 10));
1031 }
1032
1033 char *
wstr2str(wchar_t * from,int alloc)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 *
str2wstr(char * from,int alloc)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
myfgetwc(FILE * fp,int idx)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
myfputwc(wchar_t wc,FILE * fp)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
myfeof(int idx)1171 myfeof(int idx)
1172 {
1173 return (ibuffer[idx].nbytes == 0 && feof(ifile[idx]));
1174 }
1175