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