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