home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / bin / sh / mkinit.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-15  |  11.1 KB  |  546 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[] = "@(#)mkinit.c    5.3 (Berkeley) 3/13/91";
  45. #endif /* not lint */
  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.  The command is executed iff init.c
  53.  * is actually changed.
  54.  *
  55.  * Usage:  mkinit command sourcefile...
  56.  */
  57.  
  58.  
  59. #include <sys/cdefs.h>
  60. #include <stdio.h>
  61. #include <fcntl.h>
  62.  
  63.  
  64. /*
  65.  * OUTFILE is the name of the output file.  Output is initially written
  66.  * to the file OUTTEMP, which is then moved to OUTFILE if OUTTEMP and
  67.  * OUTFILE are different.
  68.  */
  69.  
  70. #define OUTFILE "init.c"
  71. #define OUTTEMP "init.c.new"
  72. #define OUTOBJ "init.o"
  73.  
  74.  
  75. /*
  76.  * A text structure is basicly just a string that grows as more characters
  77.  * are added onto the end of it.  It is implemented as a linked list of
  78.  * blocks of characters.  The routines addstr and addchar append a string
  79.  * or a single character, respectively, to a text structure.  Writetext
  80.  * writes the contents of a text structure to a file.
  81.  */
  82.  
  83. #define BLOCKSIZE 512
  84.  
  85. struct text {
  86.     char *nextc;
  87.     int nleft;
  88.     struct block *start;
  89.     struct block *last;
  90. };      
  91.  
  92. struct block {
  93.     struct block *next;
  94.     char text[BLOCKSIZE];
  95. };
  96.  
  97.  
  98. /*
  99.  * There is one event structure for each event that mkinit handles.
  100.  */
  101.  
  102. struct event {
  103.     char *name;        /* name of event (e.g. INIT) */
  104.     char *routine;        /* name of routine called on event */
  105.     char *comment;        /* comment describing routine */
  106.     struct text code;        /* code for handling event */
  107. };
  108.  
  109.  
  110. char writer[] = "\
  111. /*\n\
  112.  * This file was generated by the mkinit program.\n\
  113.  */\n\
  114. \n";
  115.  
  116. char init[] = "\
  117. /*\n\
  118.  * Initialization code.\n\
  119.  */\n";
  120.  
  121. char reset[] = "\
  122. /*\n\
  123.  * This routine is called when an error or an interrupt occurs in an\n\
  124.  * interactive shell and control is returned to the main command loop.\n\
  125.  */\n";
  126.  
  127. char shellproc[] = "\
  128. /*\n\
  129.  * This routine is called to initialize the shell to run a shell procedure.\n\
  130.  */\n";
  131.  
  132.  
  133. struct event event[] = {
  134.     {"INIT", "init", init},
  135.     {"RESET", "reset", reset},
  136.     {"SHELLPROC", "initshellproc", shellproc},
  137.     {NULL, NULL}
  138. };
  139.  
  140.  
  141. char *curfile;                /* current file */
  142. int linno;                /* current line */
  143. char *header_files[200];        /* list of header files */
  144. struct text defines;            /* #define statements */
  145. struct text decls;            /* declarations */
  146. int amiddecls;                /* for formatting */
  147.  
  148.  
  149. void readfile(), doevent(), doinclude(), dodecl(), output();
  150. void addstr(), addchar(), writetext();
  151.  
  152. #define equal(s1, s2)    (strcmp(s1, s2) == 0)
  153.  
  154. FILE *ckfopen();
  155. char *savestr();
  156. void *ckmalloc __P((int));
  157. void error();
  158.  
  159. main(argc, argv)
  160.     char **argv;
  161.     {
  162.     char **ap;
  163.     int fd;
  164.     char c;
  165.  
  166.     if (argc < 2)
  167.         error("Usage:  mkinit command file...");
  168.     header_files[0] = "\"shell.h\"";
  169.     header_files[1] = "\"mystring.h\"";
  170.     for (ap = argv + 2 ; *ap ; ap++)
  171.         readfile(*ap);
  172.     output();
  173.     if (file_changed()) {
  174.         unlink(OUTFILE);
  175.         link(OUTTEMP, OUTFILE);
  176.         unlink(OUTTEMP);
  177.     } else {
  178.         unlink(OUTTEMP);
  179.         if (touch(OUTOBJ))
  180.             exit(0);        /* no compilation necessary */
  181.     }
  182.     printf("%s\n", argv[1]);
  183.     execl("/bin/sh", "sh", "-c", argv[1], (char *)0);
  184.     error("Can't exec shell");
  185. }
  186.  
  187.  
  188. /*
  189.  * Parse an input file.
  190.  */
  191.  
  192. void
  193. readfile(fname)
  194.     char *fname;
  195.     {
  196.     FILE *fp;
  197.     char line[1024];
  198.     struct event *ep;
  199.  
  200.     fp = ckfopen(fname, "r");
  201.     curfile = fname;
  202.     linno = 0;
  203.     amiddecls = 0;
  204.     while (fgets(line, sizeof line, fp) != NULL) {
  205.         linno++;
  206.         for (ep = event ; ep->name ; ep++) {
  207.             if (line[0] == ep->name[0] && match(ep->name, line)) {
  208.                 doevent(ep, fp, fname);
  209.                 break;
  210.             }
  211.         }
  212.         if (line[0] == 'I' && match("INCLUDE", line))
  213.             doinclude(line);
  214.         if (line[0] == 'M' && match("MKINIT", line))
  215.             dodecl(line, fp);
  216.         if (line[0] == '#' && gooddefine(line))
  217.             addstr(line, &defines);
  218.     }
  219.     fclose(fp);
  220. }
  221.  
  222.  
  223. int
  224. match(name, line)
  225.     char *name;
  226.     char *line;
  227.     {
  228.     register char *p, *q;
  229.  
  230.     p = name, q = line;
  231.     while (*p) {
  232.         if (*p++ != *q++)
  233.             return 0;
  234.     }
  235.     if (*q != '{' && *q != ' ' && *q != '\t' && *q != '\n')
  236.         return 0;
  237.     return 1;
  238. }
  239.  
  240.  
  241. int
  242. gooddefine(line)
  243.     char *line;
  244.     {
  245.     register char *p;
  246.  
  247.     if (! match("#define", line))
  248.         return 0;            /* not a define */
  249.     p = line + 7;
  250.     while (*p == ' ' || *p == '\t')
  251.         p++;
  252.     while (*p != ' ' && *p != '\t') {
  253.         if (*p == '(')
  254.             return 0;        /* macro definition */
  255.         p++;
  256.     }
  257.     while (*p != '\n' && *p != '\0')
  258.         p++;
  259.     if (p[-1] == '\\')
  260.         return 0;            /* multi-line definition */
  261.     return 1;
  262. }
  263.  
  264.  
  265. void
  266. doevent(ep, fp, fname)
  267.     register struct event *ep;
  268.     FILE *fp;
  269.     char *fname;
  270.     {
  271.     char line[1024];
  272.     int indent;
  273.     char *p;
  274.  
  275.     sprintf(line, "\n      /* from %s: */\n", fname);
  276.     addstr(line, &ep->code);
  277.     addstr("      {\n", &ep->code);
  278.     for (;;) {
  279.         linno++;
  280.         if (fgets(line, sizeof line, fp) == NULL)
  281.             error("Unexpected EOF");
  282.         if (equal(line, "}\n"))
  283.             break;
  284.         indent = 6;
  285.         for (p = line ; *p == '\t' ; p++)
  286.             indent += 8;
  287.         for ( ; *p == ' ' ; p++)
  288.             indent++;
  289.         if (*p == '\n' || *p == '#')
  290.             indent = 0;
  291.         while (indent >= 8) {
  292.             addchar('\t', &ep->code);
  293.             indent -= 8;
  294.         }
  295.         while (indent > 0) {
  296.             addchar(' ', &ep->code);
  297.             indent--;
  298.         }
  299.         addstr(p, &ep->code);
  300.     }
  301.     addstr("      }\n", &ep->code);
  302. }
  303.  
  304.  
  305. void
  306. doinclude(line)
  307.     char *line;
  308.     {
  309.     register char *p;
  310.     char *name;
  311.     register char **pp;
  312.  
  313.     for (p = line ; *p != '"' && *p != '<' && *p != '\0' ; p++);
  314.     if (*p == '\0')
  315.         error("Expecting '\"' or '<'");
  316.     name = p;
  317.     while (*p != ' ' && *p != '\t' && *p != '\n')
  318.         p++;
  319.     if (p[-1] != '"' && p[-1] != '>')
  320.         error("Missing terminator");
  321.     *p = '\0';
  322.  
  323.     /* name now contains the name of the include file */
  324.     for (pp = header_files ; *pp && ! equal(*pp, name) ; pp++);
  325.     if (*pp == NULL)
  326.         *pp = savestr(name);
  327. }
  328.  
  329.  
  330. void
  331. dodecl(line1, fp)
  332.     char *line1;
  333.     FILE *fp;
  334.     {
  335.     char line[1024];
  336.     register 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 != '=' && *p != '/' ; p++);
  352.         if (*p == '=') {        /* eliminate initialization */
  353.             for (q = p ; *q && *q != ';' ; q++);
  354.             if (*q == '\0')
  355.                 q = NULL;
  356.             else {
  357.                 while (p[-1] == ' ')
  358.                     p--;
  359.                 *p = '\0';
  360.             }
  361.         }
  362.         addstr("extern", &decls);
  363.         addstr(line1 + 6, &decls);
  364.         if (q != NULL)
  365.             addstr(q, &decls);
  366.         amiddecls = 1;
  367.     }
  368. }
  369.  
  370.  
  371.  
  372. /*
  373.  * Write the output to the file OUTTEMP.
  374.  */
  375.  
  376. void
  377. output() {
  378.     FILE *fp;
  379.     char **pp;
  380.     struct event *ep;
  381.  
  382.     fp = ckfopen(OUTTEMP, "w");
  383.     fputs(writer, fp);
  384.     for (pp = header_files ; *pp ; pp++)
  385.         fprintf(fp, "#include %s\n", *pp);
  386.     fputs("\n\n\n", fp);
  387.     writetext(&defines, fp);
  388.     fputs("\n\n", fp);
  389.     writetext(&decls, fp);
  390.     for (ep = event ; ep->name ; ep++) {
  391.         fputs("\n\n\n", fp);
  392.         fputs(ep->comment, fp);
  393.         fprintf(fp, "\nvoid\n%s() {\n", ep->routine);
  394.         writetext(&ep->code, fp);
  395.         fprintf(fp, "}\n");
  396.     }
  397.     fclose(fp);
  398. }
  399.  
  400.  
  401. /*
  402.  * Return true if the new output file is different from the old one.
  403.  */
  404.  
  405. int
  406. file_changed() {
  407.     register FILE *f1, *f2;
  408.     register int c;
  409.  
  410.     if ((f1 = fopen(OUTFILE, "r")) == NULL
  411.      || (f2 = fopen(OUTTEMP, "r")) == NULL)
  412.         return 1;
  413.     while ((c = getc(f1)) == getc(f2)) {
  414.         if (c == EOF)
  415.             return 0;
  416.     }
  417.     return 1;
  418. }
  419.  
  420.  
  421. /*
  422.  * Touch a file.  Returns 0 on failure, 1 on success.
  423.  */
  424.  
  425. int
  426. touch(file)
  427.     char *file;
  428.     {
  429.     int fd;
  430.     char c;
  431.  
  432.     if ((fd = open(file, O_RDWR)) < 0)
  433.         return 0;
  434.     if (read(fd, &c, 1) != 1) {
  435.         close(fd);
  436.         return 0;
  437.     }
  438.     lseek(fd, 0L, 0);
  439.     write(fd, &c, 1);
  440.     close(fd);
  441.     return 1;
  442. }
  443.  
  444.  
  445.  
  446. /*
  447.  * A text structure is simply a block of text that is kept in memory.
  448.  * Addstr appends a string to the text struct, and addchar appends a single
  449.  * character.
  450.  */
  451.  
  452. void
  453. addstr(s, text)
  454.     register char *s;
  455.     register struct text *text;
  456.     {
  457.     while (*s) {
  458.         if (--text->nleft < 0)
  459.             addchar(*s++, text);
  460.         else
  461.             *text->nextc++ = *s++;
  462.     }
  463. }
  464.  
  465.  
  466. void
  467. addchar(c, text)
  468.     register struct text *text;
  469.     {
  470.     struct block *bp;
  471.  
  472.     if (--text->nleft < 0) {
  473.         bp = ckmalloc(sizeof *bp);
  474.         if (text->start == NULL)
  475.             text->start = bp;
  476.         else
  477.             text->last->next = bp;
  478.         text->last = bp;
  479.         text->nextc = bp->text;
  480.         text->nleft = BLOCKSIZE - 1;
  481.     }
  482.     *text->nextc++ = c;
  483. }
  484.  
  485. /*
  486.  * Write the contents of a text structure to a file.
  487.  */
  488. void
  489. writetext(text, fp)
  490.     struct text *text;
  491.     FILE *fp;
  492.     {
  493.     struct block *bp;
  494.  
  495.     if (text->start != NULL) {
  496.         for (bp = text->start ; bp != text->last ; bp = bp->next)
  497.             fwrite(bp->text, sizeof (char), BLOCKSIZE, fp);
  498.         fwrite(bp->text, sizeof (char), BLOCKSIZE - text->nleft, fp);
  499.     }
  500. }
  501.  
  502. FILE *
  503. ckfopen(file, mode)
  504.     char *file;
  505.     char *mode;
  506.     {
  507.     FILE *fp;
  508.  
  509.     if ((fp = fopen(file, mode)) == NULL) {
  510.         fprintf(stderr, "Can't open %s\n", file);
  511.         exit(2);
  512.     }
  513.     return fp;
  514. }
  515.  
  516. void *
  517. ckmalloc(nbytes) {
  518.     register char *p;
  519.     char *malloc();
  520.  
  521.     if ((p = malloc(nbytes)) == NULL)
  522.         error("Out of space");
  523.     return p;
  524. }
  525.  
  526. char *
  527. savestr(s)
  528.     char *s;
  529.     {
  530.     register char *p;
  531.  
  532.     p = ckmalloc(strlen(s) + 1);
  533.     strcpy(p, s);
  534.     return p;
  535. }
  536.  
  537. void
  538. error(msg)
  539.     char *msg;
  540.     {
  541.     if (curfile != NULL)
  542.         fprintf(stderr, "%s:%d: ", curfile, linno);
  543.     fprintf(stderr, "%s\n", msg);
  544.     exit(2);
  545. }
  546.