source: trunk/minix/commands/ash/mkinit.c@ 15

Last change on this file since 15 was 9, checked in by Mattia Monga, 14 years ago

Minix 3.1.2a

File size: 11.1 KB
Line 
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 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37#ifndef lint
38char copyright[] =
39"@(#) Copyright (c) 1991 The Regents of the University of California.\n\
40 All rights reserved.\n";
41#endif /* not lint */
42
43#ifndef lint
44static char sccsid[] = "@(#)mkinit.c 5.3 (Berkeley) 3/13/91";
45#endif /* not lint */
46
47/*
48 * This program scans all the source files for code to handle various
49 * special events and combines this code into one file. This (allegedly)
50 * improves the structure of the program since there is no need for
51 * anyone outside of a module to know that that module performs special
52 * operations on particular events. The command is executed iff init.c
53 * is actually changed.
54 *
55 * Usage: mkinit command sourcefile...
56 */
57
58
59#include <sys/cdefs.h>
60
61#include <sys/types.h>
62#include <stdio.h>
63#include <fcntl.h>
64
65
66/*
67 * OUTFILE is the name of the output file. Output is initially written
68 * to the file OUTTEMP, which is then moved to OUTFILE if OUTTEMP and
69 * OUTFILE are different.
70 */
71
72#define OUTFILE "init.c"
73#define OUTTEMP "init.c.new"
74#define OUTOBJ "init.o"
75
76
77/*
78 * A text structure is basicly just a string that grows as more characters
79 * are added onto the end of it. It is implemented as a linked list of
80 * blocks of characters. The routines addstr and addchar append a string
81 * or a single character, respectively, to a text structure. Writetext
82 * writes the contents of a text structure to a file.
83 */
84
85#define BLOCKSIZE 512
86
87struct text {
88 char *nextc;
89 int nleft;
90 struct block *start;
91 struct block *last;
92};
93
94struct block {
95 struct block *next;
96 char text[BLOCKSIZE];
97};
98
99
100/*
101 * There is one event structure for each event that mkinit handles.
102 */
103
104struct event {
105 char *name; /* name of event (e.g. INIT) */
106 char *routine; /* name of routine called on event */
107 char *comment; /* comment describing routine */
108 struct text code; /* code for handling event */
109};
110
111
112char writer[] = "\
113/*\n\
114 * This file was generated by the mkinit program.\n\
115 */\n\
116\n";
117
118char init[] = "\
119/*\n\
120 * Initialization code.\n\
121 */\n";
122
123char reset[] = "\
124/*\n\
125 * This routine is called when an error or an interrupt occurs in an\n\
126 * interactive shell and control is returned to the main command loop.\n\
127 */\n";
128
129char shellproc[] = "\
130/*\n\
131 * This routine is called to initialize the shell to run a shell procedure.\n\
132 */\n";
133
134
135struct event event[] = {
136 {"INIT", "init", init},
137 {"RESET", "reset", reset},
138 {"SHELLPROC", "initshellproc", shellproc},
139 {NULL, NULL}
140};
141
142
143char *curfile; /* current file */
144int linno; /* current line */
145char *header_files[200]; /* list of header files */
146struct text defines; /* #define statements */
147struct text decls; /* declarations */
148int amiddecls; /* for formatting */
149
150
151void readfile(), doevent(), doinclude(), dodecl(), output();
152void addstr(), addchar(), writetext();
153
154#define equal(s1, s2) (strcmp(s1, s2) == 0)
155
156FILE *ckfopen();
157char *savestr();
158void *ckmalloc __P((int));
159void error();
160
161main(argc, argv)
162 char **argv;
163 {
164 char **ap;
165 int fd;
166 char c;
167
168 if (argc < 2)
169 error("Usage: mkinit command file...");
170 header_files[0] = "\"shell.h\"";
171 header_files[1] = "\"mystring.h\"";
172 for (ap = argv + 2 ; *ap ; ap++)
173 readfile(*ap);
174 output();
175 if (file_changed()) {
176 unlink(OUTFILE);
177 link(OUTTEMP, OUTFILE);
178 unlink(OUTTEMP);
179 } else {
180 unlink(OUTTEMP);
181 if (touch(OUTOBJ))
182 exit(0); /* no compilation necessary */
183 }
184 printf("%s\n", argv[1]);
185 execl("/bin/sh", "sh", "-c", argv[1], (char *)0);
186 error("Can't exec shell");
187}
188
189
190/*
191 * Parse an input file.
192 */
193
194void
195readfile(fname)
196 char *fname;
197 {
198 FILE *fp;
199 char line[1024];
200 struct event *ep;
201
202 fp = ckfopen(fname, "r");
203 curfile = fname;
204 linno = 0;
205 amiddecls = 0;
206 while (fgets(line, sizeof line, fp) != NULL) {
207 linno++;
208 for (ep = event ; ep->name ; ep++) {
209 if (line[0] == ep->name[0] && match(ep->name, line)) {
210 doevent(ep, fp, fname);
211 break;
212 }
213 }
214 if (line[0] == 'I' && match("INCLUDE", line))
215 doinclude(line);
216 if (line[0] == 'M' && match("MKINIT", line))
217 dodecl(line, fp);
218 if (line[0] == '#' && gooddefine(line))
219 addstr(line, &defines);
220 }
221 fclose(fp);
222}
223
224
225int
226match(name, line)
227 char *name;
228 char *line;
229 {
230 register char *p, *q;
231
232 p = name, q = line;
233 while (*p) {
234 if (*p++ != *q++)
235 return 0;
236 }
237 if (*q != '{' && *q != ' ' && *q != '\t' && *q != '\n')
238 return 0;
239 return 1;
240}
241
242
243int
244gooddefine(line)
245 char *line;
246 {
247 register 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
267void
268doevent(ep, fp, fname)
269 register struct event *ep;
270 FILE *fp;
271 char *fname;
272 {
273 char line[1024];
274 int indent;
275 char *p;
276
277 sprintf(line, "\n /* from %s: */\n", fname);
278 addstr(line, &ep->code);
279 addstr(" {\n", &ep->code);
280 for (;;) {
281 linno++;
282 if (fgets(line, sizeof line, fp) == NULL)
283 error("Unexpected EOF");
284 if (equal(line, "}\n"))
285 break;
286 indent = 6;
287 for (p = line ; *p == '\t' ; p++)
288 indent += 8;
289 for ( ; *p == ' ' ; p++)
290 indent++;
291 if (*p == '\n' || *p == '#')
292 indent = 0;
293 while (indent >= 8) {
294 addchar('\t', &ep->code);
295 indent -= 8;
296 }
297 while (indent > 0) {
298 addchar(' ', &ep->code);
299 indent--;
300 }
301 addstr(p, &ep->code);
302 }
303 addstr(" }\n", &ep->code);
304}
305
306
307void
308doinclude(line)
309 char *line;
310 {
311 register char *p;
312 char *name;
313 register 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(line1, fp)
334 char *line1;
335 FILE *fp;
336 {
337 char line[1024];
338 register char *p, *q;
339
340 if (strcmp(line1, "MKINIT\n") == 0) { /* start of struct/union decl */
341 addchar('\n', &decls);
342 do {
343 linno++;
344 if (fgets(line, sizeof line, fp) == NULL)
345 error("Unterminated structure declaration");
346 addstr(line, &decls);
347 } while (line[0] != '}');
348 amiddecls = 0;
349 } else {
350 if (! amiddecls)
351 addchar('\n', &decls);
352 q = NULL;
353 for (p = line1 + 6 ; *p != '=' && *p != '/' ; p++);
354 if (*p == '=') { /* eliminate initialization */
355 for (q = p ; *q && *q != ';' ; q++);
356 if (*q == '\0')
357 q = NULL;
358 else {
359 while (p[-1] == ' ')
360 p--;
361 *p = '\0';
362 }
363 }
364 addstr("extern", &decls);
365 addstr(line1 + 6, &decls);
366 if (q != NULL)
367 addstr(q, &decls);
368 amiddecls = 1;
369 }
370}
371
372
373
374/*
375 * Write the output to the file OUTTEMP.
376 */
377
378void
379output() {
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() {\n", ep->routine);
396 writetext(&ep->code, fp);
397 fprintf(fp, "}\n");
398 }
399 fclose(fp);
400}
401
402
403/*
404 * Return true if the new output file is different from the old one.
405 */
406
407int
408file_changed() {
409 register FILE *f1, *f2;
410 register int c;
411
412 if ((f1 = fopen(OUTFILE, "r")) == NULL
413 || (f2 = fopen(OUTTEMP, "r")) == NULL)
414 return 1;
415 while ((c = getc(f1)) == getc(f2)) {
416 if (c == EOF)
417 return 0;
418 }
419 return 1;
420}
421
422
423/*
424 * Touch a file. Returns 0 on failure, 1 on success.
425 */
426
427int
428touch(file)
429 char *file;
430 {
431 int fd;
432 char c;
433
434 if ((fd = open(file, O_RDWR)) < 0)
435 return 0;
436 if (read(fd, &c, 1) != 1) {
437 close(fd);
438 return 0;
439 }
440 lseek(fd, 0L, 0);
441 write(fd, &c, 1);
442 close(fd);
443 return 1;
444}
445
446
447
448/*
449 * A text structure is simply a block of text that is kept in memory.
450 * Addstr appends a string to the text struct, and addchar appends a single
451 * character.
452 */
453
454void
455addstr(s, text)
456 register char *s;
457 register struct text *text;
458 {
459 while (*s) {
460 if (--text->nleft < 0)
461 addchar(*s++, text);
462 else
463 *text->nextc++ = *s++;
464 }
465}
466
467
468void
469addchar(c, text)
470 register struct text *text;
471 {
472 struct block *bp;
473
474 if (--text->nleft < 0) {
475 bp = ckmalloc(sizeof *bp);
476 if (text->start == NULL)
477 text->start = bp;
478 else
479 text->last->next = bp;
480 text->last = bp;
481 text->nextc = bp->text;
482 text->nleft = BLOCKSIZE - 1;
483 }
484 *text->nextc++ = c;
485}
486
487/*
488 * Write the contents of a text structure to a file.
489 */
490void
491writetext(text, fp)
492 struct text *text;
493 FILE *fp;
494 {
495 struct block *bp;
496
497 if (text->start != NULL) {
498 for (bp = text->start ; bp != text->last ; bp = bp->next)
499 fwrite(bp->text, sizeof (char), BLOCKSIZE, fp);
500 fwrite(bp->text, sizeof (char), BLOCKSIZE - text->nleft, fp);
501 }
502}
503
504FILE *
505ckfopen(file, mode)
506 char *file;
507 char *mode;
508 {
509 FILE *fp;
510
511 if ((fp = fopen(file, mode)) == NULL) {
512 fprintf(stderr, "Can't open %s\n", file);
513 exit(2);
514 }
515 return fp;
516}
517
518void *
519ckmalloc(nbytes) {
520 register char *p;
521 char *malloc();
522
523 if ((p = malloc(nbytes)) == NULL)
524 error("Out of space");
525 return p;
526}
527
528char *
529savestr(s)
530 char *s;
531 {
532 register char *p;
533
534 p = ckmalloc(strlen(s) + 1);
535 strcpy(p, s);
536 return p;
537}
538
539void
540error(msg)
541 char *msg;
542 {
543 if (curfile != NULL)
544 fprintf(stderr, "%s:%d: ", curfile, linno);
545 fprintf(stderr, "%s\n", msg);
546 exit(2);
547}
Note: See TracBrowser for help on using the repository browser.