summary refs log tree commit diff
path: root/bin/dash/src/mkinit.c
diff options
context:
space:
mode:
Diffstat (limited to 'bin/dash/src/mkinit.c')
-rw-r--r--bin/dash/src/mkinit.c493
1 files changed, 493 insertions, 0 deletions
diff --git a/bin/dash/src/mkinit.c b/bin/dash/src/mkinit.c
new file mode 100644
index 00000000..9025862e
--- /dev/null
+++ b/bin/dash/src/mkinit.c
@@ -0,0 +1,493 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1997-2005
+ *	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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. 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.
+ */
+
+/*
+ * This program scans all the source files for code to handle various
+ * special events and combines this code into one file.  This (allegedly)
+ * improves the structure of the program since there is no need for
+ * anyone outside of a module to know that that module performs special
+ * operations on particular events.
+ *
+ * Usage:  mkinit sourcefile...
+ */
+
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+
+/*
+ * OUTFILE is the name of the output file.  Output is initially written
+ * to the file OUTTEMP, which is then moved to OUTFILE.
+ */
+
+#define OUTFILE "init.c"
+#define OUTTEMP "init.c.new"
+
+
+/*
+ * A text structure is basicly just a string that grows as more characters
+ * are added onto the end of it.  It is implemented as a linked list of
+ * blocks of characters.  The routines addstr and addchar append a string
+ * or a single character, respectively, to a text structure.  Writetext
+ * writes the contents of a text structure to a file.
+ */
+
+#define BLOCKSIZE 512
+
+struct text {
+	char *nextc;
+	int nleft;
+	struct block *start;
+	struct block *last;
+};
+
+struct block {
+	struct block *next;
+	char text[BLOCKSIZE];
+};
+
+
+/*
+ * There is one event structure for each event that mkinit handles.
+ */
+
+struct event {
+	char *name;		/* name of event (e.g. INIT) */
+	char *routine;		/* name of routine called on event */
+	char *comment;		/* comment describing routine */
+	struct text code;	/* code for handling event */
+};
+
+
+char writer[] = "\
+/*\n\
+ * This file was generated by the mkinit program.\n\
+ */\n\
+\n";
+
+char init[] = "\
+/*\n\
+ * Initialization code.\n\
+ */\n";
+
+char exitreset[] = "\
+/*\n\
+ * This routine is called when an error or an interrupt occurs in an\n\
+ * interactive shell and control is returned to the main command loop\n\
+ * but prior to exitshell. \n\
+ */\n";
+
+char forkreset[] = "\
+/*\n\
+ * This routine is called when we enter a subshell.\n\
+ */\n";
+
+char reset[] = "\
+/*\n\
+ * This routine is called when an error or an interrupt occurs in an\n\
+ * interactive shell and control is returned to the main command loop.\n\
+ */\n";
+
+
+struct event event[] = {
+	{"INIT", "init", init},
+	{"EXITRESET", "exitreset", exitreset},
+	{"FORKRESET", "forkreset", forkreset},
+	{"RESET", "reset", reset},
+	{NULL, NULL}
+};
+
+
+char *curfile;				/* current file */
+int linno;				/* current line */
+char *header_files[200];		/* list of header files */
+struct text defines;			/* #define statements */
+struct text decls;			/* declarations */
+int amiddecls;				/* for formatting */
+
+
+void readfile(char *);
+int match(char *, char *);
+int gooddefine(char *);
+void doevent(struct event *, FILE *, char *);
+void doinclude(char *);
+void dodecl(char *, FILE *);
+void output(void);
+void addstr(char *, struct text *);
+void addchar(int, struct text *);
+void writetext(struct text *, FILE *);
+FILE *ckfopen(char *, char *);
+void *ckmalloc(int);
+char *savestr(char *);
+static void error(char *);
+int main(int, char **);
+
+#define equal(s1, s2)	(strcmp(s1, s2) == 0)
+
+int
+main(int argc, char **argv)
+{
+	char **ap;
+
+	header_files[0] = "\"shell.h\"";
+	header_files[1] = "\"mystring.h\"";
+	header_files[2] = "\"init.h\"";
+	for (ap = argv + 1 ; *ap ; ap++)
+		readfile(*ap);
+	output();
+	rename(OUTTEMP, OUTFILE);
+	exit(0);
+	/* NOTREACHED */
+}
+
+
+/*
+ * Parse an input file.
+ */
+
+void
+readfile(char *fname)
+{
+	FILE *fp;
+	char line[1024];
+	struct event *ep;
+
+	fp = ckfopen(fname, "r");
+	curfile = fname;
+	linno = 0;
+	amiddecls = 0;
+	while (fgets(line, sizeof line, fp) != NULL) {
+		linno++;
+		for (ep = event ; ep->name ; ep++) {
+			if (line[0] == ep->name[0] && match(ep->name, line)) {
+				doevent(ep, fp, fname);
+				break;
+			}
+		}
+		if (line[0] == 'I' && match("INCLUDE", line))
+			doinclude(line);
+		if (line[0] == 'M' && match("MKINIT", line))
+			dodecl(line, fp);
+		if (line[0] == '#' && gooddefine(line)) {
+		        char *cp;
+			char line2[1024];
+			static const char undef[] = "#undef ";
+
+			strcpy(line2, line);
+			memcpy(line2, undef, sizeof(undef) - 1);
+			cp = line2 + sizeof(undef) - 1;
+			while(*cp && (*cp == ' ' || *cp == '\t'))
+			        cp++;
+			while(*cp && *cp != ' ' && *cp != '\t' && *cp != '\n')
+			        cp++;
+			*cp++ = '\n'; *cp = '\0';
+			addstr(line2, &defines);
+			addstr(line, &defines);
+		}
+	}
+	fclose(fp);
+}
+
+
+int
+match(char *name, char *line)
+{
+	char *p, *q;
+
+	p = name, q = line;
+	while (*p) {
+		if (*p++ != *q++)
+			return 0;
+	}
+	if (*q != '{' && *q != ' ' && *q != '\t' && *q != '\n')
+		return 0;
+	return 1;
+}
+
+
+int
+gooddefine(char *line)
+{
+	char *p;
+
+	if (! match("#define", line))
+		return 0;			/* not a define */
+	p = line + 7;
+	while (*p == ' ' || *p == '\t')
+		p++;
+	while (*p != ' ' && *p != '\t') {
+		if (*p == '(')
+			return 0;		/* macro definition */
+		p++;
+	}
+	while (*p != '\n' && *p != '\0')
+		p++;
+	if (p[-1] == '\\')
+		return 0;			/* multi-line definition */
+	return 1;
+}
+
+
+void
+doevent(struct event *ep, FILE *fp, char *fname)
+{
+	char line[1024];
+	int indent;
+	char *p;
+
+	sprintf(line, "\n      /* from %s: */\n", fname);
+	addstr(line, &ep->code);
+	addstr("      {\n", &ep->code);
+	for (;;) {
+		linno++;
+		if (fgets(line, sizeof line, fp) == NULL)
+			error("Unexpected EOF");
+		if (equal(line, "}\n"))
+			break;
+		indent = 6;
+		for (p = line ; *p == '\t' ; p++)
+			indent += 8;
+		for ( ; *p == ' ' ; p++)
+			indent++;
+		if (*p == '\n' || *p == '#')
+			indent = 0;
+		while (indent >= 8) {
+			addchar('\t', &ep->code);
+			indent -= 8;
+		}
+		while (indent > 0) {
+			addchar(' ', &ep->code);
+			indent--;
+		}
+		addstr(p, &ep->code);
+	}
+	addstr("      }\n", &ep->code);
+}
+
+
+void
+doinclude(char *line)
+{
+	char *p;
+	char *name;
+	char **pp;
+
+	for (p = line ; *p != '"' && *p != '<' && *p != '\0' ; p++);
+	if (*p == '\0')
+		error("Expecting '\"' or '<'");
+	name = p;
+	while (*p != ' ' && *p != '\t' && *p != '\n')
+		p++;
+	if (p[-1] != '"' && p[-1] != '>')
+		error("Missing terminator");
+	*p = '\0';
+
+	/* name now contains the name of the include file */
+	for (pp = header_files ; *pp && ! equal(*pp, name) ; pp++);
+	if (*pp == NULL)
+		*pp = savestr(name);
+}
+
+
+void
+dodecl(char *line1, FILE *fp)
+{
+	char line[1024];
+	char *p, *q;
+
+	if (strcmp(line1, "MKINIT\n") == 0) { /* start of struct/union decl */
+		addchar('\n', &decls);
+		do {
+			linno++;
+			if (fgets(line, sizeof line, fp) == NULL)
+				error("Unterminated structure declaration");
+			addstr(line, &decls);
+		} while (line[0] != '}');
+		amiddecls = 0;
+	} else {
+		if (! amiddecls)
+			addchar('\n', &decls);
+		q = NULL;
+		for (p = line1 + 6 ; *p && strchr("=/\n", *p) == NULL; p++)
+			continue;
+		if (*p == '=') {		/* eliminate initialization */
+			for (q = p ; *q && *q != ';' ; q++);
+			if (*q == '\0')
+				q = NULL;
+			else {
+				while (p[-1] == ' ')
+					p--;
+				*p = '\0';
+			}
+		}
+		addstr("extern", &decls);
+		addstr(line1 + 6, &decls);
+		if (q != NULL)
+			addstr(q, &decls);
+		amiddecls = 1;
+	}
+}
+
+
+
+/*
+ * Write the output to the file OUTTEMP.
+ */
+
+void
+output(void)
+{
+	FILE *fp;
+	char **pp;
+	struct event *ep;
+
+	fp = ckfopen(OUTTEMP, "w");
+	fputs(writer, fp);
+	for (pp = header_files ; *pp ; pp++)
+		fprintf(fp, "#include %s\n", *pp);
+	fputs("\n\n\n", fp);
+	writetext(&defines, fp);
+	fputs("\n\n", fp);
+	writetext(&decls, fp);
+	for (ep = event ; ep->name ; ep++) {
+		fputs("\n\n\n", fp);
+		fputs(ep->comment, fp);
+		fprintf(fp, "\nvoid\n%s() {\n", ep->routine);
+		writetext(&ep->code, fp);
+		fprintf(fp, "}\n");
+	}
+	fclose(fp);
+}
+
+
+/*
+ * A text structure is simply a block of text that is kept in memory.
+ * Addstr appends a string to the text struct, and addchar appends a single
+ * character.
+ */
+
+void
+addstr(char *s, struct text *text)
+{
+	while (*s) {
+		if (--text->nleft < 0)
+			addchar(*s++, text);
+		else
+			*text->nextc++ = *s++;
+	}
+}
+
+
+void
+addchar(int c, struct text *text)
+{
+	struct block *bp;
+
+	if (--text->nleft < 0) {
+		bp = ckmalloc(sizeof *bp);
+		if (text->start == NULL)
+			text->start = bp;
+		else
+			text->last->next = bp;
+		text->last = bp;
+		text->nextc = bp->text;
+		text->nleft = BLOCKSIZE - 1;
+	}
+	*text->nextc++ = c;
+}
+
+/*
+ * Write the contents of a text structure to a file.
+ */
+void
+writetext(struct text *text, FILE *fp)
+{
+	struct block *bp;
+
+	if (text->start != NULL) {
+		for (bp = text->start ; bp != text->last ; bp = bp->next) {
+			if ((fwrite(bp->text, sizeof (char), BLOCKSIZE, fp)) != BLOCKSIZE)
+				error("Can't write data\n");
+		}
+		if ((fwrite(bp->text, sizeof (char), BLOCKSIZE - text->nleft, fp)) != (BLOCKSIZE - text->nleft))
+			error("Can't write data\n");
+	}
+}
+
+FILE *
+ckfopen(char *file, char *mode)
+{
+	FILE *fp;
+
+	if ((fp = fopen(file, mode)) == NULL) {
+		fprintf(stderr, "Can't open %s\n", file);
+		exit(2);
+	}
+	return fp;
+}
+
+void *
+ckmalloc(int nbytes)
+{
+	char *p;
+
+	if ((p = malloc(nbytes)) == NULL)
+		error("Out of space");
+	return p;
+}
+
+char *
+savestr(char *s)
+{
+	char *p;
+
+	p = ckmalloc(strlen(s) + 1);
+	strcpy(p, s);
+	return p;
+}
+
+static void
+error(char *msg)
+{
+	if (curfile != NULL)
+		fprintf(stderr, "%s:%d: ", curfile, linno);
+	fprintf(stderr, "%s\n", msg);
+	exit(2);
+	/* NOTREACHED */
+}