main.c revision 1.46
11.38Schristos/* $OpenBSD: main.c,v 1.77 2009/10/14 17:19:47 sthen Exp $ */ 21.46Schristos/* $NetBSD: main.c,v 1.46 2016/01/23 14:24:43 christos Exp $ */ 31.9Stls 41.8Sglass/*- 51.8Sglass * Copyright (c) 1989, 1993 61.8Sglass * The Regents of the University of California. All rights reserved. 71.8Sglass * 81.8Sglass * This code is derived from software contributed to Berkeley by 91.8Sglass * Ozan Yigit at York University. 101.8Sglass * 111.8Sglass * Redistribution and use in source and binary forms, with or without 121.8Sglass * modification, are permitted provided that the following conditions 131.8Sglass * are met: 141.8Sglass * 1. Redistributions of source code must retain the above copyright 151.8Sglass * notice, this list of conditions and the following disclaimer. 161.8Sglass * 2. Redistributions in binary form must reproduce the above copyright 171.8Sglass * notice, this list of conditions and the following disclaimer in the 181.8Sglass * documentation and/or other materials provided with the distribution. 191.34Sagc * 3. Neither the name of the University nor the names of its contributors 201.8Sglass * may be used to endorse or promote products derived from this software 211.8Sglass * without specific prior written permission. 221.8Sglass * 231.8Sglass * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 241.8Sglass * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 251.8Sglass * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 261.8Sglass * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 271.8Sglass * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 281.8Sglass * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 291.8Sglass * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 301.8Sglass * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 311.8Sglass * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 321.8Sglass * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 331.8Sglass * SUCH DAMAGE. 341.8Sglass */ 351.1Scgd 361.1Scgd/* 371.8Sglass * main.c 381.8Sglass * Facility: m4 macro processor 391.8Sglass * by: oz 401.1Scgd */ 411.38Schristos#if HAVE_NBTOOL_CONFIG_H 421.38Schristos#include "nbtool_config.h" 431.38Schristos#endif 441.38Schristos#include <sys/cdefs.h> 451.46Schristos__RCSID("$NetBSD: main.c,v 1.46 2016/01/23 14:24:43 christos Exp $"); 461.27Stv#include <assert.h> 471.38Schristos#include <signal.h> 481.43Schristos#include <getopt.h> 491.38Schristos#include <err.h> 501.38Schristos#include <errno.h> 511.38Schristos#include <unistd.h> 521.38Schristos#include <stdio.h> 531.13Slukem#include <ctype.h> 541.38Schristos#include <string.h> 551.27Stv#include <stddef.h> 561.38Schristos#include <stdint.h> 571.16Skleink#include <stdlib.h> 581.38Schristos#include <ohash.h> 591.8Sglass#include "mdef.h" 601.8Sglass#include "stdd.h" 611.8Sglass#include "extern.h" 621.8Sglass#include "pathnames.h" 631.8Sglass 641.8Sglassndptr hashtab[HASHSIZE]; /* hash table for macros etc. */ 651.27Stvstae *mstack; /* stack of m4 machine */ 661.27Stvchar *sstack; /* shadow stack, for string space extension */ 671.27Stvstatic size_t STACKMAX; /* current maximum size of stack */ 681.1Scgdint sp; /* current m4 stack pointer */ 691.1Scgdint fp; /* m4 call frame pointer */ 701.27Stvstruct input_file infile[MAXINP];/* input file stack (0=stdin) */ 711.27StvFILE **outfile; /* diversion array(0=bitbucket)*/ 721.27Stvint maxout; 731.1ScgdFILE *active; /* active output file pointer */ 741.1Scgdint ilevel = 0; /* input file stack pointer */ 751.1Scgdint oindex = 0; /* diversion index.. */ 761.38Schristosconst char *null = ""; /* as it says.. just a null.. */ 771.38Schristoschar **m4wraps = NULL; /* m4wraps array. */ 781.38Schristosint maxwraps = 0; /* size of m4wraps array */ 791.38Schristosint wrapindex = 0; /* current offset in m4wraps */ 801.11Spkchar lquote[MAXCCHARS+1] = {LQUOTE}; /* left quote character (`) */ 811.11Spkchar rquote[MAXCCHARS+1] = {RQUOTE}; /* right quote character (') */ 821.11Spkchar scommt[MAXCCHARS+1] = {SCOMMT}; /* start character for comment */ 831.11Spkchar ecommt[MAXCCHARS+1] = {ECOMMT}; /* end character for comment */ 841.38Schristosint synch_lines = 0; /* line synchronisation for C preprocessor */ 851.38Schristosint prefix_builtins = 0; /* -P option to prefix builtin keywords */ 861.43Schristosint fatal_warnings = 0; /* -E option to exit on warnings */ 871.43Schristosint quiet = 0; /* -Q option to silence warnings */ 881.43Schristosint nesting_limit = -1; /* -L for nesting limit */ 891.43Schristosconst char *freeze = NULL; /* -F to freeze state */ 901.43Schristosconst char *reload = NULL; /* -R to reload state */ 911.43Schristos#ifndef REAL_FREEZE 921.43SchristosFILE *freezef = NULL; 931.43Schristosint thawing = 0; 941.43Schristos#endif 951.38Schristos 961.38Schristosstruct keyblk { 971.38Schristos const char *knam; /* keyword name */ 981.38Schristos int ktyp; /* keyword type */ 991.38Schristos}; 1001.2Sglass 1011.8Sglassstruct keyblk keywrds[] = { /* m4 keywords to be installed */ 1021.13Slukem { "include", INCLTYPE }, 1031.13Slukem { "sinclude", SINCTYPE }, 1041.13Slukem { "define", DEFITYPE }, 1051.13Slukem { "defn", DEFNTYPE }, 1061.27Stv { "divert", DIVRTYPE | NOARGS }, 1071.13Slukem { "expr", EXPRTYPE }, 1081.13Slukem { "eval", EXPRTYPE }, 1091.13Slukem { "substr", SUBSTYPE }, 1101.13Slukem { "ifelse", IFELTYPE }, 1111.13Slukem { "ifdef", IFDFTYPE }, 1121.13Slukem { "len", LENGTYPE }, 1131.13Slukem { "incr", INCRTYPE }, 1141.13Slukem { "decr", DECRTYPE }, 1151.27Stv { "dnl", DNLNTYPE | NOARGS }, 1161.27Stv { "changequote", CHNQTYPE | NOARGS }, 1171.27Stv { "changecom", CHNCTYPE | NOARGS }, 1181.13Slukem { "index", INDXTYPE }, 1191.8Sglass#ifdef EXTENDED 1201.13Slukem { "paste", PASTTYPE }, 1211.13Slukem { "spaste", SPASTYPE }, 1221.27Stv /* Newer extensions, needed to handle gnu-m4 scripts */ 1231.27Stv { "indir", INDIRTYPE}, 1241.27Stv { "builtin", BUILTINTYPE}, 1251.27Stv { "patsubst", PATSTYPE}, 1261.27Stv { "regexp", REGEXPTYPE}, 1271.27Stv { "esyscmd", ESYSCMDTYPE}, 1281.27Stv { "__file__", FILENAMETYPE | NOARGS}, 1291.27Stv { "__line__", LINETYPE | NOARGS}, 1301.8Sglass#endif 1311.13Slukem { "popdef", POPDTYPE }, 1321.13Slukem { "pushdef", PUSDTYPE }, 1331.27Stv { "dumpdef", DUMPTYPE | NOARGS }, 1341.27Stv { "shift", SHIFTYPE | NOARGS }, 1351.13Slukem { "translit", TRNLTYPE }, 1361.13Slukem { "undefine", UNDFTYPE }, 1371.27Stv { "undivert", UNDVTYPE | NOARGS }, 1381.27Stv { "divnum", DIVNTYPE | NOARGS }, 1391.13Slukem { "maketemp", MKTMTYPE }, 1401.27Stv { "errprint", ERRPTYPE | NOARGS }, 1411.27Stv { "m4wrap", M4WRTYPE | NOARGS }, 1421.27Stv { "m4exit", EXITTYPE | NOARGS }, 1431.13Slukem { "syscmd", SYSCTYPE }, 1441.27Stv { "sysval", SYSVTYPE | NOARGS }, 1451.27Stv { "traceon", TRACEONTYPE | NOARGS }, 1461.27Stv { "traceoff", TRACEOFFTYPE | NOARGS }, 1471.2Sglass 1481.27Stv#if defined(unix) || defined(__unix__) 1491.27Stv { "unix", SELFTYPE | NOARGS }, 1501.2Sglass#else 1511.8Sglass#ifdef vms 1521.27Stv { "vms", SELFTYPE | NOARGS }, 1531.1Scgd#endif 1541.1Scgd#endif 1551.8Sglass}; 1561.8Sglass 1571.8Sglass#define MAXKEYS (sizeof(keywrds)/sizeof(struct keyblk)) 1581.1Scgd 1591.27Stv#define MAXRECORD 50 1601.27Stvstatic struct position { 1611.27Stv char *name; 1621.27Stv unsigned long line; 1631.27Stv} quotes[MAXRECORD], paren[MAXRECORD]; 1641.27Stv 1651.38Schristosstatic void record(struct position *, int); 1661.38Schristosstatic void dump_stack(struct position *, int); 1671.27Stv 1681.38Schristosstatic void macro(void); 1691.38Schristosstatic void initkwds(void); 1701.38Schristosstatic ndptr inspect(int, char *); 1711.38Schristosstatic int do_look_ahead(int, const char *); 1721.38Schristosstatic void reallyoutputstr(const char *); 1731.38Schristosstatic void reallyputchar(int); 1741.27Stv 1751.38Schristosstatic void enlarge_stack(void); 1761.43Schristosstatic void help(void); 1771.27Stv 1781.43Schristosstatic void 1791.43Schristosusage(FILE *f) 1801.41Sjoerg{ 1811.43Schristos fprintf(f, "Usage: %s [-EGgiPQsv] [-Dname[=value]] [-d flags] " 1821.43Schristos "[-I dirname] [-o filename] [-L limit]\n" 1831.43Schristos "\t[-t macro] [-Uname] [file ...]\n", getprogname()); 1841.41Sjoerg} 1851.41Sjoerg 1861.41Sjoerg__dead static void 1871.41Sjoergonintr(int signo) 1881.41Sjoerg{ 1891.41Sjoerg char intrmessage[] = "m4: interrupted.\n"; 1901.41Sjoerg write(STDERR_FILENO, intrmessage, sizeof(intrmessage)-1); 1911.41Sjoerg _exit(1); 1921.41Sjoerg} 1931.1Scgd 1941.43Schristos#define OPT_HELP 1 1951.43Schristos 1961.43Schristosstruct option longopts[] = { 1971.43Schristos { "debug", optional_argument, 0, 'd' }, 1981.43Schristos { "define", required_argument, 0, 'D' }, 1991.43Schristos { "error-output", required_argument, 0, 'e' }, 2001.43Schristos { "fatal-warnings", no_argument, 0, 'E' }, 2011.43Schristos { "freeze-state", required_argument, 0, 'F' }, 2021.43Schristos { "gnu", no_argument, 0, 'g' }, 2031.43Schristos { "help", no_argument, 0, OPT_HELP }, 2041.43Schristos { "include", required_argument, 0, 'I' }, 2051.43Schristos { "interactive", no_argument, 0, 'i' }, 2061.43Schristos { "nesting-limit", required_argument, 0, 'L' }, 2071.43Schristos { "prefix-builtins", no_argument, 0, 'P' }, 2081.43Schristos { "quiet", no_argument, 0, 'Q' }, 2091.43Schristos { "reload-state", required_argument, 0, 'R' }, 2101.43Schristos { "silent", no_argument, 0, 'Q' }, 2111.43Schristos { "synclines", no_argument, 0, 's' }, 2121.43Schristos { "trace", required_argument, 0, 't' }, 2131.43Schristos { "traditional", no_argument, 0, 'G' }, 2141.43Schristos { "undefine", required_argument, 0, 'U' }, 2151.43Schristos { "version", no_argument, 0, 'v' }, 2161.43Schristos#ifdef notyet 2171.43Schristos { "arglength", required_argument, 0, 'l' }, 2181.43Schristos { "debugfile", optional_argument, 0, OPT_DEBUGFILE }, 2191.43Schristos { "hashsize", required_argument, 0, 'H' }, 2201.43Schristos { "warn-macro-sequence",optional_argument, 0, OPT_WARN_SEQUENCE }, 2211.43Schristos#endif 2221.43Schristos { 0, 0, 0, 0 }, 2231.43Schristos}; 2241.43Schristos 2251.8Sglassint 2261.38Schristosmain(int argc, char *argv[]) 2271.8Sglass{ 2281.13Slukem int c; 2291.13Slukem int n; 2301.8Sglass char *p; 2311.8Sglass 2321.39Sjoerg setprogname(argv[0]); 2331.39Sjoerg 2341.8Sglass if (signal(SIGINT, SIG_IGN) != SIG_IGN) 2351.8Sglass signal(SIGINT, onintr); 2361.1Scgd 2371.38Schristos init_macros(); 2381.27Stv initspaces(); 2391.27Stv STACKMAX = INITSTACKMAX; 2401.27Stv 2411.38Schristos mstack = (stae *)xalloc(sizeof(stae) * STACKMAX, NULL); 2421.38Schristos sstack = (char *)xalloc(STACKMAX, NULL); 2431.1Scgd 2441.27Stv maxout = 0; 2451.27Stv outfile = NULL; 2461.27Stv resizedivs(MAXOUT); 2471.1Scgd 2481.45Schristos while ((c = getopt_long(argc, argv, "D:d:e:EF:GgI:iL:o:PR:Qst:U:v", 2491.43Schristos longopts, NULL)) != -1) 2501.38Schristos switch(c) { 2511.8Sglass case 'D': /* define something..*/ 2521.8Sglass for (p = optarg; *p; p++) 2531.8Sglass if (*p == '=') 2541.8Sglass break; 2551.8Sglass if (*p) 2561.8Sglass *p++ = EOS; 2571.8Sglass dodefine(optarg, p); 2581.8Sglass break; 2591.43Schristos case 'd': 2601.43Schristos set_trace_flags(optarg); 2611.43Schristos break; 2621.43Schristos case 'E': 2631.43Schristos fatal_warnings++; 2641.43Schristos break; 2651.43Schristos case 'e': 2661.43Schristos if (freopen(optarg, "w+", stderr) == NULL) 2671.43Schristos err(EXIT_FAILURE, "Can't redirect errors to `%s'", 2681.43Schristos optarg); 2691.43Schristos break; 2701.43Schristos case 'F': 2711.43Schristos freeze = optarg; 2721.43Schristos#ifndef REAL_FREEZE 2731.43Schristos if ((freezef = fopen(freeze, "w")) == NULL) 2741.43Schristos err(EXIT_FAILURE, "Can't open `%s'", freeze); 2751.43Schristos#endif 2761.43Schristos break; 2771.27Stv case 'I': 2781.27Stv addtoincludepath(optarg); 2791.27Stv break; 2801.43Schristos case 'i': 2811.43Schristos setvbuf(stdout, NULL, _IONBF, 0); 2821.43Schristos signal(SIGINT, SIG_IGN); 2831.27Stv break; 2841.43Schristos case 'G': 2851.43Schristos mimic_gnu = 0; 2861.38Schristos break; 2871.38Schristos case 'g': 2881.38Schristos mimic_gnu = 1; 2891.8Sglass break; 2901.43Schristos case 'L': 2911.43Schristos nesting_limit = atoi(optarg); 2921.43Schristos break; 2931.43Schristos case 'o': 2941.43Schristos trace_file(optarg); 2951.43Schristos break; 2961.43Schristos case 'P': 2971.43Schristos prefix_builtins = 1; 2981.43Schristos break; 2991.43Schristos case 'Q': 3001.43Schristos quiet++; 3011.43Schristos break; 3021.43Schristos case 'R': 3031.43Schristos reload = optarg; 3041.27Stv break; 3051.38Schristos case 's': 3061.38Schristos synch_lines = 1; 3071.38Schristos break; 3081.38Schristos case 't': 3091.38Schristos mark_traced(optarg, 1); 3101.27Stv break; 3111.43Schristos case 'U': /* undefine... */ 3121.43Schristos macro_popdef(optarg); 3131.43Schristos break; 3141.43Schristos case 'v': 3151.43Schristos fprintf(stderr, "%s version %d\n", getprogname(), 3161.43Schristos VERSION); 3171.43Schristos return EXIT_SUCCESS; 3181.43Schristos case OPT_HELP: 3191.43Schristos help(); 3201.43Schristos return EXIT_SUCCESS; 3211.8Sglass case '?': 3221.43Schristos default: 3231.43Schristos usage(stderr); 3241.43Schristos return EXIT_FAILURE; 3251.2Sglass } 3261.1Scgd 3271.43Schristos#ifdef REDIRECT 3281.46Schristos /* 3291.46Schristos * This is meant only for debugging; it makes all output 3301.46Schristos * go to a known file, even if the command line options 3311.46Schristos * send it elsewhere. It should not be turned of in production code. 3321.46Schristos */ 3331.43Schristos if (freopen("/tmp/m4", "w+", stderr) == NULL) 3341.43Schristos err(EXIT_FAILURE, "Can't redirect errors to `%s'", 3351.43Schristos "/tmp/m4"); 3361.43Schristos#endif 3371.8Sglass argc -= optind; 3381.8Sglass argv += optind; 3391.2Sglass 3401.43Schristos 3411.38Schristos initkwds(); 3421.38Schristos if (mimic_gnu) 3431.38Schristos setup_builtin("format", FORMATTYPE); 3441.38Schristos 3451.8Sglass active = stdout; /* default active output */ 3461.8Sglass bbase[0] = bufbase; 3471.43Schristos 3481.43Schristos if (reload) { 3491.43Schristos#ifdef REAL_FREEZE 3501.43Schristos thaw_state(reload); 3511.43Schristos#else 3521.43Schristos if (fopen_trypath(infile, reload) == NULL) 3531.43Schristos err(1, "Can't open `%s'", reload); 3541.43Schristos sp = -1; 3551.43Schristos fp = 0; 3561.43Schristos thawing = 1; 3571.43Schristos macro(); 3581.43Schristos thawing = 0; 3591.43Schristos release_input(infile); 3601.43Schristos#endif 3611.43Schristos } 3621.43Schristos 3631.8Sglass if (!argc) { 3641.8Sglass sp = -1; /* stack pointer initialized */ 3651.8Sglass fp = 0; /* frame pointer initialized */ 3661.27Stv set_input(infile+0, stdin, "stdin"); 3671.27Stv /* default input (naturally) */ 3681.8Sglass macro(); 3691.8Sglass } else 3701.8Sglass for (; argc--; ++argv) { 3711.8Sglass p = *argv; 3721.27Stv if (p[0] == '-' && p[1] == EOS) 3731.27Stv set_input(infile, stdin, "stdin"); 3741.27Stv else if (fopen_trypath(infile, p) == NULL) 3751.13Slukem err(1, "%s", p); 3761.8Sglass sp = -1; 3771.8Sglass fp = 0; 3781.8Sglass macro(); 3791.27Stv release_input(infile); 3801.8Sglass } 3811.2Sglass 3821.38Schristos if (wrapindex) { 3831.38Schristos int i; 3841.38Schristos 3851.8Sglass ilevel = 0; /* in case m4wrap includes.. */ 3861.8Sglass bufbase = bp = buf; /* use the entire buffer */ 3871.38Schristos if (mimic_gnu) { 3881.38Schristos while (wrapindex != 0) { 3891.38Schristos for (i = 0; i < wrapindex; i++) 3901.38Schristos pbstr(m4wraps[i]); 3911.38Schristos wrapindex =0; 3921.38Schristos macro(); 3931.38Schristos } 3941.38Schristos } else { 3951.38Schristos for (i = 0; i < wrapindex; i++) { 3961.38Schristos pbstr(m4wraps[i]); 3971.38Schristos macro(); 3981.38Schristos } 3991.38Schristos } 4001.8Sglass } 4011.2Sglass 4021.8Sglass if (active != stdout) 4031.8Sglass active = stdout; /* reset output just in case */ 4041.27Stv for (n = 1; n < maxout; n++) /* default wrap-up: undivert */ 4051.8Sglass if (outfile[n] != NULL) 4061.8Sglass getdiv(n); 4071.27Stv /* remove bitbucket if used */ 4081.27Stv if (outfile[0] != NULL) { 4091.8Sglass (void) fclose(outfile[0]); 4101.27Stv } 4111.8Sglass 4121.43Schristos#ifdef REAL_FREEZE 4131.43Schristos if (freeze) 4141.43Schristos freeze_state(freeze); 4151.43Schristos#else 4161.43Schristos if (freezef) 4171.43Schristos fclose(freezef); 4181.43Schristos#endif 4191.43Schristos 4201.8Sglass return 0; 4211.8Sglass} 4221.2Sglass 4231.8Sglass/* 4241.27Stv * Look ahead for `token'. 4251.11Spk * (on input `t == token[0]') 4261.11Spk * Used for comment and quoting delimiters. 4271.11Spk * Returns 1 if `token' present; copied to output. 4281.11Spk * 0 if `token' not found; all characters pushed back 4291.11Spk */ 4301.27Stvstatic int 4311.38Schristosdo_look_ahead(int t, const char *token) 4321.11Spk{ 4331.11Spk int i; 4341.11Spk 4351.27Stv assert((unsigned char)t == (unsigned char)token[0]); 4361.11Spk 4371.11Spk for (i = 1; *++token; i++) { 4381.11Spk t = gpbc(); 4391.27Stv if (t == EOF || (unsigned char)t != (unsigned char)*token) { 4401.38Schristos pushback(t); 4411.11Spk while (--i) 4421.38Schristos pushback(*--token); 4431.11Spk return 0; 4441.11Spk } 4451.11Spk } 4461.11Spk return 1; 4471.11Spk} 4481.11Spk 4491.27Stv#define LOOK_AHEAD(t, token) (t != EOF && \ 4501.27Stv (unsigned char)(t)==(unsigned char)(token)[0] && \ 4511.27Stv do_look_ahead(t,token)) 4521.11Spk 4531.11Spk/* 4541.8Sglass * macro - the work horse.. 4551.8Sglass */ 4561.27Stvstatic void 4571.38Schristosmacro(void) 4581.13Slukem{ 4591.27Stv char token[MAXTOK+1]; 4601.13Slukem int t, l; 4611.13Slukem ndptr p; 4621.13Slukem int nlpar; 4631.1Scgd 4641.8Sglass cycle { 4651.11Spk t = gpbc(); 4661.27Stv 4671.38Schristos if (LOOK_AHEAD(t,lquote)) { /* strip quotes */ 4681.27Stv nlpar = 0; 4691.27Stv record(quotes, nlpar++); 4701.27Stv /* 4711.27Stv * Opening quote: scan forward until matching 4721.27Stv * closing quote has been found. 4731.27Stv */ 4741.8Sglass do { 4751.12Scgd 4761.11Spk l = gpbc(); 4771.12Scgd if (LOOK_AHEAD(l,rquote)) { 4781.27Stv if (--nlpar > 0) 4791.27Stv outputstr(rquote); 4801.12Scgd } else if (LOOK_AHEAD(l,lquote)) { 4811.27Stv record(quotes, nlpar++); 4821.27Stv outputstr(lquote); 4831.27Stv } else if (l == EOF) { 4841.43Schristos if (!quiet) { 4851.43Schristos if (nlpar == 1) 4861.43Schristos warnx("unclosed quote:"); 4871.43Schristos else 4881.43Schristos warnx( 4891.43Schristos "%d unclosed quotes:", 4901.43Schristos nlpar); 4911.43Schristos dump_stack(quotes, nlpar); 4921.43Schristos } 4931.43Schristos exit(EXIT_FAILURE); 4941.27Stv } else { 4951.27Stv if (nlpar > 0) { 4961.27Stv if (sp < 0) 4971.38Schristos reallyputchar(l); 4981.27Stv else 4991.27Stv CHRSAVE(l); 5001.27Stv } 5011.2Sglass } 5021.8Sglass } 5031.8Sglass while (nlpar != 0); 5041.38Schristos } else if (sp < 0 && LOOK_AHEAD(t, scommt)) { 5051.38Schristos reallyoutputstr(scommt); 5061.11Spk 5071.11Spk for(;;) { 5081.11Spk t = gpbc(); 5091.11Spk if (LOOK_AHEAD(t, ecommt)) { 5101.38Schristos reallyoutputstr(ecommt); 5111.11Spk break; 5121.11Spk } 5131.11Spk if (t == EOF) 5141.11Spk break; 5151.38Schristos reallyputchar(t); 5161.1Scgd } 5171.38Schristos } else if (t == '_' || isalpha(t)) { 5181.38Schristos p = inspect(t, token); 5191.38Schristos if (p != NULL) 5201.38Schristos pushback(l = gpbc()); 5211.38Schristos if (p == NULL || (l != LPAREN && 5221.38Schristos (macro_getdef(p)->type & NEEDARGS) != 0)) 5231.38Schristos outputstr(token); 5241.38Schristos else { 5251.38Schristos /* 5261.38Schristos * real thing.. First build a call frame: 5271.38Schristos */ 5281.38Schristos pushf(fp); /* previous call frm */ 5291.38Schristos pushf(macro_getdef(p)->type); /* type of the call */ 5301.38Schristos pushf(is_traced(p)); 5311.38Schristos pushf(0); /* parenthesis level */ 5321.38Schristos fp = sp; /* new frame pointer */ 5331.38Schristos /* 5341.38Schristos * now push the string arguments: 5351.38Schristos */ 5361.38Schristos pushs1(macro_getdef(p)->defn); /* defn string */ 5371.38Schristos pushs1((char *)macro_name(p)); /* macro name */ 5381.38Schristos pushs(ep); /* start next..*/ 5391.38Schristos 5401.38Schristos if (l != LPAREN && PARLEV == 0) { 5411.38Schristos /* no bracks */ 5421.38Schristos chrsave(EOS); 5431.38Schristos 5441.38Schristos if ((size_t)sp == STACKMAX) 5451.38Schristos errx(1, "internal stack overflow"); 5461.38Schristos eval((const char **) mstack+fp+1, 2, 5471.38Schristos CALTYP, TRACESTATUS); 5481.11Spk 5491.38Schristos ep = PREVEP; /* flush strspace */ 5501.38Schristos sp = PREVSP; /* previous sp.. */ 5511.38Schristos fp = PREVFP; /* rewind stack...*/ 5521.38Schristos } 5531.38Schristos } 5541.38Schristos } else if (t == EOF) { 5551.38Schristos if (sp > -1 && ilevel <= 0) { 5561.43Schristos if (!quiet) { 5571.43Schristos warnx("unexpected end of input, " 5581.43Schristos "unclosed parenthesis:"); 5591.43Schristos dump_stack(paren, PARLEV); 5601.43Schristos } 5611.43Schristos exit(EXIT_FAILURE); 5621.38Schristos } 5631.38Schristos if (ilevel <= 0) 5641.38Schristos break; /* all done thanks.. */ 5651.38Schristos release_input(infile+ilevel--); 5661.38Schristos emit_synchline(); 5671.38Schristos bufbase = bbase[ilevel]; 5681.38Schristos continue; 5691.38Schristos } else if (sp < 0) { /* not in a macro at all */ 5701.38Schristos reallyputchar(t); /* output directly.. */ 5711.8Sglass } 5721.1Scgd 5731.8Sglass else switch(t) { 5741.2Sglass 5751.8Sglass case LPAREN: 5761.8Sglass if (PARLEV > 0) 5771.8Sglass chrsave(t); 5781.38Schristos while (isspace(l = gpbc())) /* skip blank, tab, nl.. */ 5791.38Schristos if (PARLEV > 0) 5801.38Schristos chrsave(l); 5811.38Schristos pushback(l); 5821.27Stv record(paren, PARLEV++); 5831.8Sglass break; 5841.1Scgd 5851.8Sglass case RPAREN: 5861.8Sglass if (--PARLEV > 0) 5871.8Sglass chrsave(t); 5881.8Sglass else { /* end of argument list */ 5891.8Sglass chrsave(EOS); 5901.8Sglass 5911.38Schristos if ((size_t)sp == STACKMAX) 5921.13Slukem errx(1, "internal stack overflow"); 5931.8Sglass 5941.27Stv eval((const char **) mstack+fp+1, sp-fp, 5951.38Schristos CALTYP, TRACESTATUS); 5961.8Sglass 5971.8Sglass ep = PREVEP; /* flush strspace */ 5981.8Sglass sp = PREVSP; /* previous sp.. */ 5991.8Sglass fp = PREVFP; /* rewind stack...*/ 6001.8Sglass } 6011.8Sglass break; 6021.1Scgd 6031.8Sglass case COMMA: 6041.8Sglass if (PARLEV == 1) { 6051.8Sglass chrsave(EOS); /* new argument */ 6061.8Sglass while (isspace(l = gpbc())) 6071.8Sglass ; 6081.38Schristos pushback(l); 6091.8Sglass pushs(ep); 6101.8Sglass } else 6111.8Sglass chrsave(t); 6121.8Sglass break; 6131.2Sglass 6141.2Sglass default: 6151.27Stv if (LOOK_AHEAD(t, scommt)) { 6161.38Schristos char *q; 6171.42Schristos for (q = scommt; *q; q++) 6181.38Schristos chrsave(*q); 6191.27Stv for(;;) { 6201.27Stv t = gpbc(); 6211.27Stv if (LOOK_AHEAD(t, ecommt)) { 6221.38Schristos for (q = ecommt; *q; q++) 6231.38Schristos chrsave(*q); 6241.27Stv break; 6251.27Stv } 6261.27Stv if (t == EOF) 6271.27Stv break; 6281.27Stv CHRSAVE(t); 6291.27Stv } 6301.27Stv } else 6311.27Stv CHRSAVE(t); /* stack the char */ 6321.8Sglass break; 6331.8Sglass } 6341.2Sglass } 6351.8Sglass} 6361.2Sglass 6371.27Stv/* 6381.27Stv * output string directly, without pushing it for reparses. 6391.27Stv */ 6401.27Stvvoid 6411.38Schristosoutputstr(const char *s) 6421.27Stv{ 6431.27Stv if (sp < 0) 6441.38Schristos reallyoutputstr(s); 6451.27Stv else 6461.27Stv while (*s) 6471.27Stv CHRSAVE(*s++); 6481.27Stv} 6491.27Stv 6501.38Schristosvoid 6511.38Schristosreallyoutputstr(const char *s) 6521.38Schristos{ 6531.38Schristos if (synch_lines) { 6541.38Schristos while (*s) { 6551.38Schristos fputc(*s, active); 6561.38Schristos if (*s++ == '\n') { 6571.38Schristos infile[ilevel].synch_lineno++; 6581.38Schristos if (infile[ilevel].synch_lineno != 6591.38Schristos infile[ilevel].lineno) 6601.38Schristos do_emit_synchline(); 6611.38Schristos } 6621.38Schristos } 6631.38Schristos } else 6641.38Schristos fputs(s, active); 6651.38Schristos} 6661.38Schristos 6671.38Schristosvoid 6681.38Schristosreallyputchar(int c) 6691.38Schristos{ 6701.38Schristos putc(c, active); 6711.38Schristos if (synch_lines && c == '\n') { 6721.38Schristos infile[ilevel].synch_lineno++; 6731.38Schristos if (infile[ilevel].synch_lineno != infile[ilevel].lineno) 6741.38Schristos do_emit_synchline(); 6751.38Schristos } 6761.38Schristos} 6771.38Schristos 6781.8Sglass/* 6791.8Sglass * build an input token.. 6801.38Schristos * consider only those starting with _ or A-Za-z. 6811.8Sglass */ 6821.27Stvstatic ndptr 6831.38Schristosinspect(int c, char *tp) 6841.8Sglass{ 6851.13Slukem char *name = tp; 6861.13Slukem char *etp = tp+MAXTOK; 6871.13Slukem ndptr p; 6881.27Stv 6891.38Schristos *tp++ = c; 6901.2Sglass 6911.27Stv while ((isalnum(c = gpbc()) || c == '_') && tp < etp) 6921.38Schristos *tp++ = c; 6931.27Stv if (c != EOF) 6941.38Schristos PUSHBACK(c); 6951.8Sglass *tp = EOS; 6961.27Stv /* token is too long, it won't match anything, but it can still 6971.27Stv * be output. */ 6981.27Stv if (tp == ep) { 6991.27Stv outputstr(name); 7001.27Stv while (isalnum(c = gpbc()) || c == '_') { 7011.27Stv if (sp < 0) 7021.38Schristos reallyputchar(c); 7031.27Stv else 7041.27Stv CHRSAVE(c); 7051.27Stv } 7061.27Stv *name = EOS; 7071.38Schristos return NULL; 7081.27Stv } 7091.1Scgd 7101.40Schristos p = ohash_find(¯os, ohash_qlookupi(¯os, name, (void *)&tp)); 7111.38Schristos if (p == NULL) 7121.38Schristos return NULL; 7131.38Schristos if (macro_getdef(p) == NULL) 7141.38Schristos return NULL; 7151.8Sglass return p; 7161.8Sglass} 7171.7Scgd 7181.8Sglass/* 7191.38Schristos * initkwds - initialise m4 keywords as fast as possible. 7201.8Sglass * This very similar to install, but without certain overheads, 7211.38Schristos * such as calling lookup. Malloc is not used for storing the 7221.13Slukem * keyword strings, since we simply use the static pointers 7231.8Sglass * within keywrds block. 7241.8Sglass */ 7251.27Stvstatic void 7261.38Schristosinitkwds(void) 7271.13Slukem{ 7281.38Schristos unsigned int type; 7291.32Stv size_t i; 7301.1Scgd 7311.8Sglass for (i = 0; i < MAXKEYS; i++) { 7321.43Schristos type = keywrds[i].ktyp; 7331.27Stv if ((keywrds[i].ktyp & NOARGS) == 0) 7341.38Schristos type |= NEEDARGS; 7351.38Schristos setup_builtin(keywrds[i].knam, type); 7361.1Scgd } 7371.27Stv} 7381.27Stv 7391.27Stvstatic void 7401.38Schristosrecord(struct position *t, int lev) 7411.27Stv{ 7421.27Stv if (lev < MAXRECORD) { 7431.27Stv t[lev].name = CURRENT_NAME; 7441.27Stv t[lev].line = CURRENT_LINE; 7451.27Stv } 7461.27Stv} 7471.27Stv 7481.27Stvstatic void 7491.38Schristosdump_stack(struct position *t, int lev) 7501.27Stv{ 7511.27Stv int i; 7521.27Stv 7531.27Stv for (i = 0; i < lev; i++) { 7541.27Stv if (i == MAXRECORD) { 7551.27Stv fprintf(stderr, " ...\n"); 7561.27Stv break; 7571.27Stv } 7581.27Stv fprintf(stderr, " %s at line %lu\n", 7591.27Stv t[i].name, t[i].line); 7601.27Stv } 7611.27Stv} 7621.27Stv 7631.27Stv 7641.27Stvstatic void 7651.38Schristosenlarge_stack(void) 7661.27Stv{ 7671.38Schristos STACKMAX += STACKMAX/2; 7681.38Schristos mstack = xrealloc(mstack, sizeof(stae) * STACKMAX, 7691.38Schristos "Evaluation stack overflow (%lu)", 7701.38Schristos (unsigned long)STACKMAX); 7711.38Schristos sstack = xrealloc(sstack, STACKMAX, 7721.38Schristos "Evaluation stack overflow (%lu)", 7731.38Schristos (unsigned long)STACKMAX); 7741.8Sglass} 7751.43Schristos 7761.43Schristosstatic const struct { 7771.43Schristos const char *n; 7781.43Schristos const char *d; 7791.43Schristos} nd [] = { 7801.43Schristos{ "-d, --debug[=flags]", "set debug flags" }, 7811.43Schristos{ "-D, --define=name[=value]", "define macro" }, 7821.43Schristos{ "-e, --error-output=file", "send error output to file" }, 7831.43Schristos{ "-E, --fatal-warnings", "exit on warnings" }, 7841.43Schristos{ "-F, --freeze-state=file", "save state to file" }, 7851.43Schristos{ "-g, --gnu", "enable gnu extensions" }, 7861.43Schristos{ " --help", "print this message and exit" }, 7871.43Schristos{ "-I, --include=file", "include file" }, 7881.43Schristos{ "-i, --interactive", "unbuffer output, ignore tty signals" }, 7891.44Schristos{ "-L, --nesting-limit=num", "macro expansion nesting limit (unimpl)" }, 7901.43Schristos{ "-P, --prefix-builtins", "prefix builtins with m4_" }, 7911.43Schristos{ "-Q, --quiet", "don't print warnings" }, 7921.43Schristos{ "-R, --reload-state=file", "restore state from file" }, 7931.43Schristos{ "-Q, --silent", "don't print warnings" }, 7941.43Schristos{ "-s, --synclines", "output line directives for cpp(1)" }, 7951.43Schristos{ "-t, --trace=macro", "trace the named macro" }, 7961.43Schristos{ "-G, --traditional", "disable gnu extensions" }, 7971.43Schristos{ "-U, --undefine=name", "undefine the named macro" }, 7981.43Schristos{ "-v, --version", "print the version number and exit" }, 7991.43Schristos}; 8001.43Schristos 8011.43Schristosstatic void 8021.43Schristoshelp(void) 8031.43Schristos{ 8041.43Schristos size_t i; 8051.43Schristos fprintf(stdout, "%s version %d\n\n", getprogname(), VERSION); 8061.43Schristos usage(stdout); 8071.43Schristos 8081.43Schristos fprintf(stdout, "\nThe long options are:\n"); 8091.43Schristos for (i = 0; i < __arraycount(nd); i++) 8101.43Schristos fprintf(stdout, "\t%-25.25s\t%s\n", nd[i].n, nd[i].d); 8111.43Schristos} 812