home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / AP / ASH / ASH-LINU.2 / ASH-LINU / ash-linux-0.2 / mkinit.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-08-24  |  11.2 KB  |  547 lines

  1. /*-
  2.  * Copyright (c) 1991 The Regents of the University of California.
  3.  * 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.  
  37. #ifndef lint
  38. char copyright[] =
  39. "@(#) Copyright (c) 1991 The Regents of the University of California.\n\
  40.  All rights reserved.\n";
  41. #endif /* not lint */
  42.  
  43. #ifndef lint
  44. /*static char sccsid[] = "from: @(#)mkinit.c    5.3 (Berkeley) 3/13/91";*/
  45. static char rcsid[] = "mkinit.c,v 1.4 1993/08/01 18:58:09 mycroft Exp";
  46. #endif /* not lint */
  47.  
  48. /*
  49.  * This program scans all the source files for code to handle various
  50.  * special events and combines this code into one file.  This (allegedly)
  51.  * improves the structure of the program since there is no need for
  52.  * anyone outside of a module to know that that module performs special
  53.  * operations on particular events.  The command is executed iff init.c
  54.  * is actually changed.
  55.  *
  56.  * Usage:  mkinit command sourcefile...
  57.  */
  58.  
  59.  
  60. #include <sys/cdefs.h>
  61. #include <stdio.h>
  62. #include <fcntl.h>
  63.  
  64.  
  65. /*
  66.  * OUTFILE is the name of the output file.  Output is initially written
  67.  * to the file OUTTEMP, which is then moved to OUTFILE if OUTTEMP and
  68.  * OUTFILE are different.
  69.  */
  70.  
  71. #define OUTFILE "init.c"
  72. #define OUTTEMP "init.c.new"
  73. #define OUTOBJ "init.o"
  74.  
  75.  
  76. /*
  77.  * A text structure is basicly 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.     char *name;        /* name of event (e.g. INIT) */
  105.     char *routine;        /* name of routine called on event */
  106.     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. char shellproc[] = "\
  129. /*\n\
  130.  * This routine is called to initialize the shell to run a shell procedure.\n\
  131.  */\n";
  132.  
  133.  
  134. struct event event[] = {
  135.     {"INIT", "init", init},
  136.     {"RESET", "reset", reset},
  137.     {"SHELLPROC", "initshellproc", shellproc},
  138.     {NULL, NULL}
  139. };
  140.  
  141.  
  142. char *curfile;                /* current file */
  143. int linno;                /* current line */
  144. char *header_files[200];        /* list of header files */
  145. struct text defines;            /* #define statements */
  146. struct text decls;            /* declarations */
  147. int amiddecls;                /* for formatting */
  148.  
  149.  
  150. void readfile(), doevent(), doinclude(), dodecl(), output();
  151. void addstr(), addchar(), writetext();
  152.  
  153. #define equal(s1, s2)    (strcmp(s1, s2) == 0)
  154.  
  155. FILE *ckfopen();
  156. char *savestr();
  157. void *ckmalloc __P((int));
  158. void error();
  159.  
  160. main(argc, argv)
  161.     char **argv;
  162.     {
  163.     char **ap;
  164.     int fd;
  165.     char c;
  166.  
  167.     if (argc < 2)
  168.         error("Usage:  mkinit command file...");
  169.     header_files[0] = "\"shell.h\"";
  170.     header_files[1] = "\"mystring.h\"";
  171.     for (ap = argv + 2 ; *ap ; ap++)
  172.         readfile(*ap);
  173.     output();
  174.     if (file_changed()) {
  175.         unlink(OUTFILE);
  176.         link(OUTTEMP, OUTFILE);
  177.         unlink(OUTTEMP);
  178.     } else {
  179.         unlink(OUTTEMP);
  180.         if (touch(OUTOBJ))
  181.             exit(0);        /* no compilation necessary */
  182.     }
  183.     printf("%s\n", argv[1]);
  184.     execl("/bin/sh", "sh", "-c", argv[1], (char *)0);
  185.     error("Can't exec shell");
  186. }
  187.  
  188.  
  189. /*
  190.  * Parse an input file.
  191.  */
  192.  
  193. void
  194. readfile(fname)
  195.     char *fname;
  196.     {
  197.     FILE *fp;
  198.     char line[1024];
  199.     struct event *ep;
  200.  
  201.     fp = ckfopen(fname, "r");
  202.     curfile = fname;
  203.     linno = 0;
  204.     amiddecls = 0;
  205.     while (fgets(line, sizeof line, fp) != NULL) {
  206.         linno++;
  207.         for (ep = event ; ep->name ; ep++) {
  208.             if (line[0] == ep->name[0] && match(ep->name, line)) {
  209.                 doevent(ep, fp, fname);
  210.                 break;
  211.             }
  212.         }
  213.         if (line[0] == 'I' && match("INCLUDE", line))
  214.             doinclude(line);
  215.         if (line[0] == 'M' && match("MKINIT", line))
  216.             dodecl(line, fp);
  217.         if (line[0] == '#' && gooddefine(line))
  218.             addstr(line, &defines);
  219.     }
  220.     fclose(fp);
  221. }
  222.  
  223.  
  224. int
  225. match(name, line)
  226.     char *name;
  227.     char *line;
  228.     {
  229.     register char *p, *q;
  230.  
  231.     p = name, q = line;
  232.     while (*p) {
  233.         if (*p++ != *q++)
  234.             return 0;
  235.     }
  236.     if (*q != '{' && *q != ' ' && *q != '\t' && *q != '\n')
  237.         return 0;
  238.     return 1;
  239. }
  240.  
  241.  
  242. int
  243. gooddefine(line)
  244.     char *line;
  245.     {
  246.     register char *p;
  247.  
  248.     if (! match("#define", line))
  249.         return 0;            /* not a define */
  250.     p = line + 7;
  251.     while (*p == ' ' || *p == '\t')
  252.         p++;
  253.     while (*p != ' ' && *p != '\t') {
  254.         if (*p == '(')
  255.             return 0;        /* macro definition */
  256.         p++;
  257.     }
  258.     while (*p != '\n' && *p != '\0')
  259.         p++;
  260.     if (p[-1] == '\\')
  261.         return 0;            /* multi-line definition */
  262.     return 1;
  263. }
  264.  
  265.  
  266. void
  267. doevent(ep, fp, fname)
  268.     register struct event *ep;
  269.     FILE *fp;
  270.     char *fname;
  271.     {
  272.     char line[1024];
  273.     int indent;
  274.     char *p;
  275.  
  276.     sprintf(line, "\n      /* from %s: */\n", fname);
  277.     addstr(line, &ep->code);
  278.     addstr("      {\n", &ep->code);
  279.     for (;;) {
  280.         linno++;
  281.         if (fgets(line, sizeof line, fp) == NULL)
  282.             error("Unexpected EOF");
  283.         if (equal(line, "}\n"))
  284.             break;
  285.         indent = 6;
  286.         for (p = line ; *p == '\t' ; p++)
  287.             indent += 8;
  288.         for ( ; *p == ' ' ; p++)
  289.             indent++;
  290.         if (*p == '\n' || *p == '#')
  291.             indent = 0;
  292.         while (indent >= 8) {
  293.             addchar('\t', &ep->code);
  294.             indent -= 8;
  295.         }
  296.         while (indent > 0) {
  297.             addchar(' ', &ep->code);
  298.             indent--;
  299.         }
  300.         addstr(p, &ep->code);
  301.     }
  302.     addstr("      }\n", &ep->code);
  303. }
  304.  
  305.  
  306. void
  307. doinclude(line)
  308.     char *line;
  309.     {
  310.     register char *p;
  311.     char *name;
  312.     register char **pp;
  313.  
  314.     for (p = line ; *p != '"' && *p != '<' && *p != '\0' ; p++);
  315.     if (*p == '\0')
  316.         error("Expecting '\"' or '<'");
  317.     name = p;
  318.     while (*p != ' ' && *p != '\t' && *p != '\n')
  319.         p++;
  320.     if (p[-1] != '"' && p[-1] != '>')
  321.         error("Missing terminator");
  322.     *p = '\0';
  323.  
  324.     /* name now contains the name of the include file */
  325.     for (pp = header_files ; *pp && ! equal(*pp, name) ; pp++);
  326.     if (*pp == NULL)
  327.         *pp = savestr(name);
  328. }
  329.  
  330.  
  331. void
  332. dodecl(line1, fp)
  333.     char *line1;
  334.     FILE *fp;
  335.     {
  336.     char line[1024];
  337.     register char *p, *q;
  338.  
  339.     if (strcmp(line1, "MKINIT\n") == 0) { /* start of struct/union decl */
  340.         addchar('\n', &decls);
  341.         do {
  342.             linno++;
  343.             if (fgets(line, sizeof line, fp) == NULL)
  344.                 error("Unterminated structure declaration");
  345.             addstr(line, &decls);
  346.         } while (line[0] != '}');
  347.         amiddecls = 0;
  348.     } else {
  349.         if (! amiddecls)
  350.             addchar('\n', &decls);
  351.         q = NULL;
  352.         for (p = line1 + 6 ; *p != '=' && *p != '/' ; p++);
  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() {
  379.     FILE *fp;
  380.     char **pp;
  381.     struct event *ep;
  382.  
  383.     fp = ckfopen(OUTTEMP, "w");
  384.     fputs(writer, fp);
  385.     for (pp = header_files ; *pp ; pp++)
  386.         fprintf(fp, "#include %s\n", *pp);
  387.     fputs("\n\n\n", fp);
  388.     writetext(&defines, fp);
  389.     fputs("\n\n", fp);
  390.     writetext(&decls, fp);
  391.     for (ep = event ; ep->name ; ep++) {
  392.         fputs("\n\n\n", fp);
  393.         fputs(ep->comment, fp);
  394.         fprintf(fp, "\nvoid\n%s() {\n", ep->routine);
  395.         writetext(&ep->code, fp);
  396.         fprintf(fp, "}\n");
  397.     }
  398.     fclose(fp);
  399. }
  400.  
  401.  
  402. /*
  403.  * Return true if the new output file is different from the old one.
  404.  */
  405.  
  406. int
  407. file_changed() {
  408.     register FILE *f1, *f2;
  409.     register int c;
  410.  
  411.     if ((f1 = fopen(OUTFILE, "r")) == NULL
  412.      || (f2 = fopen(OUTTEMP, "r")) == NULL)
  413.         return 1;
  414.     while ((c = getc(f1)) == getc(f2)) {
  415.         if (c == EOF)
  416.             return 0;
  417.     }
  418.     return 1;
  419. }
  420.  
  421.  
  422. /*
  423.  * Touch a file.  Returns 0 on failure, 1 on success.
  424.  */
  425.  
  426. int
  427. touch(file)
  428.     char *file;
  429.     {
  430.     int fd;
  431.     char c;
  432.  
  433.     if ((fd = open(file, O_RDWR)) < 0)
  434.         return 0;
  435.     if (read(fd, &c, 1) != 1) {
  436.         close(fd);
  437.         return 0;
  438.     }
  439.     lseek(fd, 0L, 0);
  440.     write(fd, &c, 1);
  441.     close(fd);
  442.     return 1;
  443. }
  444.  
  445.  
  446.  
  447. /*
  448.  * A text structure is simply a block of text that is kept in memory.
  449.  * Addstr appends a string to the text struct, and addchar appends a single
  450.  * character.
  451.  */
  452.  
  453. void
  454. addstr(s, text)
  455.     register char *s;
  456.     register struct text *text;
  457.     {
  458.     while (*s) {
  459.         if (--text->nleft < 0)
  460.             addchar(*s++, text);
  461.         else
  462.             *text->nextc++ = *s++;
  463.     }
  464. }
  465.  
  466.  
  467. void
  468. addchar(c, text)
  469.     register struct text *text;
  470.     {
  471.     struct block *bp;
  472.  
  473.     if (--text->nleft < 0) {
  474.         bp = ckmalloc(sizeof *bp);
  475.         if (text->start == NULL)
  476.             text->start = bp;
  477.         else
  478.             text->last->next = bp;
  479.         text->last = bp;
  480.         text->nextc = bp->text;
  481.         text->nleft = BLOCKSIZE - 1;
  482.     }
  483.     *text->nextc++ = c;
  484. }
  485.  
  486. /*
  487.  * Write the contents of a text structure to a file.
  488.  */
  489. void
  490. writetext(text, fp)
  491.     struct text *text;
  492.     FILE *fp;
  493.     {
  494.     struct block *bp;
  495.  
  496.     if (text->start != NULL) {
  497.         for (bp = text->start ; bp != text->last ; bp = bp->next)
  498.             fwrite(bp->text, sizeof (char), BLOCKSIZE, fp);
  499.         fwrite(bp->text, sizeof (char), BLOCKSIZE - text->nleft, fp);
  500.     }
  501. }
  502.  
  503. FILE *
  504. ckfopen(file, mode)
  505.     char *file;
  506.     char *mode;
  507.     {
  508.     FILE *fp;
  509.  
  510.     if ((fp = fopen(file, mode)) == NULL) {
  511.         fprintf(stderr, "Can't open %s\n", file);
  512.         exit(2);
  513.     }
  514.     return fp;
  515. }
  516.  
  517. void *
  518. ckmalloc(nbytes) {
  519.     register char *p;
  520.     char *malloc();
  521.  
  522.     if ((p = malloc(nbytes)) == NULL)
  523.         error("Out of space");
  524.     return p;
  525. }
  526.  
  527. char *
  528. savestr(s)
  529.     char *s;
  530.     {
  531.     register char *p;
  532.  
  533.     p = ckmalloc(strlen(s) + 1);
  534.     strcpy(p, s);
  535.     return p;
  536. }
  537.  
  538. void
  539. error(msg)
  540.     char *msg;
  541.     {
  542.     if (curfile != NULL)
  543.         fprintf(stderr, "%s:%d: ", curfile, linno);
  544.     fprintf(stderr, "%s\n", msg);
  545.     exit(2);
  546. }
  547.