Tue Jul 7 10:40:46 2020 UTC ()
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.


(martin)
diff -r1.19 -r1.19.18.1 src/usr.bin/m4/extern.h
diff -r1.27 -r1.27.18.1 src/usr.bin/m4/m4.1
diff -r1.48 -r1.48.2.1 src/usr.bin/m4/main.c
diff -r1.8 -r1.8.34.1 src/usr.bin/m4/trace.c

cvs diff -r1.19 -r1.19.18.1 src/usr.bin/m4/extern.h (switch to unified diff)

--- 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 */
39extern void eval(const char *[], int, int, int); 39extern void eval(const char *[], int, int, int);
40extern void dodefine(const char *, const char *); 40extern void dodefine(const char *, const char *);
41extern unsigned long expansion_id; 41extern unsigned long expansion_id;
42 42
43/* expr.c */ 43/* expr.c */
44extern int expr(const char *); 44extern int expr(const char *);
45 45
46/* gnum4.c */ 46/* gnum4.c */
47extern void addtoincludepath(const char *); 47extern void addtoincludepath(const char *);
48extern struct input_file *fopen_trypath(struct input_file *, const char *); 48extern struct input_file *fopen_trypath(struct input_file *, const char *);
49extern void doindir(const char *[], int); 49extern void doindir(const char *[], int);
50extern void dobuiltin(const char *[], int); 50extern void dobuiltin(const char *[], int);
51extern void dopatsubst(const char *[], int); 51extern void dopatsubst(const char *[], int);
52extern void doregexp(const char *[], int); 52extern void doregexp(const char *[], int);
53 53
54extern void doprintlineno(struct input_file *); 54extern void doprintlineno(struct input_file *);
55extern void doprintfilename(struct input_file *); 55extern void doprintfilename(struct input_file *);
56 56
57extern void doesyscmd(const char *); 57extern void doesyscmd(const char *);
58extern void getdivfile(const char *); 58extern void getdivfile(const char *);
59extern void doformat(const char *[], int); 59extern void doformat(const char *[], int);
60#ifdef REAL_FREEZE 60#ifdef REAL_FREEZE
61extern void freeze_state(const char *); 61extern void freeze_state(const char *);
62extern void thaw_state(const char *); 62extern 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
72extern void init_macros(void); 72extern void init_macros(void);
73extern ndptr lookup(const char *); 73extern ndptr lookup(const char *);
74extern void mark_traced(const char *, int); 74extern void mark_traced(const char *, int);
75extern struct ohash macros; 75extern struct ohash macros;
76 76
77extern struct macro_definition *lookup_macro_definition(const char *); 77extern struct macro_definition *lookup_macro_definition(const char *);
78extern void macro_define(const char *, const char *); 78extern void macro_define(const char *, const char *);
79extern void macro_pushdef(const char *, const char *); 79extern void macro_pushdef(const char *, const char *);
80extern void macro_popdef(const char *); 80extern void macro_popdef(const char *);
81extern void macro_undefine(const char *); 81extern void macro_undefine(const char *);
82extern void setup_builtin(const char *, unsigned int); 82extern void setup_builtin(const char *, unsigned int);
83extern void macro_for_all(void (*)(const char *, struct macro_definition *)); 83extern 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
89extern ndptr macro_getbuiltin(const char *); 89extern ndptr macro_getbuiltin(const char *);
90#ifdef REAL_FREEZE 90#ifdef REAL_FREEZE
91extern void dump_state(FILE *); 91extern void dump_state(FILE *);
92extern void restore_state(FILE *); 92extern void restore_state(FILE *);
93#endif 93#endif
94 94
95/* main.c */ 95/* main.c */
96extern void outputstr(const char *); 96extern void outputstr(const char *);
97extern void do_emit_synchline(void); 97extern 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 */
101extern void chrsave(int); 101extern void chrsave(int);
102extern char *compute_prevep(void); 102extern char *compute_prevep(void);
103extern void getdiv(int); 103extern void getdiv(int);
104extern ptrdiff_t indx(const char *, const char *); 104extern ptrdiff_t indx(const char *, const char *);
105extern void initspaces(void); 105extern void initspaces(void);
106extern void killdiv(void); 106extern void killdiv(void);
107extern void pbnum(int); 107extern void pbnum(int);
108extern void pbnumbase(int, int, int); 108extern void pbnumbase(int, int, int);
109extern void pbunsigned(unsigned long); 109extern void pbunsigned(unsigned long);
110extern void pbstr(const char *); 110extern void pbstr(const char *);
111extern void pushback(int); 111extern void pushback(int);
112extern void *xalloc(size_t, const char *fmt, ...) __printflike(2, 3); 112extern void *xalloc(size_t, const char *fmt, ...) __printflike(2, 3);
113extern void *xrealloc(void *, size_t, const char *fmt, ...) 113extern void *xrealloc(void *, size_t, const char *fmt, ...)
114 __printflike(3, 4); 114 __printflike(3, 4);
115extern char *xstrdup(const char *); 115extern char *xstrdup(const char *);
116extern void resizedivs(int); 116extern void resizedivs(int);
117extern size_t buffer_mark(void); 117extern size_t buffer_mark(void);
118extern void dump_buffer(FILE *, size_t); 118extern void dump_buffer(FILE *, size_t);
119extern void __dead m4errx(int, const char *, ...) __printflike(2, 3); 119extern void __dead m4errx(int, const char *, ...) __printflike(2, 3);
120 120
121extern int obtain_char(struct input_file *); 121extern int obtain_char(struct input_file *);
122extern void set_input(struct input_file *, FILE *, const char *); 122extern void set_input(struct input_file *, FILE *, const char *);
123extern void release_input(struct input_file *); 123extern 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 */
141extern void enlarge_bufspace(void); 141extern void enlarge_bufspace(void);
142extern void enlarge_strspace(void); 142extern void enlarge_strspace(void);
143extern unsigned char *endpbb; 143extern unsigned char *endpbb;
144extern char *endest; 144extern char *endest;
145 145
146/* trace.c */ 146/* trace.c */
147extern unsigned int trace_flags; 147extern unsigned int trace_flags;
148#define TRACE_ALL 512 148#define TRACE_ALL 512
149extern void trace_file(const char *); 149extern int trace_file(const char *);
150extern size_t trace(const char **, int, struct input_file *); 150extern size_t trace(const char **, int, struct input_file *);
151extern void finish_trace(size_t); 151extern void finish_trace(size_t);
152extern void set_trace_flags(const char *); 152extern void set_trace_flags(const char *);
153extern FILE *traceout; 153extern FILE *traceout;
154 154
155extern ndptr hashtab[]; /* hash table for macros etc. */ 155extern ndptr hashtab[]; /* hash table for macros etc. */
156extern stae *mstack; /* stack of m4 machine */ 156extern stae *mstack; /* stack of m4 machine */
157extern char *sstack; /* shadow stack, for string space extension */ 157extern char *sstack; /* shadow stack, for string space extension */
158extern FILE *active; /* active output file pointer */ 158extern FILE *active; /* active output file pointer */
159extern struct input_file infile[];/* input file stack (0=stdin) */ 159extern struct input_file infile[];/* input file stack (0=stdin) */
160extern FILE **outfile; /* diversion array(0=bitbucket) */ 160extern FILE **outfile; /* diversion array(0=bitbucket) */
161extern int maxout; /* maximum number of diversions */ 161extern int maxout; /* maximum number of diversions */
162extern int fp; /* m4 call frame pointer */ 162extern int fp; /* m4 call frame pointer */
163extern int ilevel; /* input file stack pointer */ 163extern int ilevel; /* input file stack pointer */
164extern int oindex; /* diversion index. */ 164extern int oindex; /* diversion index. */
165extern int sp; /* current m4 stack pointer */ 165extern int sp; /* current m4 stack pointer */
166extern unsigned char *bp; /* first available character */ 166extern unsigned char *bp; /* first available character */
167extern unsigned char *buf; /* push-back buffer */ 167extern unsigned char *buf; /* push-back buffer */
168extern unsigned char *bufbase; /* buffer base for this ilevel */ 168extern unsigned char *bufbase; /* buffer base for this ilevel */
169extern unsigned char *bbase[]; /* buffer base per ilevel */ 169extern unsigned char *bbase[]; /* buffer base per ilevel */
170extern char ecommt[MAXCCHARS+1];/* end character for comment */ 170extern char ecommt[MAXCCHARS+1];/* end character for comment */
171extern char *ep; /* first free char in strspace */ 171extern char *ep; /* first free char in strspace */
172extern char lquote[MAXCCHARS+1];/* left quote character (`) */ 172extern char lquote[MAXCCHARS+1];/* left quote character (`) */
173extern char **m4wraps; /* m4wrap string default. */ 173extern char **m4wraps; /* m4wrap string default. */
174extern int maxwraps; /* size of m4wraps array */ 174extern int maxwraps; /* size of m4wraps array */
175extern int wrapindex; /* current index in m4wraps */ 175extern int wrapindex; /* current index in m4wraps */
176extern int fatal_warnings; /* exit on warning */ 176extern int fatal_warnings; /* exit on warning */
177extern int quiet; /* no warnings */ 177extern int quiet; /* no warnings */
178extern int nesting_limit; /* macro expansion nesting limit */ 178extern int nesting_limit; /* macro expansion nesting limit */
179#ifndef REAL_FREEZE 179#ifndef REAL_FREEZE
180extern FILE *freezef; /* copy of input */ 180extern FILE *freezef; /* copy of input */
181extern int thawing; /* don't process includes during thaw */ 181extern int thawing; /* don't process includes during thaw */
182#endif 182#endif
183 183
184extern const char *null; /* as it says.. just a null. */ 184extern const char *null; /* as it says.. just a null. */
185extern char rquote[MAXCCHARS+1];/* right quote character (') */ 185extern char rquote[MAXCCHARS+1];/* right quote character (') */
186extern char scommt[MAXCCHARS+1];/* start character for comment */ 186extern char scommt[MAXCCHARS+1];/* start character for comment */
187extern int synch_lines; /* line synchronisation directives */ 187extern int synch_lines; /* line synchronisation directives */
188 188
189extern int mimic_gnu; /* behaves like gnu-m4 */ 189extern int mimic_gnu; /* behaves like gnu-m4 */
190extern int prefix_builtins; /* prefix builtin macros with m4_ */ 190extern int prefix_builtins; /* prefix builtin macros with m4_ */

