xref: /csrg-svn/bin/sh/mkinit.c (revision 69272)
147130Sbostic /*-
260698Sbostic  * Copyright (c) 1991, 1993
360698Sbostic  *	The Regents of the University of California.  All rights reserved.
447130Sbostic  *
547130Sbostic  * This code is derived from software contributed to Berkeley by
647130Sbostic  * Kenneth Almquist.
747130Sbostic  *
847130Sbostic  * %sccs.include.redist.c%
947130Sbostic  */
1047130Sbostic 
1147130Sbostic #ifndef lint
1260698Sbostic static char copyright[] =
1360698Sbostic "@(#) Copyright (c) 1991, 1993\n\
1460698Sbostic 	The Regents of the University of California.  All rights reserved.\n";
1547130Sbostic #endif /* not lint */
1647130Sbostic 
1747130Sbostic #ifndef lint
18*69272Schristos static char sccsid[] = "@(#)mkinit.c	8.2 (Berkeley) 05/04/95";
1947130Sbostic #endif /* not lint */
2047130Sbostic 
2147130Sbostic /*
2247130Sbostic  * This program scans all the source files for code to handle various
2347130Sbostic  * special events and combines this code into one file.  This (allegedly)
2447130Sbostic  * improves the structure of the program since there is no need for
2547130Sbostic  * anyone outside of a module to know that that module performs special
2647130Sbostic  * operations on particular events.  The command is executed iff init.c
2747130Sbostic  * is actually changed.
2847298Smarc  *
2947298Smarc  * Usage:  mkinit command sourcefile...
3047130Sbostic  */
3147130Sbostic 
3247130Sbostic 
3347166Sbostic #include <sys/cdefs.h>
3454319Smarc #include <sys/types.h>
3547130Sbostic #include <stdio.h>
36*69272Schristos #include <stdlib.h>
37*69272Schristos #include <string.h>
3847298Smarc #include <fcntl.h>
3954319Smarc #include <unistd.h>
4047130Sbostic 
4147130Sbostic 
4247130Sbostic /*
4347130Sbostic  * OUTFILE is the name of the output file.  Output is initially written
4447130Sbostic  * to the file OUTTEMP, which is then moved to OUTFILE if OUTTEMP and
4547130Sbostic  * OUTFILE are different.
4647130Sbostic  */
4747130Sbostic 
4847130Sbostic #define OUTFILE "init.c"
4947130Sbostic #define OUTTEMP "init.c.new"
5047130Sbostic #define OUTOBJ "init.o"
5147130Sbostic 
5247130Sbostic 
5347130Sbostic /*
5447130Sbostic  * A text structure is basicly just a string that grows as more characters
5547130Sbostic  * are added onto the end of it.  It is implemented as a linked list of
5647130Sbostic  * blocks of characters.  The routines addstr and addchar append a string
5747130Sbostic  * or a single character, respectively, to a text structure.  Writetext
5847130Sbostic  * writes the contents of a text structure to a file.
5947130Sbostic  */
6047130Sbostic 
6147130Sbostic #define BLOCKSIZE 512
6247130Sbostic 
6347130Sbostic struct text {
6447130Sbostic 	char *nextc;
6547130Sbostic 	int nleft;
6647130Sbostic 	struct block *start;
6747130Sbostic 	struct block *last;
6847130Sbostic };
6947130Sbostic 
7047130Sbostic struct block {
7147130Sbostic 	struct block *next;
7247130Sbostic 	char text[BLOCKSIZE];
7347130Sbostic };
7447130Sbostic 
7547130Sbostic 
7647130Sbostic /*
7747130Sbostic  * There is one event structure for each event that mkinit handles.
7847130Sbostic  */
7947130Sbostic 
8047130Sbostic struct event {
8147130Sbostic 	char *name;		/* name of event (e.g. INIT) */
8247130Sbostic 	char *routine;		/* name of routine called on event */
8347130Sbostic 	char *comment;		/* comment describing routine */
8447130Sbostic 	struct text code;		/* code for handling event */
8547130Sbostic };
8647130Sbostic 
8747130Sbostic 
8847130Sbostic char writer[] = "\
8947130Sbostic /*\n\
9047130Sbostic  * This file was generated by the mkinit program.\n\
9147130Sbostic  */\n\
9247130Sbostic \n";
9347130Sbostic 
9447130Sbostic char init[] = "\
9547130Sbostic /*\n\
9647130Sbostic  * Initialization code.\n\
9747130Sbostic  */\n";
9847130Sbostic 
9947130Sbostic char reset[] = "\
10047130Sbostic /*\n\
10147130Sbostic  * This routine is called when an error or an interrupt occurs in an\n\
10247130Sbostic  * interactive shell and control is returned to the main command loop.\n\
10347130Sbostic  */\n";
10447130Sbostic 
10547130Sbostic char shellproc[] = "\
10647130Sbostic /*\n\
10747130Sbostic  * This routine is called to initialize the shell to run a shell procedure.\n\
10847130Sbostic  */\n";
10947130Sbostic 
11047130Sbostic 
11147130Sbostic struct event event[] = {
11247130Sbostic 	{"INIT", "init", init},
11347130Sbostic 	{"RESET", "reset", reset},
11447130Sbostic 	{"SHELLPROC", "initshellproc", shellproc},
11547130Sbostic 	{NULL, NULL}
11647130Sbostic };
11747130Sbostic 
11847130Sbostic 
11947130Sbostic char *curfile;				/* current file */
12047130Sbostic int linno;				/* current line */
12147130Sbostic char *header_files[200];		/* list of header files */
12247130Sbostic struct text defines;			/* #define statements */
12347130Sbostic struct text decls;			/* declarations */
12447130Sbostic int amiddecls;				/* for formatting */
12547130Sbostic 
12647130Sbostic 
127*69272Schristos void readfile __P((char *));
128*69272Schristos int match __P((char *, char *));
129*69272Schristos int gooddefine __P((char *));
130*69272Schristos void doevent __P((struct event *, FILE *, char *));
131*69272Schristos void doinclude __P((char *));
132*69272Schristos void dodecl __P((char *, FILE *));
133*69272Schristos void output __P((void));
134*69272Schristos int file_changed __P((void));
135*69272Schristos int touch __P((char *));
136*69272Schristos void addstr __P((char *, struct text *));
137*69272Schristos void addchar __P((int, struct text *));
138*69272Schristos void writetext __P((struct text *, FILE *));
139*69272Schristos FILE *ckfopen __P((char *, char *));
140*69272Schristos void *ckmalloc __P((int));
141*69272Schristos char *savestr __P((char *));
142*69272Schristos void error __P((char *));
14347130Sbostic 
14447130Sbostic #define equal(s1, s2)	(strcmp(s1, s2) == 0)
14547130Sbostic 
146*69272Schristos int
main(argc,argv)14747130Sbostic main(argc, argv)
148*69272Schristos 	int argc;
14947130Sbostic 	char **argv;
150*69272Schristos {
15147130Sbostic 	char **ap;
15247130Sbostic 
15347130Sbostic 	if (argc < 2)
15447130Sbostic 		error("Usage:  mkinit command file...");
15547130Sbostic 	header_files[0] = "\"shell.h\"";
15647130Sbostic 	header_files[1] = "\"mystring.h\"";
15747130Sbostic 	for (ap = argv + 2 ; *ap ; ap++)
15847130Sbostic 		readfile(*ap);
15947130Sbostic 	output();
16047130Sbostic 	if (file_changed()) {
16147130Sbostic 		unlink(OUTFILE);
16247130Sbostic 		link(OUTTEMP, OUTFILE);
16347130Sbostic 		unlink(OUTTEMP);
16447130Sbostic 	} else {
16547130Sbostic 		unlink(OUTTEMP);
16647298Smarc 		if (touch(OUTOBJ))
16747298Smarc 			exit(0);		/* no compilation necessary */
16847130Sbostic 	}
16947298Smarc 	printf("%s\n", argv[1]);
17047298Smarc 	execl("/bin/sh", "sh", "-c", argv[1], (char *)0);
17147298Smarc 	error("Can't exec shell");
172*69272Schristos 
173*69272Schristos 	exit(1);
17447130Sbostic }
17547130Sbostic 
17647130Sbostic 
17747130Sbostic /*
17847130Sbostic  * Parse an input file.
17947130Sbostic  */
18047130Sbostic 
18147130Sbostic void
readfile(fname)18247130Sbostic readfile(fname)
18347130Sbostic 	char *fname;
18447130Sbostic 	{
18547130Sbostic 	FILE *fp;
18647130Sbostic 	char line[1024];
18747130Sbostic 	struct event *ep;
18847130Sbostic 
18947130Sbostic 	fp = ckfopen(fname, "r");
19047130Sbostic 	curfile = fname;
19147130Sbostic 	linno = 0;
19247130Sbostic 	amiddecls = 0;
19347130Sbostic 	while (fgets(line, sizeof line, fp) != NULL) {
19447130Sbostic 		linno++;
19547130Sbostic 		for (ep = event ; ep->name ; ep++) {
19647130Sbostic 			if (line[0] == ep->name[0] && match(ep->name, line)) {
19747130Sbostic 				doevent(ep, fp, fname);
19847130Sbostic 				break;
19947130Sbostic 			}
20047130Sbostic 		}
20147130Sbostic 		if (line[0] == 'I' && match("INCLUDE", line))
20247130Sbostic 			doinclude(line);
20347130Sbostic 		if (line[0] == 'M' && match("MKINIT", line))
20447130Sbostic 			dodecl(line, fp);
20547130Sbostic 		if (line[0] == '#' && gooddefine(line))
20647130Sbostic 			addstr(line, &defines);
20747130Sbostic 	}
20847130Sbostic 	fclose(fp);
20947130Sbostic }
21047130Sbostic 
21147130Sbostic 
21247130Sbostic int
match(name,line)21347130Sbostic match(name, line)
21447130Sbostic 	char *name;
21547130Sbostic 	char *line;
216*69272Schristos {
21747130Sbostic 	register char *p, *q;
21847130Sbostic 
21947130Sbostic 	p = name, q = line;
22047130Sbostic 	while (*p) {
22147130Sbostic 		if (*p++ != *q++)
22247130Sbostic 			return 0;
22347130Sbostic 	}
22447130Sbostic 	if (*q != '{' && *q != ' ' && *q != '\t' && *q != '\n')
22547130Sbostic 		return 0;
22647130Sbostic 	return 1;
22747130Sbostic }
22847130Sbostic 
22947130Sbostic 
23047130Sbostic int
gooddefine(line)23147130Sbostic gooddefine(line)
23247130Sbostic 	char *line;
233*69272Schristos {
23447130Sbostic 	register char *p;
23547130Sbostic 
23647130Sbostic 	if (! match("#define", line))
23747130Sbostic 		return 0;			/* not a define */
23847130Sbostic 	p = line + 7;
23947130Sbostic 	while (*p == ' ' || *p == '\t')
24047130Sbostic 		p++;
24147130Sbostic 	while (*p != ' ' && *p != '\t') {
24247130Sbostic 		if (*p == '(')
24347130Sbostic 			return 0;		/* macro definition */
24447130Sbostic 		p++;
24547130Sbostic 	}
24647130Sbostic 	while (*p != '\n' && *p != '\0')
24747130Sbostic 		p++;
24847130Sbostic 	if (p[-1] == '\\')
24947130Sbostic 		return 0;			/* multi-line definition */
25047130Sbostic 	return 1;
25147130Sbostic }
25247130Sbostic 
25347130Sbostic 
25447130Sbostic void
doevent(ep,fp,fname)25547130Sbostic doevent(ep, fp, fname)
25647130Sbostic 	register struct event *ep;
25747130Sbostic 	FILE *fp;
25847130Sbostic 	char *fname;
25947130Sbostic 	{
26047130Sbostic 	char line[1024];
26147130Sbostic 	int indent;
26247130Sbostic 	char *p;
26347130Sbostic 
26447130Sbostic 	sprintf(line, "\n      /* from %s: */\n", fname);
26547130Sbostic 	addstr(line, &ep->code);
26647130Sbostic 	addstr("      {\n", &ep->code);
26747130Sbostic 	for (;;) {
26847130Sbostic 		linno++;
26947130Sbostic 		if (fgets(line, sizeof line, fp) == NULL)
27047130Sbostic 			error("Unexpected EOF");
27147130Sbostic 		if (equal(line, "}\n"))
27247130Sbostic 			break;
27347130Sbostic 		indent = 6;
27447130Sbostic 		for (p = line ; *p == '\t' ; p++)
27547130Sbostic 			indent += 8;
27647130Sbostic 		for ( ; *p == ' ' ; p++)
27747130Sbostic 			indent++;
27847130Sbostic 		if (*p == '\n' || *p == '#')
27947130Sbostic 			indent = 0;
28047130Sbostic 		while (indent >= 8) {
28147130Sbostic 			addchar('\t', &ep->code);
28247130Sbostic 			indent -= 8;
28347130Sbostic 		}
28447130Sbostic 		while (indent > 0) {
28547130Sbostic 			addchar(' ', &ep->code);
28647130Sbostic 			indent--;
28747130Sbostic 		}
28847130Sbostic 		addstr(p, &ep->code);
28947130Sbostic 	}
29047130Sbostic 	addstr("      }\n", &ep->code);
29147130Sbostic }
29247130Sbostic 
29347130Sbostic 
29447130Sbostic void
doinclude(line)29547130Sbostic doinclude(line)
29647130Sbostic 	char *line;
29747130Sbostic 	{
29847130Sbostic 	register char *p;
29947130Sbostic 	char *name;
30047130Sbostic 	register char **pp;
30147130Sbostic 
30247130Sbostic 	for (p = line ; *p != '"' && *p != '<' && *p != '\0' ; p++);
30347130Sbostic 	if (*p == '\0')
30447130Sbostic 		error("Expecting '\"' or '<'");
30547130Sbostic 	name = p;
30647130Sbostic 	while (*p != ' ' && *p != '\t' && *p != '\n')
30747130Sbostic 		p++;
30847130Sbostic 	if (p[-1] != '"' && p[-1] != '>')
30947130Sbostic 		error("Missing terminator");
31047130Sbostic 	*p = '\0';
31147130Sbostic 
31247130Sbostic 	/* name now contains the name of the include file */
31347130Sbostic 	for (pp = header_files ; *pp && ! equal(*pp, name) ; pp++);
31447130Sbostic 	if (*pp == NULL)
31547130Sbostic 		*pp = savestr(name);
31647130Sbostic }
31747130Sbostic 
31847130Sbostic 
31947130Sbostic void
dodecl(line1,fp)32047130Sbostic dodecl(line1, fp)
32147130Sbostic 	char *line1;
32247130Sbostic 	FILE *fp;
32347130Sbostic 	{
32447130Sbostic 	char line[1024];
32547130Sbostic 	register char *p, *q;
32647130Sbostic 
32747130Sbostic 	if (strcmp(line1, "MKINIT\n") == 0) { /* start of struct/union decl */
32847130Sbostic 		addchar('\n', &decls);
32947130Sbostic 		do {
33047130Sbostic 			linno++;
33147130Sbostic 			if (fgets(line, sizeof line, fp) == NULL)
33247130Sbostic 				error("Unterminated structure declaration");
33347130Sbostic 			addstr(line, &decls);
33447130Sbostic 		} while (line[0] != '}');
33547130Sbostic 		amiddecls = 0;
33647130Sbostic 	} else {
33747130Sbostic 		if (! amiddecls)
33847130Sbostic 			addchar('\n', &decls);
33947130Sbostic 		q = NULL;
340*69272Schristos 		for (p = line1 + 6 ; *p != '\0' && *p != '=' && *p != '/' ; p++);
34147130Sbostic 		if (*p == '=') {		/* eliminate initialization */
34247130Sbostic 			for (q = p ; *q && *q != ';' ; q++);
34347130Sbostic 			if (*q == '\0')
34447130Sbostic 				q = NULL;
34547130Sbostic 			else {
34647130Sbostic 				while (p[-1] == ' ')
34747130Sbostic 					p--;
34847130Sbostic 				*p = '\0';
34947130Sbostic 			}
35047130Sbostic 		}
35147130Sbostic 		addstr("extern", &decls);
35247130Sbostic 		addstr(line1 + 6, &decls);
35347130Sbostic 		if (q != NULL)
35447130Sbostic 			addstr(q, &decls);
35547130Sbostic 		amiddecls = 1;
35647130Sbostic 	}
35747130Sbostic }
35847130Sbostic 
35947130Sbostic 
36047130Sbostic 
36147130Sbostic /*
36247130Sbostic  * Write the output to the file OUTTEMP.
36347130Sbostic  */
36447130Sbostic 
36547130Sbostic void
output()36647130Sbostic output() {
36747130Sbostic 	FILE *fp;
36847130Sbostic 	char **pp;
36947130Sbostic 	struct event *ep;
37047130Sbostic 
37147130Sbostic 	fp = ckfopen(OUTTEMP, "w");
37247130Sbostic 	fputs(writer, fp);
37347130Sbostic 	for (pp = header_files ; *pp ; pp++)
37447130Sbostic 		fprintf(fp, "#include %s\n", *pp);
37547130Sbostic 	fputs("\n\n\n", fp);
37647130Sbostic 	writetext(&defines, fp);
37747130Sbostic 	fputs("\n\n", fp);
37847130Sbostic 	writetext(&decls, fp);
37947130Sbostic 	for (ep = event ; ep->name ; ep++) {
38047130Sbostic 		fputs("\n\n\n", fp);
38147130Sbostic 		fputs(ep->comment, fp);
38247130Sbostic 		fprintf(fp, "\nvoid\n%s() {\n", ep->routine);
38347130Sbostic 		writetext(&ep->code, fp);
38447130Sbostic 		fprintf(fp, "}\n");
38547130Sbostic 	}
38647130Sbostic 	fclose(fp);
38747130Sbostic }
38847130Sbostic 
38947130Sbostic 
39047130Sbostic /*
39147130Sbostic  * Return true if the new output file is different from the old one.
39247130Sbostic  */
39347130Sbostic 
39447130Sbostic int
file_changed()395*69272Schristos file_changed()
396*69272Schristos {
39747130Sbostic 	register FILE *f1, *f2;
39847130Sbostic 	register int c;
39947130Sbostic 
40047130Sbostic 	if ((f1 = fopen(OUTFILE, "r")) == NULL
40147130Sbostic 	 || (f2 = fopen(OUTTEMP, "r")) == NULL)
40247130Sbostic 		return 1;
40347130Sbostic 	while ((c = getc(f1)) == getc(f2)) {
40447130Sbostic 		if (c == EOF)
40547130Sbostic 			return 0;
40647130Sbostic 	}
40747130Sbostic 	return 1;
40847130Sbostic }
40947130Sbostic 
41047130Sbostic 
41147298Smarc /*
41247298Smarc  * Touch a file.  Returns 0 on failure, 1 on success.
41347298Smarc  */
41447130Sbostic 
41547298Smarc int
touch(file)41647298Smarc touch(file)
41747298Smarc 	char *file;
418*69272Schristos {
41947298Smarc 	int fd;
42047298Smarc 	char c;
42147298Smarc 
42247298Smarc 	if ((fd = open(file, O_RDWR)) < 0)
42347298Smarc 		return 0;
42447298Smarc 	if (read(fd, &c, 1) != 1) {
42547298Smarc 		close(fd);
42647298Smarc 		return 0;
42747298Smarc 	}
42854319Smarc 	lseek(fd, (off_t)0, 0);
42947298Smarc 	write(fd, &c, 1);
43047298Smarc 	close(fd);
43147298Smarc 	return 1;
43247298Smarc }
43347298Smarc 
43447298Smarc 
43547298Smarc 
43647130Sbostic /*
43747130Sbostic  * A text structure is simply a block of text that is kept in memory.
43847130Sbostic  * Addstr appends a string to the text struct, and addchar appends a single
43947130Sbostic  * character.
44047130Sbostic  */
44147130Sbostic 
44247130Sbostic void
addstr(s,text)44347130Sbostic addstr(s, text)
44447130Sbostic 	register char *s;
44547130Sbostic 	register struct text *text;
44647130Sbostic 	{
44747130Sbostic 	while (*s) {
44847130Sbostic 		if (--text->nleft < 0)
44947130Sbostic 			addchar(*s++, text);
45047130Sbostic 		else
45147130Sbostic 			*text->nextc++ = *s++;
45247130Sbostic 	}
45347130Sbostic }
45447130Sbostic 
45547130Sbostic 
45647130Sbostic void
addchar(c,text)45747130Sbostic addchar(c, text)
458*69272Schristos 	int c;
45947130Sbostic 	register struct text *text;
460*69272Schristos {
46147130Sbostic 	struct block *bp;
46247130Sbostic 
46347130Sbostic 	if (--text->nleft < 0) {
46447130Sbostic 		bp = ckmalloc(sizeof *bp);
46547130Sbostic 		if (text->start == NULL)
46647130Sbostic 			text->start = bp;
46747130Sbostic 		else
46847130Sbostic 			text->last->next = bp;
46947130Sbostic 		text->last = bp;
47047130Sbostic 		text->nextc = bp->text;
47147130Sbostic 		text->nleft = BLOCKSIZE - 1;
47247130Sbostic 	}
47347130Sbostic 	*text->nextc++ = c;
47447130Sbostic }
47547130Sbostic 
47647130Sbostic /*
47747130Sbostic  * Write the contents of a text structure to a file.
47847130Sbostic  */
47947130Sbostic void
writetext(text,fp)48047130Sbostic writetext(text, fp)
48147130Sbostic 	struct text *text;
48247130Sbostic 	FILE *fp;
48347130Sbostic 	{
48447130Sbostic 	struct block *bp;
48547130Sbostic 
48647130Sbostic 	if (text->start != NULL) {
48747130Sbostic 		for (bp = text->start ; bp != text->last ; bp = bp->next)
48847130Sbostic 			fwrite(bp->text, sizeof (char), BLOCKSIZE, fp);
48947130Sbostic 		fwrite(bp->text, sizeof (char), BLOCKSIZE - text->nleft, fp);
49047130Sbostic 	}
49147130Sbostic }
49247130Sbostic 
49347130Sbostic FILE *
ckfopen(file,mode)49447130Sbostic ckfopen(file, mode)
49547130Sbostic 	char *file;
49647130Sbostic 	char *mode;
49747130Sbostic 	{
49847130Sbostic 	FILE *fp;
49947130Sbostic 
50047130Sbostic 	if ((fp = fopen(file, mode)) == NULL) {
50147130Sbostic 		fprintf(stderr, "Can't open %s\n", file);
50247130Sbostic 		exit(2);
50347130Sbostic 	}
50447130Sbostic 	return fp;
50547130Sbostic }
50647130Sbostic 
50747130Sbostic void *
ckmalloc(nbytes)508*69272Schristos ckmalloc(nbytes)
509*69272Schristos 	int nbytes;
510*69272Schristos {
51147130Sbostic 	register char *p;
51247130Sbostic 
51347130Sbostic 	if ((p = malloc(nbytes)) == NULL)
51447130Sbostic 		error("Out of space");
51547130Sbostic 	return p;
51647130Sbostic }
51747130Sbostic 
51847130Sbostic char *
savestr(s)51947130Sbostic savestr(s)
52047130Sbostic 	char *s;
52147130Sbostic 	{
52247130Sbostic 	register char *p;
52347130Sbostic 
52447130Sbostic 	p = ckmalloc(strlen(s) + 1);
52547130Sbostic 	strcpy(p, s);
52647130Sbostic 	return p;
52747130Sbostic }
52847130Sbostic 
52947130Sbostic void
error(msg)53047130Sbostic error(msg)
53147130Sbostic 	char *msg;
53247130Sbostic 	{
53347130Sbostic 	if (curfile != NULL)
53447130Sbostic 		fprintf(stderr, "%s:%d: ", curfile, linno);
53547130Sbostic 	fprintf(stderr, "%s\n", msg);
53647130Sbostic 	exit(2);
53747130Sbostic }
538