1 /*-
2 * Copyright (c) 1991, 1993
3 * The Regents of the University of California. All rights reserved.
4 * Copyright (c) 1997-2005
5 * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Kenneth Almquist.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35 /*
36 * This program scans all the source files for code to handle various
37 * special events and combines this code into one file. This (allegedly)
38 * improves the structure of the program since there is no need for
39 * anyone outside of a module to know that that module performs special
40 * operations on particular events.
41 *
42 * Usage: mkinit sourcefile...
43 */
44
45
46 #include <sys/types.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <fcntl.h>
51 #include <unistd.h>
52
53
54 /*
55 * OUTFILE is the name of the output file. Output is initially written
56 * to the file OUTTEMP, which is then moved to OUTFILE.
57 */
58
59 #define OUTFILE "init.c"
60 #define OUTTEMP "init.c.new"
61
62
63 /*
64 * A text structure is basicly just a string that grows as more characters
65 * are added onto the end of it. It is implemented as a linked list of
66 * blocks of characters. The routines addstr and addchar append a string
67 * or a single character, respectively, to a text structure. Writetext
68 * writes the contents of a text structure to a file.
69 */
70
71 #define BLOCKSIZE 512
72
73 struct text {
74 char *nextc;
75 int nleft;
76 struct block *start;
77 struct block *last;
78 };
79
80 struct block {
81 struct block *next;
82 char text[BLOCKSIZE];
83 };
84
85
86 /*
87 * There is one event structure for each event that mkinit handles.
88 */
89
90 struct event {
91 char *name; /* name of event (e.g. INIT) */
92 char *routine; /* name of routine called on event */
93 char *comment; /* comment describing routine */
94 struct text code; /* code for handling event */
95 };
96
97
98 char writer[] = "\
99 /*\n\
100 * This file was generated by the mkinit program.\n\
101 */\n\
102 \n";
103
104 char init[] = "\
105 /*\n\
106 * Initialization code.\n\
107 */\n";
108
109 char exitreset[] = "\
110 /*\n\
111 * This routine is called when an error or an interrupt occurs in an\n\
112 * interactive shell and control is returned to the main command loop\n\
113 * but prior to exitshell. \n\
114 */\n";
115
116 char forkreset[] = "\
117 /*\n\
118 * This routine is called when we enter a subshell.\n\
119 */\n";
120
121 char reset[] = "\
122 /*\n\
123 * This routine is called when an error or an interrupt occurs in an\n\
124 * interactive shell and control is returned to the main command loop.\n\
125 */\n";
126
127
128 struct event event[] = {
129 {"INIT", "init", init},
130 {"EXITRESET", "exitreset", exitreset},
131 {"FORKRESET", "forkreset", forkreset},
132 {"RESET", "reset", reset},
133 {NULL, NULL}
134 };
135
136
137 char *curfile; /* current file */
138 int linno; /* current line */
139 char *header_files[200]; /* list of header files */
140 struct text defines; /* #define statements */
141 struct text decls; /* declarations */
142 int amiddecls; /* for formatting */
143
144
145 void readfile(char *);
146 int match(char *, char *);
147 int gooddefine(char *);
148 void doevent(struct event *, FILE *, char *);
149 void doinclude(char *);
150 void dodecl(char *, FILE *);
151 void output(void);
152 void addstr(char *, struct text *);
153 void addchar(int, struct text *);
154 void writetext(struct text *, FILE *);
155 FILE *ckfopen(char *, char *);
156 void *ckmalloc(int);
157 char *savestr(char *);
158 static void error(char *);
159 int main(int, char **);
160
161 #define equal(s1, s2) (strcmp(s1, s2) == 0)
162
163 int
main(int argc,char ** argv)164 main(int argc, char **argv)
165 {
166 char **ap;
167
168 header_files[0] = "\"shell.h\"";
169 header_files[1] = "\"mystring.h\"";
170 header_files[2] = "\"init.h\"";
171 for (ap = argv + 1 ; *ap ; ap++)
172 readfile(*ap);
173 output();
174 rename(OUTTEMP, OUTFILE);
175 exit(0);
176 /* NOTREACHED */
177 }
178
179
180 /*
181 * Parse an input file.
182 */
183
184 void
readfile(char * fname)185 readfile(char *fname)
186 {
187 FILE *fp;
188 char line[1024];
189 struct event *ep;
190
191 fp = ckfopen(fname, "r");
192 curfile = fname;
193 linno = 0;
194 amiddecls = 0;
195 while (fgets(line, sizeof line, fp) != NULL) {
196 linno++;
197 for (ep = event ; ep->name ; ep++) {
198 if (line[0] == ep->name[0] && match(ep->name, line)) {
199 doevent(ep, fp, fname);
200 break;
201 }
202 }
203 if (line[0] == 'I' && match("INCLUDE", line))
204 doinclude(line);
205 if (line[0] == 'M' && match("MKINIT", line))
206 dodecl(line, fp);
207 if (line[0] == '#' && gooddefine(line)) {
208 char *cp;
209 char line2[1024];
210 static const char undef[] = "#undef ";
211
212 strcpy(line2, line);
213 memcpy(line2, undef, sizeof(undef) - 1);
214 cp = line2 + sizeof(undef) - 1;
215 while(*cp && (*cp == ' ' || *cp == '\t'))
216 cp++;
217 while(*cp && *cp != ' ' && *cp != '\t' && *cp != '\n')
218 cp++;
219 *cp++ = '\n'; *cp = '\0';
220 addstr(line2, &defines);
221 addstr(line, &defines);
222 }
223 }
224 fclose(fp);
225 }
226
227
228 int
match(char * name,char * line)229 match(char *name, char *line)
230 {
231 char *p, *q;
232
233 p = name, q = line;
234 while (*p) {
235 if (*p++ != *q++)
236 return 0;
237 }
238 if (*q != '{' && *q != ' ' && *q != '\t' && *q != '\n')
239 return 0;
240 return 1;
241 }
242
243
244 int
gooddefine(char * line)245 gooddefine(char *line)
246 {
247 char *p;
248
249 if (! match("#define", line))
250 return 0; /* not a define */
251 p = line + 7;
252 while (*p == ' ' || *p == '\t')
253 p++;
254 while (*p != ' ' && *p != '\t') {
255 if (*p == '(')
256 return 0; /* macro definition */
257 p++;
258 }
259 while (*p != '\n' && *p != '\0')
260 p++;
261 if (p[-1] == '\\')
262 return 0; /* multi-line definition */
263 return 1;
264 }
265
266
267 void
doevent(struct event * ep,FILE * fp,char * fname)268 doevent(struct event *ep, FILE *fp, char *fname)
269 {
270 char line[1024];
271 int indent;
272 char *p;
273
274 sprintf(line, "\n /* from %s: */\n", fname);
275 addstr(line, &ep->code);
276 addstr(" {\n", &ep->code);
277 for (;;) {
278 linno++;
279 if (fgets(line, sizeof line, fp) == NULL)
280 error("Unexpected EOF");
281 if (equal(line, "}\n"))
282 break;
283 indent = 6;
284 for (p = line ; *p == '\t' ; p++)
285 indent += 8;
286 for ( ; *p == ' ' ; p++)
287 indent++;
288 if (*p == '\n' || *p == '#')
289 indent = 0;
290 while (indent >= 8) {
291 addchar('\t', &ep->code);
292 indent -= 8;
293 }
294 while (indent > 0) {
295 addchar(' ', &ep->code);
296 indent--;
297 }
298 addstr(p, &ep->code);
299 }
300 addstr(" }\n", &ep->code);
301 }
302
303
304 void
doinclude(char * line)305 doinclude(char *line)
306 {
307 char *p;
308 char *name;
309 char **pp;
310
311 for (p = line ; *p != '"' && *p != '<' && *p != '\0' ; p++);
312 if (*p == '\0')
313 error("Expecting '\"' or '<'");
314 name = p;
315 while (*p != ' ' && *p != '\t' && *p != '\n')
316 p++;
317 if (p[-1] != '"' && p[-1] != '>')
318 error("Missing terminator");
319 *p = '\0';
320
321 /* name now contains the name of the include file */
322 for (pp = header_files ; *pp && ! equal(*pp, name) ; pp++);
323 if (*pp == NULL)
324 *pp = savestr(name);
325 }
326
327
328 void
dodecl(char * line1,FILE * fp)329 dodecl(char *line1, FILE *fp)
330 {
331 char line[1024];
332 char *p, *q;
333
334 if (strcmp(line1, "MKINIT\n") == 0) { /* start of struct/union decl */
335 addchar('\n', &decls);
336 do {
337 linno++;
338 if (fgets(line, sizeof line, fp) == NULL)
339 error("Unterminated structure declaration");
340 addstr(line, &decls);
341 } while (line[0] != '}');
342 amiddecls = 0;
343 } else {
344 if (! amiddecls)
345 addchar('\n', &decls);
346 q = NULL;
347 for (p = line1 + 6 ; *p && strchr("=/\n", *p) == NULL; p++)
348 continue;
349 if (*p == '=') { /* eliminate initialization */
350 for (q = p ; *q && *q != ';' ; q++);
351 if (*q == '\0')
352 q = NULL;
353 else {
354 while (p[-1] == ' ')
355 p--;
356 *p = '\0';
357 }
358 }
359 addstr("extern", &decls);
360 addstr(line1 + 6, &decls);
361 if (q != NULL)
362 addstr(q, &decls);
363 amiddecls = 1;
364 }
365 }
366
367
368
369 /*
370 * Write the output to the file OUTTEMP.
371 */
372
373 void
output(void)374 output(void)
375 {
376 FILE *fp;
377 char **pp;
378 struct event *ep;
379
380 fp = ckfopen(OUTTEMP, "w");
381 fputs(writer, fp);
382 for (pp = header_files ; *pp ; pp++)
383 fprintf(fp, "#include %s\n", *pp);
384 fputs("\n\n\n", fp);
385 writetext(&defines, fp);
386 fputs("\n\n", fp);
387 writetext(&decls, fp);
388 for (ep = event ; ep->name ; ep++) {
389 fputs("\n\n\n", fp);
390 fputs(ep->comment, fp);
391 fprintf(fp, "\nvoid\n%s() {\n", ep->routine);
392 writetext(&ep->code, fp);
393 fprintf(fp, "}\n");
394 }
395 fclose(fp);
396 }
397
398
399 /*
400 * A text structure is simply a block of text that is kept in memory.
401 * Addstr appends a string to the text struct, and addchar appends a single
402 * character.
403 */
404
405 void
addstr(char * s,struct text * text)406 addstr(char *s, struct text *text)
407 {
408 while (*s) {
409 if (--text->nleft < 0)
410 addchar(*s++, text);
411 else
412 *text->nextc++ = *s++;
413 }
414 }
415
416
417 void
addchar(int c,struct text * text)418 addchar(int c, struct text *text)
419 {
420 struct block *bp;
421
422 if (--text->nleft < 0) {
423 bp = ckmalloc(sizeof *bp);
424 if (text->start == NULL)
425 text->start = bp;
426 else
427 text->last->next = bp;
428 text->last = bp;
429 text->nextc = bp->text;
430 text->nleft = BLOCKSIZE - 1;
431 }
432 *text->nextc++ = c;
433 }
434
435 /*
436 * Write the contents of a text structure to a file.
437 */
438 void
writetext(struct text * text,FILE * fp)439 writetext(struct text *text, FILE *fp)
440 {
441 struct block *bp;
442
443 if (text->start != NULL) {
444 for (bp = text->start ; bp != text->last ; bp = bp->next) {
445 if ((fwrite(bp->text, sizeof (char), BLOCKSIZE, fp)) != BLOCKSIZE)
446 error("Can't write data\n");
447 }
448 if ((fwrite(bp->text, sizeof (char), BLOCKSIZE - text->nleft, fp)) != (BLOCKSIZE - text->nleft))
449 error("Can't write data\n");
450 }
451 }
452
453 FILE *
ckfopen(char * file,char * mode)454 ckfopen(char *file, char *mode)
455 {
456 FILE *fp;
457
458 if ((fp = fopen(file, mode)) == NULL) {
459 fprintf(stderr, "Can't open %s\n", file);
460 exit(2);
461 }
462 return fp;
463 }
464
465 void *
ckmalloc(int nbytes)466 ckmalloc(int nbytes)
467 {
468 char *p;
469
470 if ((p = malloc(nbytes)) == NULL)
471 error("Out of space");
472 return p;
473 }
474
475 char *
savestr(char * s)476 savestr(char *s)
477 {
478 char *p;
479
480 p = ckmalloc(strlen(s) + 1);
481 strcpy(p, s);
482 return p;
483 }
484
485 static void
error(char * msg)486 error(char *msg)
487 {
488 if (curfile != NULL)
489 fprintf(stderr, "%s:%d: ", curfile, linno);
490 fprintf(stderr, "%s\n", msg);
491 exit(2);
492 /* NOTREACHED */
493 }
494