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