mkinit.c revision 25905
1/*-
2 * Copyright (c) 1991, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Kenneth Almquist.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 *    must display the following acknowledgement:
18 *	This product includes software developed by the University of
19 *	California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 *    may be used to endorse or promote products derived from this software
22 *    without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 *	$Id: mkinit.c,v 1.10 1997/04/28 03:06:37 steve Exp $
37 */
38
39#ifndef lint
40static char const copyright[] =
41"@(#) Copyright (c) 1991, 1993\n\
42	The Regents of the University of California.  All rights reserved.\n";
43#endif /* not lint */
44
45#ifndef lint
46static char const sccsid[] = "@(#)mkinit.c	8.2 (Berkeley) 5/4/95";
47#endif /* not lint */
48
49/*
50 * This program scans all the source files for code to handle various
51 * special events and combines this code into one file.  This (allegedly)
52 * improves the structure of the program since there is no need for
53 * anyone outside of a module to know that that module performs special
54 * operations on particular events.
55 *
56 * Usage:  mkinit sourcefile...
57 */
58
59
60#include <sys/cdefs.h>
61#include <sys/types.h>
62#include <stdio.h>
63#include <stdlib.h>
64#include <string.h>
65#include <fcntl.h>
66#include <unistd.h>
67
68
69/*
70 * OUTFILE is the name of the output file.  Output is initially written
71 * to the file OUTTEMP, which is then moved to OUTFILE.
72 */
73
74#define OUTFILE "init.c"
75#define OUTTEMP "init.c.new"
76
77
78/*
79 * A text structure is basicly just a string that grows as more characters
80 * are added onto the end of it.  It is implemented as a linked list of
81 * blocks of characters.  The routines addstr and addchar append a string
82 * or a single character, respectively, to a text structure.  Writetext
83 * writes the contents of a text structure to a file.
84 */
85
86#define BLOCKSIZE 512
87
88struct text {
89	char *nextc;
90	int nleft;
91	struct block *start;
92	struct block *last;
93};
94
95struct block {
96	struct block *next;
97	char text[BLOCKSIZE];
98};
99
100
101/*
102 * There is one event structure for each event that mkinit handles.
103 */
104
105struct event {
106	char *name;		/* name of event (e.g. INIT) */
107	char *routine;		/* name of routine called on event */
108	char *comment;		/* comment describing routine */
109	struct text code;	/* code for handling event */
110};
111
112
113char writer[] = "\
114/*\n\
115 * This file was generated by the mkinit program.\n\
116 */\n\
117\n";
118
119char init[] = "\
120/*\n\
121 * Initialization code.\n\
122 */\n";
123
124char reset[] = "\
125/*\n\
126 * This routine is called when an error or an interrupt occurs in an\n\
127 * interactive shell and control is returned to the main command loop.\n\
128 */\n";
129
130char shellproc[] = "\
131/*\n\
132 * This routine is called to initialize the shell to run a shell procedure.\n\
133 */\n";
134
135
136struct event event[] = {
137	{"INIT", "init", init},
138	{"RESET", "reset", reset},
139	{"SHELLPROC", "initshellproc", shellproc},
140	{NULL, NULL}
141};
142
143
144char *curfile;				/* current file */
145int linno;				/* current line */
146char *header_files[200];		/* list of header files */
147struct text defines;			/* #define statements */
148struct text decls;			/* declarations */
149int amiddecls;				/* for formatting */
150
151
152void readfile __P((char *));
153int match __P((char *, char *));
154int gooddefine __P((char *));
155void doevent __P((struct event *, FILE *, char *));
156void doinclude __P((char *));
157void dodecl __P((char *, FILE *));
158void output __P((void));
159void addstr __P((char *, struct text *));
160void addchar __P((int, struct text *));
161void writetext __P((struct text *, FILE *));
162FILE *ckfopen __P((char *, char *));
163void *ckmalloc __P((int));
164char *savestr __P((char *));
165void error __P((char *));
166
167#define equal(s1, s2)	(strcmp(s1, s2) == 0)
168
169int
170main(argc, argv)
171	int argc __unused;
172	char **argv;
173{
174	char **ap;
175
176	header_files[0] = "\"shell.h\"";
177	header_files[1] = "\"mystring.h\"";
178	for (ap = argv + 1 ; *ap ; ap++)
179		readfile(*ap);
180	output();
181	rename(OUTTEMP, OUTFILE);
182	exit(0);
183}
184
185
186/*
187 * Parse an input file.
188 */
189
190void
191readfile(fname)
192	char *fname;
193	{
194	FILE *fp;
195	char line[1024];
196	struct event *ep;
197
198	fp = ckfopen(fname, "r");
199	curfile = fname;
200	linno = 0;
201	amiddecls = 0;
202	while (fgets(line, sizeof line, fp) != NULL) {
203		linno++;
204		for (ep = event ; ep->name ; ep++) {
205			if (line[0] == ep->name[0] && match(ep->name, line)) {
206				doevent(ep, fp, fname);
207				break;
208			}
209		}
210		if (line[0] == 'I' && match("INCLUDE", line))
211			doinclude(line);
212		if (line[0] == 'M' && match("MKINIT", line))
213			dodecl(line, fp);
214		if (line[0] == '#' && gooddefine(line)) {
215			char *cp;
216			char line2[1024];
217			static const char undef[] = "#undef ";
218
219			strcpy(line2, line);
220			memcpy(line2, undef, sizeof(undef) - 1);
221			cp = line2 + sizeof(undef) - 1;
222			while(*cp && (*cp == ' ' || *cp == '\t'))
223			        cp++;
224			while(*cp && *cp != ' ' && *cp != '\t' && *cp != '\n')
225			        cp++;
226			*cp++ = '\n'; *cp = '\0';
227			addstr(line2, &defines);
228			addstr(line, &defines);
229		}
230	}
231	fclose(fp);
232}
233
234
235int
236match(name, line)
237	char *name;
238	char *line;
239{
240	char *p, *q;
241
242	p = name, q = line;
243	while (*p) {
244		if (*p++ != *q++)
245			return 0;
246	}
247	if (*q != '{' && *q != ' ' && *q != '\t' && *q != '\n')
248		return 0;
249	return 1;
250}
251
252
253int
254gooddefine(line)
255	char *line;
256{
257	char *p;
258
259	if (! match("#define", line))
260		return 0;			/* not a define */
261	p = line + 7;
262	while (*p == ' ' || *p == '\t')
263		p++;
264	while (*p != ' ' && *p != '\t') {
265		if (*p == '(')
266			return 0;		/* macro definition */
267		p++;
268	}
269	while (*p != '\n' && *p != '\0')
270		p++;
271	if (p[-1] == '\\')
272		return 0;			/* multi-line definition */
273	return 1;
274}
275
276
277void
278doevent(ep, fp, fname)
279	struct event *ep;
280	FILE *fp;
281	char *fname;
282	{
283	char line[1024];
284	int indent;
285	char *p;
286
287	sprintf(line, "\n      /* from %s: */\n", fname);
288	addstr(line, &ep->code);
289	addstr("      {\n", &ep->code);
290	for (;;) {
291		linno++;
292		if (fgets(line, sizeof line, fp) == NULL)
293			error("Unexpected EOF");
294		if (equal(line, "}\n"))
295			break;
296		indent = 6;
297		for (p = line ; *p == '\t' ; p++)
298			indent += 8;
299		for ( ; *p == ' ' ; p++)
300			indent++;
301		if (*p == '\n' || *p == '#')
302			indent = 0;
303		while (indent >= 8) {
304			addchar('\t', &ep->code);
305			indent -= 8;
306		}
307		while (indent > 0) {
308			addchar(' ', &ep->code);
309			indent--;
310		}
311		addstr(p, &ep->code);
312	}
313	addstr("      }\n", &ep->code);
314}
315
316
317void
318doinclude(line)
319	char *line;
320	{
321	char *p;
322	char *name;
323	char **pp;
324
325	for (p = line ; *p != '"' && *p != '<' && *p != '\0' ; p++);
326	if (*p == '\0')
327		error("Expecting '\"' or '<'");
328	name = p;
329	while (*p != ' ' && *p != '\t' && *p != '\n')
330		p++;
331	if (p[-1] != '"' && p[-1] != '>')
332		error("Missing terminator");
333	*p = '\0';
334
335	/* name now contains the name of the include file */
336	for (pp = header_files ; *pp && ! equal(*pp, name) ; pp++);
337	if (*pp == NULL)
338		*pp = savestr(name);
339}
340
341
342void
343dodecl(line1, fp)
344	char *line1;
345	FILE *fp;
346	{
347	char line[1024];
348	char *p, *q;
349
350	if (strcmp(line1, "MKINIT\n") == 0) { /* start of struct/union decl */
351		addchar('\n', &decls);
352		do {
353			linno++;
354			if (fgets(line, sizeof line, fp) == NULL)
355				error("Unterminated structure declaration");
356			addstr(line, &decls);
357		} while (line[0] != '}');
358		amiddecls = 0;
359	} else {
360		if (! amiddecls)
361			addchar('\n', &decls);
362		q = NULL;
363		for (p = line1 + 6 ; *p && strchr("=/\n", *p) == NULL; p++)
364			continue;
365		if (*p == '=') {		/* eliminate initialization */
366			for (q = p ; *q && *q != ';' ; q++);
367			if (*q == '\0')
368				q = NULL;
369			else {
370				while (p[-1] == ' ')
371					p--;
372				*p = '\0';
373			}
374		}
375		addstr("extern", &decls);
376		addstr(line1 + 6, &decls);
377		if (q != NULL)
378			addstr(q, &decls);
379		amiddecls = 1;
380	}
381}
382
383
384
385/*
386 * Write the output to the file OUTTEMP.
387 */
388
389void
390output() {
391	FILE *fp;
392	char **pp;
393	struct event *ep;
394
395	fp = ckfopen(OUTTEMP, "w");
396	fputs(writer, fp);
397	for (pp = header_files ; *pp ; pp++)
398		fprintf(fp, "#include %s\n", *pp);
399	fputs("\n\n\n", fp);
400	writetext(&defines, fp);
401	fputs("\n\n", fp);
402	writetext(&decls, fp);
403	for (ep = event ; ep->name ; ep++) {
404		fputs("\n\n\n", fp);
405		fputs(ep->comment, fp);
406		fprintf(fp, "\nvoid\n%s() {\n", ep->routine);
407		writetext(&ep->code, fp);
408		fprintf(fp, "}\n");
409	}
410	fclose(fp);
411}
412
413
414/*
415 * A text structure is simply a block of text that is kept in memory.
416 * Addstr appends a string to the text struct, and addchar appends a single
417 * character.
418 */
419
420void
421addstr(s, text)
422	char *s;
423	struct text *text;
424	{
425	while (*s) {
426		if (--text->nleft < 0)
427			addchar(*s++, text);
428		else
429			*text->nextc++ = *s++;
430	}
431}
432
433
434void
435addchar(c, text)
436	int c;
437	struct text *text;
438{
439	struct block *bp;
440
441	if (--text->nleft < 0) {
442		bp = ckmalloc(sizeof *bp);
443		if (text->start == NULL)
444			text->start = bp;
445		else
446			text->last->next = bp;
447		text->last = bp;
448		text->nextc = bp->text;
449		text->nleft = BLOCKSIZE - 1;
450	}
451	*text->nextc++ = c;
452}
453
454/*
455 * Write the contents of a text structure to a file.
456 */
457void
458writetext(text, fp)
459	struct text *text;
460	FILE *fp;
461	{
462	struct block *bp;
463
464	if (text->start != NULL) {
465		for (bp = text->start ; bp != text->last ; bp = bp->next)
466			fwrite(bp->text, sizeof (char), BLOCKSIZE, fp);
467		fwrite(bp->text, sizeof (char), BLOCKSIZE - text->nleft, fp);
468	}
469}
470
471FILE *
472ckfopen(file, mode)
473	char *file;
474	char *mode;
475	{
476	FILE *fp;
477
478	if ((fp = fopen(file, mode)) == NULL) {
479		fprintf(stderr, "Can't open %s\n", file);
480		exit(2);
481	}
482	return fp;
483}
484
485void *
486ckmalloc(nbytes)
487	int nbytes;
488{
489	char *p;
490
491	if ((p = malloc(nbytes)) == NULL)
492		error("Out of space");
493	return p;
494}
495
496char *
497savestr(s)
498	char *s;
499	{
500	char *p;
501
502	p = ckmalloc(strlen(s) + 1);
503	strcpy(p, s);
504	return p;
505}
506
507void
508error(msg)
509	char *msg;
510	{
511	if (curfile != NULL)
512		fprintf(stderr, "%s:%d: ", curfile, linno);
513	fprintf(stderr, "%s\n", msg);
514	exit(2);
515}
516