cvs diff -r1.27 -r1.27.18.1 src/usr.bin/m4/m4.1 (switch to unified diff)

--- 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
59The 58The
60.Nm m4 59.Nm m4
61utility is a macro processor that can be used as a front end to any 60utility is a macro processor that can be used as a front end to any
62language (e.g., C, ratfor, fortran, lex, and yacc). 61language (e.g., C, ratfor, fortran, lex, and yacc).
63If no input files are given, 62If no input files are given,
64.Nm m4 63.Nm m4
65reads from the standard input, 64reads from the standard input,
66otherwise files specified on the command line are 65otherwise files specified on the command line are
67processed in the given order. 66processed in the given order.
68Input files can be regular files, files in the m4 include paths, or a 67Input files can be regular files, files in the m4 include paths, or a
69single dash 68single dash
70.Pq Sq - , 69.Pq Sq - ,
71denoting standard input. 70denoting standard input.
72.Nm m4 71.Nm m4
73writes 72writes
74the processed text to the standard output, unless told otherwise. 73the processed text to the standard output, unless told otherwise.
75.Pp 74.Pp
76Macro calls have the form name(argument1[, argument2, ..., argumentN]). 75Macro calls have the form name(argument1[, argument2, ..., argumentN]).
77.Pp 76.Pp
78There cannot be any space following the macro name and the open 77There cannot be any space following the macro name and the open
79parenthesis 78parenthesis
80.Sq \&( . 79.Sq \&( .
81If the macro name is not followed by an open 80If the macro name is not followed by an open
82parenthesis it is processed with no arguments. 81parenthesis it is processed with no arguments.
83.Pp 82.Pp
84Macro names consist of a leading alphabetic or underscore 83Macro names consist of a leading alphabetic or underscore
85possibly followed by alphanumeric or underscore characters, e.g., 84possibly followed by alphanumeric or underscore characters, e.g.,
86valid macro names match the pattern 85valid 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
89In arguments to macros, leading unquoted space, tab, and newline 88In arguments to macros, leading unquoted space, tab, and newline
90.Pq Sq \en 89.Pq Sq \en
91characters are ignored. 90characters are ignored.
92To quote strings, use left and right single quotes 91To 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 .
96You can change the quote characters with the 95You can change the quote characters with the
97.Ic changequote 96.Ic changequote
98built-in macro. 97built-in macro.
99.Pp 98.Pp
100Most built-ins don't make any sense without arguments, and hence are not 99Most built-ins don't make any sense without arguments, and hence are not
101recognized as special when not followed by an open parenthesis. 100recognized as special when not followed by an open parenthesis.
102.Pp 101.Pp
103The options are as follows: 102The 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
106Define the symbol 105Define the symbol
107.Ar name 106.Ar name
108to have some value (or 107to 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"
111Set trace flags. 110Set trace flags.
112.Ar flags 111.Ar flags
113may hold the following: 112may hold the following:
114.Bl -tag -width Ds 113.Bl -tag -width Ds
115.It Ar a 114.It Ar a
116print macro arguments. 115print macro arguments.
117.It Ar c 116.It Ar c
118print macro expansion over several lines. 117print macro expansion over several lines.
119.It Ar e 118.It Ar e
120print result of macro expansion. 119print result of macro expansion.
121.It Ar f 120.It Ar f
122print filename location. 121print filename location.
123.It Ar l 122.It Ar l
124print line number. 123print line number.
125.It Ar q 124.It Ar q
126quote arguments and expansion with the current quotes. 125quote arguments and expansion with the current quotes.
127.It Ar t 126.It Ar t
128start with all macros traced. 127start with all macros traced.
129.It Ar x 128.It Ar x
130number macro expansions. 129number macro expansions.
131.It Ar V 130.It Ar V
132turn on all options. 131turn on all options.
133.El 132.El
134.Pp 133.Pp
135By default, trace is set to 134By 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
138Warnings make 137Warnings make
139.Nm 138.Nm
140exit. 139exit.
141.It Fl e , Fl Fl error-output Ar filename 
142Redirect error output to filename. 
143.It Fl F , Fl Fl freeze-state Ar filename 140.It Fl F , Fl Fl freeze-state Ar filename
144Save the input state to 141Save the input state to
145.Ar filename . 142.Ar filename .
146.It Fl G , Fl Fl traditional 143.It Fl G , Fl Fl traditional
147Disable GNU-m4 extensions. 144Disable GNU-m4 extensions.
148.It Fl g , Fl Fl gnu 145.It Fl g , Fl Fl gnu
149Activate GNU-m4 compatibility mode. 146Activate GNU-m4 compatibility mode.
150In this mode, translit handles simple character 147In this mode, translit handles simple character
151ranges (e.g., a-z), regular expressions mimic emacs behavior, 148ranges (e.g., a-z), regular expressions mimic emacs behavior,
152multiple m4wrap calls are handled as a stack, 149multiple m4wrap calls are handled as a stack,
153the number of diversions is unlimited, 150the number of diversions is unlimited,
154empty names for macro definitions are allowed, 151empty names for macro definitions are allowed,
155and eval understands 152and eval understands
156.Sq 0rbase:value 153.Sq 0rbase:value
157numbers. 154numbers.
158.It Fl Fl help 155.It Fl Fl help
159Print help message and exit. 156Print help message and exit.
160.It Fl I , Fl Fl include Ar "dirname" 157.It Fl I , Fl Fl include Ar "dirname"
161Add directory 158Add directory
162.Ar dirname 159.Ar dirname
163to the include path. 160to the include path.
164.It Fl i , Fl Fl interactive 161.It Fl i , Fl Fl interactive
165Set unbuffered output, disable tty signals. 162Set unbuffered output, disable tty signals.
166.It Fl L , Fl Fl nesting-limit 163.It Fl L , Fl Fl nesting-limit
167Set the nesting limit in macro expansions. 164Set the nesting limit in macro expansions.
168This is unimplemented and unlimited. 165This is unimplemented and unlimited.
169.It Fl o Ar filename 166.It Fl o , Fl Fl error-output Ar filename
170Send trace output to 167Send 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
173Prefix all built-in macros with 170Prefix all built-in macros with
174.Sq m4_ . 171.Sq m4_ .
175For example, instead of writing 172For example, instead of writing
176.Ic define , 173.Ic define ,
177use 174use
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
180Don't print warnings. 177Don't print warnings.
181.It Fl R , Fl Fl reload-state Ar filename 178.It Fl R , Fl Fl reload-state Ar filename
182Reload a previously saved state from 179Reload 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
185Output line synchronization directives, suitable for 182Output 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
188Turn tracing on for 185Turn 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"
191Undefine the symbol 188Undefine the symbol
192.Ar name . 189.Ar name .
193.It Fl v , Fl Fl version 190.It Fl v , Fl Fl version
194Print the version and exit. 191Print the version and exit.
195.El 192.El
196.Sh SYNTAX 193.Sh SYNTAX
197.Nm m4 194.Nm m4
198provides the following built-in macros. 195provides the following built-in macros.
199They may be redefined, losing their original meaning. 196They may be redefined, losing their original meaning.
200Return values are null unless otherwise stated. 197Return 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
203Calls a built-in by its 200Calls a built-in by its
204.Fa name , 201.Fa name ,
205overriding possible redefinitions. 202overriding possible redefinitions.
206.It Fn changecom startcomment endcomment 203.It Fn changecom startcomment endcomment
207Changes the start comment and end comment sequences. 204Changes the start comment and end comment sequences.
208Comment sequences may be up to five characters long. 205Comment sequences may be up to five characters long.
209The default values are the hash sign 206The default values are the hash sign
210and the newline character. 207and 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
215With no arguments, comments are turned off. 212With no arguments, comments are turned off.
216With one single argument, the end comment sequence is set 213With one single argument, the end comment sequence is set
217to the newline character. 214to the newline character.
218.It Fn changequote beginquote endquote 215.It Fn changequote beginquote endquote
219Defines the open quote and close quote sequences. 216Defines the open quote and close quote sequences.
220Quote sequences may be up to five characters long. 217Quote sequences may be up to five characters long.
221The default values are the backquote character and the quote 218The default values are the backquote character and the quote
222character. 219character.
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
227With no arguments, the default quotes are restored. 224With no arguments, the default quotes are restored.
228With one single argument, the close quote sequence is set 225With one single argument, the close quote sequence is set
229to the newline character. 226to the newline character.
230.It Fn decr arg 227.It Fn decr arg
231Decrements the argument 228Decrements the argument
232.Fa arg 229.Fa arg
233by 1. 230by 1.
234The argument 231The argument
235.Fa arg 232.Fa arg
236must be a valid numeric string. 233must be a valid numeric string.
237.It Fn define name value 234.It Fn define name value
238Define a new macro named by the first argument 235Define a new macro named by the first argument
239.Fa name 236.Fa name
240to have the 237to have the
241value of the second argument 238value of the second argument
242.Fa value . 239.Fa value .
243Each occurrence of 240Each occurrence of
244.Sq $n 241.Sq $n
245(where 242(where
246.Ar n 243.Ar n
247is 0 through 9) is replaced by the 244is 0 through 9) is replaced by the
248.Ar n Ns 'th 245.Ar n Ns 'th
249argument. 246argument.
250.Sq $0 247.Sq $0
251is the name of the calling macro. 248is the name of the calling macro.
252Undefined arguments are replaced by a null string. 249Undefined arguments are replaced by a null string.
253.Sq $# 250.Sq $#
254is replaced by the number of arguments; 251is replaced by the number of arguments;
255.Sq $* 252.Sq $*
256is replaced by all arguments comma separated; 253is replaced by all arguments comma separated;
257.Sq $@ 254.Sq $@
258is the same as 255is the same as
259.Sq $* 256.Sq $*
260but all arguments are quoted against further expansion. 257but all arguments are quoted against further expansion.
261.It Fn defn name ... 258.It Fn defn name ...
262Returns the quoted definition for each argument. 259Returns the quoted definition for each argument.
263This can be used to rename 260This can be used to rename
264macro definitions (even for built-in macros). 261macro definitions (even for built-in macros).
265.It Fn divert num 262.It Fn divert num
266There are 10 output queues (numbered 0-9). 263There are 10 output queues (numbered 0-9).
267At the end of processing 264At the end of processing
268.Nm m4 265.Nm m4
269concatenates all the queues in numerical order to produce the 266concatenates all the queues in numerical order to produce the
270final output. 267final output.
271Initially the output queue is 0. 268Initially the output queue is 0.
272The divert 269The divert
273macro allows you to select a new output queue (an invalid argument 270macro allows you to select a new output queue (an invalid argument
274passed to divert causes output to be discarded). 271passed to divert causes output to be discarded).
275.It Ic divnum 272.It Ic divnum
276Returns the current output queue number. 273Returns the current output queue number.
277.It Ic dnl 274.It Ic dnl
278Discard input characters up to and including the next newline. 275Discard input characters up to and including the next newline.
279.It Fn dumpdef name ... 276.It Fn dumpdef name ...
280Prints the names and definitions for the named items, or for everything 277Prints the names and definitions for the named items, or for everything
281if no arguments are passed. 278if no arguments are passed.
282.It Fn errprint msg 279.It Fn errprint msg
283Prints the first argument on the standard error output stream. 280Prints the first argument on the standard error output stream.
284.It Fn esyscmd cmd 281.It Fn esyscmd cmd
285Passes its first argument to a shell and returns the shell's standard output. 282Passes its first argument to a shell and returns the shell's standard output.
286Note that the shell shares its standard input and standard error with 283Note 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]]
289Computes the first argument as an arithmetic expression using 32-bit 286Computes the first argument as an arithmetic expression using 32-bit
290arithmetic. 287arithmetic.
291Operators are the standard C ternary, arithmetic, logical, 288Operators are the standard C ternary, arithmetic, logical,
292shift, relational, bitwise, and parentheses operators. 289shift, relational, bitwise, and parentheses operators.
293You can specify 290You can specify
294octal, decimal, and hexadecimal numbers as in C. 291octal, decimal, and hexadecimal numbers as in C.
295The optional second argument 292The optional second argument
296.Fa radix 293.Fa radix
297specifies the radix for the result and the optional third argument 294specifies the radix for the result and the optional third argument
298.Fa minimum 295.Fa minimum
299specifies the minimum number of digits in the result. 296specifies the minimum number of digits in the result.
300.It Fn expr expr 297.It Fn expr expr
301This is an alias for 298This is an alias for
302.Ic eval . 299.Ic eval .
303.It Fn format formatstring arg1 ... 300.It Fn format formatstring arg1 ...
304Returns 301Returns
305.Fa formatstring 302.Fa formatstring
306with escape sequences substituted with 303with escape sequences substituted with
307.Fa arg1 304.Fa arg1
308and following arguments, in a way similar to 305and following arguments, in a way similar to
309.Xr printf 3 . 306.Xr printf 3 .
310This built-in is only available in GNU-m4 compatibility mode, and the only 307This built-in is only available in GNU-m4 compatibility mode, and the only
311parameters implemented are there for autoconf compatibility: 308parameters implemented are there for autoconf compatibility:
312left-padding flag, an optional field width, a maximum field width, 309left-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
315If the macro named by the first argument is defined then return the second 312If the macro named by the first argument is defined then return the second
316argument, otherwise the third. 313argument, otherwise the third.
317If there is no third argument, the value is 314If there is no third argument, the value is
318.Dv NULL . 315.Dv NULL .
319The word 316The word
320.Qq unix 317.Qq unix
321is predefined. 318is predefined.
322.It Fn ifelse a b yes ... 319.It Fn ifelse a b yes ...
323If the first argument 320If the first argument
324.Fa a 321.Fa a
325matches the second argument 322matches the second argument
326.Fa b 323.Fa b
327then 324then
328.Fn ifelse 325.Fn ifelse
329returns 326returns
330the third argument 327the third argument
331.Fa yes . 328.Fa yes .
332If the match fails the three arguments are 329If the match fails the three arguments are
333discarded and the next three arguments are used until there is 330discarded and the next three arguments are used until there is
334zero or one arguments left, either this last argument or 331zero or one arguments left, either this last argument or
335.Dv NULL 332.Dv NULL
336is returned if no other matches were found. 333is returned if no other matches were found.
337.It Fn include name 334.It Fn include name
338Returns the contents of the file specified in the first argument. 335Returns the contents of the file specified in the first argument.
339If the file is not found as is, look through the include path: 336If the file is not found as is, look through the include path:
340first the directories specified with 337first the directories specified with
341.Fl I 338.Fl I
342on the command line, then the environment variable 339on the command line, then the environment variable
343.Ev M4PATH , 340.Ev M4PATH ,
344as a colon-separated list of directories. 341as a colon-separated list of directories.
345Include aborts with an error message if the file cannot be included. 342Include aborts with an error message if the file cannot be included.
346.It Fn incr arg 343.It Fn incr arg
347Increments the argument by 1. 344Increments the argument by 1.
348The argument must be a valid numeric string. 345The argument must be a valid numeric string.
349.It Fn index string substring 346.It Fn index string substring
350Returns the index of the second argument in the first argument (e.g., 347Returns 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)
352returns 16). 349returns 16).
353If the second 350If the second
354argument is not found index returns \-1. 351argument is not found index returns \-1.
355.It Fn indir macro arg1 ... 352.It Fn indir macro arg1 ...
356Indirectly calls the macro whose name is passed as the first argument, 353Indirectly calls the macro whose name is passed as the first argument,
357with the remaining arguments passed as first, ... arguments. 354with the remaining arguments passed as first, ... arguments.
358.It Fn len arg 355.It Fn len arg
359Returns the number of characters in the first argument. 356Returns the number of characters in the first argument.
360Extra arguments 357Extra arguments
361are ignored. 358are ignored.
362.It Fn m4exit code 359.It Fn m4exit code
363Immediately exits with the return value specified by the first argument, 360Immediately exits with the return value specified by the first argument,
3640 if none. 3610 if none.
365.It Fn m4wrap todo 362.It Fn m4wrap todo
366Allows you to define what happens at the final 363Allows you to define what happens at the final
367.Dv EOF , 364.Dv EOF ,
368usually for cleanup purposes (e.g., 365usually for cleanup purposes (e.g.,
369.Ic m4wrap("cleanup(tempfile)") 366.Ic m4wrap("cleanup(tempfile)")
370causes the macro cleanup to be 367causes the macro cleanup to be
371invoked after all other processing is done). 368invoked after all other processing is done).
372.Pp 369.Pp
373Multiple calls to 370Multiple calls to
374.Fn m4wrap 371.Fn m4wrap
375get inserted in sequence at the final 372get inserted in sequence at the final
376.Dv EOF . 373.Dv EOF .
377.It Fn maketemp template 374.It Fn maketemp template
378Invokes 375Invokes
379.Xr mkstemp 3 376.Xr mkstemp 3
380on the first argument, and returns the modified string. 377on the first argument, and returns the modified string.
381This can be used to create unique 378This can be used to create unique
382temporary file names. 379temporary file names.
383.It Fn paste file 380.It Fn paste file
384Includes the contents of the file specified by the first argument without 381Includes the contents of the file specified by the first argument without
385any macro processing. 382any macro processing.
386Aborts with an error message if the file cannot be 383Aborts with an error message if the file cannot be
387included. 384included.
388.It Fn patsubst string regexp replacement 385.It Fn patsubst string regexp replacement
389Substitutes a regular expression in a string with a replacement string. 386Substitutes a regular expression in a string with a replacement string.
390Usual substitution patterns apply: an ampersand 387Usual substitution patterns apply: an ampersand
391.Pq Sq \&& 388.Pq Sq \&&
392is replaced by the string matching the regular expression. 389is replaced by the string matching the regular expression.
393The string 390The string
394.Sq \e# , 391.Sq \e# ,
395where 392where
396.Sq # 393.Sq #
397is a digit, is replaced by the corresponding back-reference. 394is a digit, is replaced by the corresponding back-reference.
398.It Fn popdef arg ... 395.It Fn popdef arg ...
399Restores the 396Restores the
400.Ic pushdef Ns ed 397.Ic pushdef Ns ed
401definition for each argument. 398definition for each argument.
402.It Fn pushdef macro def 399.It Fn pushdef macro def
403Takes the same arguments as 400Takes the same arguments as
404.Ic define , 401.Ic define ,
405but it saves the definition on a 402but it saves the definition on a
406stack for later retrieval by 403stack for later retrieval by
407.Fn popdef . 404.Fn popdef .
408.It Fn regexp string regexp replacement 405.It Fn regexp string regexp replacement
409Finds a regular expression in a string. 406Finds a regular expression in a string.
410If no further arguments are given, 407If no further arguments are given,
411it returns the first match position or \-1 if no match. 408it returns the first match position or \-1 if no match.
412If a third argument 409If a third argument
413is provided, it returns the replacement string, with sub-patterns replaced. 410is provided, it returns the replacement string, with sub-patterns replaced.
414.It Fn shift arg1 ... 411.It Fn shift arg1 ...
415Returns all but the first argument, the remaining arguments are 412Returns all but the first argument, the remaining arguments are
416quoted and pushed back with commas in between. 413quoted and pushed back with commas in between.
417The quoting 414The quoting
418nullifies the effect of the extra scan that will subsequently be 415nullifies the effect of the extra scan that will subsequently be
419performed. 416performed.
420.It Fn sinclude file 417.It Fn sinclude file
421Similar to 418Similar to
422.Ic include , 419.Ic include ,
423except it ignores any errors. 420except it ignores any errors.
424.It Fn spaste file 421.It Fn spaste file
425Similar to 422Similar to
426.Fn paste , 423.Fn paste ,
427except it ignores any errors. 424except it ignores any errors.
428.It Fn substr string offset length 425.It Fn substr string offset length
429Returns a substring of the first argument starting at the offset specified 426Returns a substring of the first argument starting at the offset specified
430by the second argument and the length specified by the third argument. 427by the second argument and the length specified by the third argument.
431If no third argument is present it returns the rest of the string. 428If no third argument is present it returns the rest of the string.
432.It Fn syscmd cmd 429.It Fn syscmd cmd
433Passes the first argument to the shell. 430Passes the first argument to the shell.
434Nothing is returned. 431Nothing is returned.
435.It Ic sysval 432.It Ic sysval
436Returns the return value from the last 433Returns the return value from the last
437.Ic syscmd . 434.Ic syscmd .
438.It Fn traceon arg ... 435.It Fn traceon arg ...
439Enables tracing of macro expansions for the given arguments, or for all 436Enables tracing of macro expansions for the given arguments, or for all
440macros if no argument is given. 437macros if no argument is given.
441.It Fn traceoff arg ... 438.It Fn traceoff arg ...
442Disables tracing of macro expansions for the given arguments, or for all 439Disables tracing of macro expansions for the given arguments, or for all
443macros if no argument is given. 440macros if no argument is given.
444.It Fn translit string mapfrom mapto 441.It Fn translit string mapfrom mapto
445Transliterate the characters in the first argument from the set 442Transliterate the characters in the first argument from the set
446given by the second argument to the set given by the third. 443given by the second argument to the set given by the third.
447You cannot use 444You cannot use
448.Xr tr 1 445.Xr tr 1
449style abbreviations. 446style abbreviations.
450.It Fn undefine name1 ... 447.It Fn undefine name1 ...
451Removes the definition for the macros specified by its arguments. 448Removes the definition for the macros specified by its arguments.
452.It Fn undivert arg ... 449.It Fn undivert arg ...
453Flushes the named output queues (or all queues if no arguments). 450Flushes the named output queues (or all queues if no arguments).
454.It Ic unix 451.It Ic unix
455A pre-defined macro for testing the OS platform. 452A pre-defined macro for testing the OS platform.
456.It Ic __line__ 453.It Ic __line__
457Returns the current file's line number. 454Returns the current file's line number.
458.It Ic __file__ 455.It Ic __file__
459Returns the current file's name. 456Returns the current file's name.
460.El 457.El
461.Sh STANDARDS 458.Sh STANDARDS
462The 459The
463.Nm 460.Nm
464utility is compliant with the 461utility is compliant with the
465.St -p1003.1-2008 462.St -p1003.1-2008
466specification. 463specification.
467.Pp 464.Pp
468The flags 465The flags
469.Op Fl dgIot 466.Op Fl dgIot
470and the macros 467and 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__ ,
482and 479and
483.Ic __file__ 480.Ic __file__
484are extensions to that specification. 481are extensions to that specification.
485.Pp 482.Pp
486The output format of tracing and of 483The output format of tracing and of
487.Ic dumpdef 484.Ic dumpdef
488are not specified in any standard, 485are not specified in any standard,
489are likely to change and should not be relied upon. 486are likely to change and should not be relied upon.
490The current format of tracing is closely modelled on 487The current format of tracing is closely modelled on
491.Nm gnu-m4 , 488.Nm gnu-m4 ,
492to allow 489to allow
493.Nm autoconf 490.Nm autoconf
494to work. 491to work.
495.Pp 492.Pp
496The built-ins 493The built-ins
497.Ic pushdef 494.Ic pushdef
498and 495and
499.Ic popdef 496.Ic popdef
500handle macro definitions as a stack. 497handle macro definitions as a stack.
501However, 498However,
502.Ic define 499.Ic define
503interacts with the stack in an undefined way. 500interacts with the stack in an undefined way.
504In this implementation, 501In this implementation,
505.Ic define 502.Ic define
506replaces the top-most definition only. 503replaces the top-most definition only.
507Other implementations may erase all definitions on the stack instead. 504Other implementations may erase all definitions on the stack instead.
508.Pp 505.Pp
509All built-ins do expand without arguments in many other 506All built-ins do expand without arguments in many other
510.Nm m4 . 507.Nm m4 .
511.Pp 508.Pp
512Many other 509Many other
513.Nm 510.Nm
514have dire size limitations with respect to buffer sizes. 511have 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
518and 515and
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
521GNU-m4 compatibility extensions by 518GNU-m4 compatibility extensions by
522.An Marc Espie Aq Mt espie@cvs.openbsd.org . 519.An Marc Espie Aq Mt espie@cvs.openbsd.org .

