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