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