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.
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.
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]
23 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
27 * Copyright (c) 2011 Gary Mills
30 /* Copyright (c) 1988 AT&T */
31 /* All Rights Reserved */
39 #define match(c, s) (c == *s && (!s[1] || inpmatch(s+1)))
41 static char tmp_name
[] = "/tmp/m4aXXXXX";
42 static wchar_t prev_char
;
43 static int mb_cur_max
;
45 static void getflags(int *, char ***, int *);
46 static void initalloc(void);
47 static void expand(wchar_t **, int);
48 static void lnsync(FILE *);
49 static void fpath(FILE *);
50 static void puttok(wchar_t *);
51 static void error3(void);
52 static wchar_t itochr(int);
53 /*LINTED: E_STATIC_UNUSED*/
54 static wchar_t *chkbltin(wchar_t *);
55 static wchar_t *inpmatch(wchar_t *);
56 static void chkspace(char **, int *, char ***);
57 static void catchsig(int);
58 static FILE *m4open(char ***, char *, int *);
59 static void showwrap(void);
60 static void sputchr(wchar_t, FILE *);
61 static void putchr(wchar_t);
62 static void *xcalloc(size_t, size_t);
63 static wint_t myfgetwc(FILE *, int);
64 static wint_t myfputwc(wchar_t, FILE *);
65 static int myfeof(int);
68 main(int argc
, char **argv
)
72 int sigs
[] = {SIGHUP
, SIGINT
, SIGPIPE
, 0};
78 for (i
= 0; sigs
[i
]; ++i
) {
79 if (signal(sigs
[i
], SIG_IGN
) != SIG_IGN
)
80 (void) signal(sigs
[i
], catchsig
);
82 tempfile
= mktemp(tmp_name
);
83 (void) close(creat(tempfile
, 0));
85 (void) setlocale(LC_ALL
, "");
87 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
88 #define TEXT_DOMAIN "SYS_TEST"
90 (void) textdomain(TEXT_DOMAIN
);
92 if ((mb_cur_max
= MB_CUR_MAX
) > 1)
96 getflags(&argc
, &argv
, &opt_end
);
103 if (strcmp(argv
[0], "-")) {
104 ifile
[ifx
] = m4open(&argv
, "r", &argc
);
110 token
[0] = t
= getchr();
115 (void) fclose(ifile
[ifx
]);
116 ipflr
= ipstk
[--ifx
];
120 getflags(&argc
, &argv
, &opt_end
);
124 * If dowrap() has been called, the m4wrap
125 * macro has been processed, and a linked
126 * list of m4wrap strings has been created.
127 * The list starts at wrapstart.
131 * Now that EOF has been processed,
132 * display the m4wrap strings.
141 if (ifile
[ifx
] != stdin
)
142 (void) fclose(ifile
[ifx
]);
144 if (strcmp(argv
[0], "-"))
145 ifile
[ifx
] = m4open(&argv
, "r", &argc
);
153 if (is_alpha(t
) || t
== '_') {
154 wchar_t *tp
= token
+1;
156 struct nlist
*macadd
; /* temp variable */
158 while ((*tp
= getchr()) != WEOF
&&
159 (is_alnum(*tp
) || *tp
== '_')) {
163 "more than %d chars in word"),
169 macadd
= lookup(token
);
170 *Ap
= (wchar_t *)macadd
;
172 if ((wchar_t *)(++Ap
) >= astklm
) {
175 "more than %d items on "
192 else /* try to fix arg count */
199 } else if (match(t
, lquote
)) {
203 token
[0] = t
= getchr();
206 if (match(t
, rquote
)) {
211 } else if (match(t
, lquote
)) {
221 } else if (match(t
, lcom
) &&
222 ((lcom
[0] != L
'#' || lcom
[1] != L
'\0') ||
226 * Don't expand commented macro (between lcom and
228 * What we know so far is that we have found the
229 * left comment char (lcom).
230 * Make sure we haven't found '#' (lcom) immediately
231 * preceded by '$' because we want to expand "$#".
236 token
[0] = t
= getchr();
238 if (match(t
, rcom
)) {
248 } else if (Cp
== NULL
) {
250 } else if (t
== '(') {
254 /* skip white before arg */
255 while ((t
= getchr()) != WEOF
&& is_space(t
))
262 } else if (t
== ')') {
267 expand(Cp
->argp
, Ap
-Cp
->argp
-1);
275 } else if (t
== ',' && Cp
->plev
<= 1) {
279 if ((wchar_t *)(++Ap
) >= astklm
) {
282 "more than %d items on argument stack"),
286 while ((t
= getchr()) != WEOF
&& is_space(t
))
297 "EOF in argument list"));
299 delexit(exitstat
, 1);
306 wchar_t *tp
= token
+1;
323 getflags(int *xargc
, char ***xargv
, int *option_end
)
330 arg
= (*xargv
)[1]; /* point arg to current argument */
333 * This argument is not an option if it equals "-" or if
334 * "--" has already been parsed.
336 if (arg
[0] != '-' || arg
[1] == EOS
|| *option_end
)
338 if (arg
[0] == '-' && arg
[1] == '-' && arg
[2] == '\0') {
343 chkspace(&arg
, xargc
, xargv
);
344 bufsize
= atoi(&arg
[2]);
346 bufsize
= DEF_BUFSIZE
;
351 chkspace(&arg
, xargc
, xargv
);
352 for (t
= &arg
[2]; *t
; t
++) {
358 s
[1] = str2wstr(&arg
[2], 1);
359 s
[2] = str2wstr(t
, 1);
365 chkspace(&arg
, xargc
, xargv
);
366 hshsize
= atoi(&arg
[2]);
368 hshsize
= DEF_HSHSIZE
;
372 chkspace(&arg
, xargc
, xargv
);
373 stksize
= atoi(&arg
[2]);
375 stksize
= DEF_STKSIZE
;
379 chkspace(&arg
, xargc
, xargv
);
380 toksize
= atoi(&arg
[2]);
382 toksize
= DEF_TOKSIZE
;
387 chkspace(&arg
, xargc
, xargv
);
388 s
[1] = str2wstr(&arg
[2], 1);
393 setbuf(stdout
, NULL
);
394 (void) signal(SIGINT
, SIG_IGN
);
397 /* turn on line sync */
401 (void) fprintf(stderr
,
402 gettext("%s: bad option: %s\n"),
406 } /* end else not "--" */
410 } /* end while options to process */
416 * If there is a space between the option and its argument,
417 * adjust argptr so that &arg[2] will point to beginning of the option argument.
418 * This will ensure that processing in getflags() will work, because &arg[2]
419 * will point to the beginning of the option argument whether or not we have
420 * a space between the option and its argument. If there is a space between
421 * the option and its argument, also adjust xargv and xargc because we are
422 * processing the next argument.
425 chkspace(char **argptr
, int *xargc
, char ***xargv
)
427 if ((*argptr
)[2] == EOS
) {
428 /* there is a space between the option and its argument */
429 (*xargv
)++; /* look at the next argument */
432 * Adjust argptr if the option is followed by an
436 *argptr
= (*xargv
)[1];
437 /* point &arg[2] to beginning of option argument */
452 hshtab
= xcalloc(hshsize
, sizeof (struct nlist
*));
453 callst
= xcalloc(stksize
/3+1, sizeof (struct call
));
454 Ap
= argstk
= xcalloc(stksize
+3, sizeof (wchar_t *));
455 ipstk
[0] = ipflr
= ip
= ibuf
= xcalloc(bufsize
+1, sizeof (wchar_t));
456 op
= obuf
= xcalloc(bufsize
+1, sizeof (wchar_t));
457 token
= xcalloc(toksize
+1, sizeof (wchar_t));
459 astklm
= (wchar_t *)(&argstk
[stksize
]);
460 ibuflm
= &ibuf
[bufsize
];
461 obuflm
= &obuf
[bufsize
];
462 toklm
= &token
[toksize
];
464 for (t
= 0; barray
[t
].bname
; ++t
) {
465 wchar_t p
[2] = {0, EOS
};
468 install(barray
[t
].bname
, p
, NOPUSH
);
470 install(L
"unix", nullstr
, NOPUSH
);
474 install(wchar_t *nam
, wchar_t *val
, int mode
)
481 (void) lookup(nam
); /* lookup sets hshval */
483 while (undef(nam
)) /* undef calls lookup */
486 np
= xcalloc(1, sizeof (*np
));
487 np
->name
= wstrdup(nam
);
488 np
->next
= hshtab
[hshval
];
491 cp
= xcalloc((l
= wcslen(val
))+1, sizeof (*val
));
504 static struct nlist nodef
;
508 for (hshval
= 0; *s1
; )
513 for (np
= hshtab
[hshval
]; np
!= NULL
; np
= np
->next
) {
514 if (*str
== *np
->name
&& wcscmp(str
, np
->name
) == 0)
521 expand(wchar_t **a1
, int c
)
526 sp
= (struct nlist
*)a1
[-1];
528 if (sp
->tflag
|| trace
) {
531 (void) fprintf(stderr
,
532 "Trace(%d): %ws", Cp
-callst
, a1
[0]);
535 (void) fprintf(stderr
, "(%ws", chkbltin(a1
[1]));
536 for (i
= 2; i
<= c
; ++i
)
537 (void) fprintf(stderr
, ",%ws", chkbltin(a1
[i
]));
538 (void) fprintf(stderr
, ")");
540 (void) fprintf(stderr
, "\n");
546 if (is_builtin(*dp
)) {
547 (*barray
[builtin_idx(*dp
)].bfunc
)(a1
, c
);
548 } else if (dp
[1] == '$') {
551 if ((n
= *dp
-'0') <= c
)
554 } else if (*dp
== '#') {
557 } else if (*dp
== '*' || *dp
== '@') {
588 if ((fname
[ifx
] = strdup(s
)) == NULL
)
589 error(gettext("out of storage"));
598 static int cline
= 0;
599 static int cfile
= 0;
601 if (!sflag
|| iop
!= stdout
)
604 if (nflag
|| ifx
!= cfile
) {
607 (void) fprintf(iop
, "#line %d \"", cline
= fline
[ifx
]);
609 (void) fprintf(iop
, "\"\n");
610 } else if (++cline
!= fline
[ifx
])
611 (void) fprintf(iop
, "#line %d\n", cline
= fline
[ifx
]);
619 if (fname
[0] == NULL
)
622 (void) fprintf(iop
, "%s", fname
[0]);
624 for (i
= 1; i
<= ifx
; ++i
)
625 (void) fprintf(iop
, ":%s", fname
[i
]);
632 (void) signal(SIGHUP
, SIG_IGN
);
633 (void) signal(SIGINT
, SIG_IGN
);
638 delexit(int code
, int flushio
)
650 ofx
= 0; /* ensure that everything comes out */
651 for (i
= 1; i
< 10; i
++)
655 (void) unlink(tempfile
);
657 /* flush standard I/O buffers, ie: call exit() not _exit() */
682 for (p
= str
+ wcslen(str
); --p
>= str
; )
687 undiv(int i
, int code
)
692 if (i
< 1 || i
> 9 || i
== ofx
|| !ofile
[i
])
695 (void) fclose(ofile
[i
]);
698 if (code
== OK
&& cf
) {
699 fp
= xfopen(tempfile
, "r");
702 while ((c
= myfgetwc(fp
, -1)) != WEOF
)
703 sputchr((wchar_t)c
, cf
);
705 while ((c
= (wint_t)getc(fp
)) != WEOF
)
706 sputchr((wchar_t)c
, cf
);
712 (void) unlink(tempfile
);
723 pbnbr(long nbr
, int base
, int len
)
766 return ((wchar_t)(i
-10+'A'));
768 return ((wchar_t)(i
+'0'));
777 while (is_space(*str
))
785 while (is_digit(*str
))
786 num
= num
*10 + *str
++ - '0';
799 xfopen(char *name
, char *mode
)
803 if ((fp
= fopen(name
, mode
)) == NULL
)
804 errorf(gettext("cannot open file: %s"),
813 * Continue processing files when unable to open the given file argument.
816 m4open(char ***argvec
, char *mode
, int *argcnt
)
821 while (*argcnt
> 0) {
822 arg
= (*argvec
)[0]; /* point arg to current file name */
823 if (arg
[0] == '-' && arg
[1] == EOS
)
826 if ((fp
= fopen(arg
, mode
)) == NULL
) {
827 (void) fprintf(stderr
, gettext(
828 "m4: cannot open %s: "), arg
);
831 /* last arg therefore exit */
835 (*argvec
)++; /* try next arg */
850 if ((ptr
= malloc(size
)) == NULL
)
851 error(gettext("out of storage"));
856 xcalloc(size_t nbr
, size_t size
)
860 ptr
= xmalloc(nbr
* size
);
861 (void) memset(ptr
, '\0', nbr
* size
);
865 /* Typical format: "cannot open file: %s" */
868 errorf(char *str
, char *serr
)
872 (void) snprintf(buf
, sizeof (buf
), str
, serr
);
878 error2(char *str
, int num
)
882 (void) snprintf(buf
, sizeof (buf
), str
, num
);
889 (void) fprintf(stderr
, "\n%s:", procnam
);
891 (void) fprintf(stderr
, ":%d %s\n", fline
[ifx
], str
);
905 for (mptr
= callst
; mptr
<= Cp
; ++mptr
) {
906 wchar_t **aptr
, **lim
;
909 lim
= (mptr
+1)->argp
-1;
911 (void) fputws(*aptr
, stderr
);
913 (void) fputs("(", stderr
);
916 (void) fputws(*aptr
++, stderr
);
919 (void) fputs(",", stderr
);
922 while (--mptr
>= callst
)
923 (void) fputs(")", stderr
);
925 (void) fputs("\n", stderr
);
933 static wchar_t buf
[24];
935 if (is_builtin(*s
)) {
936 (void) swprintf(buf
, sizeof (buf
)/sizeof (wchar_t), L
"<%ls>",
937 barray
[builtin_idx(*s
)].bname
);
952 C
= (wchar_t)(myfeof(ifx
) ? WEOF
: myfgetwc(NULL
, ifx
));
954 C
= (wchar_t)(feof(ifile
[ifx
]) ?
955 WEOF
: (wint_t)getc(ifile
[ifx
]));
965 * Loop through the list of m4wrap strings. Call pbstr() so that the
966 * string will be displayed, then delete the list entry and free the memory
975 pbstr(wrapstart
->wrapstr
);
976 free(wrapstart
->wrapstr
);
978 wrapstart
= wrapstart
->nxt
;
984 sputchr(wchar_t c
, FILE *f
)
991 ret
= myfputwc(c
, f
);
993 ret
= (wint_t)putc((int)c
, f
);
995 error(gettext("output error"));
1014 ret
= myfputwc(c
, cf
);
1016 ret
= (wint_t)putc((int)c
, cf
);
1018 error(gettext("output error"));
1027 size_t len
= wcslen(p
);
1030 ret
= xmalloc((len
+ 1) * sizeof (wchar_t));
1031 (void) wcscpy(ret
, p
);
1038 return ((int)wcstol(p
, NULL
, 10));
1042 wstr2str(wchar_t *from
, int alloc
)
1044 static char *retbuf
;
1049 ret
= p
= xmalloc(wcslen(from
) * mb_cur_max
+ 1);
1051 while (bsiz
< (wcslen(from
) * mb_cur_max
+ 1)) {
1052 if ((p
= realloc(retbuf
, bsiz
+ 256)) == NULL
)
1053 error(gettext("out of storage"));
1064 if (*from
& INVALID_CHAR
) {
1065 *p
= (char)(*from
& ~INVALID_CHAR
);
1068 if ((len
= wctomb(p
, *from
)) == -1) {
1078 *p
++ = (char)*from
++;
1086 str2wstr(char *from
, int alloc
)
1088 static wchar_t *retbuf
;
1093 ret
= p
= xmalloc((strlen(from
) + 1) * sizeof (wchar_t));
1095 while (bsiz
< (strlen(from
) + 1)) {
1096 if ((p
= reallocarray(retbuf
, bsiz
+ 256,
1097 sizeof (wchar_t))) == NULL
) {
1098 error(gettext("out of storage"));
1111 if ((len
= mbtowc(&wc
, from
, mb_cur_max
)) <= 0) {
1112 wc
= *from
| INVALID_CHAR
;
1120 *p
++ = (unsigned char) *from
++;
1128 myfgetwc(FILE *fp
, int idx
)
1137 idx
= 10; /* extra slot */
1138 buf
= ibuffer
[idx
].buffer
;
1139 nb
= ibuffer
[idx
].nbytes
;
1141 for (i
= 1; i
<= mb_cur_max
; i
++) {
1150 buf
[nb
++] = (unsigned char)c
;
1152 if ((len
= mbtowc(&wc
, (char *)buf
, i
)) >= 0)
1156 wc
= buf
[0] | INVALID_CHAR
;
1161 for (i
= 0; i
< nb
; i
++)
1162 buf
[i
] = buf
[i
+ len
];
1164 ibuffer
[idx
].nbytes
= nb
;
1169 myfputwc(wchar_t wc
, FILE *fp
)
1171 if (wc
& INVALID_CHAR
) {
1172 wc
&= ~INVALID_CHAR
;
1173 return (fputc((int)wc
, fp
));
1175 return (fputwc(wc
, fp
));
1181 return (ibuffer
[idx
].nbytes
== 0 && feof(ifile
[idx
]));