home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 22 gnu / 22-gnu.zip / ash02emx.zip / mkinit.c < prev    next >
C/C++ Source or Header  |  1997-12-25  |  12KB  |  555 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. #ifdef __EMX__
  177.                 rename(OUTTEMP, OUTFILE);
  178. #else
  179.         link(OUTTEMP, OUTFILE);
  180.         unlink(OUTTEMP);
  181. #endif
  182.     } else {
  183.         unlink(OUTTEMP);
  184.         if (touch(OUTOBJ))
  185.             exit(0);        /* no compilation necessary */
  186.     }
  187.     printf("%s\n", argv[1]);
  188. #ifdef __EMX__
  189.     execl("cmd.exe", "cmd.exe", "/c", argv[1], (char *)0);
  190. #else
  191.     execl("/bin/sh", "sh", "-c", argv[1], (char *)0);
  192. #endif
  193.     error("Can't exec shell");
  194. }
  195.  
  196.  
  197. /*
  198.  * Parse an input file.
  199.  */
  200.  
  201. void
  202. readfile(fname)
  203.     char *fname;
  204.     {
  205.     FILE *fp;
  206.     char line[1024];
  207.     struct event *ep;
  208.  
  209.     fp = ckfopen(fname, "r");
  210.     curfile = fname;
  211.     linno = 0;
  212.     amiddecls = 0;
  213.     while (fgets(line, sizeof line, fp) != NULL) {
  214.         linno++;
  215.         for (ep = event ; ep->name ; ep++) {
  216.             if (line[0] == ep->name[0] && match(ep->name, line)) {
  217.                 doevent(ep, fp, fname);
  218.                 break;
  219.             }
  220.         }
  221.         if (line[0] == 'I' && match("INCLUDE", line))
  222.             doinclude(line);
  223.         if (line[0] == 'M' && match("MKINIT", line))
  224.             dodecl(line, fp);
  225.         if (line[0] == '#' && gooddefine(line))
  226.             addstr(line, &defines);
  227.     }
  228.     fclose(fp);
  229. }
  230.  
  231.  
  232. int
  233. match(name, line)
  234.     char *name;
  235.     char *line;
  236.     {
  237.     register char *p, *q;
  238.  
  239.     p = name, q = line;
  240.     while (*p) {
  241.         if (*p++ != *q++)
  242.             return 0;
  243.     }
  244.     if (*q != '{' && *q != ' ' && *q != '\t' && *q != '\n')
  245.         return 0;
  246.     return 1;
  247. }
  248.  
  249.  
  250. int
  251. gooddefine(line)
  252.     char *line;
  253.     {
  254.     register char *p;
  255.  
  256.     if (! match("#define", line))
  257.         return 0;            /* not a define */
  258.     p = line + 7;
  259.     while (*p == ' ' || *p == '\t')
  260.         p++;
  261.     while (*p != ' ' && *p != '\t') {
  262.         if (*p == '(')
  263.             return 0;        /* macro definition */
  264.         p++;
  265.     }
  266.     while (*p != '\n' && *p != '\0')
  267.         p++;
  268.     if (p[-1] == '\\')
  269.         return 0;            /* multi-line definition */
  270.     return 1;
  271. }
  272.  
  273.  
  274. void
  275. doevent(ep, fp, fname)
  276.     register struct event *ep;
  277.     FILE *fp;
  278.     char *fname;
  279.     {
  280.     char line[1024];
  281.     int indent;
  282.     char *p;
  283.  
  284.     sprintf(line, "\n      /* from %s: */\n", fname);
  285.     addstr(line, &ep->code);
  286.     addstr("      {\n", &ep->code);
  287.     for (;;) {
  288.         linno++;
  289.         if (fgets(line, sizeof line, fp) == NULL)
  290.             error("Unexpected EOF");
  291.         if (equal(line, "}\n"))
  292.             break;
  293.         indent = 6;
  294.         for (p = line ; *p == '\t' ; p++)
  295.             indent += 8;
  296.         for ( ; *p == ' ' ; p++)
  297.             indent++;
  298.         if (*p == '\n' || *p == '#')
  299.             indent = 0;
  300.         while (indent >= 8) {
  301.             addchar('\t', &ep->code);
  302.             indent -= 8;
  303.         }
  304.         while (indent > 0) {
  305.             addchar(' ', &ep->code);
  306.             indent--;
  307.         }
  308.         addstr(p, &ep->code);
  309.     }
  310.     addstr("      }\n", &ep->code);
  311. }
  312.  
  313.  
  314. void
  315. doinclude(line)
  316.     char *line;
  317.     {
  318.     register char *p;
  319.     char *name;
  320.     register char **pp;
  321.  
  322.     for (p = line ; *p != '"' && *p != '<' && *p != '\0' ; p++);
  323.     if (*p == '\0')
  324.         error("Expecting '\"' or '<'");
  325.     name = p;
  326.     while (*p != ' ' && *p != '\t' && *p != '\n')
  327.         p++;
  328.     if (p[-1] != '"' && p[-1] != '>')
  329.         error("Missing terminator");
  330.     *p = '\0';
  331.  
  332.     /* name now contains the name of the include file */
  333.     for (pp = header_files ; *pp && ! equal(*pp, name) ; pp++);
  334.     if (*pp == NULL)
  335.         *pp = savestr(name);
  336. }
  337.  
  338.  
  339. void
  340. dodecl(line1, fp)
  341.     char *line1;
  342.     FILE *fp;
  343.     {
  344.     char line[1024];
  345.     register char *p, *q;
  346.  
  347.     if (strcmp(line1, "MKINIT\n") == 0) { /* start of struct/union decl */
  348.         addchar('\n', &decls);
  349.         do {
  350.             linno++;
  351.             if (fgets(line, sizeof line, fp) == NULL)
  352.                 error("Unterminated structure declaration");
  353.             addstr(line, &decls);
  354.         } while (line[0] != '}');
  355.         amiddecls = 0;
  356.     } else {
  357.         if (! amiddecls)
  358.             addchar('\n', &decls);
  359.         q = NULL;
  360.         for (p = line1 + 6 ; *p != '=' && *p != '/' ; p++);
  361.         if (*p == '=') {        /* eliminate initialization */
  362.             for (q = p ; *q && *q != ';' ; q++);
  363.             if (*q == '\0')
  364.                 q = NULL;
  365.             else {
  366.                 while (p[-1] == ' ')
  367.                     p--;
  368.                 *p = '\0';
  369.             }
  370.         }
  371.         addstr("extern", &decls);
  372.         addstr(line1 + 6, &decls);
  373.         if (q != NULL)
  374.             addstr(q, &decls);
  375.         amiddecls = 1;
  376.     }
  377. }
  378.  
  379.  
  380.  
  381. /*
  382.  * Write the output to the file OUTTEMP.
  383.  */
  384.  
  385. void
  386. output() {
  387.     FILE *fp;
  388.     char **pp;
  389.     struct event *ep;
  390.  
  391.     fp = ckfopen(OUTTEMP, "w");
  392.     fputs(writer, fp);
  393.     for (pp = header_files ; *pp ; pp++)
  394.         fprintf(fp, "#include %s\n", *pp);
  395.     fputs("\n\n\n", fp);
  396.     writetext(&defines, fp);
  397.     fputs("\n\n", fp);
  398.     writetext(&decls, fp);
  399.     for (ep = event ; ep->name ; ep++) {
  400.         fputs("\n\n\n", fp);
  401.         fputs(ep->comment, fp);
  402.         fprintf(fp, "\nvoid\n%s() {\n", ep->routine);
  403.         writetext(&ep->code, fp);
  404.         fprintf(fp, "}\n");
  405.     }
  406.     fclose(fp);
  407. }
  408.  
  409.  
  410. /*
  411.  * Return true if the new output file is different from the old one.
  412.  */
  413.  
  414. int
  415. file_changed() {
  416.     register FILE *f1, *f2;
  417.     register int c;
  418.  
  419.     if ((f1 = fopen(OUTFILE, "r")) == NULL
  420.      || (f2 = fopen(OUTTEMP, "r")) == NULL)
  421.         return 1;
  422.     while ((c = getc(f1)) == getc(f2)) {
  423.         if (c == EOF)
  424.             return 0;
  425.     }
  426.     return 1;
  427. }
  428.  
  429.  
  430. /*
  431.  * Touch a file.  Returns 0 on failure, 1 on success.
  432.  */
  433.  
  434. int
  435. touch(file)
  436.     char *file;
  437.     {
  438.     int fd;
  439.     char c;
  440.  
  441.     if ((fd = open(file, O_RDWR)) < 0)
  442.         return 0;
  443.     if (read(fd, &c, 1) != 1) {
  444.         close(fd);
  445.         return 0;
  446.     }
  447.     lseek(fd, 0L, 0);
  448.     write(fd, &c, 1);
  449.     close(fd);
  450.     return 1;
  451. }
  452.  
  453.  
  454.  
  455. /*
  456.  * A text structure is simply a block of text that is kept in memory.
  457.  * Addstr appends a string to the text struct, and addchar appends a single
  458.  * character.
  459.  */
  460.  
  461. void
  462. addstr(s, text)
  463.     register char *s;
  464.     register struct text *text;
  465.     {
  466.     while (*s) {
  467.         if (--text->nleft < 0)
  468.             addchar(*s++, text);
  469.         else
  470.             *text->nextc++ = *s++;
  471.     }
  472. }
  473.  
  474.  
  475. void
  476. addchar(c, text)
  477.     register struct text *text;
  478.     {
  479.     struct block *bp;
  480.  
  481.     if (--text->nleft < 0) {
  482.         bp = ckmalloc(sizeof *bp);
  483.         if (text->start == NULL)
  484.             text->start = bp;
  485.         else
  486.             text->last->next = bp;
  487.         text->last = bp;
  488.         text->nextc = bp->text;
  489.         text->nleft = BLOCKSIZE - 1;
  490.     }
  491.     *text->nextc++ = c;
  492. }
  493.  
  494. /*
  495.  * Write the contents of a text structure to a file.
  496.  */
  497. void
  498. writetext(text, fp)
  499.     struct text *text;
  500.     FILE *fp;
  501.     {
  502.     struct block *bp;
  503.  
  504.     if (text->start != NULL) {
  505.         for (bp = text->start ; bp != text->last ; bp = bp->next)
  506.             fwrite(bp->text, sizeof (char), BLOCKSIZE, fp);
  507.         fwrite(bp->text, sizeof (char), BLOCKSIZE - text->nleft, fp);
  508.     }
  509. }
  510.  
  511. FILE *
  512. ckfopen(file, mode)
  513.     char *file;
  514.     char *mode;
  515.     {
  516.     FILE *fp;
  517.  
  518.     if ((fp = fopen(file, mode)) == NULL) {
  519.         fprintf(stderr, "Can't open %s\n", file);
  520.         exit(2);
  521.     }
  522.     return fp;
  523. }
  524.  
  525. void *
  526. ckmalloc(nbytes) {
  527.     register char *p;
  528.     char *malloc();
  529.  
  530.     if ((p = malloc(nbytes)) == NULL)
  531.         error("Out of space");
  532.     return p;
  533. }
  534.  
  535. char *
  536. savestr(s)
  537.     char *s;
  538.     {
  539.     register char *p;
  540.  
  541.     p = ckmalloc(strlen(s) + 1);
  542.     strcpy(p, s);
  543.     return p;
  544. }
  545.  
  546. void
  547. error(msg)
  548.     char *msg;
  549.     {
  550.     if (curfile != NULL)
  551.         fprintf(stderr, "%s:%d: ", curfile, linno);
  552.     fprintf(stderr, "%s\n", msg);
  553.     exit(2);
  554. }
  555.