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