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