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