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