summaryrefslogtreecommitdiff
path: root/usr.bin/m4/main.c
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>1995-10-18 08:53:40 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>1995-10-18 08:53:40 +0000
commitd6583bb2a13f329cf0332ef2570eb8bb8fc0e39c (patch)
treeece253b876159b39c620e62b6c9b1174642e070e /usr.bin/m4/main.c
initial import of NetBSD tree
Diffstat (limited to 'usr.bin/m4/main.c')
-rw-r--r--usr.bin/m4/main.c431
1 files changed, 431 insertions, 0 deletions
diff --git a/usr.bin/m4/main.c b/usr.bin/m4/main.c
new file mode 100644
index 00000000000..9c8bd87d735
--- /dev/null
+++ b/usr.bin/m4/main.c
@@ -0,0 +1,431 @@
+/* $NetBSD: main.c,v 1.10 1995/09/29 00:27:51 cgd Exp $ */
+
+/*-
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Ozan Yigit at York University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1989, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/6/93";
+#else
+static char rcsid[] = "$NetBSD: main.c,v 1.10 1995/09/29 00:27:51 cgd Exp $";
+#endif
+#endif /* not lint */
+
+/*
+ * main.c
+ * Facility: m4 macro processor
+ * by: oz
+ */
+
+#include <sys/types.h>
+#include <signal.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include "mdef.h"
+#include "stdd.h"
+#include "extern.h"
+#include "pathnames.h"
+
+ndptr hashtab[HASHSIZE]; /* hash table for macros etc. */
+char buf[BUFSIZE]; /* push-back buffer */
+char *bufbase = buf; /* the base for current ilevel */
+char *bbase[MAXINP]; /* the base for each ilevel */
+char *bp = buf; /* first available character */
+char *endpbb = buf+BUFSIZE; /* end of push-back buffer */
+stae mstack[STACKMAX+1]; /* stack of m4 machine */
+char strspace[STRSPMAX+1]; /* string space for evaluation */
+char *ep = strspace; /* first free char in strspace */
+char *endest= strspace+STRSPMAX;/* end of string space */
+int sp; /* current m4 stack pointer */
+int fp; /* m4 call frame pointer */
+FILE *infile[MAXINP]; /* input file stack (0=stdin) */
+FILE *outfile[MAXOUT]; /* diversion array(0=bitbucket)*/
+FILE *active; /* active output file pointer */
+char *m4temp; /* filename for diversions */
+int ilevel = 0; /* input file stack pointer */
+int oindex = 0; /* diversion index.. */
+char *null = ""; /* as it says.. just a null.. */
+char *m4wraps = ""; /* m4wrap string default.. */
+char *progname; /* name of this program */
+char lquote = LQUOTE; /* left quote character (`) */
+char rquote = RQUOTE; /* right quote character (') */
+char scommt = SCOMMT; /* start character for comment */
+char ecommt = ECOMMT; /* end character for comment */
+
+struct keyblk keywrds[] = { /* m4 keywords to be installed */
+ "include", INCLTYPE,
+ "sinclude", SINCTYPE,
+ "define", DEFITYPE,
+ "defn", DEFNTYPE,
+ "divert", DIVRTYPE,
+ "expr", EXPRTYPE,
+ "eval", EXPRTYPE,
+ "substr", SUBSTYPE,
+ "ifelse", IFELTYPE,
+ "ifdef", IFDFTYPE,
+ "len", LENGTYPE,
+ "incr", INCRTYPE,
+ "decr", DECRTYPE,
+ "dnl", DNLNTYPE,
+ "changequote", CHNQTYPE,
+ "changecom", CHNCTYPE,
+ "index", INDXTYPE,
+#ifdef EXTENDED
+ "paste", PASTTYPE,
+ "spaste", SPASTYPE,
+#endif
+ "popdef", POPDTYPE,
+ "pushdef", PUSDTYPE,
+ "dumpdef", DUMPTYPE,
+ "shift", SHIFTYPE,
+ "translit", TRNLTYPE,
+ "undefine", UNDFTYPE,
+ "undivert", UNDVTYPE,
+ "divnum", DIVNTYPE,
+ "maketemp", MKTMTYPE,
+ "errprint", ERRPTYPE,
+ "m4wrap", M4WRTYPE,
+ "m4exit", EXITTYPE,
+ "syscmd", SYSCTYPE,
+ "sysval", SYSVTYPE,
+
+#if defined(unix) || defined(__NetBSD__)
+ "unix", MACRTYPE,
+#else
+#ifdef vms
+ "vms", MACRTYPE,
+#endif
+#endif
+};
+
+#define MAXKEYS (sizeof(keywrds)/sizeof(struct keyblk))
+
+extern int optind;
+extern char *optarg;
+
+void macro();
+void initkwds();
+extern int getopt();
+
+int
+main(argc,argv)
+ int argc;
+ char *argv[];
+{
+ register int c;
+ register int n;
+ char *p;
+ register FILE *ifp;
+
+ progname = basename(argv[0]);
+
+ if (signal(SIGINT, SIG_IGN) != SIG_IGN)
+ signal(SIGINT, onintr);
+
+ initkwds();
+
+ while ((c = getopt(argc, argv, "tD:U:o:")) != EOF)
+ switch(c) {
+
+ case 'D': /* define something..*/
+ for (p = optarg; *p; p++)
+ if (*p == '=')
+ break;
+ if (*p)
+ *p++ = EOS;
+ dodefine(optarg, p);
+ break;
+ case 'U': /* undefine... */
+ remhash(optarg, TOP);
+ break;
+ case 'o': /* specific output */
+ case '?':
+ usage();
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ active = stdout; /* default active output */
+ /* filename for diversions */
+ m4temp = mktemp(xstrdup(_PATH_DIVNAME));
+
+ bbase[0] = bufbase;
+ if (!argc) {
+ sp = -1; /* stack pointer initialized */
+ fp = 0; /* frame pointer initialized */
+ infile[0] = stdin; /* default input (naturally) */
+ macro();
+ } else
+ for (; argc--; ++argv) {
+ p = *argv;
+ if (p[0] == '-' && p[1] == '\0')
+ ifp = stdin;
+ else if ((ifp = fopen(p, "r")) == NULL)
+ oops("%s: %s", p, strerror(errno));
+ sp = -1;
+ fp = 0;
+ infile[0] = ifp;
+ macro();
+ if (ifp != stdin)
+ (void)fclose(ifp);
+ }
+
+ if (*m4wraps) { /* anything for rundown ?? */
+ ilevel = 0; /* in case m4wrap includes.. */
+ bufbase = bp = buf; /* use the entire buffer */
+ putback(EOF); /* eof is a must !! */
+ pbstr(m4wraps); /* user-defined wrapup act */
+ macro(); /* last will and testament */
+ }
+
+ if (active != stdout)
+ active = stdout; /* reset output just in case */
+ for (n = 1; n < MAXOUT; n++) /* default wrap-up: undivert */
+ if (outfile[n] != NULL)
+ getdiv(n);
+ /* remove bitbucket if used */
+ if (outfile[0] != NULL) {
+ (void) fclose(outfile[0]);
+ m4temp[UNIQUE] = '0';
+#ifdef vms
+ (void) remove(m4temp);
+#else
+ (void) unlink(m4temp);
+#endif
+ }
+
+ return 0;
+}
+
+ndptr inspect();
+
+/*
+ * macro - the work horse..
+ */
+void
+macro() {
+ char token[MAXTOK];
+ register char *s;
+ register int t, l;
+ register ndptr p;
+ register int nlpar;
+
+ cycle {
+ if ((t = gpbc()) == '_' || isalpha(t)) {
+ putback(t);
+ if ((p = inspect(s = token)) == nil) {
+ if (sp < 0)
+ while (*s)
+ putc(*s++, active);
+ else
+ while (*s)
+ chrsave(*s++);
+ }
+ else {
+ /*
+ * real thing.. First build a call frame:
+ */
+ pushf(fp); /* previous call frm */
+ pushf(p->type); /* type of the call */
+ pushf(0); /* parenthesis level */
+ fp = sp; /* new frame pointer */
+ /*
+ * now push the string arguments:
+ */
+ pushs(p->defn); /* defn string */
+ pushs(p->name); /* macro name */
+ pushs(ep); /* start next..*/
+
+ putback(l = gpbc());
+ if (l != LPAREN) { /* add bracks */
+ putback(RPAREN);
+ putback(LPAREN);
+ }
+ }
+ }
+ else if (t == EOF) {
+ if (sp > -1)
+ oops("unexpected end of input", "");
+ if (ilevel <= 0)
+ break; /* all done thanks.. */
+ --ilevel;
+ (void) fclose(infile[ilevel+1]);
+ bufbase = bbase[ilevel];
+ continue;
+ }
+ /*
+ * non-alpha single-char token seen..
+ * [the order of else if .. stmts is important.]
+ */
+ else if (t == lquote) { /* strip quotes */
+ nlpar = 1;
+ do {
+ if ((l = gpbc()) == rquote)
+ nlpar--;
+ else if (l == lquote)
+ nlpar++;
+ else if (l == EOF)
+ oops("missing right quote", "");
+ if (nlpar > 0) {
+ if (sp < 0)
+ putc(l, active);
+ else
+ chrsave(l);
+ }
+ }
+ while (nlpar != 0);
+ }
+
+ else if (sp < 0) { /* not in a macro at all */
+ if (t == scommt) { /* comment handling here */
+ putc(t, active);
+ while ((t = gpbc()) != ecommt)
+ putc(t, active);
+ }
+ putc(t, active); /* output directly.. */
+ }
+
+ else switch(t) {
+
+ case LPAREN:
+ if (PARLEV > 0)
+ chrsave(t);
+ while (isspace(l = gpbc()))
+ ; /* skip blank, tab, nl.. */
+ putback(l);
+ PARLEV++;
+ break;
+
+ case RPAREN:
+ if (--PARLEV > 0)
+ chrsave(t);
+ else { /* end of argument list */
+ chrsave(EOS);
+
+ if (sp == STACKMAX)
+ oops("internal stack overflow", "");
+
+ if (CALTYP == MACRTYPE)
+ expand((char **) mstack+fp+1, sp-fp);
+ else
+ eval((char **) mstack+fp+1, sp-fp, CALTYP);
+
+ ep = PREVEP; /* flush strspace */
+ sp = PREVSP; /* previous sp.. */
+ fp = PREVFP; /* rewind stack...*/
+ }
+ break;
+
+ case COMMA:
+ if (PARLEV == 1) {
+ chrsave(EOS); /* new argument */
+ while (isspace(l = gpbc()))
+ ;
+ putback(l);
+ pushs(ep);
+ } else
+ chrsave(t);
+ break;
+
+ default:
+ chrsave(t); /* stack the char */
+ break;
+ }
+ }
+}
+
+/*
+ * build an input token..
+ * consider only those starting with _ or A-Za-z. This is a
+ * combo with lookup to speed things up.
+ */
+ndptr
+inspect(tp)
+register char *tp;
+{
+ register char c;
+ register char *name = tp;
+ register char *etp = tp+MAXTOK;
+ register ndptr p;
+ register unsigned long h = 0;
+
+ while ((isalnum(c = gpbc()) || c == '_') && tp < etp)
+ h = (h << 5) + h + (*tp++ = c);
+ putback(c);
+ if (tp == etp)
+ oops("token too long", "");
+
+ *tp = EOS;
+
+ for (p = hashtab[h%HASHSIZE]; p != nil; p = p->nxtptr)
+ if (STREQ(name, p->name))
+ break;
+ return p;
+}
+
+/*
+ * initkwds - initialise m4 keywords as fast as possible.
+ * This very similar to install, but without certain overheads,
+ * such as calling lookup. Malloc is not used for storing the
+ * keyword strings, since we simply use the static pointers
+ * within keywrds block.
+ */
+void
+initkwds() {
+ register int i;
+ register int h;
+ register ndptr p;
+
+ for (i = 0; i < MAXKEYS; i++) {
+ h = hash(keywrds[i].knam);
+ p = (ndptr) xalloc(sizeof(struct ndblock));
+ p->nxtptr = hashtab[h];
+ hashtab[h] = p;
+ p->name = keywrds[i].knam;
+ p->defn = null;
+ p->type = keywrds[i].ktyp | STATIC;
+ }
+}