main.c revision 1.40 1 1.38 christos /* $OpenBSD: main.c,v 1.77 2009/10/14 17:19:47 sthen Exp $ */
2 1.40 christos /* $NetBSD: main.c,v 1.40 2011/08/14 12:59:25 christos Exp $ */
3 1.9 tls
4 1.8 glass /*-
5 1.8 glass * Copyright (c) 1989, 1993
6 1.8 glass * The Regents of the University of California. All rights reserved.
7 1.8 glass *
8 1.8 glass * This code is derived from software contributed to Berkeley by
9 1.8 glass * Ozan Yigit at York University.
10 1.8 glass *
11 1.8 glass * Redistribution and use in source and binary forms, with or without
12 1.8 glass * modification, are permitted provided that the following conditions
13 1.8 glass * are met:
14 1.8 glass * 1. Redistributions of source code must retain the above copyright
15 1.8 glass * notice, this list of conditions and the following disclaimer.
16 1.8 glass * 2. Redistributions in binary form must reproduce the above copyright
17 1.8 glass * notice, this list of conditions and the following disclaimer in the
18 1.8 glass * documentation and/or other materials provided with the distribution.
19 1.34 agc * 3. Neither the name of the University nor the names of its contributors
20 1.8 glass * may be used to endorse or promote products derived from this software
21 1.8 glass * without specific prior written permission.
22 1.8 glass *
23 1.8 glass * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 1.8 glass * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 1.8 glass * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 1.8 glass * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 1.8 glass * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 1.8 glass * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 1.8 glass * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 1.8 glass * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 1.8 glass * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 1.8 glass * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 1.8 glass * SUCH DAMAGE.
34 1.8 glass */
35 1.1 cgd
36 1.1 cgd /*
37 1.8 glass * main.c
38 1.8 glass * Facility: m4 macro processor
39 1.8 glass * by: oz
40 1.1 cgd */
41 1.38 christos #if HAVE_NBTOOL_CONFIG_H
42 1.38 christos #include "nbtool_config.h"
43 1.38 christos #endif
44 1.38 christos #include <sys/cdefs.h>
45 1.40 christos __RCSID("$NetBSD: main.c,v 1.40 2011/08/14 12:59:25 christos Exp $");
46 1.27 tv #include <assert.h>
47 1.38 christos #include <signal.h>
48 1.38 christos #include <err.h>
49 1.38 christos #include <errno.h>
50 1.38 christos #include <unistd.h>
51 1.38 christos #include <stdio.h>
52 1.13 lukem #include <ctype.h>
53 1.38 christos #include <string.h>
54 1.27 tv #include <stddef.h>
55 1.38 christos #include <stdint.h>
56 1.16 kleink #include <stdlib.h>
57 1.38 christos #include <ohash.h>
58 1.8 glass #include "mdef.h"
59 1.8 glass #include "stdd.h"
60 1.8 glass #include "extern.h"
61 1.8 glass #include "pathnames.h"
62 1.8 glass
63 1.8 glass ndptr hashtab[HASHSIZE]; /* hash table for macros etc. */
64 1.27 tv stae *mstack; /* stack of m4 machine */
65 1.27 tv char *sstack; /* shadow stack, for string space extension */
66 1.27 tv static size_t STACKMAX; /* current maximum size of stack */
67 1.1 cgd int sp; /* current m4 stack pointer */
68 1.1 cgd int fp; /* m4 call frame pointer */
69 1.27 tv struct input_file infile[MAXINP];/* input file stack (0=stdin) */
70 1.27 tv FILE **outfile; /* diversion array(0=bitbucket)*/
71 1.27 tv int maxout;
72 1.1 cgd FILE *active; /* active output file pointer */
73 1.1 cgd int ilevel = 0; /* input file stack pointer */
74 1.1 cgd int oindex = 0; /* diversion index.. */
75 1.38 christos const char *null = ""; /* as it says.. just a null.. */
76 1.38 christos char **m4wraps = NULL; /* m4wraps array. */
77 1.38 christos int maxwraps = 0; /* size of m4wraps array */
78 1.38 christos int wrapindex = 0; /* current offset in m4wraps */
79 1.11 pk char lquote[MAXCCHARS+1] = {LQUOTE}; /* left quote character (`) */
80 1.11 pk char rquote[MAXCCHARS+1] = {RQUOTE}; /* right quote character (') */
81 1.11 pk char scommt[MAXCCHARS+1] = {SCOMMT}; /* start character for comment */
82 1.11 pk char ecommt[MAXCCHARS+1] = {ECOMMT}; /* end character for comment */
83 1.38 christos int synch_lines = 0; /* line synchronisation for C preprocessor */
84 1.38 christos int prefix_builtins = 0; /* -P option to prefix builtin keywords */
85 1.38 christos
86 1.38 christos struct keyblk {
87 1.38 christos const char *knam; /* keyword name */
88 1.38 christos int ktyp; /* keyword type */
89 1.38 christos };
90 1.2 glass
91 1.8 glass struct keyblk keywrds[] = { /* m4 keywords to be installed */
92 1.13 lukem { "include", INCLTYPE },
93 1.13 lukem { "sinclude", SINCTYPE },
94 1.13 lukem { "define", DEFITYPE },
95 1.13 lukem { "defn", DEFNTYPE },
96 1.27 tv { "divert", DIVRTYPE | NOARGS },
97 1.13 lukem { "expr", EXPRTYPE },
98 1.13 lukem { "eval", EXPRTYPE },
99 1.13 lukem { "substr", SUBSTYPE },
100 1.13 lukem { "ifelse", IFELTYPE },
101 1.13 lukem { "ifdef", IFDFTYPE },
102 1.13 lukem { "len", LENGTYPE },
103 1.13 lukem { "incr", INCRTYPE },
104 1.13 lukem { "decr", DECRTYPE },
105 1.27 tv { "dnl", DNLNTYPE | NOARGS },
106 1.27 tv { "changequote", CHNQTYPE | NOARGS },
107 1.27 tv { "changecom", CHNCTYPE | NOARGS },
108 1.13 lukem { "index", INDXTYPE },
109 1.8 glass #ifdef EXTENDED
110 1.13 lukem { "paste", PASTTYPE },
111 1.13 lukem { "spaste", SPASTYPE },
112 1.27 tv /* Newer extensions, needed to handle gnu-m4 scripts */
113 1.27 tv { "indir", INDIRTYPE},
114 1.27 tv { "builtin", BUILTINTYPE},
115 1.27 tv { "patsubst", PATSTYPE},
116 1.27 tv { "regexp", REGEXPTYPE},
117 1.27 tv { "esyscmd", ESYSCMDTYPE},
118 1.27 tv { "__file__", FILENAMETYPE | NOARGS},
119 1.27 tv { "__line__", LINETYPE | NOARGS},
120 1.8 glass #endif
121 1.13 lukem { "popdef", POPDTYPE },
122 1.13 lukem { "pushdef", PUSDTYPE },
123 1.27 tv { "dumpdef", DUMPTYPE | NOARGS },
124 1.27 tv { "shift", SHIFTYPE | NOARGS },
125 1.13 lukem { "translit", TRNLTYPE },
126 1.13 lukem { "undefine", UNDFTYPE },
127 1.27 tv { "undivert", UNDVTYPE | NOARGS },
128 1.27 tv { "divnum", DIVNTYPE | NOARGS },
129 1.13 lukem { "maketemp", MKTMTYPE },
130 1.27 tv { "errprint", ERRPTYPE | NOARGS },
131 1.27 tv { "m4wrap", M4WRTYPE | NOARGS },
132 1.27 tv { "m4exit", EXITTYPE | NOARGS },
133 1.13 lukem { "syscmd", SYSCTYPE },
134 1.27 tv { "sysval", SYSVTYPE | NOARGS },
135 1.27 tv { "traceon", TRACEONTYPE | NOARGS },
136 1.27 tv { "traceoff", TRACEOFFTYPE | NOARGS },
137 1.2 glass
138 1.27 tv #if defined(unix) || defined(__unix__)
139 1.27 tv { "unix", SELFTYPE | NOARGS },
140 1.2 glass #else
141 1.8 glass #ifdef vms
142 1.27 tv { "vms", SELFTYPE | NOARGS },
143 1.1 cgd #endif
144 1.1 cgd #endif
145 1.8 glass };
146 1.8 glass
147 1.8 glass #define MAXKEYS (sizeof(keywrds)/sizeof(struct keyblk))
148 1.1 cgd
149 1.27 tv extern int optind;
150 1.27 tv extern char *optarg;
151 1.27 tv
152 1.27 tv #define MAXRECORD 50
153 1.27 tv static struct position {
154 1.27 tv char *name;
155 1.27 tv unsigned long line;
156 1.27 tv } quotes[MAXRECORD], paren[MAXRECORD];
157 1.27 tv
158 1.38 christos static void record(struct position *, int);
159 1.38 christos static void dump_stack(struct position *, int);
160 1.27 tv
161 1.38 christos static void macro(void);
162 1.38 christos static void initkwds(void);
163 1.38 christos static ndptr inspect(int, char *);
164 1.38 christos static int do_look_ahead(int, const char *);
165 1.38 christos static void reallyoutputstr(const char *);
166 1.38 christos static void reallyputchar(int);
167 1.27 tv
168 1.38 christos static void enlarge_stack(void);
169 1.27 tv
170 1.38 christos int main(int, char *[]);
171 1.1 cgd
172 1.8 glass int
173 1.38 christos main(int argc, char *argv[])
174 1.8 glass {
175 1.13 lukem int c;
176 1.13 lukem int n;
177 1.8 glass char *p;
178 1.8 glass
179 1.39 joerg setprogname(argv[0]);
180 1.39 joerg
181 1.8 glass if (signal(SIGINT, SIG_IGN) != SIG_IGN)
182 1.8 glass signal(SIGINT, onintr);
183 1.1 cgd
184 1.38 christos init_macros();
185 1.27 tv initspaces();
186 1.27 tv STACKMAX = INITSTACKMAX;
187 1.27 tv
188 1.38 christos mstack = (stae *)xalloc(sizeof(stae) * STACKMAX, NULL);
189 1.38 christos sstack = (char *)xalloc(STACKMAX, NULL);
190 1.1 cgd
191 1.27 tv maxout = 0;
192 1.27 tv outfile = NULL;
193 1.27 tv resizedivs(MAXOUT);
194 1.1 cgd
195 1.38 christos while ((c = getopt(argc, argv, "gst:d:D:U:o:I:P")) != -1)
196 1.38 christos switch(c) {
197 1.38 christos
198 1.8 glass case 'D': /* define something..*/
199 1.8 glass for (p = optarg; *p; p++)
200 1.8 glass if (*p == '=')
201 1.8 glass break;
202 1.8 glass if (*p)
203 1.8 glass *p++ = EOS;
204 1.8 glass dodefine(optarg, p);
205 1.8 glass break;
206 1.27 tv case 'I':
207 1.27 tv addtoincludepath(optarg);
208 1.27 tv break;
209 1.27 tv case 'P':
210 1.38 christos prefix_builtins = 1;
211 1.27 tv break;
212 1.8 glass case 'U': /* undefine... */
213 1.38 christos macro_popdef(optarg);
214 1.38 christos break;
215 1.38 christos case 'g':
216 1.38 christos mimic_gnu = 1;
217 1.8 glass break;
218 1.27 tv case 'd':
219 1.27 tv set_trace_flags(optarg);
220 1.27 tv break;
221 1.38 christos case 's':
222 1.38 christos synch_lines = 1;
223 1.38 christos break;
224 1.38 christos case 't':
225 1.38 christos mark_traced(optarg, 1);
226 1.27 tv break;
227 1.27 tv case 'o':
228 1.27 tv trace_file(optarg);
229 1.27 tv break;
230 1.8 glass case '?':
231 1.38 christos usage();
232 1.2 glass }
233 1.1 cgd
234 1.8 glass argc -= optind;
235 1.8 glass argv += optind;
236 1.2 glass
237 1.38 christos initkwds();
238 1.38 christos if (mimic_gnu)
239 1.38 christos setup_builtin("format", FORMATTYPE);
240 1.38 christos
241 1.8 glass active = stdout; /* default active output */
242 1.8 glass bbase[0] = bufbase;
243 1.8 glass if (!argc) {
244 1.8 glass sp = -1; /* stack pointer initialized */
245 1.8 glass fp = 0; /* frame pointer initialized */
246 1.27 tv set_input(infile+0, stdin, "stdin");
247 1.27 tv /* default input (naturally) */
248 1.8 glass macro();
249 1.8 glass } else
250 1.8 glass for (; argc--; ++argv) {
251 1.8 glass p = *argv;
252 1.27 tv if (p[0] == '-' && p[1] == EOS)
253 1.27 tv set_input(infile, stdin, "stdin");
254 1.27 tv else if (fopen_trypath(infile, p) == NULL)
255 1.13 lukem err(1, "%s", p);
256 1.8 glass sp = -1;
257 1.8 glass fp = 0;
258 1.8 glass macro();
259 1.27 tv release_input(infile);
260 1.8 glass }
261 1.2 glass
262 1.38 christos if (wrapindex) {
263 1.38 christos int i;
264 1.38 christos
265 1.8 glass ilevel = 0; /* in case m4wrap includes.. */
266 1.8 glass bufbase = bp = buf; /* use the entire buffer */
267 1.38 christos if (mimic_gnu) {
268 1.38 christos while (wrapindex != 0) {
269 1.38 christos for (i = 0; i < wrapindex; i++)
270 1.38 christos pbstr(m4wraps[i]);
271 1.38 christos wrapindex =0;
272 1.38 christos macro();
273 1.38 christos }
274 1.38 christos } else {
275 1.38 christos for (i = 0; i < wrapindex; i++) {
276 1.38 christos pbstr(m4wraps[i]);
277 1.38 christos macro();
278 1.38 christos }
279 1.38 christos }
280 1.8 glass }
281 1.2 glass
282 1.8 glass if (active != stdout)
283 1.8 glass active = stdout; /* reset output just in case */
284 1.27 tv for (n = 1; n < maxout; n++) /* default wrap-up: undivert */
285 1.8 glass if (outfile[n] != NULL)
286 1.8 glass getdiv(n);
287 1.27 tv /* remove bitbucket if used */
288 1.27 tv if (outfile[0] != NULL) {
289 1.8 glass (void) fclose(outfile[0]);
290 1.27 tv }
291 1.8 glass
292 1.8 glass return 0;
293 1.8 glass }
294 1.2 glass
295 1.8 glass /*
296 1.27 tv * Look ahead for `token'.
297 1.11 pk * (on input `t == token[0]')
298 1.11 pk * Used for comment and quoting delimiters.
299 1.11 pk * Returns 1 if `token' present; copied to output.
300 1.11 pk * 0 if `token' not found; all characters pushed back
301 1.11 pk */
302 1.27 tv static int
303 1.38 christos do_look_ahead(int t, const char *token)
304 1.11 pk {
305 1.11 pk int i;
306 1.11 pk
307 1.27 tv assert((unsigned char)t == (unsigned char)token[0]);
308 1.11 pk
309 1.11 pk for (i = 1; *++token; i++) {
310 1.11 pk t = gpbc();
311 1.27 tv if (t == EOF || (unsigned char)t != (unsigned char)*token) {
312 1.38 christos pushback(t);
313 1.11 pk while (--i)
314 1.38 christos pushback(*--token);
315 1.11 pk return 0;
316 1.11 pk }
317 1.11 pk }
318 1.11 pk return 1;
319 1.11 pk }
320 1.11 pk
321 1.27 tv #define LOOK_AHEAD(t, token) (t != EOF && \
322 1.27 tv (unsigned char)(t)==(unsigned char)(token)[0] && \
323 1.27 tv do_look_ahead(t,token))
324 1.11 pk
325 1.11 pk /*
326 1.8 glass * macro - the work horse..
327 1.8 glass */
328 1.27 tv static void
329 1.38 christos macro(void)
330 1.13 lukem {
331 1.27 tv char token[MAXTOK+1];
332 1.13 lukem int t, l;
333 1.13 lukem ndptr p;
334 1.13 lukem int nlpar;
335 1.1 cgd
336 1.8 glass cycle {
337 1.11 pk t = gpbc();
338 1.27 tv
339 1.38 christos if (LOOK_AHEAD(t,lquote)) { /* strip quotes */
340 1.27 tv nlpar = 0;
341 1.27 tv record(quotes, nlpar++);
342 1.27 tv /*
343 1.27 tv * Opening quote: scan forward until matching
344 1.27 tv * closing quote has been found.
345 1.27 tv */
346 1.8 glass do {
347 1.12 cgd
348 1.11 pk l = gpbc();
349 1.12 cgd if (LOOK_AHEAD(l,rquote)) {
350 1.27 tv if (--nlpar > 0)
351 1.27 tv outputstr(rquote);
352 1.12 cgd } else if (LOOK_AHEAD(l,lquote)) {
353 1.27 tv record(quotes, nlpar++);
354 1.27 tv outputstr(lquote);
355 1.27 tv } else if (l == EOF) {
356 1.27 tv if (nlpar == 1)
357 1.27 tv warnx("unclosed quote:");
358 1.8 glass else
359 1.27 tv warnx("%d unclosed quotes:", nlpar);
360 1.27 tv dump_stack(quotes, nlpar);
361 1.27 tv exit(1);
362 1.27 tv } else {
363 1.27 tv if (nlpar > 0) {
364 1.27 tv if (sp < 0)
365 1.38 christos reallyputchar(l);
366 1.27 tv else
367 1.27 tv CHRSAVE(l);
368 1.27 tv }
369 1.2 glass }
370 1.8 glass }
371 1.8 glass while (nlpar != 0);
372 1.38 christos } else if (sp < 0 && LOOK_AHEAD(t, scommt)) {
373 1.38 christos reallyoutputstr(scommt);
374 1.11 pk
375 1.11 pk for(;;) {
376 1.11 pk t = gpbc();
377 1.11 pk if (LOOK_AHEAD(t, ecommt)) {
378 1.38 christos reallyoutputstr(ecommt);
379 1.11 pk break;
380 1.11 pk }
381 1.11 pk if (t == EOF)
382 1.11 pk break;
383 1.38 christos reallyputchar(t);
384 1.1 cgd }
385 1.38 christos } else if (t == '_' || isalpha(t)) {
386 1.38 christos p = inspect(t, token);
387 1.38 christos if (p != NULL)
388 1.38 christos pushback(l = gpbc());
389 1.38 christos if (p == NULL || (l != LPAREN &&
390 1.38 christos (macro_getdef(p)->type & NEEDARGS) != 0))
391 1.38 christos outputstr(token);
392 1.38 christos else {
393 1.38 christos /*
394 1.38 christos * real thing.. First build a call frame:
395 1.38 christos */
396 1.38 christos pushf(fp); /* previous call frm */
397 1.38 christos pushf(macro_getdef(p)->type); /* type of the call */
398 1.38 christos pushf(is_traced(p));
399 1.38 christos pushf(0); /* parenthesis level */
400 1.38 christos fp = sp; /* new frame pointer */
401 1.38 christos /*
402 1.38 christos * now push the string arguments:
403 1.38 christos */
404 1.38 christos pushs1(macro_getdef(p)->defn); /* defn string */
405 1.38 christos pushs1((char *)macro_name(p)); /* macro name */
406 1.38 christos pushs(ep); /* start next..*/
407 1.38 christos
408 1.38 christos if (l != LPAREN && PARLEV == 0) {
409 1.38 christos /* no bracks */
410 1.38 christos chrsave(EOS);
411 1.38 christos
412 1.38 christos if ((size_t)sp == STACKMAX)
413 1.38 christos errx(1, "internal stack overflow");
414 1.38 christos eval((const char **) mstack+fp+1, 2,
415 1.38 christos CALTYP, TRACESTATUS);
416 1.11 pk
417 1.38 christos ep = PREVEP; /* flush strspace */
418 1.38 christos sp = PREVSP; /* previous sp.. */
419 1.38 christos fp = PREVFP; /* rewind stack...*/
420 1.38 christos }
421 1.38 christos }
422 1.38 christos } else if (t == EOF) {
423 1.38 christos if (sp > -1 && ilevel <= 0) {
424 1.38 christos warnx( "unexpected end of input, unclosed parenthesis:");
425 1.38 christos dump_stack(paren, PARLEV);
426 1.38 christos exit(1);
427 1.38 christos }
428 1.38 christos if (ilevel <= 0)
429 1.38 christos break; /* all done thanks.. */
430 1.38 christos release_input(infile+ilevel--);
431 1.38 christos emit_synchline();
432 1.38 christos bufbase = bbase[ilevel];
433 1.38 christos continue;
434 1.38 christos } else if (sp < 0) { /* not in a macro at all */
435 1.38 christos reallyputchar(t); /* output directly.. */
436 1.8 glass }
437 1.1 cgd
438 1.8 glass else switch(t) {
439 1.2 glass
440 1.8 glass case LPAREN:
441 1.8 glass if (PARLEV > 0)
442 1.8 glass chrsave(t);
443 1.38 christos while (isspace(l = gpbc())) /* skip blank, tab, nl.. */
444 1.38 christos if (PARLEV > 0)
445 1.38 christos chrsave(l);
446 1.38 christos pushback(l);
447 1.27 tv record(paren, PARLEV++);
448 1.8 glass break;
449 1.1 cgd
450 1.8 glass case RPAREN:
451 1.8 glass if (--PARLEV > 0)
452 1.8 glass chrsave(t);
453 1.8 glass else { /* end of argument list */
454 1.8 glass chrsave(EOS);
455 1.8 glass
456 1.38 christos if ((size_t)sp == STACKMAX)
457 1.13 lukem errx(1, "internal stack overflow");
458 1.8 glass
459 1.27 tv eval((const char **) mstack+fp+1, sp-fp,
460 1.38 christos CALTYP, TRACESTATUS);
461 1.8 glass
462 1.8 glass ep = PREVEP; /* flush strspace */
463 1.8 glass sp = PREVSP; /* previous sp.. */
464 1.8 glass fp = PREVFP; /* rewind stack...*/
465 1.8 glass }
466 1.8 glass break;
467 1.1 cgd
468 1.8 glass case COMMA:
469 1.8 glass if (PARLEV == 1) {
470 1.8 glass chrsave(EOS); /* new argument */
471 1.8 glass while (isspace(l = gpbc()))
472 1.8 glass ;
473 1.38 christos pushback(l);
474 1.8 glass pushs(ep);
475 1.8 glass } else
476 1.8 glass chrsave(t);
477 1.8 glass break;
478 1.2 glass
479 1.2 glass default:
480 1.27 tv if (LOOK_AHEAD(t, scommt)) {
481 1.38 christos char *q;
482 1.38 christos for (q = scommt; *q; p++)
483 1.38 christos chrsave(*q);
484 1.27 tv for(;;) {
485 1.27 tv t = gpbc();
486 1.27 tv if (LOOK_AHEAD(t, ecommt)) {
487 1.38 christos for (q = ecommt; *q; q++)
488 1.38 christos chrsave(*q);
489 1.27 tv break;
490 1.27 tv }
491 1.27 tv if (t == EOF)
492 1.27 tv break;
493 1.27 tv CHRSAVE(t);
494 1.27 tv }
495 1.27 tv } else
496 1.27 tv CHRSAVE(t); /* stack the char */
497 1.8 glass break;
498 1.8 glass }
499 1.2 glass }
500 1.8 glass }
501 1.2 glass
502 1.27 tv /*
503 1.27 tv * output string directly, without pushing it for reparses.
504 1.27 tv */
505 1.27 tv void
506 1.38 christos outputstr(const char *s)
507 1.27 tv {
508 1.27 tv if (sp < 0)
509 1.38 christos reallyoutputstr(s);
510 1.27 tv else
511 1.27 tv while (*s)
512 1.27 tv CHRSAVE(*s++);
513 1.27 tv }
514 1.27 tv
515 1.38 christos void
516 1.38 christos reallyoutputstr(const char *s)
517 1.38 christos {
518 1.38 christos if (synch_lines) {
519 1.38 christos while (*s) {
520 1.38 christos fputc(*s, active);
521 1.38 christos if (*s++ == '\n') {
522 1.38 christos infile[ilevel].synch_lineno++;
523 1.38 christos if (infile[ilevel].synch_lineno !=
524 1.38 christos infile[ilevel].lineno)
525 1.38 christos do_emit_synchline();
526 1.38 christos }
527 1.38 christos }
528 1.38 christos } else
529 1.38 christos fputs(s, active);
530 1.38 christos }
531 1.38 christos
532 1.38 christos void
533 1.38 christos reallyputchar(int c)
534 1.38 christos {
535 1.38 christos putc(c, active);
536 1.38 christos if (synch_lines && c == '\n') {
537 1.38 christos infile[ilevel].synch_lineno++;
538 1.38 christos if (infile[ilevel].synch_lineno != infile[ilevel].lineno)
539 1.38 christos do_emit_synchline();
540 1.38 christos }
541 1.38 christos }
542 1.38 christos
543 1.8 glass /*
544 1.8 glass * build an input token..
545 1.38 christos * consider only those starting with _ or A-Za-z.
546 1.8 glass */
547 1.27 tv static ndptr
548 1.38 christos inspect(int c, char *tp)
549 1.8 glass {
550 1.13 lukem char *name = tp;
551 1.13 lukem char *etp = tp+MAXTOK;
552 1.13 lukem ndptr p;
553 1.27 tv
554 1.38 christos *tp++ = c;
555 1.2 glass
556 1.27 tv while ((isalnum(c = gpbc()) || c == '_') && tp < etp)
557 1.38 christos *tp++ = c;
558 1.27 tv if (c != EOF)
559 1.38 christos PUSHBACK(c);
560 1.8 glass *tp = EOS;
561 1.27 tv /* token is too long, it won't match anything, but it can still
562 1.27 tv * be output. */
563 1.27 tv if (tp == ep) {
564 1.27 tv outputstr(name);
565 1.27 tv while (isalnum(c = gpbc()) || c == '_') {
566 1.27 tv if (sp < 0)
567 1.38 christos reallyputchar(c);
568 1.27 tv else
569 1.27 tv CHRSAVE(c);
570 1.27 tv }
571 1.27 tv *name = EOS;
572 1.38 christos return NULL;
573 1.27 tv }
574 1.1 cgd
575 1.40 christos p = ohash_find(¯os, ohash_qlookupi(¯os, name, (void *)&tp));
576 1.38 christos if (p == NULL)
577 1.38 christos return NULL;
578 1.38 christos if (macro_getdef(p) == NULL)
579 1.38 christos return NULL;
580 1.8 glass return p;
581 1.8 glass }
582 1.7 cgd
583 1.8 glass /*
584 1.38 christos * initkwds - initialise m4 keywords as fast as possible.
585 1.8 glass * This very similar to install, but without certain overheads,
586 1.38 christos * such as calling lookup. Malloc is not used for storing the
587 1.13 lukem * keyword strings, since we simply use the static pointers
588 1.8 glass * within keywrds block.
589 1.8 glass */
590 1.27 tv static void
591 1.38 christos initkwds(void)
592 1.13 lukem {
593 1.38 christos unsigned int type;
594 1.32 tv size_t i;
595 1.1 cgd
596 1.8 glass for (i = 0; i < MAXKEYS; i++) {
597 1.38 christos type = keywrds[i].ktyp & TYPEMASK;
598 1.27 tv if ((keywrds[i].ktyp & NOARGS) == 0)
599 1.38 christos type |= NEEDARGS;
600 1.38 christos setup_builtin(keywrds[i].knam, type);
601 1.1 cgd }
602 1.27 tv }
603 1.27 tv
604 1.27 tv static void
605 1.38 christos record(struct position *t, int lev)
606 1.27 tv {
607 1.27 tv if (lev < MAXRECORD) {
608 1.27 tv t[lev].name = CURRENT_NAME;
609 1.27 tv t[lev].line = CURRENT_LINE;
610 1.27 tv }
611 1.27 tv }
612 1.27 tv
613 1.27 tv static void
614 1.38 christos dump_stack(struct position *t, int lev)
615 1.27 tv {
616 1.27 tv int i;
617 1.27 tv
618 1.27 tv for (i = 0; i < lev; i++) {
619 1.27 tv if (i == MAXRECORD) {
620 1.27 tv fprintf(stderr, " ...\n");
621 1.27 tv break;
622 1.27 tv }
623 1.27 tv fprintf(stderr, " %s at line %lu\n",
624 1.27 tv t[i].name, t[i].line);
625 1.27 tv }
626 1.27 tv }
627 1.27 tv
628 1.27 tv
629 1.27 tv static void
630 1.38 christos enlarge_stack(void)
631 1.27 tv {
632 1.38 christos STACKMAX += STACKMAX/2;
633 1.38 christos mstack = xrealloc(mstack, sizeof(stae) * STACKMAX,
634 1.38 christos "Evaluation stack overflow (%lu)",
635 1.38 christos (unsigned long)STACKMAX);
636 1.38 christos sstack = xrealloc(sstack, STACKMAX,
637 1.38 christos "Evaluation stack overflow (%lu)",
638 1.38 christos (unsigned long)STACKMAX);
639 1.8 glass }
640