]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - bin/sh/mkinit.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.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/cdefs.h>
59 #include <sys/types.h>
60 #include <stdio.h>
61 #include <stdlib.h>
62 #include <string.h>
63 #include <fcntl.h>
64 #include <unistd.h>
65 #include <errno.h>
66
67
68 /*
69  * OUTFILE is the name of the output file.  Output is initially written
70  * to the file OUTTEMP, which is then moved to OUTFILE.
71  */
72
73 #define OUTFILE "init.c"
74 #define OUTTEMP "init.c.new"
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
87 struct text {
88         char *nextc;
89         int nleft;
90         struct block *start;
91         struct block *last;
92 };
93
94 struct 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
104 struct 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
112 char writer[] = "\
113 /*\n\
114  * This file was generated by the mkinit program.\n\
115  */\n\
116 \n";
117
118 char init[] = "\
119 /*\n\
120  * Initialization code.\n\
121  */\n";
122
123 char 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
129 char shellproc[] = "\
130 /*\n\
131  * This routine is called to initialize the shell to run a shell procedure.\n\
132  */\n";
133
134
135 struct event event[] = {
136         { "INIT", "init", init, { NULL, 0, NULL, NULL } },
137         { "RESET", "reset", reset, { NULL, 0, NULL, NULL } },
138         { "SHELLPROC", "initshellproc", shellproc, { NULL, 0, NULL, NULL } },
139         { NULL, NULL, NULL, { NULL, 0, NULL, NULL } }
140 };
141
142
143 char *curfile;                          /* current file */
144 int linno;                              /* current line */
145 char *header_files[200];                /* list of header files */
146 struct text defines;                    /* #define statements */
147 struct text decls;                      /* declarations */
148 int amiddecls;                          /* for formatting */
149
150
151 void readfile(char *);
152 int match(char *, char *);
153 int gooddefine(char *);
154 void doevent(struct event *, FILE *, char *);
155 void doinclude(char *);
156 void dodecl(char *, FILE *);
157 void output(void);
158 void addstr(char *, struct text *);
159 void addchar(int, struct text *);
160 void writetext(struct text *, FILE *);
161 FILE *ckfopen(char *, char *);
162 void *ckmalloc(size_t);
163 char *savestr(char *);
164 void error(char *);
165
166 #define equal(s1, s2)   (strcmp(s1, s2) == 0)
167
168 int
169 main(int argc __unused, char *argv[])
170 {
171         char **ap;
172
173         header_files[0] = "\"shell.h\"";
174         header_files[1] = "\"mystring.h\"";
175         header_files[2] = "\"init.h\"";
176         for (ap = argv + 1 ; *ap ; ap++)
177                 readfile(*ap);
178         output();
179         rename(OUTTEMP, OUTFILE);
180         exit(0);
181 }
182
183
184 /*
185  * Parse an input file.
186  */
187
188 void
189 readfile(char *fname)
190 {
191         FILE *fp;
192         char line[1024];
193         struct event *ep;
194
195         fp = ckfopen(fname, "r");
196         curfile = fname;
197         linno = 0;
198         amiddecls = 0;
199         while (fgets(line, sizeof line, fp) != NULL) {
200                 linno++;
201                 for (ep = event ; ep->name ; ep++) {
202                         if (line[0] == ep->name[0] && match(ep->name, line)) {
203                                 doevent(ep, fp, fname);
204                                 break;
205                         }
206                 }
207                 if (line[0] == 'I' && match("INCLUDE", line))
208                         doinclude(line);
209                 if (line[0] == 'M' && match("MKINIT", line))
210                         dodecl(line, fp);
211                 if (line[0] == '#' && gooddefine(line)) {
212                         char *cp;
213                         char line2[1024];
214                         static const char undef[] = "#undef ";
215
216                         strcpy(line2, line);
217                         memcpy(line2, undef, sizeof(undef) - 1);
218                         cp = line2 + sizeof(undef) - 1;
219                         while(*cp && (*cp == ' ' || *cp == '\t'))
220                                 cp++;
221                         while(*cp && *cp != ' ' && *cp != '\t' && *cp != '\n')
222                                 cp++;
223                         *cp++ = '\n'; *cp = '\0';
224                         addstr(line2, &defines);
225                         addstr(line, &defines);
226                 }
227         }
228         fclose(fp);
229 }
230
231
232 int
233 match(char *name, char *line)
234 {
235         char *p, *q;
236
237         p = name, q = line;
238         while (*p) {
239                 if (*p++ != *q++)
240                         return 0;
241         }
242         if (*q != '{' && *q != ' ' && *q != '\t' && *q != '\n')
243                 return 0;
244         return 1;
245 }
246
247
248 int
249 gooddefine(char *line)
250 {
251         char *p;
252
253         if (! match("#define", line))
254                 return 0;                       /* not a define */
255         p = line + 7;
256         while (*p == ' ' || *p == '\t')
257                 p++;
258         while (*p != ' ' && *p != '\t') {
259                 if (*p == '(')
260                         return 0;               /* macro definition */
261                 p++;
262         }
263         while (*p != '\n' && *p != '\0')
264                 p++;
265         if (p[-1] == '\\')
266                 return 0;                       /* multi-line definition */
267         return 1;
268 }
269
270
271 void
272 doevent(struct event *ep, FILE *fp, char *fname)
273 {
274         char line[1024];
275         int indent;
276         char *p;
277
278         sprintf(line, "\n      /* from %s: */\n", fname);
279         addstr(line, &ep->code);
280         addstr("      {\n", &ep->code);
281         for (;;) {
282                 linno++;
283                 if (fgets(line, sizeof line, fp) == NULL)
284                         error("Unexpected EOF");
285                 if (equal(line, "}\n"))
286                         break;
287                 indent = 6;
288                 for (p = line ; *p == '\t' ; p++)
289                         indent += 8;
290                 for ( ; *p == ' ' ; p++)
291                         indent++;
292                 if (*p == '\n' || *p == '#')
293                         indent = 0;
294                 while (indent >= 8) {
295                         addchar('\t', &ep->code);
296                         indent -= 8;
297                 }
298                 while (indent > 0) {
299                         addchar(' ', &ep->code);
300                         indent--;
301                 }
302                 addstr(p, &ep->code);
303         }
304         addstr("      }\n", &ep->code);
305 }
306
307
308 void
309 doinclude(char *line)
310 {
311         char *p;
312         char *name;
313         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
332 void
333 dodecl(char *line1, FILE *fp)
334 {
335         char line[1024];
336         char *p, *q;
337
338         if (strcmp(line1, "MKINIT\n") == 0) { /* start of struct/union decl */
339                 addchar('\n', &decls);
340                 do {
341                         linno++;
342                         if (fgets(line, sizeof line, fp) == NULL)
343                                 error("Unterminated structure declaration");
344                         addstr(line, &decls);
345                 } while (line[0] != '}');
346                 amiddecls = 0;
347         } else {
348                 if (! amiddecls)
349                         addchar('\n', &decls);
350                 q = NULL;
351                 for (p = line1 + 6 ; *p && strchr("=/\n", *p) == NULL; p++)
352                         continue;
353                 if (*p == '=') {                /* eliminate initialization */
354                         for (q = p ; *q && *q != ';' ; q++);
355                         if (*q == '\0')
356                                 q = NULL;
357                         else {
358                                 while (p[-1] == ' ')
359                                         p--;
360                                 *p = '\0';
361                         }
362                 }
363                 addstr("extern", &decls);
364                 addstr(line1 + 6, &decls);
365                 if (q != NULL)
366                         addstr(q, &decls);
367                 amiddecls = 1;
368         }
369 }
370
371
372
373 /*
374  * Write the output to the file OUTTEMP.
375  */
376
377 void
378 output(void)
379 {
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(void)\n{\n", ep->routine);
396                 writetext(&ep->code, fp);
397                 fprintf(fp, "}\n");
398         }
399         fclose(fp);
400 }
401
402
403 /*
404  * A text structure is simply a block of text that is kept in memory.
405  * Addstr appends a string to the text struct, and addchar appends a single
406  * character.
407  */
408
409 void
410 addstr(char *s, struct text *text)
411 {
412         while (*s) {
413                 if (--text->nleft < 0)
414                         addchar(*s++, text);
415                 else
416                         *text->nextc++ = *s++;
417         }
418 }
419
420
421 void
422 addchar(int c, struct text *text)
423 {
424         struct block *bp;
425
426         if (--text->nleft < 0) {
427                 bp = ckmalloc(sizeof *bp);
428                 if (text->start == NULL)
429                         text->start = bp;
430                 else
431                         text->last->next = bp;
432                 text->last = bp;
433                 text->nextc = bp->text;
434                 text->nleft = BLOCKSIZE - 1;
435         }
436         *text->nextc++ = c;
437 }
438
439 /*
440  * Write the contents of a text structure to a file.
441  */
442 void
443 writetext(struct text *text, FILE *fp)
444 {
445         struct block *bp;
446
447         if (text->start != NULL) {
448                 for (bp = text->start ; bp != text->last ; bp = bp->next)
449                         fwrite(bp->text, sizeof (char), BLOCKSIZE, fp);
450                 fwrite(bp->text, sizeof (char), BLOCKSIZE - text->nleft, fp);
451         }
452 }
453
454 FILE *
455 ckfopen(char *file, char *mode)
456 {
457         FILE *fp;
458
459         if ((fp = fopen(file, mode)) == NULL) {
460                 fprintf(stderr, "Can't open %s: %s\n", file, strerror(errno));
461                 exit(2);
462         }
463         return fp;
464 }
465
466 void *
467 ckmalloc(size_t nbytes)
468 {
469         char *p;
470
471         if ((p = malloc(nbytes)) == NULL)
472                 error("Out of space");
473         return p;
474 }
475
476 char *
477 savestr(char *s)
478 {
479         char *p;
480
481         p = ckmalloc(strlen(s) + 1);
482         strcpy(p, s);
483         return p;
484 }
485
486 void
487 error(char *msg)
488 {
489         if (curfile != NULL)
490                 fprintf(stderr, "%s:%d: ", curfile, linno);
491         fprintf(stderr, "%s\n", msg);
492         exit(2);
493 }