Pull up following revision(s) (requested by uwe in ticket #981): usr.bin/m4/m4.1: revision 1.28 usr.bin/m4/m4.1: revision 1.29 usr.bin/m4/extern.h: revision 1.20 usr.bin/m4/main.c: revision 1.49 usr.bin/m4/m4.1: revision 1.30 usr.bin/m4/trace.c: revision 1.9 usr.bin/m4/main.c: revision 1.50 Try not to lose error output with --error-output. Try to avoid the trap we set up ourselves while avoiding freopen(3). When exit flushes and closes open streams it may close sfp first and when it comes about to flush and close stderr, the descriptor is already gone and we lose any buffered error output. This actually happens on some hosts, breaking --trace output used by autoconf. Fix --error-output to be more like GNU m4. GNU m4 --error-output is the same as -o despite the name. It does NOT affect warnings, error messages, and 'errprint' output so drop the misguided bit of code that tried to freopen stderr without closing it on failure. Drop -e (which was our local invention) and make merge --error-output with -o so that both set traceout. Make trace_file() preserve the old traceout on error and return error status so that the caller can emit appropriate warning. Do not yet support disabling tracing with an empty name, the rest of the code is not ready, we don't do -o positionally and we don't have `debugfile'. Fix --error-output to be more like GNU m4. It's a long version of -o. Bump date for previous. Use a date that is actually a real date.diff -r1.19 -r1.19.18.1 src/usr.bin/m4/extern.h
(martin)
--- src/usr.bin/m4/extern.h 2016/01/16 18:30:57 1.19
+++ src/usr.bin/m4/extern.h 2020/07/07 10:40:46 1.19.18.1
@@ -1,190 +1,190 @@ | @@ -1,190 +1,190 @@ | |||
1 | /* $OpenBSD: extern.h,v 1.49 2009/10/14 17:19:47 sthen Exp $ */ | 1 | /* $OpenBSD: extern.h,v 1.49 2009/10/14 17:19:47 sthen Exp $ */ | |
2 | /* $NetBSD: extern.h,v 1.19 2016/01/16 18:30:57 christos Exp $ */ | 2 | /* $NetBSD: extern.h,v 1.19.18.1 2020/07/07 10:40:46 martin Exp $ */ | |
3 | 3 | |||
4 | /*- | 4 | /*- | |
5 | * Copyright (c) 1991, 1993 | 5 | * Copyright (c) 1991, 1993 | |
6 | * The Regents of the University of California. All rights reserved. | 6 | * The Regents of the University of California. All rights reserved. | |
7 | * | 7 | * | |
8 | * This code is derived from software contributed to Berkeley by | 8 | * This code is derived from software contributed to Berkeley by | |
9 | * Ozan Yigit at York University. | 9 | * Ozan Yigit at York University. | |
10 | * | 10 | * | |
11 | * Redistribution and use in source and binary forms, with or without | 11 | * Redistribution and use in source and binary forms, with or without | |
12 | * modification, are permitted provided that the following conditions | 12 | * modification, are permitted provided that the following conditions | |
13 | * are met: | 13 | * are met: | |
14 | * 1. Redistributions of source code must retain the above copyright | 14 | * 1. Redistributions of source code must retain the above copyright | |
15 | * notice, this list of conditions and the following disclaimer. | 15 | * notice, this list of conditions and the following disclaimer. | |
16 | * 2. Redistributions in binary form must reproduce the above copyright | 16 | * 2. Redistributions in binary form must reproduce the above copyright | |
17 | * notice, this list of conditions and the following disclaimer in the | 17 | * notice, this list of conditions and the following disclaimer in the | |
18 | * documentation and/or other materials provided with the distribution. | 18 | * documentation and/or other materials provided with the distribution. | |
19 | * 3. Neither the name of the University nor the names of its contributors | 19 | * 3. Neither the name of the University nor the names of its contributors | |
20 | * may be used to endorse or promote products derived from this software | 20 | * may be used to endorse or promote products derived from this software | |
21 | * without specific prior written permission. | 21 | * without specific prior written permission. | |
22 | * | 22 | * | |
23 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | 23 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
24 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 24 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
25 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 25 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
26 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | 26 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
27 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 27 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
28 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 28 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
29 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 29 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
30 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 30 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
31 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 31 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
32 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 32 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
33 | * SUCH DAMAGE. | 33 | * SUCH DAMAGE. | |
34 | * | 34 | * | |
35 | * @(#)extern.h 8.1 (Berkeley) 6/6/93 | 35 | * @(#)extern.h 8.1 (Berkeley) 6/6/93 | |
36 | */ | 36 | */ | |
37 | 37 | |||
38 | /* eval.c */ | 38 | /* eval.c */ | |
39 | extern void eval(const char *[], int, int, int); | 39 | extern void eval(const char *[], int, int, int); | |
40 | extern void dodefine(const char *, const char *); | 40 | extern void dodefine(const char *, const char *); | |
41 | extern unsigned long expansion_id; | 41 | extern unsigned long expansion_id; | |
42 | 42 | |||
43 | /* expr.c */ | 43 | /* expr.c */ | |
44 | extern int expr(const char *); | 44 | extern int expr(const char *); | |
45 | 45 | |||
46 | /* gnum4.c */ | 46 | /* gnum4.c */ | |
47 | extern void addtoincludepath(const char *); | 47 | extern void addtoincludepath(const char *); | |
48 | extern struct input_file *fopen_trypath(struct input_file *, const char *); | 48 | extern struct input_file *fopen_trypath(struct input_file *, const char *); | |
49 | extern void doindir(const char *[], int); | 49 | extern void doindir(const char *[], int); | |
50 | extern void dobuiltin(const char *[], int); | 50 | extern void dobuiltin(const char *[], int); | |
51 | extern void dopatsubst(const char *[], int); | 51 | extern void dopatsubst(const char *[], int); | |
52 | extern void doregexp(const char *[], int); | 52 | extern void doregexp(const char *[], int); | |
53 | 53 | |||
54 | extern void doprintlineno(struct input_file *); | 54 | extern void doprintlineno(struct input_file *); | |
55 | extern void doprintfilename(struct input_file *); | 55 | extern void doprintfilename(struct input_file *); | |
56 | 56 | |||
57 | extern void doesyscmd(const char *); | 57 | extern void doesyscmd(const char *); | |
58 | extern void getdivfile(const char *); | 58 | extern void getdivfile(const char *); | |
59 | extern void doformat(const char *[], int); | 59 | extern void doformat(const char *[], int); | |
60 | #ifdef REAL_FREEZE | 60 | #ifdef REAL_FREEZE | |
61 | extern void freeze_state(const char *); | 61 | extern void freeze_state(const char *); | |
62 | extern void thaw_state(const char *); | 62 | extern void thaw_state(const char *); | |
63 | #endif | 63 | #endif | |
64 | 64 | |||
65 | 65 | |||
66 | /* look.c */ | 66 | /* look.c */ | |
67 | 67 | |||
68 | #define FLAG_UNTRACED 0 | 68 | #define FLAG_UNTRACED 0 | |
69 | #define FLAG_TRACED 1 | 69 | #define FLAG_TRACED 1 | |
70 | #define FLAG_NO_TRACE 2 | 70 | #define FLAG_NO_TRACE 2 | |
71 | 71 | |||
72 | extern void init_macros(void); | 72 | extern void init_macros(void); | |
73 | extern ndptr lookup(const char *); | 73 | extern ndptr lookup(const char *); | |
74 | extern void mark_traced(const char *, int); | 74 | extern void mark_traced(const char *, int); | |
75 | extern struct ohash macros; | 75 | extern struct ohash macros; | |
76 | 76 | |||
77 | extern struct macro_definition *lookup_macro_definition(const char *); | 77 | extern struct macro_definition *lookup_macro_definition(const char *); | |
78 | extern void macro_define(const char *, const char *); | 78 | extern void macro_define(const char *, const char *); | |
79 | extern void macro_pushdef(const char *, const char *); | 79 | extern void macro_pushdef(const char *, const char *); | |
80 | extern void macro_popdef(const char *); | 80 | extern void macro_popdef(const char *); | |
81 | extern void macro_undefine(const char *); | 81 | extern void macro_undefine(const char *); | |
82 | extern void setup_builtin(const char *, unsigned int); | 82 | extern void setup_builtin(const char *, unsigned int); | |
83 | extern void macro_for_all(void (*)(const char *, struct macro_definition *)); | 83 | extern void macro_for_all(void (*)(const char *, struct macro_definition *)); | |
84 | #define macro_getdef(p) ((p)->d) | 84 | #define macro_getdef(p) ((p)->d) | |
85 | #define macro_name(p) ((p)->name) | 85 | #define macro_name(p) ((p)->name) | |
86 | #define macro_builtin_type(p) ((p)->builtin_type) | 86 | #define macro_builtin_type(p) ((p)->builtin_type) | |
87 | #define is_traced(p) ((p)->trace_flags == FLAG_NO_TRACE ? (trace_flags & TRACE_ALL) : (p)->trace_flags) | 87 | #define is_traced(p) ((p)->trace_flags == FLAG_NO_TRACE ? (trace_flags & TRACE_ALL) : (p)->trace_flags) | |
88 | 88 | |||
89 | extern ndptr macro_getbuiltin(const char *); | 89 | extern ndptr macro_getbuiltin(const char *); | |
90 | #ifdef REAL_FREEZE | 90 | #ifdef REAL_FREEZE | |
91 | extern void dump_state(FILE *); | 91 | extern void dump_state(FILE *); | |
92 | extern void restore_state(FILE *); | 92 | extern void restore_state(FILE *); | |
93 | #endif | 93 | #endif | |
94 | 94 | |||
95 | /* main.c */ | 95 | /* main.c */ | |
96 | extern void outputstr(const char *); | 96 | extern void outputstr(const char *); | |
97 | extern void do_emit_synchline(void); | 97 | extern void do_emit_synchline(void); | |
98 | #define emit_synchline() do { if (synch_lines) do_emit_synchline(); } while(0) | 98 | #define emit_synchline() do { if (synch_lines) do_emit_synchline(); } while(0) | |
99 | 99 | |||
100 | /* misc.c */ | 100 | /* misc.c */ | |
101 | extern void chrsave(int); | 101 | extern void chrsave(int); | |
102 | extern char *compute_prevep(void); | 102 | extern char *compute_prevep(void); | |
103 | extern void getdiv(int); | 103 | extern void getdiv(int); | |
104 | extern ptrdiff_t indx(const char *, const char *); | 104 | extern ptrdiff_t indx(const char *, const char *); | |
105 | extern void initspaces(void); | 105 | extern void initspaces(void); | |
106 | extern void killdiv(void); | 106 | extern void killdiv(void); | |
107 | extern void pbnum(int); | 107 | extern void pbnum(int); | |
108 | extern void pbnumbase(int, int, int); | 108 | extern void pbnumbase(int, int, int); | |
109 | extern void pbunsigned(unsigned long); | 109 | extern void pbunsigned(unsigned long); | |
110 | extern void pbstr(const char *); | 110 | extern void pbstr(const char *); | |
111 | extern void pushback(int); | 111 | extern void pushback(int); | |
112 | extern void *xalloc(size_t, const char *fmt, ...) __printflike(2, 3); | 112 | extern void *xalloc(size_t, const char *fmt, ...) __printflike(2, 3); | |
113 | extern void *xrealloc(void *, size_t, const char *fmt, ...) | 113 | extern void *xrealloc(void *, size_t, const char *fmt, ...) | |
114 | __printflike(3, 4); | 114 | __printflike(3, 4); | |
115 | extern char *xstrdup(const char *); | 115 | extern char *xstrdup(const char *); | |
116 | extern void resizedivs(int); | 116 | extern void resizedivs(int); | |
117 | extern size_t buffer_mark(void); | 117 | extern size_t buffer_mark(void); | |
118 | extern void dump_buffer(FILE *, size_t); | 118 | extern void dump_buffer(FILE *, size_t); | |
119 | extern void __dead m4errx(int, const char *, ...) __printflike(2, 3); | 119 | extern void __dead m4errx(int, const char *, ...) __printflike(2, 3); | |
120 | 120 | |||
121 | extern int obtain_char(struct input_file *); | 121 | extern int obtain_char(struct input_file *); | |
122 | extern void set_input(struct input_file *, FILE *, const char *); | 122 | extern void set_input(struct input_file *, FILE *, const char *); | |
123 | extern void release_input(struct input_file *); | 123 | extern void release_input(struct input_file *); | |
124 | 124 | |||
125 | /* speeded-up versions of chrsave/pushback */ | 125 | /* speeded-up versions of chrsave/pushback */ | |
126 | #define PUSHBACK(c) \ | 126 | #define PUSHBACK(c) \ | |
127 | do { \ | 127 | do { \ | |
128 | if (bp >= endpbb) \ | 128 | if (bp >= endpbb) \ | |
129 | enlarge_bufspace(); \ | 129 | enlarge_bufspace(); \ | |
130 | *bp++ = (c); \ | 130 | *bp++ = (c); \ | |
131 | } while(0) | 131 | } while(0) | |
132 | 132 | |||
133 | #define CHRSAVE(c) \ | 133 | #define CHRSAVE(c) \ | |
134 | do { \ | 134 | do { \ | |
135 | if (ep >= endest) \ | 135 | if (ep >= endest) \ | |
136 | enlarge_strspace(); \ | 136 | enlarge_strspace(); \ | |
137 | *ep++ = (c); \ | 137 | *ep++ = (c); \ | |
138 | } while(0) | 138 | } while(0) | |
139 | 139 | |||
140 | /* and corresponding exposure for local symbols */ | 140 | /* and corresponding exposure for local symbols */ | |
141 | extern void enlarge_bufspace(void); | 141 | extern void enlarge_bufspace(void); | |
142 | extern void enlarge_strspace(void); | 142 | extern void enlarge_strspace(void); | |
143 | extern unsigned char *endpbb; | 143 | extern unsigned char *endpbb; | |
144 | extern char *endest; | 144 | extern char *endest; | |
145 | 145 | |||
146 | /* trace.c */ | 146 | /* trace.c */ | |
147 | extern unsigned int trace_flags; | 147 | extern unsigned int trace_flags; | |
148 | #define TRACE_ALL 512 | 148 | #define TRACE_ALL 512 | |
149 | extern void trace_file(const char *); | 149 | extern int trace_file(const char *); | |
150 | extern size_t trace(const char **, int, struct input_file *); | 150 | extern size_t trace(const char **, int, struct input_file *); | |
151 | extern void finish_trace(size_t); | 151 | extern void finish_trace(size_t); | |
152 | extern void set_trace_flags(const char *); | 152 | extern void set_trace_flags(const char *); | |
153 | extern FILE *traceout; | 153 | extern FILE *traceout; | |
154 | 154 | |||
155 | extern ndptr hashtab[]; /* hash table for macros etc. */ | 155 | extern ndptr hashtab[]; /* hash table for macros etc. */ | |
156 | extern stae *mstack; /* stack of m4 machine */ | 156 | extern stae *mstack; /* stack of m4 machine */ | |
157 | extern char *sstack; /* shadow stack, for string space extension */ | 157 | extern char *sstack; /* shadow stack, for string space extension */ | |
158 | extern FILE *active; /* active output file pointer */ | 158 | extern FILE *active; /* active output file pointer */ | |
159 | extern struct input_file infile[];/* input file stack (0=stdin) */ | 159 | extern struct input_file infile[];/* input file stack (0=stdin) */ | |
160 | extern FILE **outfile; /* diversion array(0=bitbucket) */ | 160 | extern FILE **outfile; /* diversion array(0=bitbucket) */ | |
161 | extern int maxout; /* maximum number of diversions */ | 161 | extern int maxout; /* maximum number of diversions */ | |
162 | extern int fp; /* m4 call frame pointer */ | 162 | extern int fp; /* m4 call frame pointer */ | |
163 | extern int ilevel; /* input file stack pointer */ | 163 | extern int ilevel; /* input file stack pointer */ | |
164 | extern int oindex; /* diversion index. */ | 164 | extern int oindex; /* diversion index. */ | |
165 | extern int sp; /* current m4 stack pointer */ | 165 | extern int sp; /* current m4 stack pointer */ | |
166 | extern unsigned char *bp; /* first available character */ | 166 | extern unsigned char *bp; /* first available character */ | |
167 | extern unsigned char *buf; /* push-back buffer */ | 167 | extern unsigned char *buf; /* push-back buffer */ | |
168 | extern unsigned char *bufbase; /* buffer base for this ilevel */ | 168 | extern unsigned char *bufbase; /* buffer base for this ilevel */ | |
169 | extern unsigned char *bbase[]; /* buffer base per ilevel */ | 169 | extern unsigned char *bbase[]; /* buffer base per ilevel */ | |
170 | extern char ecommt[MAXCCHARS+1];/* end character for comment */ | 170 | extern char ecommt[MAXCCHARS+1];/* end character for comment */ | |
171 | extern char *ep; /* first free char in strspace */ | 171 | extern char *ep; /* first free char in strspace */ | |
172 | extern char lquote[MAXCCHARS+1];/* left quote character (`) */ | 172 | extern char lquote[MAXCCHARS+1];/* left quote character (`) */ | |
173 | extern char **m4wraps; /* m4wrap string default. */ | 173 | extern char **m4wraps; /* m4wrap string default. */ | |
174 | extern int maxwraps; /* size of m4wraps array */ | 174 | extern int maxwraps; /* size of m4wraps array */ | |
175 | extern int wrapindex; /* current index in m4wraps */ | 175 | extern int wrapindex; /* current index in m4wraps */ | |
176 | extern int fatal_warnings; /* exit on warning */ | 176 | extern int fatal_warnings; /* exit on warning */ | |
177 | extern int quiet; /* no warnings */ | 177 | extern int quiet; /* no warnings */ | |
178 | extern int nesting_limit; /* macro expansion nesting limit */ | 178 | extern int nesting_limit; /* macro expansion nesting limit */ | |
179 | #ifndef REAL_FREEZE | 179 | #ifndef REAL_FREEZE | |
180 | extern FILE *freezef; /* copy of input */ | 180 | extern FILE *freezef; /* copy of input */ | |
181 | extern int thawing; /* don't process includes during thaw */ | 181 | extern int thawing; /* don't process includes during thaw */ | |
182 | #endif | 182 | #endif | |
183 | 183 | |||
184 | extern const char *null; /* as it says.. just a null. */ | 184 | extern const char *null; /* as it says.. just a null. */ | |
185 | extern char rquote[MAXCCHARS+1];/* right quote character (') */ | 185 | extern char rquote[MAXCCHARS+1];/* right quote character (') */ | |
186 | extern char scommt[MAXCCHARS+1];/* start character for comment */ | 186 | extern char scommt[MAXCCHARS+1];/* start character for comment */ | |
187 | extern int synch_lines; /* line synchronisation directives */ | 187 | extern int synch_lines; /* line synchronisation directives */ | |
188 | 188 | |||
189 | extern int mimic_gnu; /* behaves like gnu-m4 */ | 189 | extern int mimic_gnu; /* behaves like gnu-m4 */ | |
190 | extern int prefix_builtins; /* prefix builtin macros with m4_ */ | 190 | extern int prefix_builtins; /* prefix builtin macros with m4_ */ |
--- src/usr.bin/m4/m4.1 2016/01/17 11:24:28 1.27
+++ src/usr.bin/m4/m4.1 2020/07/07 10:40:46 1.27.18.1
@@ -1,522 +1,519 @@ | @@ -1,522 +1,519 @@ | |||
1 | .\" $NetBSD: m4.1,v 1.27 2016/01/17 11:24:28 wiz Exp $ | 1 | .\" $NetBSD: m4.1,v 1.27.18.1 2020/07/07 10:40:46 martin Exp $ | |
2 | .\" @(#) $OpenBSD: m4.1,v 1.56 2009/10/14 17:19:47 sthen Exp $ | 2 | .\" @(#) $OpenBSD: m4.1,v 1.56 2009/10/14 17:19:47 sthen Exp $ | |
3 | .\" | 3 | .\" | |
4 | .\" Copyright (c) 1989, 1993 | 4 | .\" Copyright (c) 1989, 1993 | |
5 | .\" The Regents of the University of California. All rights reserved. | 5 | .\" The Regents of the University of California. All rights reserved. | |
6 | .\" | 6 | .\" | |
7 | .\" This code is derived from software contributed to Berkeley by | 7 | .\" This code is derived from software contributed to Berkeley by | |
8 | .\" Ozan Yigit at York University. | 8 | .\" Ozan Yigit at York University. | |
9 | .\" | 9 | .\" | |
10 | .\" Redistribution and use in source and binary forms, with or without | 10 | .\" Redistribution and use in source and binary forms, with or without | |
11 | .\" modification, are permitted provided that the following conditions | 11 | .\" modification, are permitted provided that the following conditions | |
12 | .\" are met: | 12 | .\" are met: | |
13 | .\" 1. Redistributions of source code must retain the above copyright | 13 | .\" 1. Redistributions of source code must retain the above copyright | |
14 | .\" notice, this list of conditions and the following disclaimer. | 14 | .\" notice, this list of conditions and the following disclaimer. | |
15 | .\" 2. Redistributions in binary form must reproduce the above copyright | 15 | .\" 2. Redistributions in binary form must reproduce the above copyright | |
16 | .\" notice, this list of conditions and the following disclaimer in the | 16 | .\" notice, this list of conditions and the following disclaimer in the | |
17 | .\" documentation and/or other materials provided with the distribution. | 17 | .\" documentation and/or other materials provided with the distribution. | |
18 | .\" 3. Neither the name of the University nor the names of its contributors | 18 | .\" 3. Neither the name of the University nor the names of its contributors | |
19 | .\" may be used to endorse or promote products derived from this software | 19 | .\" may be used to endorse or promote products derived from this software | |
20 | .\" without specific prior written permission. | 20 | .\" without specific prior written permission. | |
21 | .\" | 21 | .\" | |
22 | .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | 22 | .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
23 | .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 23 | .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
24 | .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 24 | .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
25 | .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | 25 | .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
26 | .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 26 | .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
27 | .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 27 | .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
28 | .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 28 | .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
29 | .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 29 | .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
30 | .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 30 | .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
31 | .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 31 | .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
32 | .\" SUCH DAMAGE. | 32 | .\" SUCH DAMAGE. | |
33 | .\" | 33 | .\" | |
34 | .Dd January 16, 2015 | 34 | .Dd June 25, 2020 | |
35 | .Dt M4 1 | 35 | .Dt M4 1 | |
36 | .Os | 36 | .Os | |
37 | .Sh NAME | 37 | .Sh NAME | |
38 | .Nm m4 | 38 | .Nm m4 | |
39 | .Nd macro language processor | 39 | .Nd macro language processor | |
40 | .Sh SYNOPSIS | 40 | .Sh SYNOPSIS | |
41 | .Nm m4 | 41 | .Nm m4 | |
42 | .Op Fl EGgiPQsv | 42 | .Op Fl EGgiPQsv | |
43 | .Oo | 43 | .Oo | |
44 | .Sm off | 44 | .Sm off | |
45 | .Fl D Ar name Op No = Ar value | 45 | .Fl D Ar name Op No = Ar value | |
46 | .Sm on | 46 | .Sm on | |
47 | .Oc | 47 | .Oc | |
48 | .Op Fl d Ar flags | 48 | .Op Fl d Ar flags | |
49 | .Op Fl e Ar filename | |||
50 | .Op Fl F Ar filename | 49 | .Op Fl F Ar filename | |
51 | .Op Fl I Ar dirname | 50 | .Op Fl I Ar dirname | |
52 | .Op Fl L Ar number | 51 | .Op Fl L Ar number | |
53 | .Op Fl o Ar filename | 52 | .Op Fl o Ar filename | |
54 | .Op Fl R Ar filename | 53 | .Op Fl R Ar filename | |
55 | .Op Fl t Ar macro | 54 | .Op Fl t Ar macro | |
56 | .Op Fl U Ns Ar name | 55 | .Op Fl U Ns Ar name | |
57 | .Op Ar | 56 | .Op Ar | |
58 | .Sh DESCRIPTION | 57 | .Sh DESCRIPTION | |
59 | The | 58 | The | |
60 | .Nm m4 | 59 | .Nm m4 | |
61 | utility is a macro processor that can be used as a front end to any | 60 | utility is a macro processor that can be used as a front end to any | |
62 | language (e.g., C, ratfor, fortran, lex, and yacc). | 61 | language (e.g., C, ratfor, fortran, lex, and yacc). | |
63 | If no input files are given, | 62 | If no input files are given, | |
64 | .Nm m4 | 63 | .Nm m4 | |
65 | reads from the standard input, | 64 | reads from the standard input, | |
66 | otherwise files specified on the command line are | 65 | otherwise files specified on the command line are | |
67 | processed in the given order. | 66 | processed in the given order. | |
68 | Input files can be regular files, files in the m4 include paths, or a | 67 | Input files can be regular files, files in the m4 include paths, or a | |
69 | single dash | 68 | single dash | |
70 | .Pq Sq - , | 69 | .Pq Sq - , | |
71 | denoting standard input. | 70 | denoting standard input. | |
72 | .Nm m4 | 71 | .Nm m4 | |
73 | writes | 72 | writes | |
74 | the processed text to the standard output, unless told otherwise. | 73 | the processed text to the standard output, unless told otherwise. | |
75 | .Pp | 74 | .Pp | |
76 | Macro calls have the form name(argument1[, argument2, ..., argumentN]). | 75 | Macro calls have the form name(argument1[, argument2, ..., argumentN]). | |
77 | .Pp | 76 | .Pp | |
78 | There cannot be any space following the macro name and the open | 77 | There cannot be any space following the macro name and the open | |
79 | parenthesis | 78 | parenthesis | |
80 | .Sq \&( . | 79 | .Sq \&( . | |
81 | If the macro name is not followed by an open | 80 | If the macro name is not followed by an open | |
82 | parenthesis it is processed with no arguments. | 81 | parenthesis it is processed with no arguments. | |
83 | .Pp | 82 | .Pp | |
84 | Macro names consist of a leading alphabetic or underscore | 83 | Macro names consist of a leading alphabetic or underscore | |
85 | possibly followed by alphanumeric or underscore characters, e.g., | 84 | possibly followed by alphanumeric or underscore characters, e.g., | |
86 | valid macro names match the pattern | 85 | valid macro names match the pattern | |
87 | .Dq [a-zA-Z_][a-zA-Z0-9_]* . | 86 | .Dq [a-zA-Z_][a-zA-Z0-9_]* . | |
88 | .Pp | 87 | .Pp | |
89 | In arguments to macros, leading unquoted space, tab, and newline | 88 | In arguments to macros, leading unquoted space, tab, and newline | |
90 | .Pq Sq \en | 89 | .Pq Sq \en | |
91 | characters are ignored. | 90 | characters are ignored. | |
92 | To quote strings, use left and right single quotes | 91 | To quote strings, use left and right single quotes | |
93 | .Po e.g.,\ \& | 92 | .Po e.g.,\ \& | |
94 | .Sq "\ this is a string with a leading space" | 93 | .Sq "\ this is a string with a leading space" | |
95 | .Pc . | 94 | .Pc . | |
96 | You can change the quote characters with the | 95 | You can change the quote characters with the | |
97 | .Ic changequote | 96 | .Ic changequote | |
98 | built-in macro. | 97 | built-in macro. | |
99 | .Pp | 98 | .Pp | |
100 | Most built-ins don't make any sense without arguments, and hence are not | 99 | Most built-ins don't make any sense without arguments, and hence are not | |
101 | recognized as special when not followed by an open parenthesis. | 100 | recognized as special when not followed by an open parenthesis. | |
102 | .Pp | 101 | .Pp | |
103 | The options are as follows: | 102 | The options are as follows: | |
104 | .Bl -tag -width Ds | 103 | .Bl -tag -width Ds | |
105 | .It Fl D , Fl Fl define Ar name Ns Op Pf = Ns Ar value | 104 | .It Fl D , Fl Fl define Ar name Ns Op Pf = Ns Ar value | |
106 | Define the symbol | 105 | Define the symbol | |
107 | .Ar name | 106 | .Ar name | |
108 | to have some value (or | 107 | to have some value (or | |
109 | .Dv NULL ) . | 108 | .Dv NULL ) . | |
110 | .It Fl d , Fl Fl debug Ar "flags" | 109 | .It Fl d , Fl Fl debug Ar "flags" | |
111 | Set trace flags. | 110 | Set trace flags. | |
112 | .Ar flags | 111 | .Ar flags | |
113 | may hold the following: | 112 | may hold the following: | |
114 | .Bl -tag -width Ds | 113 | .Bl -tag -width Ds | |
115 | .It Ar a | 114 | .It Ar a | |
116 | print macro arguments. | 115 | print macro arguments. | |
117 | .It Ar c | 116 | .It Ar c | |
118 | print macro expansion over several lines. | 117 | print macro expansion over several lines. | |
119 | .It Ar e | 118 | .It Ar e | |
120 | print result of macro expansion. | 119 | print result of macro expansion. | |
121 | .It Ar f | 120 | .It Ar f | |
122 | print filename location. | 121 | print filename location. | |
123 | .It Ar l | 122 | .It Ar l | |
124 | print line number. | 123 | print line number. | |
125 | .It Ar q | 124 | .It Ar q | |
126 | quote arguments and expansion with the current quotes. | 125 | quote arguments and expansion with the current quotes. | |
127 | .It Ar t | 126 | .It Ar t | |
128 | start with all macros traced. | 127 | start with all macros traced. | |
129 | .It Ar x | 128 | .It Ar x | |
130 | number macro expansions. | 129 | number macro expansions. | |
131 | .It Ar V | 130 | .It Ar V | |
132 | turn on all options. | 131 | turn on all options. | |
133 | .El | 132 | .El | |
134 | .Pp | 133 | .Pp | |
135 | By default, trace is set to | 134 | By default, trace is set to | |
136 | .Qq eq . | 135 | .Qq eq . | |
137 | .It Fl E , Fl Fl fatal-warnings | 136 | .It Fl E , Fl Fl fatal-warnings | |
138 | Warnings make | 137 | Warnings make | |
139 | .Nm | 138 | .Nm | |
140 | exit. | 139 | exit. | |
141 | .It Fl e , Fl Fl error-output Ar filename | |||
142 | Redirect error output to filename. | |||
143 | .It Fl F , Fl Fl freeze-state Ar filename | 140 | .It Fl F , Fl Fl freeze-state Ar filename | |
144 | Save the input state to | 141 | Save the input state to | |
145 | .Ar filename . | 142 | .Ar filename . | |
146 | .It Fl G , Fl Fl traditional | 143 | .It Fl G , Fl Fl traditional | |
147 | Disable GNU-m4 extensions. | 144 | Disable GNU-m4 extensions. | |
148 | .It Fl g , Fl Fl gnu | 145 | .It Fl g , Fl Fl gnu | |
149 | Activate GNU-m4 compatibility mode. | 146 | Activate GNU-m4 compatibility mode. | |
150 | In this mode, translit handles simple character | 147 | In this mode, translit handles simple character | |
151 | ranges (e.g., a-z), regular expressions mimic emacs behavior, | 148 | ranges (e.g., a-z), regular expressions mimic emacs behavior, | |
152 | multiple m4wrap calls are handled as a stack, | 149 | multiple m4wrap calls are handled as a stack, | |
153 | the number of diversions is unlimited, | 150 | the number of diversions is unlimited, | |
154 | empty names for macro definitions are allowed, | 151 | empty names for macro definitions are allowed, | |
155 | and eval understands | 152 | and eval understands | |
156 | .Sq 0rbase:value | 153 | .Sq 0rbase:value | |
157 | numbers. | 154 | numbers. | |
158 | .It Fl Fl help | 155 | .It Fl Fl help | |
159 | Print help message and exit. | 156 | Print help message and exit. | |
160 | .It Fl I , Fl Fl include Ar "dirname" | 157 | .It Fl I , Fl Fl include Ar "dirname" | |
161 | Add directory | 158 | Add directory | |
162 | .Ar dirname | 159 | .Ar dirname | |
163 | to the include path. | 160 | to the include path. | |
164 | .It Fl i , Fl Fl interactive | 161 | .It Fl i , Fl Fl interactive | |
165 | Set unbuffered output, disable tty signals. | 162 | Set unbuffered output, disable tty signals. | |
166 | .It Fl L , Fl Fl nesting-limit | 163 | .It Fl L , Fl Fl nesting-limit | |
167 | Set the nesting limit in macro expansions. | 164 | Set the nesting limit in macro expansions. | |
168 | This is unimplemented and unlimited. | 165 | This is unimplemented and unlimited. | |
169 | .It Fl o Ar filename | 166 | .It Fl o , Fl Fl error-output Ar filename | |
170 | Send trace output to | 167 | Send trace output to | |
171 | .Ar filename . | 168 | .Ar filename . | |
172 | .It Fl P , Fl Fl prefix-builtins | 169 | .It Fl P , Fl Fl prefix-builtins | |
173 | Prefix all built-in macros with | 170 | Prefix all built-in macros with | |
174 | .Sq m4_ . | 171 | .Sq m4_ . | |
175 | For example, instead of writing | 172 | For example, instead of writing | |
176 | .Ic define , | 173 | .Ic define , | |
177 | use | 174 | use | |
178 | .Ic m4_define . | 175 | .Ic m4_define . | |
179 | .It Fl Q , Fl Fl quiet , Fl Fl silent | 176 | .It Fl Q , Fl Fl quiet , Fl Fl silent | |
180 | Don't print warnings. | 177 | Don't print warnings. | |
181 | .It Fl R , Fl Fl reload-state Ar filename | 178 | .It Fl R , Fl Fl reload-state Ar filename | |
182 | Reload a previously saved state from | 179 | Reload a previously saved state from | |
183 | .Ar filename . | 180 | .Ar filename . | |
184 | .It Fl s , Fl Fl synclines | 181 | .It Fl s , Fl Fl synclines | |
185 | Output line synchronization directives, suitable for | 182 | Output line synchronization directives, suitable for | |
186 | .Xr cpp 1 . | 183 | .Xr cpp 1 . | |
187 | .It Fl t , Fl Fl trace Ar macro | 184 | .It Fl t , Fl Fl trace Ar macro | |
188 | Turn tracing on for | 185 | Turn tracing on for | |
189 | .Ar macro . | 186 | .Ar macro . | |
190 | .It Fl U , Fl Fl undefine Ar "name" | 187 | .It Fl U , Fl Fl undefine Ar "name" | |
191 | Undefine the symbol | 188 | Undefine the symbol | |
192 | .Ar name . | 189 | .Ar name . | |
193 | .It Fl v , Fl Fl version | 190 | .It Fl v , Fl Fl version | |
194 | Print the version and exit. | 191 | Print the version and exit. | |
195 | .El | 192 | .El | |
196 | .Sh SYNTAX | 193 | .Sh SYNTAX | |
197 | .Nm m4 | 194 | .Nm m4 | |
198 | provides the following built-in macros. | 195 | provides the following built-in macros. | |
199 | They may be redefined, losing their original meaning. | 196 | They may be redefined, losing their original meaning. | |
200 | Return values are null unless otherwise stated. | 197 | Return values are null unless otherwise stated. | |
201 | .Bl -tag -width changequote | 198 | .Bl -tag -width changequote | |
202 | .It Fn builtin name | 199 | .It Fn builtin name | |
203 | Calls a built-in by its | 200 | Calls a built-in by its | |
204 | .Fa name , | 201 | .Fa name , | |
205 | overriding possible redefinitions. | 202 | overriding possible redefinitions. | |
206 | .It Fn changecom startcomment endcomment | 203 | .It Fn changecom startcomment endcomment | |
207 | Changes the start comment and end comment sequences. | 204 | Changes the start comment and end comment sequences. | |
208 | Comment sequences may be up to five characters long. | 205 | Comment sequences may be up to five characters long. | |
209 | The default values are the hash sign | 206 | The default values are the hash sign | |
210 | and the newline character. | 207 | and the newline character. | |
211 | .Bd -literal -offset indent | 208 | .Bd -literal -offset indent | |
212 | # This is a comment | 209 | # This is a comment | |
213 | .Ed | 210 | .Ed | |
214 | .Pp | 211 | .Pp | |
215 | With no arguments, comments are turned off. | 212 | With no arguments, comments are turned off. | |
216 | With one single argument, the end comment sequence is set | 213 | With one single argument, the end comment sequence is set | |
217 | to the newline character. | 214 | to the newline character. | |
218 | .It Fn changequote beginquote endquote | 215 | .It Fn changequote beginquote endquote | |
219 | Defines the open quote and close quote sequences. | 216 | Defines the open quote and close quote sequences. | |
220 | Quote sequences may be up to five characters long. | 217 | Quote sequences may be up to five characters long. | |
221 | The default values are the backquote character and the quote | 218 | The default values are the backquote character and the quote | |
222 | character. | 219 | character. | |
223 | .Bd -literal -offset indent | 220 | .Bd -literal -offset indent | |
224 | `Here is a quoted string' | 221 | `Here is a quoted string' | |
225 | .Ed | 222 | .Ed | |
226 | .Pp | 223 | .Pp | |
227 | With no arguments, the default quotes are restored. | 224 | With no arguments, the default quotes are restored. | |
228 | With one single argument, the close quote sequence is set | 225 | With one single argument, the close quote sequence is set | |
229 | to the newline character. | 226 | to the newline character. | |
230 | .It Fn decr arg | 227 | .It Fn decr arg | |
231 | Decrements the argument | 228 | Decrements the argument | |
232 | .Fa arg | 229 | .Fa arg | |
233 | by 1. | 230 | by 1. | |
234 | The argument | 231 | The argument | |
235 | .Fa arg | 232 | .Fa arg | |
236 | must be a valid numeric string. | 233 | must be a valid numeric string. | |
237 | .It Fn define name value | 234 | .It Fn define name value | |
238 | Define a new macro named by the first argument | 235 | Define a new macro named by the first argument | |
239 | .Fa name | 236 | .Fa name | |
240 | to have the | 237 | to have the | |
241 | value of the second argument | 238 | value of the second argument | |
242 | .Fa value . | 239 | .Fa value . | |
243 | Each occurrence of | 240 | Each occurrence of | |
244 | .Sq $n | 241 | .Sq $n | |
245 | (where | 242 | (where | |
246 | .Ar n | 243 | .Ar n | |
247 | is 0 through 9) is replaced by the | 244 | is 0 through 9) is replaced by the | |
248 | .Ar n Ns 'th | 245 | .Ar n Ns 'th | |
249 | argument. | 246 | argument. | |
250 | .Sq $0 | 247 | .Sq $0 | |
251 | is the name of the calling macro. | 248 | is the name of the calling macro. | |
252 | Undefined arguments are replaced by a null string. | 249 | Undefined arguments are replaced by a null string. | |
253 | .Sq $# | 250 | .Sq $# | |
254 | is replaced by the number of arguments; | 251 | is replaced by the number of arguments; | |
255 | .Sq $* | 252 | .Sq $* | |
256 | is replaced by all arguments comma separated; | 253 | is replaced by all arguments comma separated; | |
257 | .Sq $@ | 254 | .Sq $@ | |
258 | is the same as | 255 | is the same as | |
259 | .Sq $* | 256 | .Sq $* | |
260 | but all arguments are quoted against further expansion. | 257 | but all arguments are quoted against further expansion. | |
261 | .It Fn defn name ... | 258 | .It Fn defn name ... | |
262 | Returns the quoted definition for each argument. | 259 | Returns the quoted definition for each argument. | |
263 | This can be used to rename | 260 | This can be used to rename | |
264 | macro definitions (even for built-in macros). | 261 | macro definitions (even for built-in macros). | |
265 | .It Fn divert num | 262 | .It Fn divert num | |
266 | There are 10 output queues (numbered 0-9). | 263 | There are 10 output queues (numbered 0-9). | |
267 | At the end of processing | 264 | At the end of processing | |
268 | .Nm m4 | 265 | .Nm m4 | |
269 | concatenates all the queues in numerical order to produce the | 266 | concatenates all the queues in numerical order to produce the | |
270 | final output. | 267 | final output. | |
271 | Initially the output queue is 0. | 268 | Initially the output queue is 0. | |
272 | The divert | 269 | The divert | |
273 | macro allows you to select a new output queue (an invalid argument | 270 | macro allows you to select a new output queue (an invalid argument | |
274 | passed to divert causes output to be discarded). | 271 | passed to divert causes output to be discarded). | |
275 | .It Ic divnum | 272 | .It Ic divnum | |
276 | Returns the current output queue number. | 273 | Returns the current output queue number. | |
277 | .It Ic dnl | 274 | .It Ic dnl | |
278 | Discard input characters up to and including the next newline. | 275 | Discard input characters up to and including the next newline. | |
279 | .It Fn dumpdef name ... | 276 | .It Fn dumpdef name ... | |
280 | Prints the names and definitions for the named items, or for everything | 277 | Prints the names and definitions for the named items, or for everything | |
281 | if no arguments are passed. | 278 | if no arguments are passed. | |
282 | .It Fn errprint msg | 279 | .It Fn errprint msg | |
283 | Prints the first argument on the standard error output stream. | 280 | Prints the first argument on the standard error output stream. | |
284 | .It Fn esyscmd cmd | 281 | .It Fn esyscmd cmd | |
285 | Passes its first argument to a shell and returns the shell's standard output. | 282 | Passes its first argument to a shell and returns the shell's standard output. | |
286 | Note that the shell shares its standard input and standard error with | 283 | Note that the shell shares its standard input and standard error with | |
287 | .Nm m4 . | 284 | .Nm m4 . | |
288 | .It Fn eval expr[,radix[,minimum]] | 285 | .It Fn eval expr[,radix[,minimum]] | |
289 | Computes the first argument as an arithmetic expression using 32-bit | 286 | Computes the first argument as an arithmetic expression using 32-bit | |
290 | arithmetic. | 287 | arithmetic. | |
291 | Operators are the standard C ternary, arithmetic, logical, | 288 | Operators are the standard C ternary, arithmetic, logical, | |
292 | shift, relational, bitwise, and parentheses operators. | 289 | shift, relational, bitwise, and parentheses operators. | |
293 | You can specify | 290 | You can specify | |
294 | octal, decimal, and hexadecimal numbers as in C. | 291 | octal, decimal, and hexadecimal numbers as in C. | |
295 | The optional second argument | 292 | The optional second argument | |
296 | .Fa radix | 293 | .Fa radix | |
297 | specifies the radix for the result and the optional third argument | 294 | specifies the radix for the result and the optional third argument | |
298 | .Fa minimum | 295 | .Fa minimum | |
299 | specifies the minimum number of digits in the result. | 296 | specifies the minimum number of digits in the result. | |
300 | .It Fn expr expr | 297 | .It Fn expr expr | |
301 | This is an alias for | 298 | This is an alias for | |
302 | .Ic eval . | 299 | .Ic eval . | |
303 | .It Fn format formatstring arg1 ... | 300 | .It Fn format formatstring arg1 ... | |
304 | Returns | 301 | Returns | |
305 | .Fa formatstring | 302 | .Fa formatstring | |
306 | with escape sequences substituted with | 303 | with escape sequences substituted with | |
307 | .Fa arg1 | 304 | .Fa arg1 | |
308 | and following arguments, in a way similar to | 305 | and following arguments, in a way similar to | |
309 | .Xr printf 3 . | 306 | .Xr printf 3 . | |
310 | This built-in is only available in GNU-m4 compatibility mode, and the only | 307 | This built-in is only available in GNU-m4 compatibility mode, and the only | |
311 | parameters implemented are there for autoconf compatibility: | 308 | parameters implemented are there for autoconf compatibility: | |
312 | left-padding flag, an optional field width, a maximum field width, | 309 | left-padding flag, an optional field width, a maximum field width, | |
313 | *-specified field widths, and the %s and %c data type. | 310 | *-specified field widths, and the %s and %c data type. | |
314 | .It Fn ifdef name yes no | 311 | .It Fn ifdef name yes no | |
315 | If the macro named by the first argument is defined then return the second | 312 | If the macro named by the first argument is defined then return the second | |
316 | argument, otherwise the third. | 313 | argument, otherwise the third. | |
317 | If there is no third argument, the value is | 314 | If there is no third argument, the value is | |
318 | .Dv NULL . | 315 | .Dv NULL . | |
319 | The word | 316 | The word | |
320 | .Qq unix | 317 | .Qq unix | |
321 | is predefined. | 318 | is predefined. | |
322 | .It Fn ifelse a b yes ... | 319 | .It Fn ifelse a b yes ... | |
323 | If the first argument | 320 | If the first argument | |
324 | .Fa a | 321 | .Fa a | |
325 | matches the second argument | 322 | matches the second argument | |
326 | .Fa b | 323 | .Fa b | |
327 | then | 324 | then | |
328 | .Fn ifelse | 325 | .Fn ifelse | |
329 | returns | 326 | returns | |
330 | the third argument | 327 | the third argument | |
331 | .Fa yes . | 328 | .Fa yes . | |
332 | If the match fails the three arguments are | 329 | If the match fails the three arguments are | |
333 | discarded and the next three arguments are used until there is | 330 | discarded and the next three arguments are used until there is | |
334 | zero or one arguments left, either this last argument or | 331 | zero or one arguments left, either this last argument or | |
335 | .Dv NULL | 332 | .Dv NULL | |
336 | is returned if no other matches were found. | 333 | is returned if no other matches were found. | |
337 | .It Fn include name | 334 | .It Fn include name | |
338 | Returns the contents of the file specified in the first argument. | 335 | Returns the contents of the file specified in the first argument. | |
339 | If the file is not found as is, look through the include path: | 336 | If the file is not found as is, look through the include path: | |
340 | first the directories specified with | 337 | first the directories specified with | |
341 | .Fl I | 338 | .Fl I | |
342 | on the command line, then the environment variable | 339 | on the command line, then the environment variable | |
343 | .Ev M4PATH , | 340 | .Ev M4PATH , | |
344 | as a colon-separated list of directories. | 341 | as a colon-separated list of directories. | |
345 | Include aborts with an error message if the file cannot be included. | 342 | Include aborts with an error message if the file cannot be included. | |
346 | .It Fn incr arg | 343 | .It Fn incr arg | |
347 | Increments the argument by 1. | 344 | Increments the argument by 1. | |
348 | The argument must be a valid numeric string. | 345 | The argument must be a valid numeric string. | |
349 | .It Fn index string substring | 346 | .It Fn index string substring | |
350 | Returns the index of the second argument in the first argument (e.g., | 347 | Returns the index of the second argument in the first argument (e.g., | |
351 | .Ic index(the quick brown fox jumped, fox) | 348 | .Ic index(the quick brown fox jumped, fox) | |
352 | returns 16). | 349 | returns 16). | |
353 | If the second | 350 | If the second | |
354 | argument is not found index returns \-1. | 351 | argument is not found index returns \-1. | |
355 | .It Fn indir macro arg1 ... | 352 | .It Fn indir macro arg1 ... | |
356 | Indirectly calls the macro whose name is passed as the first argument, | 353 | Indirectly calls the macro whose name is passed as the first argument, | |
357 | with the remaining arguments passed as first, ... arguments. | 354 | with the remaining arguments passed as first, ... arguments. | |
358 | .It Fn len arg | 355 | .It Fn len arg | |
359 | Returns the number of characters in the first argument. | 356 | Returns the number of characters in the first argument. | |
360 | Extra arguments | 357 | Extra arguments | |
361 | are ignored. | 358 | are ignored. | |
362 | .It Fn m4exit code | 359 | .It Fn m4exit code | |
363 | Immediately exits with the return value specified by the first argument, | 360 | Immediately exits with the return value specified by the first argument, | |
364 | 0 if none. | 361 | 0 if none. | |
365 | .It Fn m4wrap todo | 362 | .It Fn m4wrap todo | |
366 | Allows you to define what happens at the final | 363 | Allows you to define what happens at the final | |
367 | .Dv EOF , | 364 | .Dv EOF , | |
368 | usually for cleanup purposes (e.g., | 365 | usually for cleanup purposes (e.g., | |
369 | .Ic m4wrap("cleanup(tempfile)") | 366 | .Ic m4wrap("cleanup(tempfile)") | |
370 | causes the macro cleanup to be | 367 | causes the macro cleanup to be | |
371 | invoked after all other processing is done). | 368 | invoked after all other processing is done). | |
372 | .Pp | 369 | .Pp | |
373 | Multiple calls to | 370 | Multiple calls to | |
374 | .Fn m4wrap | 371 | .Fn m4wrap | |
375 | get inserted in sequence at the final | 372 | get inserted in sequence at the final | |
376 | .Dv EOF . | 373 | .Dv EOF . | |
377 | .It Fn maketemp template | 374 | .It Fn maketemp template | |
378 | Invokes | 375 | Invokes | |
379 | .Xr mkstemp 3 | 376 | .Xr mkstemp 3 | |
380 | on the first argument, and returns the modified string. | 377 | on the first argument, and returns the modified string. | |
381 | This can be used to create unique | 378 | This can be used to create unique | |
382 | temporary file names. | 379 | temporary file names. | |
383 | .It Fn paste file | 380 | .It Fn paste file | |
384 | Includes the contents of the file specified by the first argument without | 381 | Includes the contents of the file specified by the first argument without | |
385 | any macro processing. | 382 | any macro processing. | |
386 | Aborts with an error message if the file cannot be | 383 | Aborts with an error message if the file cannot be | |
387 | included. | 384 | included. | |
388 | .It Fn patsubst string regexp replacement | 385 | .It Fn patsubst string regexp replacement | |
389 | Substitutes a regular expression in a string with a replacement string. | 386 | Substitutes a regular expression in a string with a replacement string. | |
390 | Usual substitution patterns apply: an ampersand | 387 | Usual substitution patterns apply: an ampersand | |
391 | .Pq Sq \&& | 388 | .Pq Sq \&& | |
392 | is replaced by the string matching the regular expression. | 389 | is replaced by the string matching the regular expression. | |
393 | The string | 390 | The string | |
394 | .Sq \e# , | 391 | .Sq \e# , | |
395 | where | 392 | where | |
396 | .Sq # | 393 | .Sq # | |
397 | is a digit, is replaced by the corresponding back-reference. | 394 | is a digit, is replaced by the corresponding back-reference. | |
398 | .It Fn popdef arg ... | 395 | .It Fn popdef arg ... | |
399 | Restores the | 396 | Restores the | |
400 | .Ic pushdef Ns ed | 397 | .Ic pushdef Ns ed | |
401 | definition for each argument. | 398 | definition for each argument. | |
402 | .It Fn pushdef macro def | 399 | .It Fn pushdef macro def | |
403 | Takes the same arguments as | 400 | Takes the same arguments as | |
404 | .Ic define , | 401 | .Ic define , | |
405 | but it saves the definition on a | 402 | but it saves the definition on a | |
406 | stack for later retrieval by | 403 | stack for later retrieval by | |
407 | .Fn popdef . | 404 | .Fn popdef . | |
408 | .It Fn regexp string regexp replacement | 405 | .It Fn regexp string regexp replacement | |
409 | Finds a regular expression in a string. | 406 | Finds a regular expression in a string. | |
410 | If no further arguments are given, | 407 | If no further arguments are given, | |
411 | it returns the first match position or \-1 if no match. | 408 | it returns the first match position or \-1 if no match. | |
412 | If a third argument | 409 | If a third argument | |
413 | is provided, it returns the replacement string, with sub-patterns replaced. | 410 | is provided, it returns the replacement string, with sub-patterns replaced. | |
414 | .It Fn shift arg1 ... | 411 | .It Fn shift arg1 ... | |
415 | Returns all but the first argument, the remaining arguments are | 412 | Returns all but the first argument, the remaining arguments are | |
416 | quoted and pushed back with commas in between. | 413 | quoted and pushed back with commas in between. | |
417 | The quoting | 414 | The quoting | |
418 | nullifies the effect of the extra scan that will subsequently be | 415 | nullifies the effect of the extra scan that will subsequently be | |
419 | performed. | 416 | performed. | |
420 | .It Fn sinclude file | 417 | .It Fn sinclude file | |
421 | Similar to | 418 | Similar to | |
422 | .Ic include , | 419 | .Ic include , | |
423 | except it ignores any errors. | 420 | except it ignores any errors. | |
424 | .It Fn spaste file | 421 | .It Fn spaste file | |
425 | Similar to | 422 | Similar to | |
426 | .Fn paste , | 423 | .Fn paste , | |
427 | except it ignores any errors. | 424 | except it ignores any errors. | |
428 | .It Fn substr string offset length | 425 | .It Fn substr string offset length | |
429 | Returns a substring of the first argument starting at the offset specified | 426 | Returns a substring of the first argument starting at the offset specified | |
430 | by the second argument and the length specified by the third argument. | 427 | by the second argument and the length specified by the third argument. | |
431 | If no third argument is present it returns the rest of the string. | 428 | If no third argument is present it returns the rest of the string. | |
432 | .It Fn syscmd cmd | 429 | .It Fn syscmd cmd | |
433 | Passes the first argument to the shell. | 430 | Passes the first argument to the shell. | |
434 | Nothing is returned. | 431 | Nothing is returned. | |
435 | .It Ic sysval | 432 | .It Ic sysval | |
436 | Returns the return value from the last | 433 | Returns the return value from the last | |
437 | .Ic syscmd . | 434 | .Ic syscmd . | |
438 | .It Fn traceon arg ... | 435 | .It Fn traceon arg ... | |
439 | Enables tracing of macro expansions for the given arguments, or for all | 436 | Enables tracing of macro expansions for the given arguments, or for all | |
440 | macros if no argument is given. | 437 | macros if no argument is given. | |
441 | .It Fn traceoff arg ... | 438 | .It Fn traceoff arg ... | |
442 | Disables tracing of macro expansions for the given arguments, or for all | 439 | Disables tracing of macro expansions for the given arguments, or for all | |
443 | macros if no argument is given. | 440 | macros if no argument is given. | |
444 | .It Fn translit string mapfrom mapto | 441 | .It Fn translit string mapfrom mapto | |
445 | Transliterate the characters in the first argument from the set | 442 | Transliterate the characters in the first argument from the set | |
446 | given by the second argument to the set given by the third. | 443 | given by the second argument to the set given by the third. | |
447 | You cannot use | 444 | You cannot use | |
448 | .Xr tr 1 | 445 | .Xr tr 1 | |
449 | style abbreviations. | 446 | style abbreviations. | |
450 | .It Fn undefine name1 ... | 447 | .It Fn undefine name1 ... | |
451 | Removes the definition for the macros specified by its arguments. | 448 | Removes the definition for the macros specified by its arguments. | |
452 | .It Fn undivert arg ... | 449 | .It Fn undivert arg ... | |
453 | Flushes the named output queues (or all queues if no arguments). | 450 | Flushes the named output queues (or all queues if no arguments). | |
454 | .It Ic unix | 451 | .It Ic unix | |
455 | A pre-defined macro for testing the OS platform. | 452 | A pre-defined macro for testing the OS platform. | |
456 | .It Ic __line__ | 453 | .It Ic __line__ | |
457 | Returns the current file's line number. | 454 | Returns the current file's line number. | |
458 | .It Ic __file__ | 455 | .It Ic __file__ | |
459 | Returns the current file's name. | 456 | Returns the current file's name. | |
460 | .El | 457 | .El | |
461 | .Sh STANDARDS | 458 | .Sh STANDARDS | |
462 | The | 459 | The | |
463 | .Nm | 460 | .Nm | |
464 | utility is compliant with the | 461 | utility is compliant with the | |
465 | .St -p1003.1-2008 | 462 | .St -p1003.1-2008 | |
466 | specification. | 463 | specification. | |
467 | .Pp | 464 | .Pp | |
468 | The flags | 465 | The flags | |
469 | .Op Fl dgIot | 466 | .Op Fl dgIot | |
470 | and the macros | 467 | and the macros | |
471 | .Ic builtin , | 468 | .Ic builtin , | |
472 | .Ic esyscmd , | 469 | .Ic esyscmd , | |
473 | .Ic expr , | 470 | .Ic expr , | |
474 | .Ic format , | 471 | .Ic format , | |
475 | .Ic indir , | 472 | .Ic indir , | |
476 | .Ic paste , | 473 | .Ic paste , | |
477 | .Ic patsubst , | 474 | .Ic patsubst , | |
478 | .Ic regexp , | 475 | .Ic regexp , | |
479 | .Ic spaste , | 476 | .Ic spaste , | |
480 | .Ic unix , | 477 | .Ic unix , | |
481 | .Ic __line__ , | 478 | .Ic __line__ , | |
482 | and | 479 | and | |
483 | .Ic __file__ | 480 | .Ic __file__ | |
484 | are extensions to that specification. | 481 | are extensions to that specification. | |
485 | .Pp | 482 | .Pp | |
486 | The output format of tracing and of | 483 | The output format of tracing and of | |
487 | .Ic dumpdef | 484 | .Ic dumpdef | |
488 | are not specified in any standard, | 485 | are not specified in any standard, | |
489 | are likely to change and should not be relied upon. | 486 | are likely to change and should not be relied upon. | |
490 | The current format of tracing is closely modelled on | 487 | The current format of tracing is closely modelled on | |
491 | .Nm gnu-m4 , | 488 | .Nm gnu-m4 , | |
492 | to allow | 489 | to allow | |
493 | .Nm autoconf | 490 | .Nm autoconf | |
494 | to work. | 491 | to work. | |
495 | .Pp | 492 | .Pp | |
496 | The built-ins | 493 | The built-ins | |
497 | .Ic pushdef | 494 | .Ic pushdef | |
498 | and | 495 | and | |
499 | .Ic popdef | 496 | .Ic popdef | |
500 | handle macro definitions as a stack. | 497 | handle macro definitions as a stack. | |
501 | However, | 498 | However, | |
502 | .Ic define | 499 | .Ic define | |
503 | interacts with the stack in an undefined way. | 500 | interacts with the stack in an undefined way. | |
504 | In this implementation, | 501 | In this implementation, | |
505 | .Ic define | 502 | .Ic define | |
506 | replaces the top-most definition only. | 503 | replaces the top-most definition only. | |
507 | Other implementations may erase all definitions on the stack instead. | 504 | Other implementations may erase all definitions on the stack instead. | |
508 | .Pp | 505 | .Pp | |
509 | All built-ins do expand without arguments in many other | 506 | All built-ins do expand without arguments in many other | |
510 | .Nm m4 . | 507 | .Nm m4 . | |
511 | .Pp | 508 | .Pp | |
512 | Many other | 509 | Many other | |
513 | .Nm | 510 | .Nm | |
514 | have dire size limitations with respect to buffer sizes. | 511 | have dire size limitations with respect to buffer sizes. | |
515 | .Sh AUTHORS | 512 | .Sh AUTHORS | |
516 | .An -nosplit | 513 | .An -nosplit | |
517 | .An Ozan Yigit Aq Mt oz@sis.yorku.ca | 514 | .An Ozan Yigit Aq Mt oz@sis.yorku.ca | |
518 | and | 515 | and | |
519 | .An Richard A. O'Keefe Aq Mt ok@goanna.cs.rmit.OZ.AU . | 516 | .An Richard A. O'Keefe Aq Mt ok@goanna.cs.rmit.OZ.AU . | |
520 | .Pp | 517 | .Pp | |
521 | GNU-m4 compatibility extensions by | 518 | GNU-m4 compatibility extensions by | |
522 | .An Marc Espie Aq Mt espie@cvs.openbsd.org . | 519 | .An Marc Espie Aq Mt espie@cvs.openbsd.org . |
--- src/usr.bin/m4/main.c 2019/03/26 16:41:06 1.48
+++ src/usr.bin/m4/main.c 2020/07/07 10:40:46 1.48.2.1
@@ -1,825 +1,815 @@ | @@ -1,825 +1,815 @@ | |||
1 | /* $OpenBSD: main.c,v 1.77 2009/10/14 17:19:47 sthen Exp $ */ | 1 | /* $OpenBSD: main.c,v 1.77 2009/10/14 17:19:47 sthen Exp $ */ | |
2 | /* $NetBSD: main.c,v 1.48 2019/03/26 16:41:06 christos Exp $ */ | 2 | /* $NetBSD: main.c,v 1.48.2.1 2020/07/07 10:40:46 martin Exp $ */ | |
3 | 3 | |||
4 | /*- | 4 | /*- | |
5 | * Copyright (c) 1989, 1993 | 5 | * Copyright (c) 1989, 1993 | |
6 | * The Regents of the University of California. All rights reserved. | 6 | * The Regents of the University of California. All rights reserved. | |
7 | * | 7 | * | |
8 | * This code is derived from software contributed to Berkeley by | 8 | * This code is derived from software contributed to Berkeley by | |
9 | * Ozan Yigit at York University. | 9 | * Ozan Yigit at York University. | |
10 | * | 10 | * | |
11 | * Redistribution and use in source and binary forms, with or without | 11 | * Redistribution and use in source and binary forms, with or without | |
12 | * modification, are permitted provided that the following conditions | 12 | * modification, are permitted provided that the following conditions | |
13 | * are met: | 13 | * are met: | |
14 | * 1. Redistributions of source code must retain the above copyright | 14 | * 1. Redistributions of source code must retain the above copyright | |
15 | * notice, this list of conditions and the following disclaimer. | 15 | * notice, this list of conditions and the following disclaimer. | |
16 | * 2. Redistributions in binary form must reproduce the above copyright | 16 | * 2. Redistributions in binary form must reproduce the above copyright | |
17 | * notice, this list of conditions and the following disclaimer in the | 17 | * notice, this list of conditions and the following disclaimer in the | |
18 | * documentation and/or other materials provided with the distribution. | 18 | * documentation and/or other materials provided with the distribution. | |
19 | * 3. Neither the name of the University nor the names of its contributors | 19 | * 3. Neither the name of the University nor the names of its contributors | |
20 | * may be used to endorse or promote products derived from this software | 20 | * may be used to endorse or promote products derived from this software | |
21 | * without specific prior written permission. | 21 | * without specific prior written permission. | |
22 | * | 22 | * | |
23 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | 23 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
24 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 24 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
25 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 25 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
26 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | 26 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
27 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 27 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
28 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 28 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
29 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 29 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
30 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 30 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
31 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 31 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
32 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 32 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
33 | * SUCH DAMAGE. | 33 | * SUCH DAMAGE. | |
34 | */ | 34 | */ | |
35 | 35 | |||
36 | /* | 36 | /* | |
37 | * main.c | 37 | * main.c | |
38 | * Facility: m4 macro processor | 38 | * Facility: m4 macro processor | |
39 | * by: oz | 39 | * by: oz | |
40 | */ | 40 | */ | |
41 | #if HAVE_NBTOOL_CONFIG_H | 41 | #if HAVE_NBTOOL_CONFIG_H | |
42 | #include "nbtool_config.h" | 42 | #include "nbtool_config.h" | |
43 | #endif | 43 | #endif | |
44 | #include <sys/cdefs.h> | 44 | #include <sys/cdefs.h> | |
45 | __RCSID("$NetBSD: main.c,v 1.48 2019/03/26 16:41:06 christos Exp $"); | 45 | __RCSID("$NetBSD: main.c,v 1.48.2.1 2020/07/07 10:40:46 martin Exp $"); | |
46 | #include <assert.h> | 46 | #include <assert.h> | |
47 | #include <signal.h> | 47 | #include <signal.h> | |
48 | #include <getopt.h> | 48 | #include <getopt.h> | |
49 | #include <err.h> | 49 | #include <err.h> | |
50 | #include <errno.h> | 50 | #include <errno.h> | |
51 | #include <unistd.h> | 51 | #include <unistd.h> | |
52 | #include <stdio.h> | 52 | #include <stdio.h> | |
53 | #include <ctype.h> | 53 | #include <ctype.h> | |
54 | #include <string.h> | 54 | #include <string.h> | |
55 | #include <stddef.h> | 55 | #include <stddef.h> | |
56 | #include <stdint.h> | 56 | #include <stdint.h> | |
57 | #include <stdlib.h> | 57 | #include <stdlib.h> | |
58 | #include <ohash.h> | 58 | #include <ohash.h> | |
59 | #include "mdef.h" | 59 | #include "mdef.h" | |
60 | #include "stdd.h" | 60 | #include "stdd.h" | |
61 | #include "extern.h" | 61 | #include "extern.h" | |
62 | #include "pathnames.h" | 62 | #include "pathnames.h" | |
63 | 63 | |||
64 | ndptr hashtab[HASHSIZE]; /* hash table for macros etc. */ | 64 | ndptr hashtab[HASHSIZE]; /* hash table for macros etc. */ | |
65 | stae *mstack; /* stack of m4 machine */ | 65 | stae *mstack; /* stack of m4 machine */ | |
66 | char *sstack; /* shadow stack, for string space extension */ | 66 | char *sstack; /* shadow stack, for string space extension */ | |
67 | static size_t STACKMAX; /* current maximum size of stack */ | 67 | static size_t STACKMAX; /* current maximum size of stack */ | |
68 | int sp; /* current m4 stack pointer */ | 68 | int sp; /* current m4 stack pointer */ | |
69 | int fp; /* m4 call frame pointer */ | 69 | int fp; /* m4 call frame pointer */ | |
70 | struct input_file infile[MAXINP];/* input file stack (0=stdin) */ | 70 | struct input_file infile[MAXINP];/* input file stack (0=stdin) */ | |
71 | FILE **outfile; /* diversion array(0=bitbucket)*/ | 71 | FILE **outfile; /* diversion array(0=bitbucket)*/ | |
72 | int maxout; | 72 | int maxout; | |
73 | FILE *active; /* active output file pointer */ | 73 | FILE *active; /* active output file pointer */ | |
74 | int ilevel = 0; /* input file stack pointer */ | 74 | int ilevel = 0; /* input file stack pointer */ | |
75 | int oindex = 0; /* diversion index.. */ | 75 | int oindex = 0; /* diversion index.. */ | |
76 | const char *null = ""; /* as it says.. just a null.. */ | 76 | const char *null = ""; /* as it says.. just a null.. */ | |
77 | char **m4wraps = NULL; /* m4wraps array. */ | 77 | char **m4wraps = NULL; /* m4wraps array. */ | |
78 | int maxwraps = 0; /* size of m4wraps array */ | 78 | int maxwraps = 0; /* size of m4wraps array */ | |
79 | int wrapindex = 0; /* current offset in m4wraps */ | 79 | int wrapindex = 0; /* current offset in m4wraps */ | |
80 | char lquote[MAXCCHARS+1] = {LQUOTE}; /* left quote character (`) */ | 80 | char lquote[MAXCCHARS+1] = {LQUOTE}; /* left quote character (`) */ | |
81 | char rquote[MAXCCHARS+1] = {RQUOTE}; /* right quote character (') */ | 81 | char rquote[MAXCCHARS+1] = {RQUOTE}; /* right quote character (') */ | |
82 | char scommt[MAXCCHARS+1] = {SCOMMT}; /* start character for comment */ | 82 | char scommt[MAXCCHARS+1] = {SCOMMT}; /* start character for comment */ | |
83 | char ecommt[MAXCCHARS+1] = {ECOMMT}; /* end character for comment */ | 83 | char ecommt[MAXCCHARS+1] = {ECOMMT}; /* end character for comment */ | |
84 | int synch_lines = 0; /* line synchronisation for C preprocessor */ | 84 | int synch_lines = 0; /* line synchronisation for C preprocessor */ | |
85 | int prefix_builtins = 0; /* -P option to prefix builtin keywords */ | 85 | int prefix_builtins = 0; /* -P option to prefix builtin keywords */ | |
86 | int fatal_warnings = 0; /* -E option to exit on warnings */ | 86 | int fatal_warnings = 0; /* -E option to exit on warnings */ | |
87 | int quiet = 0; /* -Q option to silence warnings */ | 87 | int quiet = 0; /* -Q option to silence warnings */ | |
88 | int nesting_limit = -1; /* -L for nesting limit */ | 88 | int nesting_limit = -1; /* -L for nesting limit */ | |
89 | const char *freeze = NULL; /* -F to freeze state */ | 89 | const char *freeze = NULL; /* -F to freeze state */ | |
90 | const char *reload = NULL; /* -R to reload state */ | 90 | const char *reload = NULL; /* -R to reload state */ | |
91 | #ifndef REAL_FREEZE | 91 | #ifndef REAL_FREEZE | |
92 | FILE *freezef = NULL; | 92 | FILE *freezef = NULL; | |
93 | int thawing = 0; | 93 | int thawing = 0; | |
94 | #endif | 94 | #endif | |
95 | 95 | |||
96 | struct keyblk { | 96 | struct keyblk { | |
97 | const char *knam; /* keyword name */ | 97 | const char *knam; /* keyword name */ | |
98 | int ktyp; /* keyword type */ | 98 | int ktyp; /* keyword type */ | |
99 | }; | 99 | }; | |
100 | 100 | |||
101 | struct keyblk keywrds[] = { /* m4 keywords to be installed */ | 101 | struct keyblk keywrds[] = { /* m4 keywords to be installed */ | |
102 | { "include", INCLTYPE }, | 102 | { "include", INCLTYPE }, | |
103 | { "sinclude", SINCTYPE }, | 103 | { "sinclude", SINCTYPE }, | |
104 | { "define", DEFITYPE }, | 104 | { "define", DEFITYPE }, | |
105 | { "defn", DEFNTYPE }, | 105 | { "defn", DEFNTYPE }, | |
106 | { "divert", DIVRTYPE | NOARGS }, | 106 | { "divert", DIVRTYPE | NOARGS }, | |
107 | { "expr", EXPRTYPE }, | 107 | { "expr", EXPRTYPE }, | |
108 | { "eval", EXPRTYPE }, | 108 | { "eval", EXPRTYPE }, | |
109 | { "substr", SUBSTYPE }, | 109 | { "substr", SUBSTYPE }, | |
110 | { "ifelse", IFELTYPE }, | 110 | { "ifelse", IFELTYPE }, | |
111 | { "ifdef", IFDFTYPE }, | 111 | { "ifdef", IFDFTYPE }, | |
112 | { "len", LENGTYPE }, | 112 | { "len", LENGTYPE }, | |
113 | { "incr", INCRTYPE }, | 113 | { "incr", INCRTYPE }, | |
114 | { "decr", DECRTYPE }, | 114 | { "decr", DECRTYPE }, | |
115 | { "dnl", DNLNTYPE | NOARGS }, | 115 | { "dnl", DNLNTYPE | NOARGS }, | |
116 | { "changequote", CHNQTYPE | NOARGS }, | 116 | { "changequote", CHNQTYPE | NOARGS }, | |
117 | { "changecom", CHNCTYPE | NOARGS }, | 117 | { "changecom", CHNCTYPE | NOARGS }, | |
118 | { "index", INDXTYPE }, | 118 | { "index", INDXTYPE }, | |
119 | #ifdef EXTENDED | 119 | #ifdef EXTENDED | |
120 | { "paste", PASTTYPE }, | 120 | { "paste", PASTTYPE }, | |
121 | { "spaste", SPASTYPE }, | 121 | { "spaste", SPASTYPE }, | |
122 | /* Newer extensions, needed to handle gnu-m4 scripts */ | 122 | /* Newer extensions, needed to handle gnu-m4 scripts */ | |
123 | { "indir", INDIRTYPE}, | 123 | { "indir", INDIRTYPE}, | |
124 | { "builtin", BUILTINTYPE}, | 124 | { "builtin", BUILTINTYPE}, | |
125 | { "patsubst", PATSTYPE}, | 125 | { "patsubst", PATSTYPE}, | |
126 | { "regexp", REGEXPTYPE}, | 126 | { "regexp", REGEXPTYPE}, | |
127 | { "esyscmd", ESYSCMDTYPE}, | 127 | { "esyscmd", ESYSCMDTYPE}, | |
128 | { "__file__", FILENAMETYPE | NOARGS}, | 128 | { "__file__", FILENAMETYPE | NOARGS}, | |
129 | { "__line__", LINETYPE | NOARGS}, | 129 | { "__line__", LINETYPE | NOARGS}, | |
130 | #endif | 130 | #endif | |
131 | { "popdef", POPDTYPE }, | 131 | { "popdef", POPDTYPE }, | |
132 | { "pushdef", PUSDTYPE }, | 132 | { "pushdef", PUSDTYPE }, | |
133 | { "dumpdef", DUMPTYPE | NOARGS }, | 133 | { "dumpdef", DUMPTYPE | NOARGS }, | |
134 | { "shift", SHIFTYPE | NOARGS }, | 134 | { "shift", SHIFTYPE | NOARGS }, | |
135 | { "translit", TRNLTYPE }, | 135 | { "translit", TRNLTYPE }, | |
136 | { "undefine", UNDFTYPE }, | 136 | { "undefine", UNDFTYPE }, | |
137 | { "undivert", UNDVTYPE | NOARGS }, | 137 | { "undivert", UNDVTYPE | NOARGS }, | |
138 | { "divnum", DIVNTYPE | NOARGS }, | 138 | { "divnum", DIVNTYPE | NOARGS }, | |
139 | { "maketemp", MKTMTYPE }, | 139 | { "maketemp", MKTMTYPE }, | |
140 | { "errprint", ERRPTYPE | NOARGS }, | 140 | { "errprint", ERRPTYPE | NOARGS }, | |
141 | { "m4wrap", M4WRTYPE | NOARGS }, | 141 | { "m4wrap", M4WRTYPE | NOARGS }, | |
142 | { "m4exit", EXITTYPE | NOARGS }, | 142 | { "m4exit", EXITTYPE | NOARGS }, | |
143 | { "syscmd", SYSCTYPE }, | 143 | { "syscmd", SYSCTYPE }, | |
144 | { "sysval", SYSVTYPE | NOARGS }, | 144 | { "sysval", SYSVTYPE | NOARGS }, | |
145 | { "traceon", TRACEONTYPE | NOARGS }, | 145 | { "traceon", TRACEONTYPE | NOARGS }, | |
146 | { "traceoff", TRACEOFFTYPE | NOARGS }, | 146 | { "traceoff", TRACEOFFTYPE | NOARGS }, | |
147 | 147 | |||
148 | #if defined(unix) || defined(__unix__) | 148 | #if defined(unix) || defined(__unix__) | |
149 | { "unix", SELFTYPE | NOARGS }, | 149 | { "unix", SELFTYPE | NOARGS }, | |
150 | #else | 150 | #else | |
151 | #ifdef vms | 151 | #ifdef vms | |
152 | { "vms", SELFTYPE | NOARGS }, | 152 | { "vms", SELFTYPE | NOARGS }, | |
153 | #endif | 153 | #endif | |
154 | #endif | 154 | #endif | |
155 | }; | 155 | }; | |
156 | 156 | |||
157 | #define MAXKEYS (sizeof(keywrds)/sizeof(struct keyblk)) | 157 | #define MAXKEYS (sizeof(keywrds)/sizeof(struct keyblk)) | |
158 | 158 | |||
159 | #define MAXRECORD 50 | 159 | #define MAXRECORD 50 | |
160 | static struct position { | 160 | static struct position { | |
161 | char *name; | 161 | char *name; | |
162 | unsigned long line; | 162 | unsigned long line; | |
163 | } quotes[MAXRECORD], paren[MAXRECORD]; | 163 | } quotes[MAXRECORD], paren[MAXRECORD]; | |
164 | 164 | |||
165 | static void record(struct position *, int); | 165 | static void record(struct position *, int); | |
166 | static void dump_stack(struct position *, int); | 166 | static void dump_stack(struct position *, int); | |
167 | 167 | |||
168 | static void macro(void); | 168 | static void macro(void); | |
169 | static void initkwds(void); | 169 | static void initkwds(void); | |
170 | static ndptr inspect(int, char *); | 170 | static ndptr inspect(int, char *); | |
171 | static int do_look_ahead(int, const char *); | 171 | static int do_look_ahead(int, const char *); | |
172 | static void reallyoutputstr(const char *); | 172 | static void reallyoutputstr(const char *); | |
173 | static void reallyputchar(int); | 173 | static void reallyputchar(int); | |
174 | 174 | |||
175 | static void enlarge_stack(void); | 175 | static void enlarge_stack(void); | |
176 | static void help(void); | 176 | static void help(void); | |
177 | 177 | |||
178 | static void | 178 | static void | |
179 | usage(FILE *f) | 179 | usage(FILE *f) | |
180 | { | 180 | { | |
181 | fprintf(f, "Usage: %s [-EGgiPQsv] [-Dname[=value]] [-d flags] " | 181 | fprintf(f, "Usage: %s [-EGgiPQsv] [-Dname[=value]] [-d flags] " | |
182 | "[-I dirname] [-o filename] [-L limit]\n" | 182 | "[-I dirname] [-o filename] [-L limit]\n" | |
183 | "\t[-t macro] [-Uname] [file ...]\n", getprogname()); | 183 | "\t[-t macro] [-Uname] [file ...]\n", getprogname()); | |
184 | } | 184 | } | |
185 | 185 | |||
186 | __dead static void | 186 | __dead static void | |
187 | onintr(int signo) | 187 | onintr(int signo) | |
188 | { | 188 | { | |
189 | char intrmessage[] = "m4: interrupted.\n"; | 189 | char intrmessage[] = "m4: interrupted.\n"; | |
190 | write(STDERR_FILENO, intrmessage, sizeof(intrmessage)-1); | 190 | write(STDERR_FILENO, intrmessage, sizeof(intrmessage)-1); | |
191 | _exit(1); | 191 | _exit(1); | |
192 | } | 192 | } | |
193 | 193 | |||
194 | #define OPT_HELP 1 | 194 | #define OPT_HELP 1 | |
195 | 195 | |||
196 | struct option longopts[] = { | 196 | struct option longopts[] = { | |
197 | { "debug", optional_argument, 0, 'd' }, | 197 | { "debug", optional_argument, 0, 'd' }, | |
198 | { "define", required_argument, 0, 'D' }, | 198 | { "define", required_argument, 0, 'D' }, | |
199 | { "error-output", required_argument, 0, 'e' }, | 199 | { "error-output", required_argument, 0, 'o' }, /* sic */ | |
200 | { "fatal-warnings", no_argument, 0, 'E' }, | 200 | { "fatal-warnings", no_argument, 0, 'E' }, | |
201 | { "freeze-state", required_argument, 0, 'F' }, | 201 | { "freeze-state", required_argument, 0, 'F' }, | |
202 | { "gnu", no_argument, 0, 'g' }, | 202 | { "gnu", no_argument, 0, 'g' }, | |
203 | { "help", no_argument, 0, OPT_HELP }, | 203 | { "help", no_argument, 0, OPT_HELP }, | |
204 | { "include", required_argument, 0, 'I' }, | 204 | { "include", required_argument, 0, 'I' }, | |
205 | { "interactive", no_argument, 0, 'i' }, | 205 | { "interactive", no_argument, 0, 'i' }, | |
206 | { "nesting-limit", required_argument, 0, 'L' }, | 206 | { "nesting-limit", required_argument, 0, 'L' }, | |
207 | { "prefix-builtins", no_argument, 0, 'P' }, | 207 | { "prefix-builtins", no_argument, 0, 'P' }, | |
208 | { "quiet", no_argument, 0, 'Q' }, | 208 | { "quiet", no_argument, 0, 'Q' }, | |
209 | { "reload-state", required_argument, 0, 'R' }, | 209 | { "reload-state", required_argument, 0, 'R' }, | |
210 | { "silent", no_argument, 0, 'Q' }, | 210 | { "silent", no_argument, 0, 'Q' }, | |
211 | { "synclines", no_argument, 0, 's' }, | 211 | { "synclines", no_argument, 0, 's' }, | |
212 | { "trace", required_argument, 0, 't' }, | 212 | { "trace", required_argument, 0, 't' }, | |
213 | { "traditional", no_argument, 0, 'G' }, | 213 | { "traditional", no_argument, 0, 'G' }, | |
214 | { "undefine", required_argument, 0, 'U' }, | 214 | { "undefine", required_argument, 0, 'U' }, | |
215 | { "version", no_argument, 0, 'v' }, | 215 | { "version", no_argument, 0, 'v' }, | |
216 | #ifdef notyet | 216 | #ifdef notyet | |
217 | { "arglength", required_argument, 0, 'l' }, | 217 | { "arglength", required_argument, 0, 'l' }, | |
218 | { "debugfile", optional_argument, 0, OPT_DEBUGFILE }, | 218 | { "debugfile", optional_argument, 0, OPT_DEBUGFILE }, | |
219 | { "hashsize", required_argument, 0, 'H' }, | 219 | { "hashsize", required_argument, 0, 'H' }, | |
220 | { "warn-macro-sequence",optional_argument, 0, OPT_WARN_SEQUENCE }, | 220 | { "warn-macro-sequence",optional_argument, 0, OPT_WARN_SEQUENCE }, | |
221 | #endif | 221 | #endif | |
222 | { 0, 0, 0, 0 }, | 222 | { 0, 0, 0, 0 }, | |
223 | }; | 223 | }; | |
224 | 224 | |||
225 | int | 225 | int | |
226 | main(int argc, char *argv[]) | 226 | main(int argc, char *argv[]) | |
227 | { | 227 | { | |
228 | int c; | 228 | int c; | |
229 | int n; | 229 | int n; | |
230 | int error; | |||
230 | char *p; | 231 | char *p; | |
231 | FILE *sfp; | |||
232 | 232 | |||
233 | setprogname(argv[0]); | 233 | setprogname(argv[0]); | |
234 | 234 | |||
235 | if (signal(SIGINT, SIG_IGN) != SIG_IGN) | 235 | if (signal(SIGINT, SIG_IGN) != SIG_IGN) | |
236 | signal(SIGINT, onintr); | 236 | signal(SIGINT, onintr); | |
237 | 237 | |||
238 | init_macros(); | 238 | init_macros(); | |
239 | initspaces(); | 239 | initspaces(); | |
240 | STACKMAX = INITSTACKMAX; | 240 | STACKMAX = INITSTACKMAX; | |
241 | 241 | |||
242 | mstack = (stae *)xalloc(sizeof(stae) * STACKMAX, NULL); | 242 | mstack = (stae *)xalloc(sizeof(stae) * STACKMAX, NULL); | |
243 | sstack = (char *)xalloc(STACKMAX, NULL); | 243 | sstack = (char *)xalloc(STACKMAX, NULL); | |
244 | 244 | |||
245 | maxout = 0; | 245 | maxout = 0; | |
246 | outfile = NULL; | 246 | outfile = NULL; | |
247 | resizedivs(MAXOUT); | 247 | resizedivs(MAXOUT); | |
248 | 248 | |||
249 | while ((c = getopt_long(argc, argv, "D:d:e:EF:GgI:iL:o:PR:Qst:U:v", | 249 | while ((c = getopt_long(argc, argv, "D:d:EF:GgI:iL:o:PR:Qst:U:v", | |
250 | longopts, NULL)) != -1) | 250 | longopts, NULL)) != -1) | |
251 | switch(c) { | 251 | switch(c) { | |
252 | case 'D': /* define something..*/ | 252 | case 'D': /* define something..*/ | |
253 | for (p = optarg; *p; p++) | 253 | for (p = optarg; *p; p++) | |
254 | if (*p == '=') | 254 | if (*p == '=') | |
255 | break; | 255 | break; | |
256 | if (*p) | 256 | if (*p) | |
257 | *p++ = EOS; | 257 | *p++ = EOS; | |
258 | dodefine(optarg, p); | 258 | dodefine(optarg, p); | |
259 | break; | 259 | break; | |
260 | case 'd': | 260 | case 'd': | |
261 | set_trace_flags(optarg); | 261 | set_trace_flags(optarg); | |
262 | break; | 262 | break; | |
263 | case 'E': | 263 | case 'E': | |
264 | fatal_warnings++; | 264 | fatal_warnings++; | |
265 | break; | 265 | break; | |
266 | case 'e': | |||
267 | /* | |||
268 | * Don't use freopen here because if it fails | |||
269 | * we lose stderr, instead trash it. | |||
270 | */ | |||
271 | if ((sfp = fopen(optarg, "w+")) == NULL) { | |||
272 | warn("Can't redirect errors to `%s'", optarg); | |||
273 | break; | |||
274 | } | |||
275 | fclose(stderr); | |||
276 | memcpy(stderr, sfp, sizeof(*sfp)); | |||
277 | break; | |||
278 | case 'F': | 266 | case 'F': | |
279 | freeze = optarg; | 267 | freeze = optarg; | |
280 | #ifndef REAL_FREEZE | 268 | #ifndef REAL_FREEZE | |
281 | if ((freezef = fopen(freeze, "w")) == NULL) | 269 | if ((freezef = fopen(freeze, "w")) == NULL) | |
282 | err(EXIT_FAILURE, "Can't open `%s'", freeze); | 270 | err(EXIT_FAILURE, "Can't open `%s'", freeze); | |
283 | #endif | 271 | #endif | |
284 | break; | 272 | break; | |
285 | case 'I': | 273 | case 'I': | |
286 | addtoincludepath(optarg); | 274 | addtoincludepath(optarg); | |
287 | break; | 275 | break; | |
288 | case 'i': | 276 | case 'i': | |
289 | setvbuf(stdout, NULL, _IONBF, 0); | 277 | setvbuf(stdout, NULL, _IONBF, 0); | |
290 | signal(SIGINT, SIG_IGN); | 278 | signal(SIGINT, SIG_IGN); | |
291 | break; | 279 | break; | |
292 | case 'G': | 280 | case 'G': | |
293 | mimic_gnu = 0; | 281 | mimic_gnu = 0; | |
294 | break; | 282 | break; | |
295 | case 'g': | 283 | case 'g': | |
296 | mimic_gnu = 1; | 284 | mimic_gnu = 1; | |
297 | break; | 285 | break; | |
298 | case 'L': | 286 | case 'L': | |
299 | nesting_limit = atoi(optarg); | 287 | nesting_limit = atoi(optarg); | |
300 | break; | 288 | break; | |
301 | case 'o': | 289 | case 'o': | |
302 | trace_file(optarg); | 290 | error = trace_file(optarg); | |
291 | if (error) | |||
292 | warn("%s", optarg); | |||
303 | break; | 293 | break; | |
304 | case 'P': | 294 | case 'P': | |
305 | prefix_builtins = 1; | 295 | prefix_builtins = 1; | |
306 | break; | 296 | break; | |
307 | case 'Q': | 297 | case 'Q': | |
308 | quiet++; | 298 | quiet++; | |
309 | break; | 299 | break; | |
310 | case 'R': | 300 | case 'R': | |
311 | reload = optarg; | 301 | reload = optarg; | |
312 | break; | 302 | break; | |
313 | case 's': | 303 | case 's': | |
314 | synch_lines = 1; | 304 | synch_lines = 1; | |
315 | break; | 305 | break; | |
316 | case 't': | 306 | case 't': | |
317 | mark_traced(optarg, 1); | 307 | mark_traced(optarg, 1); | |
318 | break; | 308 | break; | |
319 | case 'U': /* undefine... */ | 309 | case 'U': /* undefine... */ | |
320 | macro_popdef(optarg); | 310 | macro_popdef(optarg); | |
321 | break; | 311 | break; | |
322 | case 'v': | 312 | case 'v': | |
323 | fprintf(stderr, "%s version %d\n", getprogname(), | 313 | fprintf(stderr, "%s version %d\n", getprogname(), | |
324 | VERSION); | 314 | VERSION); | |
325 | return EXIT_SUCCESS; | 315 | return EXIT_SUCCESS; | |
326 | case OPT_HELP: | 316 | case OPT_HELP: | |
327 | help(); | 317 | help(); | |
328 | return EXIT_SUCCESS; | 318 | return EXIT_SUCCESS; | |
329 | case '?': | 319 | case '?': | |
330 | default: | 320 | default: | |
331 | usage(stderr); | 321 | usage(stderr); | |
332 | return EXIT_FAILURE; | 322 | return EXIT_FAILURE; | |
333 | } | 323 | } | |
334 | 324 | |||
335 | #ifdef REDIRECT | 325 | #ifdef REDIRECT | |
336 | /* | 326 | /* | |
337 | * This is meant only for debugging; it makes all output | 327 | * This is meant only for debugging; it makes all output | |
338 | * go to a known file, even if the command line options | 328 | * go to a known file, even if the command line options | |
339 | * send it elsewhere. It should not be turned of in production code. | 329 | * send it elsewhere. It should not be turned of in production code. | |
340 | */ | 330 | */ | |
341 | if (freopen("/tmp/m4", "w+", stderr) == NULL) | 331 | if (freopen("/tmp/m4", "w+", stderr) == NULL) | |
342 | err(EXIT_FAILURE, "Can't redirect errors to `%s'", | 332 | err(EXIT_FAILURE, "Can't redirect errors to `%s'", | |
343 | "/tmp/m4"); | 333 | "/tmp/m4"); | |
344 | #endif | 334 | #endif | |
345 | argc -= optind; | 335 | argc -= optind; | |
346 | argv += optind; | 336 | argv += optind; | |
347 | 337 | |||
348 | 338 | |||
349 | initkwds(); | 339 | initkwds(); | |
350 | if (mimic_gnu) | 340 | if (mimic_gnu) | |
351 | setup_builtin("format", FORMATTYPE); | 341 | setup_builtin("format", FORMATTYPE); | |
352 | 342 | |||
353 | active = stdout; /* default active output */ | 343 | active = stdout; /* default active output */ | |
354 | bbase[0] = bufbase; | 344 | bbase[0] = bufbase; | |
355 | 345 | |||
356 | if (reload) { | 346 | if (reload) { | |
357 | #ifdef REAL_FREEZE | 347 | #ifdef REAL_FREEZE | |
358 | thaw_state(reload); | 348 | thaw_state(reload); | |
359 | #else | 349 | #else | |
360 | if (fopen_trypath(infile, reload) == NULL) | 350 | if (fopen_trypath(infile, reload) == NULL) | |
361 | err(1, "Can't open `%s'", reload); | 351 | err(1, "Can't open `%s'", reload); | |
362 | sp = -1; | 352 | sp = -1; | |
363 | fp = 0; | 353 | fp = 0; | |
364 | thawing = 1; | 354 | thawing = 1; | |
365 | macro(); | 355 | macro(); | |
366 | thawing = 0; | 356 | thawing = 0; | |
367 | release_input(infile); | 357 | release_input(infile); | |
368 | #endif | 358 | #endif | |
369 | } | 359 | } | |
370 | 360 | |||
371 | if (!argc) { | 361 | if (!argc) { | |
372 | sp = -1; /* stack pointer initialized */ | 362 | sp = -1; /* stack pointer initialized */ | |
373 | fp = 0; /* frame pointer initialized */ | 363 | fp = 0; /* frame pointer initialized */ | |
374 | set_input(infile+0, stdin, "stdin"); | 364 | set_input(infile+0, stdin, "stdin"); | |
375 | /* default input (naturally) */ | 365 | /* default input (naturally) */ | |
376 | macro(); | 366 | macro(); | |
377 | } else | 367 | } else | |
378 | for (; argc--; ++argv) { | 368 | for (; argc--; ++argv) { | |
379 | p = *argv; | 369 | p = *argv; | |
380 | if (p[0] == '-' && p[1] == EOS) | 370 | if (p[0] == '-' && p[1] == EOS) | |
381 | set_input(infile, stdin, "stdin"); | 371 | set_input(infile, stdin, "stdin"); | |
382 | else if (fopen_trypath(infile, p) == NULL) | 372 | else if (fopen_trypath(infile, p) == NULL) | |
383 | err(1, "%s", p); | 373 | err(1, "%s", p); | |
384 | sp = -1; | 374 | sp = -1; | |
385 | fp = 0; | 375 | fp = 0; | |
386 | macro(); | 376 | macro(); | |
387 | release_input(infile); | 377 | release_input(infile); | |
388 | } | 378 | } | |
389 | 379 | |||
390 | if (wrapindex) { | 380 | if (wrapindex) { | |
391 | int i; | 381 | int i; | |
392 | 382 | |||
393 | ilevel = 0; /* in case m4wrap includes.. */ | 383 | ilevel = 0; /* in case m4wrap includes.. */ | |
394 | bufbase = bp = buf; /* use the entire buffer */ | 384 | bufbase = bp = buf; /* use the entire buffer */ | |
395 | if (mimic_gnu) { | 385 | if (mimic_gnu) { | |
396 | while (wrapindex != 0) { | 386 | while (wrapindex != 0) { | |
397 | for (i = 0; i < wrapindex; i++) | 387 | for (i = 0; i < wrapindex; i++) | |
398 | pbstr(m4wraps[i]); | 388 | pbstr(m4wraps[i]); | |
399 | wrapindex =0; | 389 | wrapindex =0; | |
400 | macro(); | 390 | macro(); | |
401 | } | 391 | } | |
402 | } else { | 392 | } else { | |
403 | for (i = 0; i < wrapindex; i++) { | 393 | for (i = 0; i < wrapindex; i++) { | |
404 | pbstr(m4wraps[i]); | 394 | pbstr(m4wraps[i]); | |
405 | macro(); | 395 | macro(); | |
406 | } | 396 | } | |
407 | } | 397 | } | |
408 | } | 398 | } | |
409 | 399 | |||
410 | if (active != stdout) | 400 | if (active != stdout) | |
411 | active = stdout; /* reset output just in case */ | 401 | active = stdout; /* reset output just in case */ | |
412 | for (n = 1; n < maxout; n++) /* default wrap-up: undivert */ | 402 | for (n = 1; n < maxout; n++) /* default wrap-up: undivert */ | |
413 | if (outfile[n] != NULL) | 403 | if (outfile[n] != NULL) | |
414 | getdiv(n); | 404 | getdiv(n); | |
415 | /* remove bitbucket if used */ | 405 | /* remove bitbucket if used */ | |
416 | if (outfile[0] != NULL) { | 406 | if (outfile[0] != NULL) { | |
417 | (void) fclose(outfile[0]); | 407 | (void) fclose(outfile[0]); | |
418 | } | 408 | } | |
419 | 409 | |||
420 | #ifdef REAL_FREEZE | 410 | #ifdef REAL_FREEZE | |
421 | if (freeze) | 411 | if (freeze) | |
422 | freeze_state(freeze); | 412 | freeze_state(freeze); | |
423 | #else | 413 | #else | |
424 | if (freezef) | 414 | if (freezef) | |
425 | fclose(freezef); | 415 | fclose(freezef); | |
426 | #endif | 416 | #endif | |
427 | 417 | |||
428 | return 0; | 418 | return 0; | |
429 | } | 419 | } | |
430 | 420 | |||
431 | /* | 421 | /* | |
432 | * Look ahead for `token'. | 422 | * Look ahead for `token'. | |
433 | * (on input `t == token[0]') | 423 | * (on input `t == token[0]') | |
434 | * Used for comment and quoting delimiters. | 424 | * Used for comment and quoting delimiters. | |
435 | * Returns 1 if `token' present; copied to output. | 425 | * Returns 1 if `token' present; copied to output. | |
436 | * 0 if `token' not found; all characters pushed back | 426 | * 0 if `token' not found; all characters pushed back | |
437 | */ | 427 | */ | |
438 | static int | 428 | static int | |
439 | do_look_ahead(int t, const char *token) | 429 | do_look_ahead(int t, const char *token) | |
440 | { | 430 | { | |
441 | int i; | 431 | int i; | |
442 | 432 | |||
443 | assert((unsigned char)t == (unsigned char)token[0]); | 433 | assert((unsigned char)t == (unsigned char)token[0]); | |
444 | 434 | |||
445 | for (i = 1; *++token; i++) { | 435 | for (i = 1; *++token; i++) { | |
446 | t = gpbc(); | 436 | t = gpbc(); | |
447 | if (t == EOF || (unsigned char)t != (unsigned char)*token) { | 437 | if (t == EOF || (unsigned char)t != (unsigned char)*token) { | |
448 | pushback(t); | 438 | pushback(t); | |
449 | while (--i) | 439 | while (--i) | |
450 | pushback(*--token); | 440 | pushback(*--token); | |
451 | return 0; | 441 | return 0; | |
452 | } | 442 | } | |
453 | } | 443 | } | |
454 | return 1; | 444 | return 1; | |
455 | } | 445 | } | |
456 | 446 | |||
457 | #define LOOK_AHEAD(t, token) (t != EOF && \ | 447 | #define LOOK_AHEAD(t, token) (t != EOF && \ | |
458 | (unsigned char)(t)==(unsigned char)(token)[0] && \ | 448 | (unsigned char)(t)==(unsigned char)(token)[0] && \ | |
459 | do_look_ahead(t,token)) | 449 | do_look_ahead(t,token)) | |
460 | 450 | |||
461 | /* | 451 | /* | |
462 | * macro - the work horse.. | 452 | * macro - the work horse.. | |
463 | */ | 453 | */ | |
464 | static void | 454 | static void | |
465 | macro(void) | 455 | macro(void) | |
466 | { | 456 | { | |
467 | char token[MAXTOK+1]; | 457 | char token[MAXTOK+1]; | |
468 | int t, l; | 458 | int t, l; | |
469 | ndptr p; | 459 | ndptr p; | |
470 | int nlpar; | 460 | int nlpar; | |
471 | 461 | |||
472 | cycle { | 462 | cycle { | |
473 | t = gpbc(); | 463 | t = gpbc(); | |
474 | 464 | |||
475 | if (LOOK_AHEAD(t,lquote)) { /* strip quotes */ | 465 | if (LOOK_AHEAD(t,lquote)) { /* strip quotes */ | |
476 | nlpar = 0; | 466 | nlpar = 0; | |
477 | record(quotes, nlpar++); | 467 | record(quotes, nlpar++); | |
478 | /* | 468 | /* | |
479 | * Opening quote: scan forward until matching | 469 | * Opening quote: scan forward until matching | |
480 | * closing quote has been found. | 470 | * closing quote has been found. | |
481 | */ | 471 | */ | |
482 | do { | 472 | do { | |
483 | 473 | |||
484 | l = gpbc(); | 474 | l = gpbc(); | |
485 | if (LOOK_AHEAD(l,rquote)) { | 475 | if (LOOK_AHEAD(l,rquote)) { | |
486 | if (--nlpar > 0) | 476 | if (--nlpar > 0) | |
487 | outputstr(rquote); | 477 | outputstr(rquote); | |
488 | } else if (LOOK_AHEAD(l,lquote)) { | 478 | } else if (LOOK_AHEAD(l,lquote)) { | |
489 | record(quotes, nlpar++); | 479 | record(quotes, nlpar++); | |
490 | outputstr(lquote); | 480 | outputstr(lquote); | |
491 | } else if (l == EOF) { | 481 | } else if (l == EOF) { | |
492 | if (!quiet) { | 482 | if (!quiet) { | |
493 | if (nlpar == 1) | 483 | if (nlpar == 1) | |
494 | warnx("unclosed quote:"); | 484 | warnx("unclosed quote:"); | |
495 | else | 485 | else | |
496 | warnx( | 486 | warnx( | |
497 | "%d unclosed quotes:", | 487 | "%d unclosed quotes:", | |
498 | nlpar); | 488 | nlpar); | |
499 | dump_stack(quotes, nlpar); | 489 | dump_stack(quotes, nlpar); | |
500 | } | 490 | } | |
501 | exit(EXIT_FAILURE); | 491 | exit(EXIT_FAILURE); | |
502 | } else { | 492 | } else { | |
503 | if (nlpar > 0) { | 493 | if (nlpar > 0) { | |
504 | if (sp < 0) | 494 | if (sp < 0) | |
505 | reallyputchar(l); | 495 | reallyputchar(l); | |
506 | else | 496 | else | |
507 | CHRSAVE(l); | 497 | CHRSAVE(l); | |
508 | } | 498 | } | |
509 | } | 499 | } | |
510 | } | 500 | } | |
511 | while (nlpar != 0); | 501 | while (nlpar != 0); | |
512 | } else if (sp < 0 && LOOK_AHEAD(t, scommt)) { | 502 | } else if (sp < 0 && LOOK_AHEAD(t, scommt)) { | |
513 | reallyoutputstr(scommt); | 503 | reallyoutputstr(scommt); | |
514 | 504 | |||
515 | for(;;) { | 505 | for(;;) { | |
516 | t = gpbc(); | 506 | t = gpbc(); | |
517 | if (LOOK_AHEAD(t, ecommt)) { | 507 | if (LOOK_AHEAD(t, ecommt)) { | |
518 | reallyoutputstr(ecommt); | 508 | reallyoutputstr(ecommt); | |
519 | break; | 509 | break; | |
520 | } | 510 | } | |
521 | if (t == EOF) | 511 | if (t == EOF) | |
522 | break; | 512 | break; | |
523 | reallyputchar(t); | 513 | reallyputchar(t); | |
524 | } | 514 | } | |
525 | } else if (t == '_' || isalpha(t)) { | 515 | } else if (t == '_' || isalpha(t)) { | |
526 | p = inspect(t, token); | 516 | p = inspect(t, token); | |
527 | if (p != NULL) | 517 | if (p != NULL) | |
528 | pushback(l = gpbc()); | 518 | pushback(l = gpbc()); | |
529 | if (p == NULL || (l != LPAREN && | 519 | if (p == NULL || (l != LPAREN && | |
530 | (macro_getdef(p)->type & NEEDARGS) != 0)) | 520 | (macro_getdef(p)->type & NEEDARGS) != 0)) | |
531 | outputstr(token); | 521 | outputstr(token); | |
532 | else { | 522 | else { | |
533 | /* | 523 | /* | |
534 | * real thing.. First build a call frame: | 524 | * real thing.. First build a call frame: | |
535 | */ | 525 | */ | |
536 | pushf(fp); /* previous call frm */ | 526 | pushf(fp); /* previous call frm */ | |
537 | pushf(macro_getdef(p)->type); /* type of the call */ | 527 | pushf(macro_getdef(p)->type); /* type of the call */ | |
538 | pushf(is_traced(p)); | 528 | pushf(is_traced(p)); | |
539 | pushf(0); /* parenthesis level */ | 529 | pushf(0); /* parenthesis level */ | |
540 | fp = sp; /* new frame pointer */ | 530 | fp = sp; /* new frame pointer */ | |
541 | /* | 531 | /* | |
542 | * now push the string arguments: | 532 | * now push the string arguments: | |
543 | * XXX: Copy the macro definition. This leaks, but too | 533 | * XXX: Copy the macro definition. This leaks, but too | |
544 | * lazy to fix properly. | 534 | * lazy to fix properly. | |
545 | * The problem is that if we evaluate a pushdef'ed | 535 | * The problem is that if we evaluate a pushdef'ed | |
546 | * macro and then popdef it while it the definition | 536 | * macro and then popdef it while it the definition | |
547 | * is still on the stack we are going to reference | 537 | * is still on the stack we are going to reference | |
548 | * free memory. | 538 | * free memory. | |
549 | */ | 539 | */ | |
550 | pushs1(xstrdup(macro_getdef(p)->defn)); /* defn string */ | 540 | pushs1(xstrdup(macro_getdef(p)->defn)); /* defn string */ | |
551 | pushs1((char *)macro_name(p)); /* macro name */ | 541 | pushs1((char *)macro_name(p)); /* macro name */ | |
552 | pushs(ep); /* start next..*/ | 542 | pushs(ep); /* start next..*/ | |
553 | 543 | |||
554 | if (l != LPAREN && PARLEV == 0) { | 544 | if (l != LPAREN && PARLEV == 0) { | |
555 | /* no bracks */ | 545 | /* no bracks */ | |
556 | chrsave(EOS); | 546 | chrsave(EOS); | |
557 | 547 | |||
558 | if ((size_t)sp == STACKMAX) | 548 | if ((size_t)sp == STACKMAX) | |
559 | errx(1, "internal stack overflow"); | 549 | errx(1, "internal stack overflow"); | |
560 | eval((const char **) mstack+fp+1, 2, | 550 | eval((const char **) mstack+fp+1, 2, | |
561 | CALTYP, TRACESTATUS); | 551 | CALTYP, TRACESTATUS); | |
562 | 552 | |||
563 | ep = PREVEP; /* flush strspace */ | 553 | ep = PREVEP; /* flush strspace */ | |
564 | sp = PREVSP; /* previous sp.. */ | 554 | sp = PREVSP; /* previous sp.. */ | |
565 | fp = PREVFP; /* rewind stack...*/ | 555 | fp = PREVFP; /* rewind stack...*/ | |
566 | } | 556 | } | |
567 | } | 557 | } | |
568 | } else if (t == EOF) { | 558 | } else if (t == EOF) { | |
569 | if (sp > -1 && ilevel <= 0) { | 559 | if (sp > -1 && ilevel <= 0) { | |
570 | if (!quiet) { | 560 | if (!quiet) { | |
571 | warnx("unexpected end of input, " | 561 | warnx("unexpected end of input, " | |
572 | "unclosed parenthesis:"); | 562 | "unclosed parenthesis:"); | |
573 | dump_stack(paren, PARLEV); | 563 | dump_stack(paren, PARLEV); | |
574 | } | 564 | } | |
575 | exit(EXIT_FAILURE); | 565 | exit(EXIT_FAILURE); | |
576 | } | 566 | } | |
577 | if (ilevel <= 0) | 567 | if (ilevel <= 0) | |
578 | break; /* all done thanks.. */ | 568 | break; /* all done thanks.. */ | |
579 | release_input(infile+ilevel--); | 569 | release_input(infile+ilevel--); | |
580 | emit_synchline(); | 570 | emit_synchline(); | |
581 | bufbase = bbase[ilevel]; | 571 | bufbase = bbase[ilevel]; | |
582 | continue; | 572 | continue; | |
583 | } else if (sp < 0) { /* not in a macro at all */ | 573 | } else if (sp < 0) { /* not in a macro at all */ | |
584 | reallyputchar(t); /* output directly.. */ | 574 | reallyputchar(t); /* output directly.. */ | |
585 | } | 575 | } | |
586 | 576 | |||
587 | else switch(t) { | 577 | else switch(t) { | |
588 | 578 | |||
589 | case LPAREN: | 579 | case LPAREN: | |
590 | if (PARLEV > 0) | 580 | if (PARLEV > 0) | |
591 | chrsave(t); | 581 | chrsave(t); | |
592 | while (isspace(l = gpbc())) /* skip blank, tab, nl.. */ | 582 | while (isspace(l = gpbc())) /* skip blank, tab, nl.. */ | |
593 | if (PARLEV > 0) | 583 | if (PARLEV > 0) | |
594 | chrsave(l); | 584 | chrsave(l); | |
595 | pushback(l); | 585 | pushback(l); | |
596 | record(paren, PARLEV++); | 586 | record(paren, PARLEV++); | |
597 | break; | 587 | break; | |
598 | 588 | |||
599 | case RPAREN: | 589 | case RPAREN: | |
600 | if (--PARLEV > 0) | 590 | if (--PARLEV > 0) | |
601 | chrsave(t); | 591 | chrsave(t); | |
602 | else { /* end of argument list */ | 592 | else { /* end of argument list */ | |
603 | chrsave(EOS); | 593 | chrsave(EOS); | |
604 | 594 | |||
605 | if ((size_t)sp == STACKMAX) | 595 | if ((size_t)sp == STACKMAX) | |
606 | errx(1, "internal stack overflow"); | 596 | errx(1, "internal stack overflow"); | |
607 | 597 | |||
608 | eval((const char **) mstack+fp+1, sp-fp, | 598 | eval((const char **) mstack+fp+1, sp-fp, | |
609 | CALTYP, TRACESTATUS); | 599 | CALTYP, TRACESTATUS); | |
610 | 600 | |||
611 | ep = PREVEP; /* flush strspace */ | 601 | ep = PREVEP; /* flush strspace */ | |
612 | sp = PREVSP; /* previous sp.. */ | 602 | sp = PREVSP; /* previous sp.. */ | |
613 | fp = PREVFP; /* rewind stack...*/ | 603 | fp = PREVFP; /* rewind stack...*/ | |
614 | } | 604 | } | |
615 | break; | 605 | break; | |
616 | 606 | |||
617 | case COMMA: | 607 | case COMMA: | |
618 | if (PARLEV == 1) { | 608 | if (PARLEV == 1) { | |
619 | chrsave(EOS); /* new argument */ | 609 | chrsave(EOS); /* new argument */ | |
620 | while (isspace(l = gpbc())) | 610 | while (isspace(l = gpbc())) | |
621 | ; | 611 | ; | |
622 | pushback(l); | 612 | pushback(l); | |
623 | pushs(ep); | 613 | pushs(ep); | |
624 | } else | 614 | } else | |
625 | chrsave(t); | 615 | chrsave(t); | |
626 | break; | 616 | break; | |
627 | 617 | |||
628 | default: | 618 | default: | |
629 | if (LOOK_AHEAD(t, scommt)) { | 619 | if (LOOK_AHEAD(t, scommt)) { | |
630 | char *q; | 620 | char *q; | |
631 | for (q = scommt; *q; q++) | 621 | for (q = scommt; *q; q++) | |
632 | chrsave(*q); | 622 | chrsave(*q); | |
633 | for(;;) { | 623 | for(;;) { | |
634 | t = gpbc(); | 624 | t = gpbc(); | |
635 | if (LOOK_AHEAD(t, ecommt)) { | 625 | if (LOOK_AHEAD(t, ecommt)) { | |
636 | for (q = ecommt; *q; q++) | 626 | for (q = ecommt; *q; q++) | |
637 | chrsave(*q); | 627 | chrsave(*q); | |
638 | break; | 628 | break; | |
639 | } | 629 | } | |
640 | if (t == EOF) | 630 | if (t == EOF) | |
641 | break; | 631 | break; | |
642 | CHRSAVE(t); | 632 | CHRSAVE(t); | |
643 | } | 633 | } | |
644 | } else | 634 | } else | |
645 | CHRSAVE(t); /* stack the char */ | 635 | CHRSAVE(t); /* stack the char */ | |
646 | break; | 636 | break; | |
647 | } | 637 | } | |
648 | } | 638 | } | |
649 | } | 639 | } | |
650 | 640 | |||
651 | /* | 641 | /* | |
652 | * output string directly, without pushing it for reparses. | 642 | * output string directly, without pushing it for reparses. | |
653 | */ | 643 | */ | |
654 | void | 644 | void | |
655 | outputstr(const char *s) | 645 | outputstr(const char *s) | |
656 | { | 646 | { | |
657 | if (sp < 0) | 647 | if (sp < 0) | |
658 | reallyoutputstr(s); | 648 | reallyoutputstr(s); | |
659 | else | 649 | else | |
660 | while (*s) | 650 | while (*s) | |
661 | CHRSAVE(*s++); | 651 | CHRSAVE(*s++); | |
662 | } | 652 | } | |
663 | 653 | |||
664 | void | 654 | void | |
665 | reallyoutputstr(const char *s) | 655 | reallyoutputstr(const char *s) | |
666 | { | 656 | { | |
667 | if (synch_lines) { | 657 | if (synch_lines) { | |
668 | while (*s) { | 658 | while (*s) { | |
669 | fputc(*s, active); | 659 | fputc(*s, active); | |
670 | if (*s++ == '\n') { | 660 | if (*s++ == '\n') { | |
671 | infile[ilevel].synch_lineno++; | 661 | infile[ilevel].synch_lineno++; | |
672 | if (infile[ilevel].synch_lineno != | 662 | if (infile[ilevel].synch_lineno != | |
673 | infile[ilevel].lineno) | 663 | infile[ilevel].lineno) | |
674 | do_emit_synchline(); | 664 | do_emit_synchline(); | |
675 | } | 665 | } | |
676 | } | 666 | } | |
677 | } else | 667 | } else | |
678 | fputs(s, active); | 668 | fputs(s, active); | |
679 | } | 669 | } | |
680 | 670 | |||
681 | void | 671 | void | |
682 | reallyputchar(int c) | 672 | reallyputchar(int c) | |
683 | { | 673 | { | |
684 | putc(c, active); | 674 | putc(c, active); | |
685 | if (synch_lines && c == '\n') { | 675 | if (synch_lines && c == '\n') { | |
686 | infile[ilevel].synch_lineno++; | 676 | infile[ilevel].synch_lineno++; | |
687 | if (infile[ilevel].synch_lineno != infile[ilevel].lineno) | 677 | if (infile[ilevel].synch_lineno != infile[ilevel].lineno) | |
688 | do_emit_synchline(); | 678 | do_emit_synchline(); | |
689 | } | 679 | } | |
690 | } | 680 | } | |
691 | 681 | |||
692 | /* | 682 | /* | |
693 | * build an input token.. | 683 | * build an input token.. | |
694 | * consider only those starting with _ or A-Za-z. | 684 | * consider only those starting with _ or A-Za-z. | |
695 | */ | 685 | */ | |
696 | static ndptr | 686 | static ndptr | |
697 | inspect(int c, char *tp) | 687 | inspect(int c, char *tp) | |
698 | { | 688 | { | |
699 | char *name = tp; | 689 | char *name = tp; | |
700 | char *etp = tp+MAXTOK; | 690 | char *etp = tp+MAXTOK; | |
701 | ndptr p; | 691 | ndptr p; | |
702 | 692 | |||
703 | *tp++ = c; | 693 | *tp++ = c; | |
704 | 694 | |||
705 | while ((isalnum(c = gpbc()) || c == '_') && tp < etp) | 695 | while ((isalnum(c = gpbc()) || c == '_') && tp < etp) | |
706 | *tp++ = c; | 696 | *tp++ = c; | |
707 | if (c != EOF) | 697 | if (c != EOF) | |
708 | PUSHBACK(c); | 698 | PUSHBACK(c); | |
709 | *tp = EOS; | 699 | *tp = EOS; | |
710 | /* token is too long, it won't match anything, but it can still | 700 | /* token is too long, it won't match anything, but it can still | |
711 | * be output. */ | 701 | * be output. */ | |
712 | if (tp == ep) { | 702 | if (tp == ep) { | |
713 | outputstr(name); | 703 | outputstr(name); | |
714 | while (isalnum(c = gpbc()) || c == '_') { | 704 | while (isalnum(c = gpbc()) || c == '_') { | |
715 | if (sp < 0) | 705 | if (sp < 0) | |
716 | reallyputchar(c); | 706 | reallyputchar(c); | |
717 | else | 707 | else | |
718 | CHRSAVE(c); | 708 | CHRSAVE(c); | |
719 | } | 709 | } | |
720 | *name = EOS; | 710 | *name = EOS; | |
721 | return NULL; | 711 | return NULL; | |
722 | } | 712 | } | |
723 | 713 | |||
724 | p = ohash_find(¯os, ohash_qlookupi(¯os, name, (void *)&tp)); | 714 | p = ohash_find(¯os, ohash_qlookupi(¯os, name, (void *)&tp)); | |
725 | if (p == NULL) | 715 | if (p == NULL) | |
726 | return NULL; | 716 | return NULL; | |
727 | if (macro_getdef(p) == NULL) | 717 | if (macro_getdef(p) == NULL) | |
728 | return NULL; | 718 | return NULL; | |
729 | return p; | 719 | return p; | |
730 | } | 720 | } | |
731 | 721 | |||
732 | /* | 722 | /* | |
733 | * initkwds - initialise m4 keywords as fast as possible. | 723 | * initkwds - initialise m4 keywords as fast as possible. | |
734 | * This very similar to install, but without certain overheads, | 724 | * This very similar to install, but without certain overheads, | |
735 | * such as calling lookup. Malloc is not used for storing the | 725 | * such as calling lookup. Malloc is not used for storing the | |
736 | * keyword strings, since we simply use the static pointers | 726 | * keyword strings, since we simply use the static pointers | |
737 | * within keywrds block. | 727 | * within keywrds block. | |
738 | */ | 728 | */ | |
739 | static void | 729 | static void | |
740 | initkwds(void) | 730 | initkwds(void) | |
741 | { | 731 | { | |
742 | unsigned int type; | 732 | unsigned int type; | |
743 | size_t i; | 733 | size_t i; | |
744 | 734 | |||
745 | for (i = 0; i < MAXKEYS; i++) { | 735 | for (i = 0; i < MAXKEYS; i++) { | |
746 | type = keywrds[i].ktyp; | 736 | type = keywrds[i].ktyp; | |
747 | if ((keywrds[i].ktyp & NOARGS) == 0) | 737 | if ((keywrds[i].ktyp & NOARGS) == 0) | |
748 | type |= NEEDARGS; | 738 | type |= NEEDARGS; | |
749 | setup_builtin(keywrds[i].knam, type); | 739 | setup_builtin(keywrds[i].knam, type); | |
750 | } | 740 | } | |
751 | } | 741 | } | |
752 | 742 | |||
753 | static void | 743 | static void | |
754 | record(struct position *t, int lev) | 744 | record(struct position *t, int lev) | |
755 | { | 745 | { | |
756 | if (lev < MAXRECORD) { | 746 | if (lev < MAXRECORD) { | |
757 | t[lev].name = CURRENT_NAME; | 747 | t[lev].name = CURRENT_NAME; | |
758 | t[lev].line = CURRENT_LINE; | 748 | t[lev].line = CURRENT_LINE; | |
759 | } | 749 | } | |
760 | } | 750 | } | |
761 | 751 | |||
762 | static void | 752 | static void | |
763 | dump_stack(struct position *t, int lev) | 753 | dump_stack(struct position *t, int lev) | |
764 | { | 754 | { | |
765 | int i; | 755 | int i; | |
766 | 756 | |||
767 | for (i = 0; i < lev; i++) { | 757 | for (i = 0; i < lev; i++) { | |
768 | if (i == MAXRECORD) { | 758 | if (i == MAXRECORD) { | |
769 | fprintf(stderr, " ...\n"); | 759 | fprintf(stderr, " ...\n"); | |
770 | break; | 760 | break; | |
771 | } | 761 | } | |
772 | fprintf(stderr, " %s at line %lu\n", | 762 | fprintf(stderr, " %s at line %lu\n", | |
773 | t[i].name, t[i].line); | 763 | t[i].name, t[i].line); | |
774 | } | 764 | } | |
775 | } | 765 | } | |
776 | 766 | |||
777 | 767 | |||
778 | static void | 768 | static void | |
779 | enlarge_stack(void) | 769 | enlarge_stack(void) | |
780 | { | 770 | { | |
781 | STACKMAX += STACKMAX/2; | 771 | STACKMAX += STACKMAX/2; | |
782 | mstack = xrealloc(mstack, sizeof(stae) * STACKMAX, | 772 | mstack = xrealloc(mstack, sizeof(stae) * STACKMAX, | |
783 | "Evaluation stack overflow (%lu)", | 773 | "Evaluation stack overflow (%lu)", | |
784 | (unsigned long)STACKMAX); | 774 | (unsigned long)STACKMAX); | |
785 | sstack = xrealloc(sstack, STACKMAX, | 775 | sstack = xrealloc(sstack, STACKMAX, | |
786 | "Evaluation stack overflow (%lu)", | 776 | "Evaluation stack overflow (%lu)", | |
787 | (unsigned long)STACKMAX); | 777 | (unsigned long)STACKMAX); | |
788 | } | 778 | } | |
789 | 779 | |||
790 | static const struct { | 780 | static const struct { | |
791 | const char *n; | 781 | const char *n; | |
792 | const char *d; | 782 | const char *d; | |
793 | } nd [] = { | 783 | } nd [] = { | |
794 | { "-d, --debug[=flags]", "set debug flags" }, | 784 | { "-d, --debug[=flags]", "set debug flags" }, | |
795 | { "-D, --define=name[=value]", "define macro" }, | 785 | { "-D, --define=name[=value]", "define macro" }, | |
796 | { "-e, --error-output=file", "send error output to file" }, | 786 | { "-e, --error-output=file", "send error output to file" }, | |
797 | { "-E, --fatal-warnings", "exit on warnings" }, | 787 | { "-E, --fatal-warnings", "exit on warnings" }, | |
798 | { "-F, --freeze-state=file", "save state to file" }, | 788 | { "-F, --freeze-state=file", "save state to file" }, | |
799 | { "-g, --gnu", "enable gnu extensions" }, | 789 | { "-g, --gnu", "enable gnu extensions" }, | |
800 | { " --help", "print this message and exit" }, | 790 | { " --help", "print this message and exit" }, | |
801 | { "-I, --include=file", "include file" }, | 791 | { "-I, --include=file", "include file" }, | |
802 | { "-i, --interactive", "unbuffer output, ignore tty signals" }, | 792 | { "-i, --interactive", "unbuffer output, ignore tty signals" }, | |
803 | { "-L, --nesting-limit=num", "macro expansion nesting limit (unimpl)" }, | 793 | { "-L, --nesting-limit=num", "macro expansion nesting limit (unimpl)" }, | |
804 | { "-P, --prefix-builtins", "prefix builtins with m4_" }, | 794 | { "-P, --prefix-builtins", "prefix builtins with m4_" }, | |
805 | { "-Q, --quiet", "don't print warnings" }, | 795 | { "-Q, --quiet", "don't print warnings" }, | |
806 | { "-R, --reload-state=file", "restore state from file" }, | 796 | { "-R, --reload-state=file", "restore state from file" }, | |
807 | { "-Q, --silent", "don't print warnings" }, | 797 | { "-Q, --silent", "don't print warnings" }, | |
808 | { "-s, --synclines", "output line directives for cpp(1)" }, | 798 | { "-s, --synclines", "output line directives for cpp(1)" }, | |
809 | { "-t, --trace=macro", "trace the named macro" }, | 799 | { "-t, --trace=macro", "trace the named macro" }, | |
810 | { "-G, --traditional", "disable gnu extensions" }, | 800 | { "-G, --traditional", "disable gnu extensions" }, | |
811 | { "-U, --undefine=name", "undefine the named macro" }, | 801 | { "-U, --undefine=name", "undefine the named macro" }, | |
812 | { "-v, --version", "print the version number and exit" }, | 802 | { "-v, --version", "print the version number and exit" }, | |
813 | }; | 803 | }; | |
814 | 804 | |||
815 | static void | 805 | static void | |
816 | help(void) | 806 | help(void) | |
817 | { | 807 | { | |
818 | size_t i; | 808 | size_t i; | |
819 | fprintf(stdout, "%s version %d\n\n", getprogname(), VERSION); | 809 | fprintf(stdout, "%s version %d\n\n", getprogname(), VERSION); | |
820 | usage(stdout); | 810 | usage(stdout); | |
821 | 811 | |||
822 | fprintf(stdout, "\nThe long options are:\n"); | 812 | fprintf(stdout, "\nThe long options are:\n"); | |
823 | for (i = 0; i < __arraycount(nd); i++) | 813 | for (i = 0; i < __arraycount(nd); i++) | |
824 | fprintf(stdout, "\t%-25.25s\t%s\n", nd[i].n, nd[i].d); | 814 | fprintf(stdout, "\t%-25.25s\t%s\n", nd[i].n, nd[i].d); | |
825 | } | 815 | } |
--- src/usr.bin/m4/trace.c 2012/03/20 20:34:58 1.8
+++ src/usr.bin/m4/trace.c 2020/07/07 10:40:46 1.8.34.1
@@ -1,203 +1,215 @@ | @@ -1,203 +1,215 @@ | |||
1 | /* $NetBSD: trace.c,v 1.8 2012/03/20 20:34:58 matt Exp $ */ | 1 | /* $NetBSD: trace.c,v 1.8.34.1 2020/07/07 10:40:46 martin Exp $ */ | |
2 | /* $OpenBSD: trace.c,v 1.15 2006/03/24 08:03:44 espie Exp $ */ | 2 | /* $OpenBSD: trace.c,v 1.15 2006/03/24 08:03:44 espie Exp $ */ | |
3 | /* | 3 | /* | |
4 | * Copyright (c) 2001 Marc Espie. | 4 | * Copyright (c) 2001 Marc Espie. | |
5 | * | 5 | * | |
6 | * Redistribution and use in source and binary forms, with or without | 6 | * Redistribution and use in source and binary forms, with or without | |
7 | * modification, are permitted provided that the following conditions | 7 | * modification, are permitted provided that the following conditions | |
8 | * are met: | 8 | * are met: | |
9 | * 1. Redistributions of source code must retain the above copyright | 9 | * 1. Redistributions of source code must retain the above copyright | |
10 | * notice, this list of conditions and the following disclaimer. | 10 | * notice, this list of conditions and the following disclaimer. | |
11 | * 2. Redistributions in binary form must reproduce the above copyright | 11 | * 2. Redistributions in binary form must reproduce the above copyright | |
12 | * notice, this list of conditions and the following disclaimer in the | 12 | * notice, this list of conditions and the following disclaimer in the | |
13 | * documentation and/or other materials provided with the distribution. | 13 | * documentation and/or other materials provided with the distribution. | |
14 | * | 14 | * | |
15 | * THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS | 15 | * THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS | |
16 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 16 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
17 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 17 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
18 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OPENBSD | 18 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OPENBSD | |
19 | * PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 19 | * PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
20 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 20 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
21 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 21 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
22 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 22 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
23 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 23 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
25 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 25 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
26 | */ | 26 | */ | |
27 | #if HAVE_NBTOOL_CONFIG_H | 27 | #if HAVE_NBTOOL_CONFIG_H | |
28 | #include "nbtool_config.h" | 28 | #include "nbtool_config.h" | |
29 | #endif | 29 | #endif | |
30 | #include <sys/cdefs.h> | 30 | #include <sys/cdefs.h> | |
31 | __RCSID("$NetBSD: trace.c,v 1.8 2012/03/20 20:34:58 matt Exp $"); | 31 | __RCSID("$NetBSD: trace.c,v 1.8.34.1 2020/07/07 10:40:46 martin Exp $"); | |
32 | 32 | |||
33 | #include <sys/types.h> | 33 | #include <sys/types.h> | |
34 | #include <err.h> | 34 | #include <err.h> | |
35 | #include <stddef.h> | 35 | #include <stddef.h> | |
36 | #include <stdint.h> | 36 | #include <stdint.h> | |
37 | #include <stdio.h> | 37 | #include <stdio.h> | |
38 | #include <stdlib.h> | 38 | #include <stdlib.h> | |
39 | #include "mdef.h" | 39 | #include "mdef.h" | |
40 | #include "stdd.h" | 40 | #include "stdd.h" | |
41 | #include "extern.h" | 41 | #include "extern.h" | |
42 | 42 | |||
43 | FILE *traceout; | 43 | FILE *traceout; | |
44 | 44 | |||
45 | #define TRACE_ARGS 1 | 45 | #define TRACE_ARGS 1 | |
46 | #define TRACE_EXPANSION 2 | 46 | #define TRACE_EXPANSION 2 | |
47 | #define TRACE_QUOTE 4 | 47 | #define TRACE_QUOTE 4 | |
48 | #define TRACE_FILENAME 8 | 48 | #define TRACE_FILENAME 8 | |
49 | #define TRACE_LINENO 16 | 49 | #define TRACE_LINENO 16 | |
50 | #define TRACE_CONT 32 | 50 | #define TRACE_CONT 32 | |
51 | #define TRACE_ID 64 | 51 | #define TRACE_ID 64 | |
52 | #define TRACE_NEWFILE 128 /* not implemented yet */ | 52 | #define TRACE_NEWFILE 128 /* not implemented yet */ | |
53 | #define TRACE_INPUT 256 /* not implemented yet */ | 53 | #define TRACE_INPUT 256 /* not implemented yet */ | |
54 | 54 | |||
55 | static unsigned int letter_to_flag(int); | 55 | static unsigned int letter_to_flag(int); | |
56 | static void print_header(struct input_file *); | 56 | static void print_header(struct input_file *); | |
57 | static int frame_level(void); | 57 | static int frame_level(void); | |
58 | 58 | |||
59 | 59 | |||
60 | unsigned int trace_flags = TRACE_QUOTE | TRACE_EXPANSION; | 60 | unsigned int trace_flags = TRACE_QUOTE | TRACE_EXPANSION; | |
61 | 61 | |||
62 | void | 62 | int | |
63 | trace_file(const char *name) | 63 | trace_file(const char *name) | |
64 | { | 64 | { | |
65 | FILE *newfp; | |||
66 | ||||
67 | if (name == NULL) | |||
68 | newfp = stderr; | |||
69 | #if 0 /* not yet */ | |||
70 | else if (*name == '\0') | |||
71 | newfp = NULL; | |||
72 | #endif | |||
73 | else { | |||
74 | newfp = fopen(name, "a"); | |||
75 | if (newfp == NULL) | |||
76 | return -1; | |||
77 | } | |||
65 | 78 | |||
66 | if (traceout && traceout != stderr) | 79 | if (traceout && traceout != stderr) | |
67 | fclose(traceout); | 80 | fclose(traceout); | |
68 | traceout = fopen(name, "w"); | 81 | traceout = newfp; | |
69 | if (!traceout) | 82 | return 0; | |
70 | err(1, "can't open %s", name); | |||
71 | } | 83 | } | |
72 | 84 | |||
73 | static unsigned int | 85 | static unsigned int | |
74 | letter_to_flag(int c) | 86 | letter_to_flag(int c) | |
75 | { | 87 | { | |
76 | switch(c) { | 88 | switch(c) { | |
77 | case 'a': | 89 | case 'a': | |
78 | return TRACE_ARGS; | 90 | return TRACE_ARGS; | |
79 | case 'e': | 91 | case 'e': | |
80 | return TRACE_EXPANSION; | 92 | return TRACE_EXPANSION; | |
81 | case 'q': | 93 | case 'q': | |
82 | return TRACE_QUOTE; | 94 | return TRACE_QUOTE; | |
83 | case 'c': | 95 | case 'c': | |
84 | return TRACE_CONT; | 96 | return TRACE_CONT; | |
85 | case 'x': | 97 | case 'x': | |
86 | return TRACE_ID; | 98 | return TRACE_ID; | |
87 | case 'f': | 99 | case 'f': | |
88 | return TRACE_FILENAME; | 100 | return TRACE_FILENAME; | |
89 | case 'l': | 101 | case 'l': | |
90 | return TRACE_LINENO; | 102 | return TRACE_LINENO; | |
91 | case 'p': | 103 | case 'p': | |
92 | return TRACE_NEWFILE; | 104 | return TRACE_NEWFILE; | |
93 | case 'i': | 105 | case 'i': | |
94 | return TRACE_INPUT; | 106 | return TRACE_INPUT; | |
95 | case 't': | 107 | case 't': | |
96 | return TRACE_ALL; | 108 | return TRACE_ALL; | |
97 | case 'V': | 109 | case 'V': | |
98 | return ~0; | 110 | return ~0; | |
99 | default: | 111 | default: | |
100 | return 0; | 112 | return 0; | |
101 | } | 113 | } | |
102 | } | 114 | } | |
103 | 115 | |||
104 | void | 116 | void | |
105 | set_trace_flags(const char *s) | 117 | set_trace_flags(const char *s) | |
106 | { | 118 | { | |
107 | char mode = 0; | 119 | char mode = 0; | |
108 | unsigned int f = 0; | 120 | unsigned int f = 0; | |
109 | 121 | |||
110 | if (*s == '+' || *s == '-') | 122 | if (*s == '+' || *s == '-') | |
111 | mode = *s++; | 123 | mode = *s++; | |
112 | while (*s) | 124 | while (*s) | |
113 | f |= letter_to_flag(*s++); | 125 | f |= letter_to_flag(*s++); | |
114 | switch(mode) { | 126 | switch(mode) { | |
115 | case 0: | 127 | case 0: | |
116 | trace_flags = f; | 128 | trace_flags = f; | |
117 | break; | 129 | break; | |
118 | case '+': | 130 | case '+': | |
119 | trace_flags |= f; | 131 | trace_flags |= f; | |
120 | break; | 132 | break; | |
121 | case '-': | 133 | case '-': | |
122 | trace_flags &= ~f; | 134 | trace_flags &= ~f; | |
123 | break; | 135 | break; | |
124 | } | 136 | } | |
125 | } | 137 | } | |
126 | 138 | |||
127 | static int | 139 | static int | |
128 | frame_level(void) | 140 | frame_level(void) | |
129 | { | 141 | { | |
130 | int level; | 142 | int level; | |
131 | int framep; | 143 | int framep; | |
132 | 144 | |||
133 | for (framep = fp, level = 0; framep != 0; | 145 | for (framep = fp, level = 0; framep != 0; | |
134 | level++,framep = mstack[framep-3].sfra) | 146 | level++,framep = mstack[framep-3].sfra) | |
135 | ; | 147 | ; | |
136 | return level; | 148 | return level; | |
137 | } | 149 | } | |
138 | 150 | |||
139 | static void | 151 | static void | |
140 | print_header(struct input_file *inp) | 152 | print_header(struct input_file *inp) | |
141 | { | 153 | { | |
142 | fprintf(traceout, "m4trace:"); | 154 | fprintf(traceout, "m4trace:"); | |
143 | if (trace_flags & TRACE_FILENAME) | 155 | if (trace_flags & TRACE_FILENAME) | |
144 | fprintf(traceout, "%s:", inp->name); | 156 | fprintf(traceout, "%s:", inp->name); | |
145 | if (trace_flags & TRACE_LINENO) | 157 | if (trace_flags & TRACE_LINENO) | |
146 | fprintf(traceout, "%lu:", TOKEN_LINE(inp)); | 158 | fprintf(traceout, "%lu:", TOKEN_LINE(inp)); | |
147 | fprintf(traceout, " -%d- ", frame_level()); | 159 | fprintf(traceout, " -%d- ", frame_level()); | |
148 | if (trace_flags & TRACE_ID) | 160 | if (trace_flags & TRACE_ID) | |
149 | fprintf(traceout, "id %lu: ", expansion_id); | 161 | fprintf(traceout, "id %lu: ", expansion_id); | |
150 | } | 162 | } | |
151 | 163 | |||
152 | size_t | 164 | size_t | |
153 | trace(const char *argv[], int argc, struct input_file *inp) | 165 | trace(const char *argv[], int argc, struct input_file *inp) | |
154 | { | 166 | { | |
155 | if (!traceout) | 167 | if (!traceout) | |
156 | traceout = stderr; | 168 | traceout = stderr; | |
157 | print_header(inp); | 169 | print_header(inp); | |
158 | if (trace_flags & TRACE_CONT) { | 170 | if (trace_flags & TRACE_CONT) { | |
159 | fprintf(traceout, "%s ...\n", argv[1]); | 171 | fprintf(traceout, "%s ...\n", argv[1]); | |
160 | print_header(inp); | 172 | print_header(inp); | |
161 | } | 173 | } | |
162 | fprintf(traceout, "%s", argv[1]); | 174 | fprintf(traceout, "%s", argv[1]); | |
163 | if ((trace_flags & TRACE_ARGS) && argc > 2) { | 175 | if ((trace_flags & TRACE_ARGS) && argc > 2) { | |
164 | char delim[3]; | 176 | char delim[3]; | |
165 | int i; | 177 | int i; | |
166 | 178 | |||
167 | delim[0] = LPAREN; | 179 | delim[0] = LPAREN; | |
168 | delim[1] = EOS; | 180 | delim[1] = EOS; | |
169 | for (i = 2; i < argc; i++) { | 181 | for (i = 2; i < argc; i++) { | |
170 | fprintf(traceout, "%s%s%s%s", delim, | 182 | fprintf(traceout, "%s%s%s%s", delim, | |
171 | (trace_flags & TRACE_QUOTE) ? lquote : "", | 183 | (trace_flags & TRACE_QUOTE) ? lquote : "", | |
172 | argv[i], | 184 | argv[i], | |
173 | (trace_flags & TRACE_QUOTE) ? rquote : ""); | 185 | (trace_flags & TRACE_QUOTE) ? rquote : ""); | |
174 | delim[0] = COMMA; | 186 | delim[0] = COMMA; | |
175 | delim[1] = ' '; | 187 | delim[1] = ' '; | |
176 | delim[2] = EOS; | 188 | delim[2] = EOS; | |
177 | } | 189 | } | |
178 | fprintf(traceout, "%c", RPAREN); | 190 | fprintf(traceout, "%c", RPAREN); | |
179 | } | 191 | } | |
180 | if (trace_flags & TRACE_CONT) { | 192 | if (trace_flags & TRACE_CONT) { | |
181 | fprintf(traceout, " -> ???\n"); | 193 | fprintf(traceout, " -> ???\n"); | |
182 | print_header(inp); | 194 | print_header(inp); | |
183 | fprintf(traceout, argc > 2 ? "%s(...)" : "%s", argv[1]); | 195 | fprintf(traceout, argc > 2 ? "%s(...)" : "%s", argv[1]); | |
184 | } | 196 | } | |
185 | if (trace_flags & TRACE_EXPANSION) | 197 | if (trace_flags & TRACE_EXPANSION) | |
186 | return buffer_mark(); | 198 | return buffer_mark(); | |
187 | else { | 199 | else { | |
188 | fprintf(traceout, "\n"); | 200 | fprintf(traceout, "\n"); | |
189 | return SIZE_MAX; | 201 | return SIZE_MAX; | |
190 | } | 202 | } | |
191 | } | 203 | } | |
192 | 204 | |||
193 | void | 205 | void | |
194 | finish_trace(size_t mark) | 206 | finish_trace(size_t mark) | |
195 | { | 207 | { | |
196 | fprintf(traceout, " -> "); | 208 | fprintf(traceout, " -> "); | |
197 | if (trace_flags & TRACE_QUOTE) | 209 | if (trace_flags & TRACE_QUOTE) | |
198 | fprintf(traceout, "%s", lquote); | 210 | fprintf(traceout, "%s", lquote); | |
199 | dump_buffer(traceout, mark); | 211 | dump_buffer(traceout, mark); | |
200 | if (trace_flags & TRACE_QUOTE) | 212 | if (trace_flags & TRACE_QUOTE) | |
201 | fprintf(traceout, "%s", rquote); | 213 | fprintf(traceout, "%s", rquote); | |
202 | fprintf(traceout, "\n"); | 214 | fprintf(traceout, "\n"); | |
203 | } | 215 | } |