mkinit.c revision 193221
1139790Simp/*-
26512Sphk * Copyright (c) 1991, 1993
33263Sdg *	The Regents of the University of California.  All rights reserved.
46512Sphk *
56512Sphk * This code is derived from software contributed to Berkeley by
63263Sdg * Kenneth Almquist.
73263Sdg *
88876Srgrimes * Redistribution and use in source and binary forms, with or without
98876Srgrimes * modification, are permitted provided that the following conditions
108876Srgrimes * are met:
113263Sdg * 1. Redistributions of source code must retain the above copyright
123263Sdg *    notice, this list of conditions and the following disclaimer.
133263Sdg * 2. Redistributions in binary form must reproduce the above copyright
143264Sdg *    notice, this list of conditions and the following disclaimer in the
1550477Speter *    documentation and/or other materials provided with the distribution.
163263Sdg * 4. Neither the name of the University nor the names of its contributors
173263Sdg *    may be used to endorse or promote products derived from this software
18215140Sjkim *    without specific prior written permission.
19215140Sjkim *
203263Sdg * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2155205Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2218444Sbde * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2318444Sbde * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2418444Sbde * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2518444Sbde * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
263263Sdg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
273263Sdg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2849197Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
293263Sdg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
303263Sdg * SUCH DAMAGE.
313263Sdg */
323263Sdg
333263Sdg#ifndef lint
343263Sdgstatic char const copyright[] =
353263Sdg"@(#) Copyright (c) 1991, 1993\n\
363263Sdg	The Regents of the University of California.  All rights reserved.\n";
373263Sdg#endif /* not lint */
383263Sdg
393263Sdg#ifndef lint
403263Sdg#if 0
413263Sdgstatic char sccsid[] = "@(#)mkinit.c	8.2 (Berkeley) 5/4/95";
423263Sdg#endif
433263Sdg#endif /* not lint */
443263Sdg#include <sys/cdefs.h>
453263Sdg__FBSDID("$FreeBSD: head/bin/sh/mkinit.c 193221 2009-06-01 10:50:17Z rse $");
463263Sdg
473263Sdg/*
483263Sdg * This program scans all the source files for code to handle various
493263Sdg * special events and combines this code into one file.  This (allegedly)
503263Sdg * improves the structure of the program since there is no need for
513263Sdg * anyone outside of a module to know that that module performs special
523263Sdg * operations on particular events.
533263Sdg *
543263Sdg * Usage:  mkinit sourcefile...
553263Sdg */
563263Sdg
5737414Simp
5837414Simp#include <sys/cdefs.h>
5937414Simp#include <sys/types.h>
6037414Simp#include <stdio.h>
613263Sdg#include <stdlib.h>
623263Sdg#include <string.h>
633263Sdg#include <fcntl.h>
643263Sdg#include <unistd.h>
653263Sdg#include <errno.h>
663263Sdg
673263Sdg
683263Sdg/*
693263Sdg * OUTFILE is the name of the output file.  Output is initially written
703263Sdg * to the file OUTTEMP, which is then moved to OUTFILE.
713263Sdg */
723263Sdg
733263Sdg#define OUTFILE "init.c"
743263Sdg#define OUTTEMP "init.c.new"
753263Sdg
763263Sdg
773263Sdg/*
783263Sdg * A text structure is basicly just a string that grows as more characters
793263Sdg * are added onto the end of it.  It is implemented as a linked list of
803263Sdg * blocks of characters.  The routines addstr and addchar append a string
813263Sdg * or a single character, respectively, to a text structure.  Writetext
823263Sdg * writes the contents of a text structure to a file.
833263Sdg */
843263Sdg
8564251Siwasaki#define BLOCKSIZE 512
863263Sdg
873263Sdgstruct text {
883263Sdg	char *nextc;
893263Sdg	int nleft;
903263Sdg	struct block *start;
913263Sdg	struct block *last;
923263Sdg};
933263Sdg
943263Sdgstruct block {
953263Sdg	struct block *next;
963263Sdg	char text[BLOCKSIZE];
973263Sdg};
983263Sdg
993263Sdg
1003263Sdg/*
1013263Sdg * There is one event structure for each event that mkinit handles.
1023263Sdg */
1033263Sdg
1043263Sdgstruct event {
1053263Sdg	char *name;		/* name of event (e.g. INIT) */
1063263Sdg	char *routine;		/* name of routine called on event */
1073263Sdg	char *comment;		/* comment describing routine */
10864615Sume	struct text code;	/* code for handling event */
10964615Sume};
11064615Sume
11164615Sume
11264615Sumechar writer[] = "\
11364615Sume/*\n\
1143263Sdg * This file was generated by the mkinit program.\n\
1153263Sdg */\n\
1163263Sdg\n";
1173263Sdg
1183263Sdgchar init[] = "\
1193263Sdg/*\n\
1203263Sdg * Initialization code.\n\
1213263Sdg */\n";
1223263Sdg
1233263Sdgchar reset[] = "\
1243263Sdg/*\n\
1253263Sdg * This routine is called when an error or an interrupt occurs in an\n\
1263263Sdg * interactive shell and control is returned to the main command loop.\n\
1273263Sdg */\n";
1283263Sdg
1296512Sphkchar shellproc[] = "\
1303263Sdg/*\n\
1313263Sdg * This routine is called to initialize the shell to run a shell procedure.\n\
1326512Sphk */\n";
1336512Sphk
13492761Salfred
1356512Sphkstruct event event[] = {
1366512Sphk	{ "INIT", "init", init, { NULL, 0, NULL, NULL } },
1376512Sphk	{ "RESET", "reset", reset, { NULL, 0, NULL, NULL } },
1386512Sphk	{ "SHELLPROC", "initshellproc", shellproc, { NULL, 0, NULL, NULL } },
1396512Sphk	{ NULL, NULL, NULL, { NULL, 0, NULL, NULL } }
1406512Sphk};
1416512Sphk
1426512Sphk
1433263Sdgchar *curfile;				/* current file */
14455205Speterint linno;				/* current line */
14537414Simpchar *header_files[200];		/* list of header files */
14637414Simpstruct text defines;			/* #define statements */
1476512Sphkstruct text decls;			/* declarations */
1486512Sphkint amiddecls;				/* for formatting */
1493263Sdg
1503263Sdg
1513263Sdgvoid readfile(char *);
15255205Speterint match(char *, char *);
15337414Simpint gooddefine(char *);
1546512Sphkvoid doevent(struct event *, FILE *, char *);
1553263Sdgvoid doinclude(char *);
1563263Sdgvoid dodecl(char *, FILE *);
1573263Sdgvoid output(void);
1583263Sdgvoid addstr(char *, struct text *);
1593263Sdgvoid addchar(int, struct text *);
1603263Sdgvoid writetext(struct text *, FILE *);
1613263SdgFILE *ckfopen(char *, char *);
1623263Sdgvoid *ckmalloc(size_t);
1633263Sdgchar *savestr(char *);
1643263Sdgvoid error(char *);
1653263Sdg
1663263Sdg#define equal(s1, s2)	(strcmp(s1, s2) == 0)
1673263Sdg
1683263Sdgint
1693263Sdgmain(int argc __unused, char *argv[])
1703263Sdg{
1713263Sdg	char **ap;
1723263Sdg
17337414Simp	header_files[0] = "\"shell.h\"";
17437414Simp	header_files[1] = "\"mystring.h\"";
1753263Sdg	header_files[2] = "\"init.h\"";
1763263Sdg	for (ap = argv + 1 ; *ap ; ap++)
1773263Sdg		readfile(*ap);
1783263Sdg	output();
1793263Sdg	rename(OUTTEMP, OUTFILE);
1806512Sphk	exit(0);
1813263Sdg}
18231126Sjdp
18331126Sjdp
18431126Sjdp/*
18531126Sjdp * Parse an input file.
18631126Sjdp */
1873263Sdg
1883263Sdgvoid
1893263Sdgreadfile(char *fname)
1903263Sdg{
1913263Sdg	FILE *fp;
19214608Snate	char line[1024];
19331126Sjdp	struct event *ep;
19431126Sjdp
19531126Sjdp	fp = ckfopen(fname, "r");
19631126Sjdp	curfile = fname;
19731126Sjdp	linno = 0;
19831126Sjdp	amiddecls = 0;
19931126Sjdp	while (fgets(line, sizeof line, fp) != NULL) {
20031126Sjdp		linno++;
20131126Sjdp		for (ep = event ; ep->name ; ep++) {
20231126Sjdp			if (line[0] == ep->name[0] && match(ep->name, line)) {
20331126Sjdp				doevent(ep, fp, fname);
20431126Sjdp				break;
20531126Sjdp			}
20631126Sjdp		}
20731126Sjdp		if (line[0] == 'I' && match("INCLUDE", line))
20831126Sjdp			doinclude(line);
20931126Sjdp		if (line[0] == 'M' && match("MKINIT", line))
21037414Simp			dodecl(line, fp);
21137414Simp		if (line[0] == '#' && gooddefine(line)) {
21237414Simp			char *cp;
2133263Sdg			char line2[1024];
2143263Sdg			static const char undef[] = "#undef ";
21564615Sume
21664615Sume			strcpy(line2, line);
21764615Sume			memcpy(line2, undef, sizeof(undef) - 1);
21864615Sume			cp = line2 + sizeof(undef) - 1;
21964615Sume			while(*cp && (*cp == ' ' || *cp == '\t'))
22064615Sume			        cp++;
22164615Sume			while(*cp && *cp != ' ' && *cp != '\t' && *cp != '\n')
22264615Sume			        cp++;
22364615Sume			*cp++ = '\n'; *cp = '\0';
22464615Sume			addstr(line2, &defines);
22564615Sume			addstr(line, &defines);
22664615Sume		}
22764615Sume	}
22864615Sume	fclose(fp);
22964615Sume}
23064615Sume
23164615Sume
23249292Smsmithint
233197536Sjkimmatch(char *name, char *line)
234197536Sjkim{
235197536Sjkim	char *p, *q;
236197536Sjkim
237197536Sjkim	p = name, q = line;
238197536Sjkim	while (*p) {
23949292Smsmith		if (*p++ != *q++)
24049292Smsmith			return 0;
24149197Smsmith	}
24249197Smsmith	if (*q != '{' && *q != ' ' && *q != '\t' && *q != '\n')
24348735Siwasaki		return 0;
24448735Siwasaki	return 1;
24548735Siwasaki}
24648735Siwasaki
2473263Sdg
24831126Sjdpint
2493263Sdggooddefine(char *line)
2503263Sdg{
2513263Sdg	char *p;
2523263Sdg
25321362Snate	if (! match("#define", line))
25449292Smsmith		return 0;			/* not a define */
25531126Sjdp	p = line + 7;
25637414Simp	while (*p == ' ' || *p == '\t')
25764615Sume		p++;
25848735Siwasaki	while (*p != ' ' && *p != '\t') {
25948735Siwasaki		if (*p == '(')
26048735Siwasaki			return 0;		/* macro definition */
2613263Sdg		p++;
2626512Sphk	}
2633263Sdg	while (*p != '\n' && *p != '\0')
264215140Sjkim		p++;
265	if (p[-1] == '\\')
266		return 0;			/* multi-line definition */
267	return 1;
268}
269
270
271void
272doevent(struct event *ep, FILE *fp, char *fname)
273{
274	char line[1024];
275	int indent;
276	char *p;
277
278	sprintf(line, "\n      /* from %s: */\n", fname);
279	addstr(line, &ep->code);
280	addstr("      {\n", &ep->code);
281	for (;;) {
282		linno++;
283		if (fgets(line, sizeof line, fp) == NULL)
284			error("Unexpected EOF");
285		if (equal(line, "}\n"))
286			break;
287		indent = 6;
288		for (p = line ; *p == '\t' ; p++)
289			indent += 8;
290		for ( ; *p == ' ' ; p++)
291			indent++;
292		if (*p == '\n' || *p == '#')
293			indent = 0;
294		while (indent >= 8) {
295			addchar('\t', &ep->code);
296			indent -= 8;
297		}
298		while (indent > 0) {
299			addchar(' ', &ep->code);
300			indent--;
301		}
302		addstr(p, &ep->code);
303	}
304	addstr("      }\n", &ep->code);
305}
306
307
308void
309doinclude(char *line)
310{
311	char *p;
312	char *name;
313	char **pp;
314
315	for (p = line ; *p != '"' && *p != '<' && *p != '\0' ; p++);
316	if (*p == '\0')
317		error("Expecting '\"' or '<'");
318	name = p;
319	while (*p != ' ' && *p != '\t' && *p != '\n')
320		p++;
321	if (p[-1] != '"' && p[-1] != '>')
322		error("Missing terminator");
323	*p = '\0';
324
325	/* name now contains the name of the include file */
326	for (pp = header_files ; *pp && ! equal(*pp, name) ; pp++);
327	if (*pp == NULL)
328		*pp = savestr(name);
329}
330
331
332void
333dodecl(char *line1, FILE *fp)
334{
335	char line[1024];
336	char *p, *q;
337
338	if (strcmp(line1, "MKINIT\n") == 0) { /* start of struct/union decl */
339		addchar('\n', &decls);
340		do {
341			linno++;
342			if (fgets(line, sizeof line, fp) == NULL)
343				error("Unterminated structure declaration");
344			addstr(line, &decls);
345		} while (line[0] != '}');
346		amiddecls = 0;
347	} else {
348		if (! amiddecls)
349			addchar('\n', &decls);
350		q = NULL;
351		for (p = line1 + 6 ; *p && strchr("=/\n", *p) == NULL; p++)
352			continue;
353		if (*p == '=') {		/* eliminate initialization */
354			for (q = p ; *q && *q != ';' ; q++);
355			if (*q == '\0')
356				q = NULL;
357			else {
358				while (p[-1] == ' ')
359					p--;
360				*p = '\0';
361			}
362		}
363		addstr("extern", &decls);
364		addstr(line1 + 6, &decls);
365		if (q != NULL)
366			addstr(q, &decls);
367		amiddecls = 1;
368	}
369}
370
371
372
373/*
374 * Write the output to the file OUTTEMP.
375 */
376
377void
378output(void)
379{
380	FILE *fp;
381	char **pp;
382	struct event *ep;
383
384	fp = ckfopen(OUTTEMP, "w");
385	fputs(writer, fp);
386	for (pp = header_files ; *pp ; pp++)
387		fprintf(fp, "#include %s\n", *pp);
388	fputs("\n\n\n", fp);
389	writetext(&defines, fp);
390	fputs("\n\n", fp);
391	writetext(&decls, fp);
392	for (ep = event ; ep->name ; ep++) {
393		fputs("\n\n\n", fp);
394		fputs(ep->comment, fp);
395		fprintf(fp, "\nvoid\n%s(void)\n{\n", ep->routine);
396		writetext(&ep->code, fp);
397		fprintf(fp, "}\n");
398	}
399	fclose(fp);
400}
401
402
403/*
404 * A text structure is simply a block of text that is kept in memory.
405 * Addstr appends a string to the text struct, and addchar appends a single
406 * character.
407 */
408
409void
410addstr(char *s, struct text *text)
411{
412	while (*s) {
413		if (--text->nleft < 0)
414			addchar(*s++, text);
415		else
416			*text->nextc++ = *s++;
417	}
418}
419
420
421void
422addchar(int c, struct text *text)
423{
424	struct block *bp;
425
426	if (--text->nleft < 0) {
427		bp = ckmalloc(sizeof *bp);
428		if (text->start == NULL)
429			text->start = bp;
430		else
431			text->last->next = bp;
432		text->last = bp;
433		text->nextc = bp->text;
434		text->nleft = BLOCKSIZE - 1;
435	}
436	*text->nextc++ = c;
437}
438
439/*
440 * Write the contents of a text structure to a file.
441 */
442void
443writetext(struct text *text, FILE *fp)
444{
445	struct block *bp;
446
447	if (text->start != NULL) {
448		for (bp = text->start ; bp != text->last ; bp = bp->next)
449			fwrite(bp->text, sizeof (char), BLOCKSIZE, fp);
450		fwrite(bp->text, sizeof (char), BLOCKSIZE - text->nleft, fp);
451	}
452}
453
454FILE *
455ckfopen(char *file, char *mode)
456{
457	FILE *fp;
458
459	if ((fp = fopen(file, mode)) == NULL) {
460		fprintf(stderr, "Can't open %s: %s\n", file, strerror(errno));
461		exit(2);
462	}
463	return fp;
464}
465
466void *
467ckmalloc(size_t nbytes)
468{
469	char *p;
470
471	if ((p = malloc(nbytes)) == NULL)
472		error("Out of space");
473	return p;
474}
475
476char *
477savestr(char *s)
478{
479	char *p;
480
481	p = ckmalloc(strlen(s) + 1);
482	strcpy(p, s);
483	return p;
484}
485
486void
487error(char *msg)
488{
489	if (curfile != NULL)
490		fprintf(stderr, "%s:%d: ", curfile, linno);
491	fprintf(stderr, "%s\n", msg);
492	exit(2);
493}
494