cvs diff -r1.48 -r1.48.2.1 src/usr.bin/m4/main.c (switch to unified diff)

--- 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
64ndptr hashtab[HASHSIZE]; /* hash table for macros etc. */ 64ndptr hashtab[HASHSIZE]; /* hash table for macros etc. */
65stae *mstack; /* stack of m4 machine */ 65stae *mstack; /* stack of m4 machine */
66char *sstack; /* shadow stack, for string space extension */ 66char *sstack; /* shadow stack, for string space extension */
67static size_t STACKMAX; /* current maximum size of stack */ 67static size_t STACKMAX; /* current maximum size of stack */
68int sp; /* current m4 stack pointer */ 68int sp; /* current m4 stack pointer */
69int fp; /* m4 call frame pointer */ 69int fp; /* m4 call frame pointer */
70struct input_file infile[MAXINP];/* input file stack (0=stdin) */ 70struct input_file infile[MAXINP];/* input file stack (0=stdin) */
71FILE **outfile; /* diversion array(0=bitbucket)*/ 71FILE **outfile; /* diversion array(0=bitbucket)*/
72int maxout; 72int maxout;
73FILE *active; /* active output file pointer */ 73FILE *active; /* active output file pointer */
74int ilevel = 0; /* input file stack pointer */ 74int ilevel = 0; /* input file stack pointer */
75int oindex = 0; /* diversion index.. */ 75int oindex = 0; /* diversion index.. */
76const char *null = ""; /* as it says.. just a null.. */ 76const char *null = ""; /* as it says.. just a null.. */
77char **m4wraps = NULL; /* m4wraps array. */ 77char **m4wraps = NULL; /* m4wraps array. */
78int maxwraps = 0; /* size of m4wraps array */ 78int maxwraps = 0; /* size of m4wraps array */
79int wrapindex = 0; /* current offset in m4wraps */ 79int wrapindex = 0; /* current offset in m4wraps */
80char lquote[MAXCCHARS+1] = {LQUOTE}; /* left quote character (`) */ 80char lquote[MAXCCHARS+1] = {LQUOTE}; /* left quote character (`) */
81char rquote[MAXCCHARS+1] = {RQUOTE}; /* right quote character (') */ 81char rquote[MAXCCHARS+1] = {RQUOTE}; /* right quote character (') */
82char scommt[MAXCCHARS+1] = {SCOMMT}; /* start character for comment */ 82char scommt[MAXCCHARS+1] = {SCOMMT}; /* start character for comment */
83char ecommt[MAXCCHARS+1] = {ECOMMT}; /* end character for comment */ 83char ecommt[MAXCCHARS+1] = {ECOMMT}; /* end character for comment */
84int synch_lines = 0; /* line synchronisation for C preprocessor */ 84int synch_lines = 0; /* line synchronisation for C preprocessor */
85int prefix_builtins = 0; /* -P option to prefix builtin keywords */ 85int prefix_builtins = 0; /* -P option to prefix builtin keywords */
86int fatal_warnings = 0; /* -E option to exit on warnings */ 86int fatal_warnings = 0; /* -E option to exit on warnings */
87int quiet = 0; /* -Q option to silence warnings */ 87int quiet = 0; /* -Q option to silence warnings */
88int nesting_limit = -1; /* -L for nesting limit */ 88int nesting_limit = -1; /* -L for nesting limit */
89const char *freeze = NULL; /* -F to freeze state */ 89const char *freeze = NULL; /* -F to freeze state */
90const char *reload = NULL; /* -R to reload state */ 90const char *reload = NULL; /* -R to reload state */
91#ifndef REAL_FREEZE 91#ifndef REAL_FREEZE
92FILE *freezef = NULL; 92FILE *freezef = NULL;
93int thawing = 0; 93int thawing = 0;
94#endif 94#endif
95 95
96struct keyblk { 96struct 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
101struct keyblk keywrds[] = { /* m4 keywords to be installed */ 101struct 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
160static struct position { 160static 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
165static void record(struct position *, int); 165static void record(struct position *, int);
166static void dump_stack(struct position *, int); 166static void dump_stack(struct position *, int);
167 167
168static void macro(void); 168static void macro(void);
169static void initkwds(void); 169static void initkwds(void);
170static ndptr inspect(int, char *); 170static ndptr inspect(int, char *);
171static int do_look_ahead(int, const char *); 171static int do_look_ahead(int, const char *);
172static void reallyoutputstr(const char *); 172static void reallyoutputstr(const char *);
173static void reallyputchar(int); 173static void reallyputchar(int);
174 174
175static void enlarge_stack(void); 175static void enlarge_stack(void);
176static void help(void); 176static void help(void);
177 177
178static void 178static void
179usage(FILE *f) 179usage(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
187onintr(int signo) 187onintr(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
196struct option longopts[] = { 196struct 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
225int 225int
226main(int argc, char *argv[]) 226main(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 */
438static int 428static int
439do_look_ahead(int t, const char *token) 429do_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 */
464static void 454static void
465macro(void) 455macro(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 */
654void 644void
655outputstr(const char *s) 645outputstr(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
664void 654void
665reallyoutputstr(const char *s) 655reallyoutputstr(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
681void 671void
682reallyputchar(int c) 672reallyputchar(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 */
696static ndptr 686static ndptr
697inspect(int c, char *tp)  687inspect(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(&macros, ohash_qlookupi(&macros, name, (void *)&tp)); 714 p = ohash_find(&macros, ohash_qlookupi(&macros, 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 */
739static void 729static void
740initkwds(void) 730initkwds(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
753static void 743static void
754record(struct position *t, int lev) 744record(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
762static void 752static void
763dump_stack(struct position *t, int lev) 753dump_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
778static void  768static void
779enlarge_stack(void) 769enlarge_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
790static const struct { 780static 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
815static void 805static void
816help(void) 806help(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}

cvs diff -r1.8 -r1.8.34.1 src/usr.bin/m4/trace.c (switch to unified diff)

--- 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
43FILE *traceout; 43FILE *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
55static unsigned int letter_to_flag(int); 55static unsigned int letter_to_flag(int);
56static void print_header(struct input_file *); 56static void print_header(struct input_file *);
57static int frame_level(void); 57static int frame_level(void);
58 58
59 59
60unsigned int trace_flags = TRACE_QUOTE | TRACE_EXPANSION; 60unsigned int trace_flags = TRACE_QUOTE | TRACE_EXPANSION;
61 61
62void 62int
63trace_file(const char *name) 63trace_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
73static unsigned int 85static unsigned int
74letter_to_flag(int c) 86letter_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
104void 116void
105set_trace_flags(const char *s) 117set_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
127static int 139static int
128frame_level(void) 140frame_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
139static void 151static void
140print_header(struct input_file *inp) 152print_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
152size_t  164size_t
153trace(const char *argv[], int argc, struct input_file *inp) 165trace(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
193void  205void
194finish_trace(size_t mark) 206finish_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}