mkinit.c

Go to the documentation of this file.
00001 /*-
00002  * Copyright (c) 1991 The Regents of the University of California.
00003  * All rights reserved.
00004  *
00005  * This code is derived from software contributed to Berkeley by
00006  * Kenneth Almquist.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions
00010  * are met:
00011  * 1. Redistributions of source code must retain the above copyright
00012  *    notice, this list of conditions and the following disclaimer.
00013  * 2. Redistributions in binary form must reproduce the above copyright
00014  *    notice, this list of conditions and the following disclaimer in the
00015  *    documentation and/or other materials provided with the distribution.
00016  * 3. All advertising materials mentioning features or use of this software
00017  *    must display the following acknowledgement:
00018  *      This product includes software developed by the University of
00019  *      California, Berkeley and its contributors.
00020  * 4. Neither the name of the University nor the names of its contributors
00021  *    may be used to endorse or promote products derived from this software
00022  *    without specific prior written permission.
00023  *
00024  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00025  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00026  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00027  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00028  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00029  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00030  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00031  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00032  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00033  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00034  * SUCH DAMAGE.
00035  */
00036 
00037 #ifndef lint
00038 char copyright[] =
00039 "@(#) Copyright (c) 1991 The Regents of the University of California.\n\
00040  All rights reserved.\n";
00041 #endif /* not lint */
00042 
00043 #ifndef lint
00044 static char sccsid[] = "@(#)mkinit.c    5.3 (Berkeley) 3/13/91";
00045 #endif /* not lint */
00046 
00047 /*
00048  * This program scans all the source files for code to handle various
00049  * special events and combines this code into one file.  This (allegedly)
00050  * improves the structure of the program since there is no need for
00051  * anyone outside of a module to know that that module performs special
00052  * operations on particular events.  The command is executed iff init.c
00053  * is actually changed.
00054  *
00055  * Usage:  mkinit command sourcefile...
00056  */
00057 
00058 
00059 #include <sys/cdefs.h>
00060 
00061 #include <sys/types.h>
00062 #include <stdio.h>
00063 #include <fcntl.h>
00064 
00065 
00066 /*
00067  * OUTFILE is the name of the output file.  Output is initially written
00068  * to the file OUTTEMP, which is then moved to OUTFILE if OUTTEMP and
00069  * OUTFILE are different.
00070  */
00071 
00072 #define OUTFILE "init.c"
00073 #define OUTTEMP "init.c.new"
00074 #define OUTOBJ "init.o"
00075 
00076 
00077 /*
00078  * A text structure is basicly just a string that grows as more characters
00079  * are added onto the end of it.  It is implemented as a linked list of
00080  * blocks of characters.  The routines addstr and addchar append a string
00081  * or a single character, respectively, to a text structure.  Writetext
00082  * writes the contents of a text structure to a file.
00083  */
00084 
00085 #define BLOCKSIZE 512
00086 
00087 struct text {
00088         char *nextc;
00089         int nleft;
00090         struct block *start;
00091         struct block *last;
00092 };      
00093 
00094 struct block {
00095         struct block *next;
00096         char text[BLOCKSIZE];
00097 };
00098 
00099 
00100 /*
00101  * There is one event structure for each event that mkinit handles.
00102  */
00103 
00104 struct event {
00105         char *name;             /* name of event (e.g. INIT) */
00106         char *routine;          /* name of routine called on event */
00107         char *comment;          /* comment describing routine */
00108         struct text code;               /* code for handling event */
00109 };
00110 
00111 
00112 char writer[] = "\
00113 /*\n\
00114  * This file was generated by the mkinit program.\n\
00115  */\n\
00116 \n";
00117 
00118 char init[] = "\
00119 /*\n\
00120  * Initialization code.\n\
00121  */\n";
00122 
00123 char reset[] = "\
00124 /*\n\
00125  * This routine is called when an error or an interrupt occurs in an\n\
00126  * interactive shell and control is returned to the main command loop.\n\
00127  */\n";
00128 
00129 char shellproc[] = "\
00130 /*\n\
00131  * This routine is called to initialize the shell to run a shell procedure.\n\
00132  */\n";
00133 
00134 
00135 struct event event[] = {
00136         {"INIT", "init", init},
00137         {"RESET", "reset", reset},
00138         {"SHELLPROC", "initshellproc", shellproc},
00139         {NULL, NULL}
00140 };
00141 
00142 
00143 char *curfile;                          /* current file */
00144 int linno;                              /* current line */
00145 char *header_files[200];                /* list of header files */
00146 struct text defines;                    /* #define statements */
00147 struct text decls;                      /* declarations */
00148 int amiddecls;                          /* for formatting */
00149 
00150 
00151 void readfile(), doevent(), doinclude(), dodecl(), output();
00152 void addstr(), addchar(), writetext();
00153 
00154 #define equal(s1, s2)   (strcmp(s1, s2) == 0)
00155 
00156 FILE *ckfopen();
00157 char *savestr();
00158 void *ckmalloc __P((int));
00159 void error();
00160 
00161 main(argc, argv)
00162         char **argv;
00163         {
00164         char **ap;
00165         int fd;
00166         char c;
00167 
00168         if (argc < 2)
00169                 error("Usage:  mkinit command file...");
00170         header_files[0] = "\"shell.h\"";
00171         header_files[1] = "\"mystring.h\"";
00172         for (ap = argv + 2 ; *ap ; ap++)
00173                 readfile(*ap);
00174         output();
00175         if (file_changed()) {
00176                 unlink(OUTFILE);
00177                 link(OUTTEMP, OUTFILE);
00178                 unlink(OUTTEMP);
00179         } else {
00180                 unlink(OUTTEMP);
00181                 if (touch(OUTOBJ))
00182                         exit(0);                /* no compilation necessary */
00183         }
00184         printf("%s\n", argv[1]);
00185         execl("/bin/sh", "sh", "-c", argv[1], (char *)0);
00186         error("Can't exec shell");
00187 }
00188 
00189 
00190 /*
00191  * Parse an input file.
00192  */
00193 
00194 void
00195 readfile(fname)
00196         char *fname;
00197         {
00198         FILE *fp;
00199         char line[1024];
00200         struct event *ep;
00201 
00202         fp = ckfopen(fname, "r");
00203         curfile = fname;
00204         linno = 0;
00205         amiddecls = 0;
00206         while (fgets(line, sizeof line, fp) != NULL) {
00207                 linno++;
00208                 for (ep = event ; ep->name ; ep++) {
00209                         if (line[0] == ep->name[0] && match(ep->name, line)) {
00210                                 doevent(ep, fp, fname);
00211                                 break;
00212                         }
00213                 }
00214                 if (line[0] == 'I' && match("INCLUDE", line))
00215                         doinclude(line);
00216                 if (line[0] == 'M' && match("MKINIT", line))
00217                         dodecl(line, fp);
00218                 if (line[0] == '#' && gooddefine(line))
00219                         addstr(line, &defines);
00220         }
00221         fclose(fp);
00222 }
00223 
00224 
00225 int
00226 match(name, line)
00227         char *name;
00228         char *line;
00229         {
00230         register char *p, *q;
00231 
00232         p = name, q = line;
00233         while (*p) {
00234                 if (*p++ != *q++)
00235                         return 0;
00236         }
00237         if (*q != '{' && *q != ' ' && *q != '\t' && *q != '\n')
00238                 return 0;
00239         return 1;
00240 }
00241 
00242 
00243 int
00244 gooddefine(line)
00245         char *line;
00246         {
00247         register char *p;
00248 
00249         if (! match("#define", line))
00250                 return 0;                       /* not a define */
00251         p = line + 7;
00252         while (*p == ' ' || *p == '\t')
00253                 p++;
00254         while (*p != ' ' && *p != '\t') {
00255                 if (*p == '(')
00256                         return 0;               /* macro definition */
00257                 p++;
00258         }
00259         while (*p != '\n' && *p != '\0')
00260                 p++;
00261         if (p[-1] == '\\')
00262                 return 0;                       /* multi-line definition */
00263         return 1;
00264 }
00265 
00266 
00267 void
00268 doevent(ep, fp, fname)
00269         register struct event *ep;
00270         FILE *fp;
00271         char *fname;
00272         {
00273         char line[1024];
00274         int indent;
00275         char *p;
00276 
00277         sprintf(line, "\n      /* from %s: */\n", fname);
00278         addstr(line, &ep->code);
00279         addstr("      {\n", &ep->code);
00280         for (;;) {
00281                 linno++;
00282                 if (fgets(line, sizeof line, fp) == NULL)
00283                         error("Unexpected EOF");
00284                 if (equal(line, "}\n"))
00285                         break;
00286                 indent = 6;
00287                 for (p = line ; *p == '\t' ; p++)
00288                         indent += 8;
00289                 for ( ; *p == ' ' ; p++)
00290                         indent++;
00291                 if (*p == '\n' || *p == '#')
00292                         indent = 0;
00293                 while (indent >= 8) {
00294                         addchar('\t', &ep->code);
00295                         indent -= 8;
00296                 }
00297                 while (indent > 0) {
00298                         addchar(' ', &ep->code);
00299                         indent--;
00300                 }
00301                 addstr(p, &ep->code);
00302         }
00303         addstr("      }\n", &ep->code);
00304 }
00305 
00306 
00307 void
00308 doinclude(line)
00309         char *line;
00310         {
00311         register char *p;
00312         char *name;
00313         register char **pp;
00314 
00315         for (p = line ; *p != '"' && *p != '<' && *p != '\0' ; p++);
00316         if (*p == '\0')
00317                 error("Expecting '\"' or '<'");
00318         name = p;
00319         while (*p != ' ' && *p != '\t' && *p != '\n')
00320                 p++;
00321         if (p[-1] != '"' && p[-1] != '>')
00322                 error("Missing terminator");
00323         *p = '\0';
00324 
00325         /* name now contains the name of the include file */
00326         for (pp = header_files ; *pp && ! equal(*pp, name) ; pp++);
00327         if (*pp == NULL)
00328                 *pp = savestr(name);
00329 }
00330 
00331 
00332 void
00333 dodecl(line1, fp)
00334         char *line1;
00335         FILE *fp;
00336         {
00337         char line[1024];
00338         register char *p, *q;
00339 
00340         if (strcmp(line1, "MKINIT\n") == 0) { /* start of struct/union decl */
00341                 addchar('\n', &decls);
00342                 do {
00343                         linno++;
00344                         if (fgets(line, sizeof line, fp) == NULL)
00345                                 error("Unterminated structure declaration");
00346                         addstr(line, &decls);
00347                 } while (line[0] != '}');
00348                 amiddecls = 0;
00349         } else {
00350                 if (! amiddecls)
00351                         addchar('\n', &decls);
00352                 q = NULL;
00353                 for (p = line1 + 6 ; *p != '=' && *p != '/' ; p++);
00354                 if (*p == '=') {                /* eliminate initialization */
00355                         for (q = p ; *q && *q != ';' ; q++);
00356                         if (*q == '\0')
00357                                 q = NULL;
00358                         else {
00359                                 while (p[-1] == ' ')
00360                                         p--;
00361                                 *p = '\0';
00362                         }
00363                 }
00364                 addstr("extern", &decls);
00365                 addstr(line1 + 6, &decls);
00366                 if (q != NULL)
00367                         addstr(q, &decls);
00368                 amiddecls = 1;
00369         }
00370 }
00371 
00372 
00373 
00374 /*
00375  * Write the output to the file OUTTEMP.
00376  */
00377 
00378 void
00379 output() {
00380         FILE *fp;
00381         char **pp;
00382         struct event *ep;
00383 
00384         fp = ckfopen(OUTTEMP, "w");
00385         fputs(writer, fp);
00386         for (pp = header_files ; *pp ; pp++)
00387                 fprintf(fp, "#include %s\n", *pp);
00388         fputs("\n\n\n", fp);
00389         writetext(&defines, fp);
00390         fputs("\n\n", fp);
00391         writetext(&decls, fp);
00392         for (ep = event ; ep->name ; ep++) {
00393                 fputs("\n\n\n", fp);
00394                 fputs(ep->comment, fp);
00395                 fprintf(fp, "\nvoid\n%s() {\n", ep->routine);
00396                 writetext(&ep->code, fp);
00397                 fprintf(fp, "}\n");
00398         }
00399         fclose(fp);
00400 }
00401 
00402 
00403 /*
00404  * Return true if the new output file is different from the old one.
00405  */
00406 
00407 int
00408 file_changed() {
00409         register FILE *f1, *f2;
00410         register int c;
00411 
00412         if ((f1 = fopen(OUTFILE, "r")) == NULL
00413          || (f2 = fopen(OUTTEMP, "r")) == NULL)
00414                 return 1;
00415         while ((c = getc(f1)) == getc(f2)) {
00416                 if (c == EOF)
00417                         return 0;
00418         }
00419         return 1;
00420 }
00421 
00422 
00423 /*
00424  * Touch a file.  Returns 0 on failure, 1 on success.
00425  */
00426 
00427 int
00428 touch(file)
00429         char *file;
00430         {
00431         int fd;
00432         char c;
00433 
00434         if ((fd = open(file, O_RDWR)) < 0)
00435                 return 0;
00436         if (read(fd, &c, 1) != 1) {
00437                 close(fd);
00438                 return 0;
00439         }
00440         lseek(fd, 0L, 0);
00441         write(fd, &c, 1);
00442         close(fd);
00443         return 1;
00444 }
00445 
00446 
00447 
00448 /*
00449  * A text structure is simply a block of text that is kept in memory.
00450  * Addstr appends a string to the text struct, and addchar appends a single
00451  * character.
00452  */
00453 
00454 void
00455 addstr(s, text)
00456         register char *s;
00457         register struct text *text;
00458         {
00459         while (*s) {
00460                 if (--text->nleft < 0)
00461                         addchar(*s++, text);
00462                 else
00463                         *text->nextc++ = *s++;
00464         }
00465 }
00466 
00467 
00468 void
00469 addchar(c, text)
00470         register struct text *text;
00471         {
00472         struct block *bp;
00473 
00474         if (--text->nleft < 0) {
00475                 bp = ckmalloc(sizeof *bp);
00476                 if (text->start == NULL)
00477                         text->start = bp;
00478                 else
00479                         text->last->next = bp;
00480                 text->last = bp;
00481                 text->nextc = bp->text;
00482                 text->nleft = BLOCKSIZE - 1;
00483         }
00484         *text->nextc++ = c;
00485 }
00486 
00487 /*
00488  * Write the contents of a text structure to a file.
00489  */
00490 void
00491 writetext(text, fp)
00492         struct text *text;
00493         FILE *fp;
00494         {
00495         struct block *bp;
00496 
00497         if (text->start != NULL) {
00498                 for (bp = text->start ; bp != text->last ; bp = bp->next)
00499                         fwrite(bp->text, sizeof (char), BLOCKSIZE, fp);
00500                 fwrite(bp->text, sizeof (char), BLOCKSIZE - text->nleft, fp);
00501         }
00502 }
00503 
00504 FILE *
00505 ckfopen(file, mode)
00506         char *file;
00507         char *mode;
00508         {
00509         FILE *fp;
00510 
00511         if ((fp = fopen(file, mode)) == NULL) {
00512                 fprintf(stderr, "Can't open %s\n", file);
00513                 exit(2);
00514         }
00515         return fp;
00516 }
00517 
00518 void *
00519 ckmalloc(nbytes) {
00520         register char *p;
00521         char *malloc();
00522 
00523         if ((p = malloc(nbytes)) == NULL)
00524                 error("Out of space");
00525         return p;
00526 }
00527 
00528 char *
00529 savestr(s)
00530         char *s;
00531         {
00532         register char *p;
00533 
00534         p = ckmalloc(strlen(s) + 1);
00535         strcpy(p, s);
00536         return p;
00537 }
00538 
00539 void
00540 error(msg)
00541         char *msg;
00542         {
00543         if (curfile != NULL)
00544                 fprintf(stderr, "%s:%d: ", curfile, linno);
00545         fprintf(stderr, "%s\n", msg);
00546         exit(2);
00547 }

Generated on Fri Apr 14 22:56:41 2006 for minix by  doxygen 1.4.6