11556Srgrimes/*-
21556Srgrimes * Copyright (c) 1991, 1993
31556Srgrimes *	The Regents of the University of California.  All rights reserved.
41556Srgrimes *
51556Srgrimes * This code is derived from software contributed to Berkeley by
61556Srgrimes * Kenneth Almquist.
71556Srgrimes *
81556Srgrimes * Redistribution and use in source and binary forms, with or without
91556Srgrimes * modification, are permitted provided that the following conditions
101556Srgrimes * are met:
111556Srgrimes * 1. Redistributions of source code must retain the above copyright
121556Srgrimes *    notice, this list of conditions and the following disclaimer.
131556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141556Srgrimes *    notice, this list of conditions and the following disclaimer in the
151556Srgrimes *    documentation and/or other materials provided with the distribution.
161556Srgrimes * 4. Neither the name of the University nor the names of its contributors
171556Srgrimes *    may be used to endorse or promote products derived from this software
181556Srgrimes *    without specific prior written permission.
191556Srgrimes *
201556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
211556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
221556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
231556Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
241556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
251556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
261556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
271556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
281556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
291556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
301556Srgrimes * SUCH DAMAGE.
311556Srgrimes */
321556Srgrimes
331556Srgrimes#ifndef lint
3420425Sstevestatic char const copyright[] =
351556Srgrimes"@(#) Copyright (c) 1991, 1993\n\
361556Srgrimes	The Regents of the University of California.  All rights reserved.\n";
371556Srgrimes#endif /* not lint */
381556Srgrimes
391556Srgrimes#ifndef lint
4036150Scharnier#if 0
4136150Scharnierstatic char sccsid[] = "@(#)mkinit.c	8.2 (Berkeley) 5/4/95";
4236150Scharnier#endif
431556Srgrimes#endif /* not lint */
4499110Sobrien#include <sys/cdefs.h>
4599110Sobrien__FBSDID("$FreeBSD$");
461556Srgrimes
471556Srgrimes/*
481556Srgrimes * This program scans all the source files for code to handle various
491556Srgrimes * special events and combines this code into one file.  This (allegedly)
501556Srgrimes * improves the structure of the program since there is no need for
511556Srgrimes * anyone outside of a module to know that that module performs special
5217987Speter * operations on particular events.
531556Srgrimes *
5417987Speter * Usage:  mkinit sourcefile...
551556Srgrimes */
561556Srgrimes
571556Srgrimes
581556Srgrimes#include <sys/types.h>
591556Srgrimes#include <stdio.h>
6017987Speter#include <stdlib.h>
6117987Speter#include <string.h>
621556Srgrimes#include <fcntl.h>
631556Srgrimes#include <unistd.h>
6453891Scracauer#include <errno.h>
651556Srgrimes
661556Srgrimes
671556Srgrimes/*
681556Srgrimes * OUTFILE is the name of the output file.  Output is initially written
6920425Ssteve * to the file OUTTEMP, which is then moved to OUTFILE.
701556Srgrimes */
711556Srgrimes
721556Srgrimes#define OUTFILE "init.c"
731556Srgrimes#define OUTTEMP "init.c.new"
741556Srgrimes
751556Srgrimes
761556Srgrimes/*
77222178Suqs * A text structure is basically just a string that grows as more characters
781556Srgrimes * are added onto the end of it.  It is implemented as a linked list of
791556Srgrimes * blocks of characters.  The routines addstr and addchar append a string
801556Srgrimes * or a single character, respectively, to a text structure.  Writetext
811556Srgrimes * writes the contents of a text structure to a file.
821556Srgrimes */
831556Srgrimes
841556Srgrimes#define BLOCKSIZE 512
851556Srgrimes
861556Srgrimesstruct text {
871556Srgrimes	char *nextc;
881556Srgrimes	int nleft;
891556Srgrimes	struct block *start;
901556Srgrimes	struct block *last;
918855Srgrimes};
921556Srgrimes
931556Srgrimesstruct block {
941556Srgrimes	struct block *next;
951556Srgrimes	char text[BLOCKSIZE];
961556Srgrimes};
971556Srgrimes
981556Srgrimes
991556Srgrimes/*
1001556Srgrimes * There is one event structure for each event that mkinit handles.
1011556Srgrimes */
1021556Srgrimes
1031556Srgrimesstruct event {
104201053Sjilles	const char *name;	/* name of event (e.g. INIT) */
105201053Sjilles	const char *routine;	/* name of routine called on event */
106201053Sjilles	const char *comment;	/* comment describing routine */
10720425Ssteve	struct text code;	/* code for handling event */
1081556Srgrimes};
1091556Srgrimes
1101556Srgrimes
1111556Srgrimeschar writer[] = "\
1121556Srgrimes/*\n\
1131556Srgrimes * This file was generated by the mkinit program.\n\
1141556Srgrimes */\n\
1151556Srgrimes\n";
1161556Srgrimes
1171556Srgrimeschar init[] = "\
1181556Srgrimes/*\n\
1191556Srgrimes * Initialization code.\n\
1201556Srgrimes */\n";
1211556Srgrimes
1221556Srgrimeschar reset[] = "\
1231556Srgrimes/*\n\
1241556Srgrimes * This routine is called when an error or an interrupt occurs in an\n\
1251556Srgrimes * interactive shell and control is returned to the main command loop.\n\
1261556Srgrimes */\n";
1271556Srgrimes
1281556Srgrimes
1291556Srgrimesstruct event event[] = {
130149019Sstefanf	{ "INIT", "init", init, { NULL, 0, NULL, NULL } },
131149019Sstefanf	{ "RESET", "reset", reset, { NULL, 0, NULL, NULL } },
132149019Sstefanf	{ NULL, NULL, NULL, { NULL, 0, NULL, NULL } }
1331556Srgrimes};
1341556Srgrimes
1351556Srgrimes
136201053Sjillesconst char *curfile;			/* current file */
1371556Srgrimesint linno;				/* current line */
1381556Srgrimeschar *header_files[200];		/* list of header files */
1391556Srgrimesstruct text defines;			/* #define statements */
1401556Srgrimesstruct text decls;			/* declarations */
1411556Srgrimesint amiddecls;				/* for formatting */
1421556Srgrimes
1431556Srgrimes
144201053Sjillesvoid readfile(const char *);
145201053Sjillesint match(const char *, const char *);
146201053Sjillesint gooddefine(const char *);
147201053Sjillesvoid doevent(struct event *, FILE *, const char *);
14890111Simpvoid doinclude(char *);
14990111Simpvoid dodecl(char *, FILE *);
15090111Simpvoid output(void);
151201053Sjillesvoid addstr(const char *, struct text *);
15290111Simpvoid addchar(int, struct text *);
15390111Simpvoid writetext(struct text *, FILE *);
154201053SjillesFILE *ckfopen(const char *, const char *);
155193221Srsevoid *ckmalloc(size_t);
156201053Sjilleschar *savestr(const char *);
157201053Sjillesvoid error(const char *);
1581556Srgrimes
1591556Srgrimes#define equal(s1, s2)	(strcmp(s1, s2) == 0)
1601556Srgrimes
16117987Speterint
16290111Simpmain(int argc __unused, char *argv[])
16317987Speter{
1641556Srgrimes	char **ap;
1651556Srgrimes
166201053Sjilles	header_files[0] = savestr("\"shell.h\"");
167201053Sjilles	header_files[1] = savestr("\"mystring.h\"");
168201053Sjilles	header_files[2] = savestr("\"init.h\"");
16917987Speter	for (ap = argv + 1 ; *ap ; ap++)
1701556Srgrimes		readfile(*ap);
1711556Srgrimes	output();
17220425Ssteve	rename(OUTTEMP, OUTFILE);
17317987Speter	exit(0);
1741556Srgrimes}
1751556Srgrimes
1761556Srgrimes
1771556Srgrimes/*
1781556Srgrimes * Parse an input file.
1791556Srgrimes */
1801556Srgrimes
1811556Srgrimesvoid
182201053Sjillesreadfile(const char *fname)
18390111Simp{
1841556Srgrimes	FILE *fp;
18520425Ssteve	char line[1024];
1861556Srgrimes	struct event *ep;
1871556Srgrimes
1881556Srgrimes	fp = ckfopen(fname, "r");
1891556Srgrimes	curfile = fname;
1901556Srgrimes	linno = 0;
1911556Srgrimes	amiddecls = 0;
1921556Srgrimes	while (fgets(line, sizeof line, fp) != NULL) {
1931556Srgrimes		linno++;
1941556Srgrimes		for (ep = event ; ep->name ; ep++) {
1951556Srgrimes			if (line[0] == ep->name[0] && match(ep->name, line)) {
1961556Srgrimes				doevent(ep, fp, fname);
1971556Srgrimes				break;
1981556Srgrimes			}
1991556Srgrimes		}
2001556Srgrimes		if (line[0] == 'I' && match("INCLUDE", line))
2011556Srgrimes			doinclude(line);
2021556Srgrimes		if (line[0] == 'M' && match("MKINIT", line))
2031556Srgrimes			dodecl(line, fp);
20411113Sjoerg		if (line[0] == '#' && gooddefine(line)) {
20511113Sjoerg			char *cp;
20620425Ssteve			char line2[1024];
20720425Ssteve			static const char undef[] = "#undef ";
20811113Sjoerg
20911113Sjoerg			strcpy(line2, line);
21020425Ssteve			memcpy(line2, undef, sizeof(undef) - 1);
21120425Ssteve			cp = line2 + sizeof(undef) - 1;
21211113Sjoerg			while(*cp && (*cp == ' ' || *cp == '\t'))
21320425Ssteve			        cp++;
21411113Sjoerg			while(*cp && *cp != ' ' && *cp != '\t' && *cp != '\n')
21520425Ssteve			        cp++;
21611113Sjoerg			*cp++ = '\n'; *cp = '\0';
21711113Sjoerg			addstr(line2, &defines);
2181556Srgrimes			addstr(line, &defines);
21911113Sjoerg		}
2201556Srgrimes	}
2211556Srgrimes	fclose(fp);
2221556Srgrimes}
2231556Srgrimes
2241556Srgrimes
2251556Srgrimesint
226201053Sjillesmatch(const char *name, const char *line)
22717987Speter{
228201053Sjilles	const char *p, *q;
2291556Srgrimes
2301556Srgrimes	p = name, q = line;
2311556Srgrimes	while (*p) {
2321556Srgrimes		if (*p++ != *q++)
2331556Srgrimes			return 0;
2341556Srgrimes	}
2351556Srgrimes	if (*q != '{' && *q != ' ' && *q != '\t' && *q != '\n')
2361556Srgrimes		return 0;
2371556Srgrimes	return 1;
2381556Srgrimes}
2391556Srgrimes
2401556Srgrimes
2411556Srgrimesint
242201053Sjillesgooddefine(const char *line)
24317987Speter{
244201053Sjilles	const char *p;
2451556Srgrimes
2461556Srgrimes	if (! match("#define", line))
2471556Srgrimes		return 0;			/* not a define */
2481556Srgrimes	p = line + 7;
2491556Srgrimes	while (*p == ' ' || *p == '\t')
2501556Srgrimes		p++;
2511556Srgrimes	while (*p != ' ' && *p != '\t') {
2521556Srgrimes		if (*p == '(')
2531556Srgrimes			return 0;		/* macro definition */
2541556Srgrimes		p++;
2551556Srgrimes	}
2561556Srgrimes	while (*p != '\n' && *p != '\0')
2571556Srgrimes		p++;
2581556Srgrimes	if (p[-1] == '\\')
2591556Srgrimes		return 0;			/* multi-line definition */
2601556Srgrimes	return 1;
2611556Srgrimes}
2621556Srgrimes
2631556Srgrimes
2641556Srgrimesvoid
265201053Sjillesdoevent(struct event *ep, FILE *fp, const char *fname)
26690111Simp{
2671556Srgrimes	char line[1024];
2681556Srgrimes	int indent;
269201053Sjilles	const char *p;
2701556Srgrimes
2711556Srgrimes	sprintf(line, "\n      /* from %s: */\n", fname);
2721556Srgrimes	addstr(line, &ep->code);
2731556Srgrimes	addstr("      {\n", &ep->code);
2741556Srgrimes	for (;;) {
2751556Srgrimes		linno++;
2761556Srgrimes		if (fgets(line, sizeof line, fp) == NULL)
2771556Srgrimes			error("Unexpected EOF");
2781556Srgrimes		if (equal(line, "}\n"))
2791556Srgrimes			break;
2801556Srgrimes		indent = 6;
2811556Srgrimes		for (p = line ; *p == '\t' ; p++)
2821556Srgrimes			indent += 8;
2831556Srgrimes		for ( ; *p == ' ' ; p++)
2841556Srgrimes			indent++;
2851556Srgrimes		if (*p == '\n' || *p == '#')
2861556Srgrimes			indent = 0;
2871556Srgrimes		while (indent >= 8) {
2881556Srgrimes			addchar('\t', &ep->code);
2891556Srgrimes			indent -= 8;
2901556Srgrimes		}
2911556Srgrimes		while (indent > 0) {
2921556Srgrimes			addchar(' ', &ep->code);
2931556Srgrimes			indent--;
2941556Srgrimes		}
2951556Srgrimes		addstr(p, &ep->code);
2961556Srgrimes	}
2971556Srgrimes	addstr("      }\n", &ep->code);
2981556Srgrimes}
2991556Srgrimes
3001556Srgrimes
3011556Srgrimesvoid
30290111Simpdoinclude(char *line)
30390111Simp{
30425222Ssteve	char *p;
3051556Srgrimes	char *name;
30625222Ssteve	char **pp;
3071556Srgrimes
3081556Srgrimes	for (p = line ; *p != '"' && *p != '<' && *p != '\0' ; p++);
3091556Srgrimes	if (*p == '\0')
3101556Srgrimes		error("Expecting '\"' or '<'");
3111556Srgrimes	name = p;
3121556Srgrimes	while (*p != ' ' && *p != '\t' && *p != '\n')
3131556Srgrimes		p++;
3141556Srgrimes	if (p[-1] != '"' && p[-1] != '>')
3151556Srgrimes		error("Missing terminator");
3161556Srgrimes	*p = '\0';
3171556Srgrimes
3181556Srgrimes	/* name now contains the name of the include file */
3191556Srgrimes	for (pp = header_files ; *pp && ! equal(*pp, name) ; pp++);
3201556Srgrimes	if (*pp == NULL)
3211556Srgrimes		*pp = savestr(name);
3221556Srgrimes}
3231556Srgrimes
3241556Srgrimes
3251556Srgrimesvoid
32690111Simpdodecl(char *line1, FILE *fp)
32790111Simp{
3281556Srgrimes	char line[1024];
32925222Ssteve	char *p, *q;
3301556Srgrimes
3311556Srgrimes	if (strcmp(line1, "MKINIT\n") == 0) { /* start of struct/union decl */
3321556Srgrimes		addchar('\n', &decls);
3331556Srgrimes		do {
3341556Srgrimes			linno++;
3351556Srgrimes			if (fgets(line, sizeof line, fp) == NULL)
3361556Srgrimes				error("Unterminated structure declaration");
3371556Srgrimes			addstr(line, &decls);
3381556Srgrimes		} while (line[0] != '}');
3391556Srgrimes		amiddecls = 0;
3401556Srgrimes	} else {
3411556Srgrimes		if (! amiddecls)
3421556Srgrimes			addchar('\n', &decls);
3431556Srgrimes		q = NULL;
34420425Ssteve		for (p = line1 + 6 ; *p && strchr("=/\n", *p) == NULL; p++)
34520425Ssteve			continue;
3461556Srgrimes		if (*p == '=') {		/* eliminate initialization */
3471556Srgrimes			for (q = p ; *q && *q != ';' ; q++);
3481556Srgrimes			if (*q == '\0')
3491556Srgrimes				q = NULL;
3501556Srgrimes			else {
3511556Srgrimes				while (p[-1] == ' ')
3521556Srgrimes					p--;
3531556Srgrimes				*p = '\0';
3541556Srgrimes			}
3551556Srgrimes		}
3561556Srgrimes		addstr("extern", &decls);
3571556Srgrimes		addstr(line1 + 6, &decls);
3581556Srgrimes		if (q != NULL)
3591556Srgrimes			addstr(q, &decls);
3601556Srgrimes		amiddecls = 1;
3611556Srgrimes	}
3621556Srgrimes}
3631556Srgrimes
3641556Srgrimes
3651556Srgrimes
3661556Srgrimes/*
3671556Srgrimes * Write the output to the file OUTTEMP.
3681556Srgrimes */
3691556Srgrimes
3701556Srgrimesvoid
37190111Simpoutput(void)
37290111Simp{
3731556Srgrimes	FILE *fp;
3741556Srgrimes	char **pp;
3751556Srgrimes	struct event *ep;
3761556Srgrimes
3771556Srgrimes	fp = ckfopen(OUTTEMP, "w");
3781556Srgrimes	fputs(writer, fp);
3791556Srgrimes	for (pp = header_files ; *pp ; pp++)
3801556Srgrimes		fprintf(fp, "#include %s\n", *pp);
3811556Srgrimes	fputs("\n\n\n", fp);
3821556Srgrimes	writetext(&defines, fp);
3831556Srgrimes	fputs("\n\n", fp);
3841556Srgrimes	writetext(&decls, fp);
3851556Srgrimes	for (ep = event ; ep->name ; ep++) {
3861556Srgrimes		fputs("\n\n\n", fp);
3871556Srgrimes		fputs(ep->comment, fp);
388149019Sstefanf		fprintf(fp, "\nvoid\n%s(void)\n{\n", ep->routine);
3891556Srgrimes		writetext(&ep->code, fp);
3901556Srgrimes		fprintf(fp, "}\n");
3911556Srgrimes	}
3921556Srgrimes	fclose(fp);
3931556Srgrimes}
3941556Srgrimes
3951556Srgrimes
3961556Srgrimes/*
3971556Srgrimes * A text structure is simply a block of text that is kept in memory.
3981556Srgrimes * Addstr appends a string to the text struct, and addchar appends a single
3991556Srgrimes * character.
4001556Srgrimes */
4011556Srgrimes
4021556Srgrimesvoid
403201053Sjillesaddstr(const char *s, struct text *text)
40490111Simp{
4051556Srgrimes	while (*s) {
4061556Srgrimes		if (--text->nleft < 0)
4071556Srgrimes			addchar(*s++, text);
4081556Srgrimes		else
4091556Srgrimes			*text->nextc++ = *s++;
4101556Srgrimes	}
4111556Srgrimes}
4121556Srgrimes
4131556Srgrimes
4141556Srgrimesvoid
41590111Simpaddchar(int c, struct text *text)
41617987Speter{
4171556Srgrimes	struct block *bp;
4181556Srgrimes
4191556Srgrimes	if (--text->nleft < 0) {
4201556Srgrimes		bp = ckmalloc(sizeof *bp);
4211556Srgrimes		if (text->start == NULL)
4221556Srgrimes			text->start = bp;
4231556Srgrimes		else
4241556Srgrimes			text->last->next = bp;
4251556Srgrimes		text->last = bp;
4261556Srgrimes		text->nextc = bp->text;
4271556Srgrimes		text->nleft = BLOCKSIZE - 1;
4281556Srgrimes	}
4291556Srgrimes	*text->nextc++ = c;
4301556Srgrimes}
4311556Srgrimes
4321556Srgrimes/*
4331556Srgrimes * Write the contents of a text structure to a file.
4341556Srgrimes */
4351556Srgrimesvoid
43690111Simpwritetext(struct text *text, FILE *fp)
43790111Simp{
4381556Srgrimes	struct block *bp;
4391556Srgrimes
4401556Srgrimes	if (text->start != NULL) {
4411556Srgrimes		for (bp = text->start ; bp != text->last ; bp = bp->next)
4421556Srgrimes			fwrite(bp->text, sizeof (char), BLOCKSIZE, fp);
4431556Srgrimes		fwrite(bp->text, sizeof (char), BLOCKSIZE - text->nleft, fp);
4441556Srgrimes	}
4451556Srgrimes}
4461556Srgrimes
4471556SrgrimesFILE *
448201053Sjillesckfopen(const char *file, const char *mode)
44990111Simp{
4501556Srgrimes	FILE *fp;
4511556Srgrimes
4521556Srgrimes	if ((fp = fopen(file, mode)) == NULL) {
45353891Scracauer		fprintf(stderr, "Can't open %s: %s\n", file, strerror(errno));
4541556Srgrimes		exit(2);
4551556Srgrimes	}
4561556Srgrimes	return fp;
4571556Srgrimes}
4581556Srgrimes
4591556Srgrimesvoid *
460193221Srseckmalloc(size_t nbytes)
46117987Speter{
46225222Ssteve	char *p;
4631556Srgrimes
4641556Srgrimes	if ((p = malloc(nbytes)) == NULL)
4651556Srgrimes		error("Out of space");
4661556Srgrimes	return p;
4671556Srgrimes}
4681556Srgrimes
4691556Srgrimeschar *
470201053Sjillessavestr(const char *s)
47190111Simp{
47225222Ssteve	char *p;
4731556Srgrimes
4741556Srgrimes	p = ckmalloc(strlen(s) + 1);
4751556Srgrimes	strcpy(p, s);
4761556Srgrimes	return p;
4771556Srgrimes}
4781556Srgrimes
4791556Srgrimesvoid
480201053Sjilleserror(const char *msg)
48190111Simp{
4821556Srgrimes	if (curfile != NULL)
4831556Srgrimes		fprintf(stderr, "%s:%d: ", curfile, linno);
4841556Srgrimes	fprintf(stderr, "%s\n", msg);
4851556Srgrimes	exit(2);
4861556Srgrimes}
487