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