| @@ -1,15 +1,15 @@ | | | @@ -1,15 +1,15 @@ |
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.42 2012/04/25 18:23:58 christos Exp $ */ | | 2 | /* $NetBSD: main.c,v 1.43 2016/01/16 18:31:29 christos 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. |
| @@ -32,29 +32,30 @@ | | | @@ -32,29 +32,30 @@ |
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.42 2012/04/25 18:23:58 christos Exp $"); | | 45 | __RCSID("$NetBSD: main.c,v 1.43 2016/01/16 18:31:29 christos Exp $"); |
46 | #include <assert.h> | | 46 | #include <assert.h> |
47 | #include <signal.h> | | 47 | #include <signal.h> |
| | | 48 | #include <getopt.h> |
48 | #include <err.h> | | 49 | #include <err.h> |
49 | #include <errno.h> | | 50 | #include <errno.h> |
50 | #include <unistd.h> | | 51 | #include <unistd.h> |
51 | #include <stdio.h> | | 52 | #include <stdio.h> |
52 | #include <ctype.h> | | 53 | #include <ctype.h> |
53 | #include <string.h> | | 54 | #include <string.h> |
54 | #include <stddef.h> | | 55 | #include <stddef.h> |
55 | #include <stdint.h> | | 56 | #include <stdint.h> |
56 | #include <stdlib.h> | | 57 | #include <stdlib.h> |
57 | #include <ohash.h> | | 58 | #include <ohash.h> |
58 | #include "mdef.h" | | 59 | #include "mdef.h" |
59 | #include "stdd.h" | | 60 | #include "stdd.h" |
60 | #include "extern.h" | | 61 | #include "extern.h" |
| @@ -72,26 +73,35 @@ int maxout; | | | @@ -72,26 +73,35 @@ int maxout; |
72 | FILE *active; /* active output file pointer */ | | 73 | FILE *active; /* active output file pointer */ |
73 | int ilevel = 0; /* input file stack pointer */ | | 74 | int ilevel = 0; /* input file stack pointer */ |
74 | int oindex = 0; /* diversion index.. */ | | 75 | int oindex = 0; /* diversion index.. */ |
75 | const char *null = ""; /* as it says.. just a null.. */ | | 76 | const char *null = ""; /* as it says.. just a null.. */ |
76 | char **m4wraps = NULL; /* m4wraps array. */ | | 77 | char **m4wraps = NULL; /* m4wraps array. */ |
77 | int maxwraps = 0; /* size of m4wraps array */ | | 78 | int maxwraps = 0; /* size of m4wraps array */ |
78 | int wrapindex = 0; /* current offset in m4wraps */ | | 79 | int wrapindex = 0; /* current offset in m4wraps */ |
79 | char lquote[MAXCCHARS+1] = {LQUOTE}; /* left quote character (`) */ | | 80 | char lquote[MAXCCHARS+1] = {LQUOTE}; /* left quote character (`) */ |
80 | char rquote[MAXCCHARS+1] = {RQUOTE}; /* right quote character (') */ | | 81 | char rquote[MAXCCHARS+1] = {RQUOTE}; /* right quote character (') */ |
81 | char scommt[MAXCCHARS+1] = {SCOMMT}; /* start character for comment */ | | 82 | char scommt[MAXCCHARS+1] = {SCOMMT}; /* start character for comment */ |
82 | char ecommt[MAXCCHARS+1] = {ECOMMT}; /* end character for comment */ | | 83 | char ecommt[MAXCCHARS+1] = {ECOMMT}; /* end character for comment */ |
83 | int synch_lines = 0; /* line synchronisation for C preprocessor */ | | 84 | int synch_lines = 0; /* line synchronisation for C preprocessor */ |
84 | int prefix_builtins = 0; /* -P option to prefix builtin keywords */ | | 85 | int prefix_builtins = 0; /* -P option to prefix builtin keywords */ |
| | | 86 | int fatal_warnings = 0; /* -E option to exit on warnings */ |
| | | 87 | int quiet = 0; /* -Q option to silence warnings */ |
| | | 88 | int nesting_limit = -1; /* -L for nesting limit */ |
| | | 89 | const char *freeze = NULL; /* -F to freeze state */ |
| | | 90 | const char *reload = NULL; /* -R to reload state */ |
| | | 91 | #ifndef REAL_FREEZE |
| | | 92 | FILE *freezef = NULL; |
| | | 93 | int thawing = 0; |
| | | 94 | #endif |
85 | | | 95 | |
86 | struct keyblk { | | 96 | struct keyblk { |
87 | const char *knam; /* keyword name */ | | 97 | const char *knam; /* keyword name */ |
88 | int ktyp; /* keyword type */ | | 98 | int ktyp; /* keyword type */ |
89 | }; | | 99 | }; |
90 | | | 100 | |
91 | struct keyblk keywrds[] = { /* m4 keywords to be installed */ | | 101 | struct keyblk keywrds[] = { /* m4 keywords to be installed */ |
92 | { "include", INCLTYPE }, | | 102 | { "include", INCLTYPE }, |
93 | { "sinclude", SINCTYPE }, | | 103 | { "sinclude", SINCTYPE }, |
94 | { "define", DEFITYPE }, | | 104 | { "define", DEFITYPE }, |
95 | { "defn", DEFNTYPE }, | | 105 | { "defn", DEFNTYPE }, |
96 | { "divert", DIVRTYPE | NOARGS }, | | 106 | { "divert", DIVRTYPE | NOARGS }, |
97 | { "expr", EXPRTYPE }, | | 107 | { "expr", EXPRTYPE }, |
| @@ -136,135 +146,225 @@ struct keyblk keywrds[] = { /* m4 keywor | | | @@ -136,135 +146,225 @@ struct keyblk keywrds[] = { /* m4 keywor |
136 | { "traceoff", TRACEOFFTYPE | NOARGS }, | | 146 | { "traceoff", TRACEOFFTYPE | NOARGS }, |
137 | | | 147 | |
138 | #if defined(unix) || defined(__unix__) | | 148 | #if defined(unix) || defined(__unix__) |
139 | { "unix", SELFTYPE | NOARGS }, | | 149 | { "unix", SELFTYPE | NOARGS }, |
140 | #else | | 150 | #else |
141 | #ifdef vms | | 151 | #ifdef vms |
142 | { "vms", SELFTYPE | NOARGS }, | | 152 | { "vms", SELFTYPE | NOARGS }, |
143 | #endif | | 153 | #endif |
144 | #endif | | 154 | #endif |
145 | }; | | 155 | }; |
146 | | | 156 | |
147 | #define MAXKEYS (sizeof(keywrds)/sizeof(struct keyblk)) | | 157 | #define MAXKEYS (sizeof(keywrds)/sizeof(struct keyblk)) |
148 | | | 158 | |
149 | extern int optind; | | | |
150 | extern char *optarg; | | | |
151 | | | | |
152 | #define MAXRECORD 50 | | 159 | #define MAXRECORD 50 |
153 | static struct position { | | 160 | static struct position { |
154 | char *name; | | 161 | char *name; |
155 | unsigned long line; | | 162 | unsigned long line; |
156 | } quotes[MAXRECORD], paren[MAXRECORD]; | | 163 | } quotes[MAXRECORD], paren[MAXRECORD]; |
157 | | | 164 | |
158 | static void record(struct position *, int); | | 165 | static void record(struct position *, int); |
159 | static void dump_stack(struct position *, int); | | 166 | static void dump_stack(struct position *, int); |
160 | | | 167 | |
161 | static void macro(void); | | 168 | static void macro(void); |
162 | static void initkwds(void); | | 169 | static void initkwds(void); |
163 | static ndptr inspect(int, char *); | | 170 | static ndptr inspect(int, char *); |
164 | static int do_look_ahead(int, const char *); | | 171 | static int do_look_ahead(int, const char *); |
165 | static void reallyoutputstr(const char *); | | 172 | static void reallyoutputstr(const char *); |
166 | static void reallyputchar(int); | | 173 | static void reallyputchar(int); |
167 | | | 174 | |
168 | static void enlarge_stack(void); | | 175 | static void enlarge_stack(void); |
| | | 176 | static void help(void); |
169 | | | 177 | |
170 | __dead static void | | 178 | static void |
171 | usage(void) | | 179 | usage(FILE *f) |
172 | { | | 180 | { |
173 | fprintf(stderr, "usage: %s [-gPs] [-Dname[=value]] [-d flags] " | | 181 | fprintf(f, "Usage: %s [-EGgiPQsv] [-Dname[=value]] [-d flags] " |
174 | "[-I dirname] [-o filename]\n" | | 182 | "[-I dirname] [-o filename] [-L limit]\n" |
175 | "\t[-t macro] [-Uname] [file ...]\n", getprogname()); | | 183 | "\t[-t macro] [-Uname] [file ...]\n", getprogname()); |
176 | exit(1); | | | |
177 | } | | 184 | } |
178 | | | 185 | |
179 | __dead static void | | 186 | __dead static void |
180 | onintr(int signo) | | 187 | onintr(int signo) |
181 | { | | 188 | { |
182 | char intrmessage[] = "m4: interrupted.\n"; | | 189 | char intrmessage[] = "m4: interrupted.\n"; |
183 | write(STDERR_FILENO, intrmessage, sizeof(intrmessage)-1); | | 190 | write(STDERR_FILENO, intrmessage, sizeof(intrmessage)-1); |
184 | _exit(1); | | 191 | _exit(1); |
185 | } | | 192 | } |
186 | | | 193 | |
| | | 194 | #define OPT_HELP 1 |
| | | 195 | |
| | | 196 | struct option longopts[] = { |
| | | 197 | { "debug", optional_argument, 0, 'd' }, |
| | | 198 | { "define", required_argument, 0, 'D' }, |
| | | 199 | { "error-output", required_argument, 0, 'e' }, |
| | | 200 | { "fatal-warnings", no_argument, 0, 'E' }, |
| | | 201 | { "freeze-state", required_argument, 0, 'F' }, |
| | | 202 | { "gnu", no_argument, 0, 'g' }, |
| | | 203 | { "help", no_argument, 0, OPT_HELP }, |
| | | 204 | { "include", required_argument, 0, 'I' }, |
| | | 205 | { "interactive", no_argument, 0, 'i' }, |
| | | 206 | { "nesting-limit", required_argument, 0, 'L' }, |
| | | 207 | { "prefix-builtins", no_argument, 0, 'P' }, |
| | | 208 | { "quiet", no_argument, 0, 'Q' }, |
| | | 209 | { "reload-state", required_argument, 0, 'R' }, |
| | | 210 | { "silent", no_argument, 0, 'Q' }, |
| | | 211 | { "synclines", no_argument, 0, 's' }, |
| | | 212 | { "trace", required_argument, 0, 't' }, |
| | | 213 | { "traditional", no_argument, 0, 'G' }, |
| | | 214 | { "undefine", required_argument, 0, 'U' }, |
| | | 215 | { "version", no_argument, 0, 'v' }, |
| | | 216 | #ifdef notyet |
| | | 217 | { "arglength", required_argument, 0, 'l' }, |
| | | 218 | { "debugfile", optional_argument, 0, OPT_DEBUGFILE }, |
| | | 219 | { "hashsize", required_argument, 0, 'H' }, |
| | | 220 | { "warn-macro-sequence",optional_argument, 0, OPT_WARN_SEQUENCE }, |
| | | 221 | #endif |
| | | 222 | { 0, 0, 0, 0 }, |
| | | 223 | }; |
| | | 224 | |
187 | int | | 225 | int |
188 | main(int argc, char *argv[]) | | 226 | main(int argc, char *argv[]) |
189 | { | | 227 | { |
190 | int c; | | 228 | int c; |
191 | int n; | | 229 | int n; |
192 | char *p; | | 230 | char *p; |
193 | | | 231 | |
194 | setprogname(argv[0]); | | 232 | setprogname(argv[0]); |
195 | | | 233 | |
196 | if (signal(SIGINT, SIG_IGN) != SIG_IGN) | | 234 | if (signal(SIGINT, SIG_IGN) != SIG_IGN) |
197 | signal(SIGINT, onintr); | | 235 | signal(SIGINT, onintr); |
198 | | | 236 | |
199 | init_macros(); | | 237 | init_macros(); |
200 | initspaces(); | | 238 | initspaces(); |
201 | STACKMAX = INITSTACKMAX; | | 239 | STACKMAX = INITSTACKMAX; |
202 | | | 240 | |
203 | mstack = (stae *)xalloc(sizeof(stae) * STACKMAX, NULL); | | 241 | mstack = (stae *)xalloc(sizeof(stae) * STACKMAX, NULL); |
204 | sstack = (char *)xalloc(STACKMAX, NULL); | | 242 | sstack = (char *)xalloc(STACKMAX, NULL); |
205 | | | 243 | |
206 | maxout = 0; | | 244 | maxout = 0; |
207 | outfile = NULL; | | 245 | outfile = NULL; |
208 | resizedivs(MAXOUT); | | 246 | resizedivs(MAXOUT); |
209 | | | 247 | |
210 | while ((c = getopt(argc, argv, "gst:d:D:U:o:I:P")) != -1) | | 248 | while ((c = getopt_long(argc, argv, "D:d:e:EF:GgIi:L:o:PR:Qst:U:v", |
| | | 249 | longopts, NULL)) != -1) |
211 | switch(c) { | | 250 | switch(c) { |
212 | | | | |
213 | case 'D': /* define something..*/ | | 251 | case 'D': /* define something..*/ |
214 | for (p = optarg; *p; p++) | | 252 | for (p = optarg; *p; p++) |
215 | if (*p == '=') | | 253 | if (*p == '=') |
216 | break; | | 254 | break; |
217 | if (*p) | | 255 | if (*p) |
218 | *p++ = EOS; | | 256 | *p++ = EOS; |
219 | dodefine(optarg, p); | | 257 | dodefine(optarg, p); |
220 | break; | | 258 | break; |
| | | 259 | case 'd': |
| | | 260 | set_trace_flags(optarg); |
| | | 261 | break; |
| | | 262 | case 'E': |
| | | 263 | fatal_warnings++; |
| | | 264 | break; |
| | | 265 | case 'e': |
| | | 266 | if (freopen(optarg, "w+", stderr) == NULL) |
| | | 267 | err(EXIT_FAILURE, "Can't redirect errors to `%s'", |
| | | 268 | optarg); |
| | | 269 | break; |
| | | 270 | case 'F': |
| | | 271 | freeze = optarg; |
| | | 272 | #ifndef REAL_FREEZE |
| | | 273 | if ((freezef = fopen(freeze, "w")) == NULL) |
| | | 274 | err(EXIT_FAILURE, "Can't open `%s'", freeze); |
| | | 275 | #endif |
| | | 276 | break; |
221 | case 'I': | | 277 | case 'I': |
222 | addtoincludepath(optarg); | | 278 | addtoincludepath(optarg); |
223 | break; | | 279 | break; |
224 | case 'P': | | 280 | case 'i': |
225 | prefix_builtins = 1; | | 281 | setvbuf(stdout, NULL, _IONBF, 0); |
| | | 282 | signal(SIGINT, SIG_IGN); |
226 | break; | | 283 | break; |
227 | case 'U': /* undefine... */ | | 284 | case 'G': |
228 | macro_popdef(optarg); | | 285 | mimic_gnu = 0; |
229 | break; | | 286 | break; |
230 | case 'g': | | 287 | case 'g': |
231 | mimic_gnu = 1; | | 288 | mimic_gnu = 1; |
232 | break; | | 289 | break; |
233 | case 'd': | | 290 | case 'L': |
234 | set_trace_flags(optarg); | | 291 | nesting_limit = atoi(optarg); |
| | | 292 | break; |
| | | 293 | case 'o': |
| | | 294 | trace_file(optarg); |
| | | 295 | break; |
| | | 296 | case 'P': |
| | | 297 | prefix_builtins = 1; |
| | | 298 | break; |
| | | 299 | case 'Q': |
| | | 300 | quiet++; |
| | | 301 | break; |
| | | 302 | case 'R': |
| | | 303 | reload = optarg; |
235 | break; | | 304 | break; |
236 | case 's': | | 305 | case 's': |
237 | synch_lines = 1; | | 306 | synch_lines = 1; |
238 | break; | | 307 | break; |
239 | case 't': | | 308 | case 't': |
240 | mark_traced(optarg, 1); | | 309 | mark_traced(optarg, 1); |
241 | break; | | 310 | break; |
242 | case 'o': | | 311 | case 'U': /* undefine... */ |
243 | trace_file(optarg); | | 312 | macro_popdef(optarg); |
244 | break; | | 313 | break; |
| | | 314 | case 'v': |
| | | 315 | fprintf(stderr, "%s version %d\n", getprogname(), |
| | | 316 | VERSION); |
| | | 317 | return EXIT_SUCCESS; |
| | | 318 | case OPT_HELP: |
| | | 319 | help(); |
| | | 320 | return EXIT_SUCCESS; |
245 | case '?': | | 321 | case '?': |
246 | usage(); | | 322 | default: |
| | | 323 | usage(stderr); |
| | | 324 | return EXIT_FAILURE; |
247 | } | | 325 | } |
248 | | | 326 | |
| | | 327 | #ifdef REDIRECT |
| | | 328 | if (freopen("/tmp/m4", "w+", stderr) == NULL) |
| | | 329 | err(EXIT_FAILURE, "Can't redirect errors to `%s'", |
| | | 330 | "/tmp/m4"); |
| | | 331 | #endif |
249 | argc -= optind; | | 332 | argc -= optind; |
250 | argv += optind; | | 333 | argv += optind; |
251 | | | 334 | |
| | | 335 | |
252 | initkwds(); | | 336 | initkwds(); |
253 | if (mimic_gnu) | | 337 | if (mimic_gnu) |
254 | setup_builtin("format", FORMATTYPE); | | 338 | setup_builtin("format", FORMATTYPE); |
255 | | | 339 | |
256 | active = stdout; /* default active output */ | | 340 | active = stdout; /* default active output */ |
257 | bbase[0] = bufbase; | | 341 | bbase[0] = bufbase; |
| | | 342 | |
| | | 343 | if (reload) { |
| | | 344 | #ifdef REAL_FREEZE |
| | | 345 | thaw_state(reload); |
| | | 346 | #else |
| | | 347 | if (fopen_trypath(infile, reload) == NULL) |
| | | 348 | err(1, "Can't open `%s'", reload); |
| | | 349 | sp = -1; |
| | | 350 | fp = 0; |
| | | 351 | thawing = 1; |
| | | 352 | macro(); |
| | | 353 | thawing = 0; |
| | | 354 | release_input(infile); |
| | | 355 | #endif |
| | | 356 | } |
| | | 357 | |
258 | if (!argc) { | | 358 | if (!argc) { |
259 | sp = -1; /* stack pointer initialized */ | | 359 | sp = -1; /* stack pointer initialized */ |
260 | fp = 0; /* frame pointer initialized */ | | 360 | fp = 0; /* frame pointer initialized */ |
261 | set_input(infile+0, stdin, "stdin"); | | 361 | set_input(infile+0, stdin, "stdin"); |
262 | /* default input (naturally) */ | | 362 | /* default input (naturally) */ |
263 | macro(); | | 363 | macro(); |
264 | } else | | 364 | } else |
265 | for (; argc--; ++argv) { | | 365 | for (; argc--; ++argv) { |
266 | p = *argv; | | 366 | p = *argv; |
267 | if (p[0] == '-' && p[1] == EOS) | | 367 | if (p[0] == '-' && p[1] == EOS) |
268 | set_input(infile, stdin, "stdin"); | | 368 | set_input(infile, stdin, "stdin"); |
269 | else if (fopen_trypath(infile, p) == NULL) | | 369 | else if (fopen_trypath(infile, p) == NULL) |
270 | err(1, "%s", p); | | 370 | err(1, "%s", p); |
| @@ -294,26 +394,34 @@ main(int argc, char *argv[]) | | | @@ -294,26 +394,34 @@ main(int argc, char *argv[]) |
294 | } | | 394 | } |
295 | } | | 395 | } |
296 | | | 396 | |
297 | if (active != stdout) | | 397 | if (active != stdout) |
298 | active = stdout; /* reset output just in case */ | | 398 | active = stdout; /* reset output just in case */ |
299 | for (n = 1; n < maxout; n++) /* default wrap-up: undivert */ | | 399 | for (n = 1; n < maxout; n++) /* default wrap-up: undivert */ |
300 | if (outfile[n] != NULL) | | 400 | if (outfile[n] != NULL) |
301 | getdiv(n); | | 401 | getdiv(n); |
302 | /* remove bitbucket if used */ | | 402 | /* remove bitbucket if used */ |
303 | if (outfile[0] != NULL) { | | 403 | if (outfile[0] != NULL) { |
304 | (void) fclose(outfile[0]); | | 404 | (void) fclose(outfile[0]); |
305 | } | | 405 | } |
306 | | | 406 | |
| | | 407 | #ifdef REAL_FREEZE |
| | | 408 | if (freeze) |
| | | 409 | freeze_state(freeze); |
| | | 410 | #else |
| | | 411 | if (freezef) |
| | | 412 | fclose(freezef); |
| | | 413 | #endif |
| | | 414 | |
307 | return 0; | | 415 | return 0; |
308 | } | | 416 | } |
309 | | | 417 | |
310 | /* | | 418 | /* |
311 | * Look ahead for `token'. | | 419 | * Look ahead for `token'. |
312 | * (on input `t == token[0]') | | 420 | * (on input `t == token[0]') |
313 | * Used for comment and quoting delimiters. | | 421 | * Used for comment and quoting delimiters. |
314 | * Returns 1 if `token' present; copied to output. | | 422 | * Returns 1 if `token' present; copied to output. |
315 | * 0 if `token' not found; all characters pushed back | | 423 | * 0 if `token' not found; all characters pushed back |
316 | */ | | 424 | */ |
317 | static int | | 425 | static int |
318 | do_look_ahead(int t, const char *token) | | 426 | do_look_ahead(int t, const char *token) |
319 | { | | 427 | { |
| @@ -358,32 +466,36 @@ macro(void) | | | @@ -358,32 +466,36 @@ macro(void) |
358 | * Opening quote: scan forward until matching | | 466 | * Opening quote: scan forward until matching |
359 | * closing quote has been found. | | 467 | * closing quote has been found. |
360 | */ | | 468 | */ |
361 | do { | | 469 | do { |
362 | | | 470 | |
363 | l = gpbc(); | | 471 | l = gpbc(); |
364 | if (LOOK_AHEAD(l,rquote)) { | | 472 | if (LOOK_AHEAD(l,rquote)) { |
365 | if (--nlpar > 0) | | 473 | if (--nlpar > 0) |
366 | outputstr(rquote); | | 474 | outputstr(rquote); |
367 | } else if (LOOK_AHEAD(l,lquote)) { | | 475 | } else if (LOOK_AHEAD(l,lquote)) { |
368 | record(quotes, nlpar++); | | 476 | record(quotes, nlpar++); |
369 | outputstr(lquote); | | 477 | outputstr(lquote); |
370 | } else if (l == EOF) { | | 478 | } else if (l == EOF) { |
371 | if (nlpar == 1) | | 479 | if (!quiet) { |
372 | warnx("unclosed quote:"); | | 480 | if (nlpar == 1) |
373 | else | | 481 | warnx("unclosed quote:"); |
374 | warnx("%d unclosed quotes:", nlpar); | | 482 | else |
375 | dump_stack(quotes, nlpar); | | 483 | warnx( |
376 | exit(1); | | 484 | "%d unclosed quotes:", |
| | | 485 | nlpar); |
| | | 486 | dump_stack(quotes, nlpar); |
| | | 487 | } |
| | | 488 | exit(EXIT_FAILURE); |
377 | } else { | | 489 | } else { |
378 | if (nlpar > 0) { | | 490 | if (nlpar > 0) { |
379 | if (sp < 0) | | 491 | if (sp < 0) |
380 | reallyputchar(l); | | 492 | reallyputchar(l); |
381 | else | | 493 | else |
382 | CHRSAVE(l); | | 494 | CHRSAVE(l); |
383 | } | | 495 | } |
384 | } | | 496 | } |
385 | } | | 497 | } |
386 | while (nlpar != 0); | | 498 | while (nlpar != 0); |
387 | } else if (sp < 0 && LOOK_AHEAD(t, scommt)) { | | 499 | } else if (sp < 0 && LOOK_AHEAD(t, scommt)) { |
388 | reallyoutputstr(scommt); | | 500 | reallyoutputstr(scommt); |
389 | | | 501 | |
| @@ -426,29 +538,32 @@ macro(void) | | | @@ -426,29 +538,32 @@ macro(void) |
426 | | | 538 | |
427 | if ((size_t)sp == STACKMAX) | | 539 | if ((size_t)sp == STACKMAX) |
428 | errx(1, "internal stack overflow"); | | 540 | errx(1, "internal stack overflow"); |
429 | eval((const char **) mstack+fp+1, 2, | | 541 | eval((const char **) mstack+fp+1, 2, |
430 | CALTYP, TRACESTATUS); | | 542 | CALTYP, TRACESTATUS); |
431 | | | 543 | |
432 | ep = PREVEP; /* flush strspace */ | | 544 | ep = PREVEP; /* flush strspace */ |
433 | sp = PREVSP; /* previous sp.. */ | | 545 | sp = PREVSP; /* previous sp.. */ |
434 | fp = PREVFP; /* rewind stack...*/ | | 546 | fp = PREVFP; /* rewind stack...*/ |
435 | } | | 547 | } |
436 | } | | 548 | } |
437 | } else if (t == EOF) { | | 549 | } else if (t == EOF) { |
438 | if (sp > -1 && ilevel <= 0) { | | 550 | if (sp > -1 && ilevel <= 0) { |
439 | warnx( "unexpected end of input, unclosed parenthesis:"); | | 551 | if (!quiet) { |
440 | dump_stack(paren, PARLEV); | | 552 | warnx("unexpected end of input, " |
441 | exit(1); | | 553 | "unclosed parenthesis:"); |
| | | 554 | dump_stack(paren, PARLEV); |
| | | 555 | } |
| | | 556 | exit(EXIT_FAILURE); |
442 | } | | 557 | } |
443 | if (ilevel <= 0) | | 558 | if (ilevel <= 0) |
444 | break; /* all done thanks.. */ | | 559 | break; /* all done thanks.. */ |
445 | release_input(infile+ilevel--); | | 560 | release_input(infile+ilevel--); |
446 | emit_synchline(); | | 561 | emit_synchline(); |
447 | bufbase = bbase[ilevel]; | | 562 | bufbase = bbase[ilevel]; |
448 | continue; | | 563 | continue; |
449 | } else if (sp < 0) { /* not in a macro at all */ | | 564 | } else if (sp < 0) { /* not in a macro at all */ |
450 | reallyputchar(t); /* output directly.. */ | | 565 | reallyputchar(t); /* output directly.. */ |
451 | } | | 566 | } |
452 | | | 567 | |
453 | else switch(t) { | | 568 | else switch(t) { |
454 | | | 569 | |
| @@ -599,27 +714,27 @@ inspect(int c, char *tp) | | | @@ -599,27 +714,27 @@ inspect(int c, char *tp) |
599 | * initkwds - initialise m4 keywords as fast as possible. | | 714 | * initkwds - initialise m4 keywords as fast as possible. |
600 | * This very similar to install, but without certain overheads, | | 715 | * This very similar to install, but without certain overheads, |
601 | * such as calling lookup. Malloc is not used for storing the | | 716 | * such as calling lookup. Malloc is not used for storing the |
602 | * keyword strings, since we simply use the static pointers | | 717 | * keyword strings, since we simply use the static pointers |
603 | * within keywrds block. | | 718 | * within keywrds block. |
604 | */ | | 719 | */ |
605 | static void | | 720 | static void |
606 | initkwds(void) | | 721 | initkwds(void) |
607 | { | | 722 | { |
608 | unsigned int type; | | 723 | unsigned int type; |
609 | size_t i; | | 724 | size_t i; |
610 | | | 725 | |
611 | for (i = 0; i < MAXKEYS; i++) { | | 726 | for (i = 0; i < MAXKEYS; i++) { |
612 | type = keywrds[i].ktyp & TYPEMASK; | | 727 | type = keywrds[i].ktyp; |
613 | if ((keywrds[i].ktyp & NOARGS) == 0) | | 728 | if ((keywrds[i].ktyp & NOARGS) == 0) |
614 | type |= NEEDARGS; | | 729 | type |= NEEDARGS; |
615 | setup_builtin(keywrds[i].knam, type); | | 730 | setup_builtin(keywrds[i].knam, type); |
616 | } | | 731 | } |
617 | } | | 732 | } |
618 | | | 733 | |
619 | static void | | 734 | static void |
620 | record(struct position *t, int lev) | | 735 | record(struct position *t, int lev) |
621 | { | | 736 | { |
622 | if (lev < MAXRECORD) { | | 737 | if (lev < MAXRECORD) { |
623 | t[lev].name = CURRENT_NAME; | | 738 | t[lev].name = CURRENT_NAME; |
624 | t[lev].line = CURRENT_LINE; | | 739 | t[lev].line = CURRENT_LINE; |
625 | } | | 740 | } |
| @@ -642,13 +757,50 @@ dump_stack(struct position *t, int lev) | | | @@ -642,13 +757,50 @@ dump_stack(struct position *t, int lev) |
642 | | | 757 | |
643 | | | 758 | |
644 | static void | | 759 | static void |
645 | enlarge_stack(void) | | 760 | enlarge_stack(void) |
646 | { | | 761 | { |
647 | STACKMAX += STACKMAX/2; | | 762 | STACKMAX += STACKMAX/2; |
648 | mstack = xrealloc(mstack, sizeof(stae) * STACKMAX, | | 763 | mstack = xrealloc(mstack, sizeof(stae) * STACKMAX, |
649 | "Evaluation stack overflow (%lu)", | | 764 | "Evaluation stack overflow (%lu)", |
650 | (unsigned long)STACKMAX); | | 765 | (unsigned long)STACKMAX); |
651 | sstack = xrealloc(sstack, STACKMAX, | | 766 | sstack = xrealloc(sstack, STACKMAX, |
652 | "Evaluation stack overflow (%lu)", | | 767 | "Evaluation stack overflow (%lu)", |
653 | (unsigned long)STACKMAX); | | 768 | (unsigned long)STACKMAX); |
654 | } | | 769 | } |
| | | 770 | |
| | | 771 | static const struct { |
| | | 772 | const char *n; |
| | | 773 | const char *d; |
| | | 774 | } nd [] = { |
| | | 775 | { "-d, --debug[=flags]", "set debug flags" }, |
| | | 776 | { "-D, --define=name[=value]", "define macro" }, |
| | | 777 | { "-e, --error-output=file", "send error output to file" }, |
| | | 778 | { "-E, --fatal-warnings", "exit on warnings" }, |
| | | 779 | { "-F, --freeze-state=file", "save state to file" }, |
| | | 780 | { "-g, --gnu", "enable gnu extensions" }, |
| | | 781 | { " --help", "print this message and exit" }, |
| | | 782 | { "-I, --include=file", "include file" }, |
| | | 783 | { "-i, --interactive", "unbuffer output, ignore tty signals" }, |
| | | 784 | { "-L, --nesting-limit=num", "macro expansion nesting limit (-1 disable)" }, |
| | | 785 | { "-P, --prefix-builtins", "prefix builtins with m4_" }, |
| | | 786 | { "-Q, --quiet", "don't print warnings" }, |
| | | 787 | { "-R, --reload-state=file", "restore state from file" }, |
| | | 788 | { "-Q, --silent", "don't print warnings" }, |
| | | 789 | { "-s, --synclines", "output line directives for cpp(1)" }, |
| | | 790 | { "-t, --trace=macro", "trace the named macro" }, |
| | | 791 | { "-G, --traditional", "disable gnu extensions" }, |
| | | 792 | { "-U, --undefine=name", "undefine the named macro" }, |
| | | 793 | { "-v, --version", "print the version number and exit" }, |
| | | 794 | }; |
| | | 795 | |
| | | 796 | static void |
| | | 797 | help(void) |
| | | 798 | { |
| | | 799 | size_t i; |
| | | 800 | fprintf(stdout, "%s version %d\n\n", getprogname(), VERSION); |
| | | 801 | usage(stdout); |
| | | 802 | |
| | | 803 | fprintf(stdout, "\nThe long options are:\n"); |
| | | 804 | for (i = 0; i < __arraycount(nd); i++) |
| | | 805 | fprintf(stdout, "\t%-25.25s\t%s\n", nd[i].n, nd[i].d); |
| | | 806 | } |