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