home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume19 / ash / part05 < prev    next >
Text File  |  1989-05-29  |  55KB  |  2,314 lines

  1. Subject:  v19i005:  A reimplementation of the System V shell, Part05/08
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: ka@june.cs.washington.edu (Kenneth Almquist)
  7. Posting-number: Volume 19, Issue 5
  8. Archive-name: ash/part05
  9.  
  10. # This is part 5 of ash.  To unpack, feed it into the shell (not csh).
  11. # The ash distribution consists of eight pieces.  Be sure you get them all.
  12. # After you unpack everything, read the file README.
  13.  
  14. echo extracting mkinit.c
  15. cat > mkinit.c <<\EOF
  16. /*
  17.  * Copyright (C) 1989 by Kenneth Almquist.  All rights reserved.
  18.  * This file is part of ash, which is distributed under the terms specified
  19.  * by the Ash General Public License.  See the file named LICENSE.
  20.  *
  21.  * Usage:  mkinit command sourcefile...
  22.  *
  23.  * This program scans all the source files for code to handle various
  24.  * special events and combines this code into one file.  This (allegedly)
  25.  * improves the structure of the program since there is no need for
  26.  * anyone outside of a module to know that that module performs special
  27.  * operations on particular events.  The command is executed iff init.c
  28.  * is actually changed.
  29.  */
  30.  
  31.  
  32. #include <stdio.h>
  33. #include <fcntl.h>
  34.  
  35.  
  36. /*
  37.  * OUTFILE is the name of the output file.  Output is initially written
  38.  * to the file OUTTEMP, which is then moved to OUTFILE if OUTTEMP and
  39.  * OUTFILE are different.
  40.  */
  41.  
  42. #define OUTFILE "init.c"
  43. #define OUTTEMP "init.c.new"
  44. #define OUTOBJ "init.o"
  45.  
  46.  
  47. /*
  48.  * A text structure is basicly just a string that grows as more characters
  49.  * are added onto the end of it.  It is implemented as a linked list of
  50.  * blocks of characters.  The routines addstr and addchar append a string
  51.  * or a single character, respectively, to a text structure.  Writetext
  52.  * writes the contents of a text structure to a file.
  53.  */
  54.  
  55. #define BLOCKSIZE 512
  56.  
  57. struct text {
  58.       char *nextc;
  59.       int nleft;
  60.       struct block *start;
  61.       struct block *last;
  62. };      
  63.  
  64. struct block {
  65.       struct block *next;
  66.       char text[BLOCKSIZE];
  67. };
  68.  
  69.  
  70. /*
  71.  * There is one event structure for each event that mkinit handles.
  72.  */
  73.  
  74. struct event {
  75.       char *name;        /* name of event (e.g. INIT) */
  76.       char *routine;        /* name of routine called on event */
  77.       char *comment;        /* comment describing routine */
  78.       struct text code;        /* code for handling event */
  79. };
  80.  
  81.  
  82. char writer[] = "\
  83. /*\n\
  84.  * This file was generated by the mkinit program.\n\
  85.  */\n\
  86. \n";
  87.  
  88. char init[] = "\
  89. /*\n\
  90.  * Initialization code.\n\
  91.  */\n";
  92.  
  93. char reset[] = "\
  94. /*\n\
  95.  * This routine is called when an error or an interrupt occurs in an\n\
  96.  * interactive shell and control is returned to the main command loop.\n\
  97.  */\n";
  98.  
  99. char shellproc[] = "\
  100. /*\n\
  101.  * This routine is called to initialize the shell to run a shell procedure.\n\
  102.  */\n";
  103.  
  104.  
  105. struct event event[] = {
  106.       {"INIT", "init", init},
  107.       {"RESET", "reset", reset},
  108.       {"SHELLPROC", "initshellproc", shellproc},
  109.       {NULL, NULL}
  110. };
  111.  
  112.  
  113. char *curfile;                /* current file */
  114. int linno;                /* current line */
  115. char *header_files[200];        /* list of header files */
  116. struct text defines;            /* #define statements */
  117. struct text decls;            /* declarations */
  118. int amiddecls;                /* for formatting */
  119.  
  120.  
  121. void readfile(), doevent(), doinclude(), dodecl(), output();
  122. void addstr(), addchar(), writetext();
  123.  
  124. #define equal(s1, s2)    (strcmp(s1, s2) == 0)
  125.  
  126. FILE *ckfopen();
  127. char *savestr();
  128. #ifdef __STDC__
  129. void *ckmalloc(int);
  130. #else
  131. char *ckmalloc();
  132. #endif
  133. void error();
  134.  
  135.  
  136.  
  137. main(argc, argv)
  138.       char **argv;
  139.       {
  140.       char **ap;
  141.       int fd;
  142.       char c;
  143.  
  144.       if (argc < 2)
  145.         error("Usage:  mkinit command file...");
  146.       header_files[0] = "\"shell.h\"";
  147.       header_files[1] = "\"mystring.h\"";
  148.       for (ap = argv + 2 ; *ap ; ap++)
  149.         readfile(*ap);
  150.       output();
  151.       if (file_changed()) {
  152.         unlink(OUTFILE);
  153.         link(OUTTEMP, OUTFILE);
  154.         unlink(OUTTEMP);
  155.       } else {
  156.         unlink(OUTTEMP);
  157.         if (touch(OUTOBJ))
  158.           exit(0);        /* no compilation necessary */
  159.       }
  160.       printf("%s\n", argv[1]);
  161.       execl("/bin/sh", "sh", "-c", argv[1], (char *)0);
  162.       error("Can't exec shell");
  163. }
  164.  
  165.  
  166. /*
  167.  * Parse an input file.
  168.  */
  169.  
  170. void
  171. readfile(fname)
  172.       char *fname;
  173.       {
  174.       FILE *fp;
  175.       char line[1024];
  176.       struct event *ep;
  177.  
  178.       fp = ckfopen(fname, "r");
  179.       curfile = fname;
  180.       linno = 0;
  181.       amiddecls = 0;
  182.       while (fgets(line, sizeof line, fp) != NULL) {
  183.         linno++;
  184.         for (ep = event ; ep->name ; ep++) {
  185.           if (line[0] == ep->name[0] && match(ep->name, line)) {
  186.             doevent(ep, fp, fname);
  187.             break;
  188.           }
  189.         }
  190.         if (line[0] == 'I' && match("INCLUDE", line))
  191.           doinclude(line);
  192.         if (line[0] == 'M' && match("MKINIT", line))
  193.           dodecl(line, fp);
  194.         if (line[0] == '#' && gooddefine(line))
  195.           addstr(line, &defines);
  196.       }
  197.       fclose(fp);
  198. }
  199.  
  200.  
  201. int
  202. match(name, line)
  203.       char *name;
  204.       char *line;
  205.       {
  206.       register char *p, *q;
  207.  
  208.       p = name, q = line;
  209.       while (*p) {
  210.         if (*p++ != *q++)
  211.           return 0;
  212.       }
  213.       if (*q != '{' && *q != ' ' && *q != '\t' && *q != '\n')
  214.         return 0;
  215.       return 1;
  216. }
  217.  
  218.  
  219. int
  220. gooddefine(line)
  221.       char *line;
  222.       {
  223.       register char *p;
  224.  
  225.       if (! match("#define", line))
  226.         return 0;            /* not a define */
  227.       p = line + 7;
  228.       while (*p == ' ' || *p == '\t')
  229.         p++;
  230.       while (*p != ' ' && *p != '\t') {
  231.         if (*p == '(')
  232.           return 0;        /* macro definition */
  233.         p++;
  234.       }
  235.       while (*p != '\n' && *p != '\0')
  236.         p++;
  237.       if (p[-1] == '\\')
  238.         return 0;            /* multi-line definition */
  239.       return 1;
  240. }
  241.  
  242.  
  243. void
  244. doevent(ep, fp, fname)
  245.       register struct event *ep;
  246.       FILE *fp;
  247.       char *fname;
  248.       {
  249.       char line[1024];
  250.       int indent;
  251.       char *p;
  252.  
  253.       sprintf(line, "\n      /* from %s: */\n", fname);
  254.       addstr(line, &ep->code);
  255.       addstr("      {\n", &ep->code);
  256.       for (;;) {
  257.         linno++;
  258.         if (fgets(line, sizeof line, fp) == NULL)
  259.           error("Unexpected EOF");
  260.         if (equal(line, "}\n"))
  261.           break;
  262.         indent = 6;
  263.         for (p = line ; *p == '\t' ; p++)
  264.           indent += 8;
  265.         for ( ; *p == ' ' ; p++)
  266.           indent++;
  267.         if (*p == '\n' || *p == '#')
  268.           indent = 0;
  269.         while (indent >= 8) {
  270.           addchar('\t', &ep->code);
  271.           indent -= 8;
  272.         }
  273.         while (indent > 0) {
  274.           addchar(' ', &ep->code);
  275.           indent--;
  276.         }
  277.         addstr(p, &ep->code);
  278.       }
  279.       addstr("      }\n", &ep->code);
  280. }
  281.  
  282.  
  283. void
  284. doinclude(line)
  285.       char *line;
  286.       {
  287.       register char *p;
  288.       char *name;
  289.       register char **pp;
  290.  
  291.       for (p = line ; *p != '"' && *p != '<' && *p != '\0' ; p++);
  292.       if (*p == '\0')
  293.         error("Expecting '\"' or '<'");
  294.       name = p;
  295.       while (*p != ' ' && *p != '\t' && *p != '\n')
  296.         p++;
  297.       if (p[-1] != '"' && p[-1] != '>')
  298.         error("Missing terminator");
  299.       *p = '\0';
  300.  
  301.       /* name now contains the name of the include file */
  302.       for (pp = header_files ; *pp && ! equal(*pp, name) ; pp++);
  303.       if (*pp == NULL)
  304.         *pp = savestr(name);
  305. }
  306.  
  307.  
  308. void
  309. dodecl(line1, fp)
  310.       char *line1;
  311.       FILE *fp;
  312.       {
  313.       char line[1024];
  314.       register char *p, *q;
  315.  
  316.       if (strcmp(line1, "MKINIT\n") == 0) { /* start of struct/union decl */
  317.         addchar('\n', &decls);
  318.         do {
  319.           linno++;
  320.           if (fgets(line, sizeof line, fp) == NULL)
  321.             error("Unterminated structure declaration");
  322.           addstr(line, &decls);
  323.         } while (line[0] != '}');
  324.         amiddecls = 0;
  325.       } else {
  326.         if (! amiddecls)
  327.           addchar('\n', &decls);
  328.         q = NULL;
  329.         for (p = line1 + 6 ; *p != '=' && *p != '/' ; p++);
  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() {
  356.       FILE *fp;
  357.       char **pp;
  358.       struct event *ep;
  359.  
  360.       fp = ckfopen(OUTTEMP, "w");
  361.       fputs(writer, fp);
  362.       for (pp = header_files ; *pp ; pp++)
  363.         fprintf(fp, "#include %s\n", *pp);
  364.       fputs("\n\n\n", fp);
  365.       writetext(&defines, fp);
  366.       fputs("\n\n", fp);
  367.       writetext(&decls, fp);
  368.       for (ep = event ; ep->name ; ep++) {
  369.         fputs("\n\n\n", fp);
  370.         fputs(ep->comment, fp);
  371.         fprintf(fp, "\nvoid\n%s() {\n", ep->routine);
  372.         writetext(&ep->code, fp);
  373.         fprintf(fp, "}\n");
  374.       }
  375.       fclose(fp);
  376. }
  377.  
  378.  
  379. /*
  380.  * Return true if the new output file is different from the old one.
  381.  */
  382.  
  383. int
  384. file_changed() {
  385.       register FILE *f1, *f2;
  386.       register int c;
  387.  
  388.       if ((f1 = fopen(OUTFILE, "r")) == NULL
  389.        || (f2 = fopen(OUTTEMP, "r")) == NULL)
  390.         return 1;
  391.       while ((c = getc(f1)) == getc(f2)) {
  392.         if (c == EOF)
  393.           return 0;
  394.       }
  395.       return 1;
  396. }
  397.  
  398.  
  399. /*
  400.  * Touch a file.  Returns 0 on failure, 1 on success.
  401.  */
  402.  
  403. int
  404. touch(file)
  405.       char *file;
  406.       {
  407.       int fd;
  408.       char c;
  409.  
  410.       if ((fd = open(file, O_RDWR)) < 0)
  411.         return 0;
  412.       if (read(fd, &c, 1) != 1) {
  413.         close(fd);
  414.         return 0;
  415.       }
  416.       lseek(fd, 0L, 0);
  417.       write(fd, &c, 1);
  418.       close(fd);
  419.       return 1;
  420. }
  421.  
  422.  
  423.  
  424. /*
  425.  * A text structure is simply a block of text that is kept in memory.
  426.  * Addstr appends a string to the text struct, and addchar appends a single
  427.  * character.
  428.  */
  429.  
  430. void
  431. addstr(s, text)
  432.       register char *s;
  433.       register struct text *text;
  434.       {
  435.       while (*s) {
  436.         if (--text->nleft < 0)
  437.           addchar(*s++, text);
  438.         else
  439.           *text->nextc++ = *s++;
  440.       }
  441. }
  442.  
  443.  
  444. void
  445. addchar(c, text)
  446.       register struct text *text;
  447.       {
  448.       struct block *bp;
  449.  
  450.       if (--text->nleft < 0) {
  451.         bp = ckmalloc(sizeof *bp);
  452.         if (text->start == NULL)
  453.           text->start = bp;
  454.         else
  455.           text->last->next = bp;
  456.         text->last = bp;
  457.         text->nextc = bp->text;
  458.         text->nleft = BLOCKSIZE - 1;
  459.       }
  460.       *text->nextc++ = c;
  461. }
  462.  
  463.  
  464. /*
  465.  * Write the contents of a text structure to a file.
  466.  */
  467.  
  468. void
  469. writetext(text, fp)
  470.       struct text *text;
  471.       FILE *fp;
  472.       {
  473.       struct block *bp;
  474.  
  475.       if (text->start != NULL) {
  476.         for (bp = text->start ; bp != text->last ; bp = bp->next)
  477.           fwrite(bp->text, sizeof (char), BLOCKSIZE, fp);
  478.         fwrite(bp->text, sizeof (char), BLOCKSIZE - text->nleft, fp);
  479.       }
  480. }
  481.  
  482.  
  483.  
  484. FILE *
  485. ckfopen(file, mode)
  486.       char *file;
  487.       char *mode;
  488.       {
  489.       FILE *fp;
  490.  
  491.       if ((fp = fopen(file, mode)) == NULL) {
  492.         fprintf(stderr, "Can't open %s\n", file);
  493.         exit(2);
  494.       }
  495.       return fp;
  496. }
  497.  
  498.  
  499.  
  500. #ifdef __STDC__
  501. void *
  502. #else
  503. char *
  504. #endif
  505. ckmalloc(nbytes) {
  506.       register char *p;
  507.       char *malloc();
  508.  
  509.       if ((p = malloc(nbytes)) == NULL)
  510.         error("Out of space");
  511.       return p;
  512. }
  513.  
  514.  
  515. char *
  516. savestr(s)
  517.       char *s;
  518.       {
  519.       register char *p;
  520.  
  521.       p = ckmalloc(strlen(s) + 1);
  522.       strcpy(p, s);
  523.       return p;
  524. }
  525.  
  526.  
  527.  
  528. void
  529. error(msg)
  530.       char *msg;
  531.       {
  532.       if (curfile != NULL)
  533.         fprintf(stderr, "%s:%d: ", curfile, linno);
  534.       fprintf(stderr, "%s\n", msg);
  535.       exit(2);
  536. }
  537. EOF
  538. if test `wc -c < mkinit.c` -ne 10550
  539. then    echo 'mkinit.c is the wrong size'
  540. fi
  541. echo extracting mknodes.c
  542. cat > mknodes.c <<\EOF
  543. /*
  544.  * This program reads the nodetypes file and nodes.c.pat file.  It generates
  545.  * the files nodes.h and nodes.c.
  546.  *
  547.  * Copyright (C) 1989 by Kenneth Almquist.  All rights reserved.
  548.  * This file is part of ash, which is distributed under the terms specified
  549.  * by the Ash General Public License.  See the file named LICENSE.
  550.  */
  551.  
  552. #include <stdio.h>
  553.  
  554.  
  555. #define MAXTYPES 50        /* max number of node types */
  556. #define MAXFIELDS 20        /* max fields in a structure */
  557. #define BUFLEN 100        /* size of character buffers */
  558.  
  559. /* field types */
  560. #define T_NODE 1        /* union node *field */
  561. #define T_NODELIST 2        /* struct nodelist *field */
  562. #define T_STRING 3
  563. #define T_INT 4            /* int field */
  564. #define T_OTHER 5        /* other */
  565. #define T_TEMP 6        /* don't copy this field */
  566.  
  567.  
  568. struct field {            /* a structure field */
  569.       char *name;        /* name of field */
  570.       int type;            /* type of field */
  571.       char *decl;        /* declaration of field */
  572. };
  573.  
  574.  
  575. struct str {            /* struct representing a node structure */
  576.       char *tag;        /* structure tag */
  577.       int nfields;        /* number of fields in the structure */
  578.       struct field field[MAXFIELDS];    /* the fields of the structure */
  579.       int done;            /* set if fully parsed */
  580. };
  581.  
  582.  
  583. int ntypes;            /* number of node types */
  584. char *nodename[MAXTYPES];    /* names of the nodes */
  585. struct str *nodestr[MAXTYPES];    /* type of structure used by the node */
  586. int nstr;            /* number of structures */
  587. struct str str[MAXTYPES];    /* the structures */
  588. struct str *curstr;        /* current structure */
  589.  
  590.  
  591. FILE *infp = stdin;
  592. char line[1024];
  593. int linno;
  594. char *linep;
  595.  
  596.  
  597. char *savestr();
  598. #define equal(s1, s2)    (strcmp(s1, s2) == 0)
  599.  
  600.  
  601. main(argc, argv)
  602.       char **argv;
  603.       {
  604.       if ((infp = fopen("nodetypes", "r")) == NULL)
  605.         error("Can't open nodetypes");
  606.       while (readline()) {
  607.         if (line[0] == ' ' || line[0] == '\t')
  608.           parsefield();
  609.         else if (line[0] != '\0')
  610.           parsenode();
  611.       }
  612.       output();
  613. }
  614.  
  615.  
  616.  
  617. parsenode() {
  618.       char name[BUFLEN];
  619.       char tag[BUFLEN];
  620.       struct str *sp;
  621.  
  622.       if (curstr && curstr->nfields > 0)
  623.         curstr->done = 1;
  624.       nextfield(name);
  625.       if (! nextfield(tag))
  626.         error("Tag expected");
  627.       if (*linep != '\0')
  628.         error("Garbage at end of line");
  629.       nodename[ntypes] = savestr(name);
  630.       for (sp = str ; sp < str + nstr ; sp++) {
  631.         if (equal(sp->tag, tag))
  632.           break;
  633.       }
  634.       if (sp >= str + nstr) {
  635.         sp->tag = savestr(tag);
  636.         sp->nfields = 0;
  637.         curstr = sp;
  638.         nstr++;
  639.       }
  640.       nodestr[ntypes] = sp;
  641.       ntypes++;
  642. }
  643.  
  644.  
  645. parsefield() {
  646.       char name[BUFLEN];
  647.       char type[BUFLEN];
  648.       char decl[2 * BUFLEN];
  649.       struct field *fp;
  650.  
  651.       if (curstr == NULL || curstr->done)
  652.         error("No current structure to add field to");
  653.       if (! nextfield(name))
  654.         error("No field name");
  655.       if (! nextfield(type))
  656.         error("No field type");
  657.       fp = &curstr->field[curstr->nfields];
  658.       fp->name = savestr(name);
  659.       if (equal(type, "nodeptr")) {
  660.         fp->type = T_NODE;
  661.         sprintf(decl, "union node *%s", name);
  662.       } else if (equal(type, "nodelist")) {
  663.         fp->type = T_NODELIST;
  664.         sprintf(decl, "struct nodelist *%s", name);
  665.       } else if (equal(type, "string")) {
  666.         fp->type = T_STRING;
  667.         sprintf(decl, "char *%s", name);
  668.       } else if (equal(type, "int")) {
  669.         fp->type = T_INT;
  670.         sprintf(decl, "int %s", name);
  671.       } else if (equal(type, "other")) {
  672.         fp->type = T_OTHER;
  673.       } else if (equal(type, "temp")) {
  674.         fp->type = T_TEMP;
  675.       } else {
  676.         error("Unknown type %s", type);
  677.       }
  678.       if (fp->type == T_OTHER || fp->type == T_TEMP) {
  679.         skipbl();
  680.         fp->decl = savestr(linep);
  681.       } else {
  682.         if (*linep)
  683.           error("Garbage at end of line");
  684.         fp->decl = savestr(decl);
  685.       }
  686.       curstr->nfields++;
  687. }
  688.  
  689.  
  690. char writer[] = "\
  691. /*\n\
  692.  * This file was generated by the mknodes program.\n\
  693.  */\n\
  694. \n";
  695.  
  696. output() {
  697.       FILE *hfile;
  698.       FILE *cfile;
  699.       FILE *patfile;
  700.       int i;
  701.       struct str *sp;
  702.       struct field *fp;
  703.       char *p;
  704.  
  705.       if ((patfile = fopen("nodes.c.pat", "r")) == NULL)
  706.         error("Can't open nodes.c.pat");
  707.       if ((hfile = fopen("nodes.h", "w")) == NULL)
  708.         error("Can't create nodes.h");
  709.       if ((cfile = fopen("nodes.c", "w")) == NULL)
  710.         error("Can't create nodes.c");
  711.       fputs(writer, hfile);
  712.       for (i = 0 ; i < ntypes ; i++)
  713.         fprintf(hfile, "#define %s %d\n", nodename[i], i);
  714.       fputs("\n\n\n", hfile);
  715.       for (sp = str ; sp < &str[nstr] ; sp++) {
  716.         fprintf(hfile, "struct %s {\n", sp->tag);
  717.         for (i = sp->nfields, fp = sp->field ; --i >= 0 ; fp++) {
  718.           fprintf(hfile, "      %s;\n", fp->decl);
  719.         }
  720.         fputs("};\n\n\n", hfile);
  721.       }
  722.       fputs("union node {\n", hfile);
  723.       fprintf(hfile, "      int type;\n");
  724.       for (sp = str ; sp < &str[nstr] ; sp++) {
  725.         fprintf(hfile, "      struct %s %s;\n", sp->tag, sp->tag);
  726.       }
  727.       fputs("};\n\n\n", hfile);
  728.       fputs("struct nodelist {\n", hfile);
  729.       fputs("\tstruct nodelist *next;\n", hfile);
  730.       fputs("\tunion node *n;\n", hfile);
  731.       fputs("};\n\n\n", hfile);
  732.       fputs("#ifdef __STDC__\n", hfile);
  733.       fputs("union node *copyfunc(union node *);\n", hfile);
  734.       fputs("void freefunc(union node *);\n", hfile);
  735.       fputs("#else\n", hfile);
  736.       fputs("union node *copyfunc();\n", hfile);
  737.       fputs("void freefunc();\n", hfile);
  738.       fputs("#endif\n", hfile);
  739.  
  740.       fputs(writer, cfile);
  741.       while (fgets(line, sizeof line, patfile) != NULL) {
  742.         for (p = line ; *p == ' ' || *p == '\t' ; p++);
  743.         if (equal(p, "%SIZES\n"))
  744.           outsizes(cfile);
  745.         else if (equal(p, "%CALCSIZE\n"))
  746.           outfunc(cfile, 1);
  747.         else if (equal(p, "%COPY\n"))
  748.           outfunc(cfile, 0);
  749.         else
  750.           fputs(line, cfile);
  751.       }
  752. }
  753.  
  754.  
  755.  
  756. outsizes(cfile)
  757.       FILE *cfile;
  758.       {
  759.       int i;
  760.  
  761.       fprintf(cfile, "static const short nodesize[%d] = {\n", ntypes);
  762.       for (i = 0 ; i < ntypes ; i++) {
  763.         fprintf(cfile, "      ALIGN(sizeof (struct %s)),\n", nodestr[i]->tag);
  764.       }
  765.       fprintf(cfile, "};\n");
  766. }
  767.  
  768.  
  769. outfunc(cfile, calcsize)
  770.       FILE *cfile;
  771.       {
  772.       struct str *sp;
  773.       struct field *fp;
  774.       int i;
  775.  
  776.       fputs("      if (n == NULL)\n", cfile);
  777.       if (calcsize)
  778.         fputs("        return;\n", cfile);
  779.       else
  780.         fputs("        return NULL;\n", cfile);
  781.       if (calcsize)
  782.         fputs("      funcblocksize += nodesize[n->type];\n", cfile);
  783.       else {
  784.         fputs("      new = funcblock;\n", cfile);
  785.         fputs("      funcblock += nodesize[n->type];\n", cfile);
  786.       }
  787.       fputs("      switch (n->type) {\n", cfile);
  788.       for (sp = str ; sp < &str[nstr] ; sp++) {
  789.         for (i = 0 ; i < ntypes ; i++) {
  790.           if (nodestr[i] == sp)
  791.             fprintf(cfile, "      case %s:\n", nodename[i]);
  792.         }
  793.         for (i = sp->nfields ; --i >= 1 ; ) {
  794.           fp = &sp->field[i];
  795.           switch (fp->type) {
  796.           case T_NODE:
  797.             if (calcsize) {
  798.                   indent(12, cfile);
  799.                   fprintf(cfile, "calcsize(n->%s.%s);\n",
  800.                     sp->tag, fp->name);
  801.             } else {
  802.                   indent(12, cfile);
  803.                   fprintf(cfile, "new->%s.%s = copynode(n->%s.%s);\n",
  804.                     sp->tag, fp->name, sp->tag, fp->name);
  805.             }
  806.             break;
  807.           case T_NODELIST:
  808.             if (calcsize) {
  809.                   indent(12, cfile);
  810.                   fprintf(cfile, "sizenodelist(n->%s.%s);\n",
  811.                     sp->tag, fp->name);
  812.             } else {
  813.                   indent(12, cfile);
  814.                   fprintf(cfile, "new->%s.%s = copynodelist(n->%s.%s);\n",
  815.                     sp->tag, fp->name, sp->tag, fp->name);
  816.             }
  817.             break;
  818.           case T_STRING:
  819.             if (calcsize) {
  820.                   indent(12, cfile);
  821.                   fprintf(cfile, "funcstringsize += strlen(n->%s.%s) + 1;\n",
  822.                     sp->tag, fp->name);
  823.             } else {
  824.                   indent(12, cfile);
  825.                   fprintf(cfile, "new->%s.%s = nodesavestr(n->%s.%s);\n",
  826.                     sp->tag, fp->name, sp->tag, fp->name);
  827.             }
  828.             break;
  829.           case T_INT:
  830.           case T_OTHER:
  831.             if (! calcsize) {
  832.                   indent(12, cfile);
  833.                   fprintf(cfile, "new->%s.%s = n->%s.%s;\n",
  834.                     sp->tag, fp->name, sp->tag, fp->name);
  835.             }
  836.             break;
  837.           }
  838.         }
  839.         indent(12, cfile);
  840.         fputs("break;\n", cfile);
  841.       }
  842.       fputs("      };\n", cfile);
  843.       if (! calcsize)
  844.         fputs("      new->type = n->type;\n", cfile);
  845. }
  846.  
  847.  
  848. indent(amount, fp)
  849.       FILE *fp;
  850.       {
  851.       while (amount >= 8) {
  852.         putc('\t', fp);
  853.         amount -= 8;
  854.       }
  855.       while (--amount >= 0) {
  856.         putc(' ', fp);
  857.       }
  858. }
  859.  
  860.  
  861. int
  862. nextfield(buf)
  863.       char *buf;
  864.       {
  865.       register char *p, *q;
  866.  
  867.       p = linep;
  868.       while (*p == ' ' || *p == '\t')
  869.         p++;
  870.       q = buf;
  871.       while (*p != ' ' && *p != '\t' && *p != '\0')
  872.         *q++ = *p++;
  873.       *q = '\0';
  874.       linep = p;
  875.       return (q > buf);
  876. }
  877.  
  878.  
  879. skipbl() {
  880.       while (*linep == ' ' || *linep == '\t')
  881.         linep++;
  882. }
  883.  
  884.  
  885. int
  886. readline() {
  887.       register char *p;
  888.  
  889.       if (fgets(line, 1024, infp) == NULL)
  890.         return 0;
  891.       for (p = line ; *p != '#' && *p != '\n' && *p != '\0' ; p++);
  892.       while (p > line && (p[-1] == ' ' || p[-1] == '\t'))
  893.         p--;
  894.       *p = '\0';
  895.       linep = line;
  896.       linno++;
  897.       if (p - line > BUFLEN)
  898.         error("Line too long");
  899.       return 1;
  900. }
  901.  
  902.  
  903.  
  904. error(msg, a1, a2, a3, a4, a5, a6)
  905.       char *msg;
  906.       {
  907.       fprintf(stderr, "line %d: ", linno);
  908.       fprintf(stderr, msg, a1, a2, a3, a4, a5, a6);
  909.       putc('\n', stderr);
  910.       exit(2);
  911. }
  912.  
  913.  
  914.  
  915. char *
  916. savestr(s)
  917.       char *s;
  918.       {
  919.       register char *p;
  920.       char *malloc();
  921.  
  922.       if ((p = malloc(strlen(s) + 1)) == NULL)
  923.         error("Out of space");
  924.       strcpy(p, s);
  925.       return p;
  926. }
  927. EOF
  928. if test `wc -c < mknodes.c` -ne 9481
  929. then    echo 'mknodes.c is the wrong size'
  930. fi
  931. echo extracting mksignames.c
  932. cat > mksignames.c <<\EOF
  933. /*
  934.  * This program generates the signames.h and signames.c files.
  935.  *
  936.  * Copyright (C) 1989 by Kenneth Almquist.  All rights reserved.
  937.  * This file is part of ash, which is distributed under the terms specified
  938.  * by the Ash General Public License.  See the file named LICENSE.
  939.  */
  940. #include <stdio.h>
  941. #include <signal.h>
  942.  
  943.  
  944.  
  945. struct sig {
  946.       int signo;        /* signal number */
  947.       char *name;        /* signal name (without leading "SIG") */
  948.       char *mesg;        /* description */
  949. };
  950.  
  951.  
  952. struct sig sigtab[] = {
  953.       SIGHUP, "HUP", "Hangup",
  954.       SIGINT, "INT", "Interrupt",    /* normally don't print message */
  955.       SIGQUIT, "QUIT", "Quit",
  956.       SIGILL, "ILL", "Illegal instruction",
  957.       SIGTRAP, "TRAP", "Trace/BPT trap",
  958. #ifdef SIGABRT
  959.       SIGABRT, "ABRT", "abort",
  960. #endif
  961. #if defined(SIGIOT) && (! defined(SIGABRT) || SIGABRT != SIGIOT)
  962.       SIGIOT, "IOT", "abort",
  963. #endif
  964. #ifdef SIGEMT
  965.       SIGEMT, "EMT", "EMT trap",
  966. #endif
  967.       SIGFPE, "FPE", "Floating exception",
  968.       SIGKILL, "KILL", "Killed",
  969.       SIGBUS, "BUS", "Bus error",
  970.       SIGSEGV, "SEGV", "Memory fault",
  971.       SIGSYS, "SYS", "Bad system call",
  972.       SIGPIPE, "PIPE", "Broken pipe",    /* normally don't print message */
  973.       SIGALRM, "ALRM", "Alarm call",
  974.       SIGTERM, "TERM", "Terminated",
  975. #ifdef SIGUSR1
  976.       SIGUSR1, "USR1", "User signal 1",
  977. #endif
  978. #ifdef SIGUSR2
  979.       SIGUSR2, "USR2", "User signal 2",
  980. #endif
  981. #ifdef SIGCLD
  982.       SIGCLD, "CLD", NULL,
  983. #endif
  984. #if defined(SIGCHLD) && ! defined(SIGCLD)
  985.       SIGCHLD, "CLD", NULL,
  986. #endif
  987. #ifdef SIGPWR
  988.       SIGPWR, "PWR", "Power fail",
  989. #endif
  990. #ifdef SIGPOLL
  991.       SIGPOLL, "POLL", "Poll",
  992. #endif
  993.       /* Now for the BSD signals */
  994. #ifdef SIGURG
  995.       SIGURG, "URG", NULL,
  996. #endif
  997. #ifdef SIGSTOP
  998.       SIGSTOP, "STOP", "Stopped",
  999. #endif
  1000. #ifdef SIGTSTP
  1001.       SIGTSTP, "TSTP", "Stopped",
  1002. #endif
  1003. #ifdef SIGCONT
  1004.       SIGCONT, "CONT", NULL,
  1005. #endif
  1006. #ifdef SIGTTIN
  1007.       SIGTTIN, "TTIN", "Stopped (input)",
  1008. #endif
  1009. #ifdef SIGTTOU
  1010.       SIGTTOU, "TTOU", "Stopped (output)",
  1011. #endif
  1012. #ifdef SIGIO
  1013.       SIGIO, "IO", NULL,
  1014. #endif
  1015. #ifdef SIGXCPU
  1016.       SIGXCPU, "XCPU", "Time limit exceeded",
  1017. #endif
  1018. #ifdef SIGXFSZ
  1019.       SIGXFSZ, "XFSZ", NULL,
  1020. #endif
  1021. #ifdef SIGVTALARM
  1022.       SIGVTALARM, "VTALARM", "Virtual alarm",
  1023. #endif
  1024. #ifdef SIGPROF
  1025.       SIGPROF, "PROF", "Profiling alarm",
  1026. #endif
  1027. #ifdef SIGWINCH
  1028.       SIGWINCH, "WINCH", NULL,
  1029. #endif
  1030.       0, NULL, NULL
  1031. };
  1032.  
  1033.  
  1034. #define MAXSIG 64
  1035.  
  1036.  
  1037. char *sigmesg[MAXSIG + 1];
  1038.  
  1039.  
  1040. char writer[] = "\
  1041. /*\n\
  1042.  * This file was generated by the mksignames program.\n\
  1043.  */\n\
  1044. \n";
  1045.  
  1046.  
  1047.  
  1048. main(argc, argv)  char **argv; {
  1049.       FILE *cfile, *hfile;    
  1050.       struct sig *sigp;
  1051.       int maxsig;
  1052.       int i;
  1053.  
  1054.       if ((cfile = fopen("signames.c", "w")) == NULL) {
  1055.         fputs("Can't create signames.c\n", stderr);
  1056.         exit(2);
  1057.       }
  1058.       if ((hfile = fopen("signames.h", "w")) == NULL) {
  1059.         fputs("Can't create signames.h\n", stderr);
  1060.         exit(2);
  1061.       }
  1062.       maxsig = 0;
  1063.       for (sigp = sigtab ; sigp->signo != 0 ; sigp++) {
  1064.         if (sigp->signo < 0 || sigp->signo > MAXSIG)
  1065.           continue;
  1066.         sigmesg[sigp->signo] = sigp->mesg;
  1067.         if (maxsig < sigp->signo)
  1068.           maxsig = sigp->signo;
  1069.       }
  1070.  
  1071.       fputs(writer, hfile);
  1072.       fprintf(hfile, "#define MAXSIG %d\n\n", maxsig);
  1073.       fprintf(hfile, "extern char *const sigmesg[MAXSIG+1];\n");
  1074.  
  1075.       fputs(writer, cfile);
  1076.       fprintf(cfile, "#include \"shell.h\"\n\n");
  1077.       fprintf(cfile, "char *const sigmesg[%d] = {\n", maxsig + 1);
  1078.       for (i = 0 ; i <= maxsig ; i++) {
  1079.         if (sigmesg[i] == NULL) {
  1080.           fprintf(cfile, "      0,\n");
  1081.         } else {
  1082.           fprintf(cfile, "      \"%s\",\n", sigmesg[i]);
  1083.         }
  1084.       }
  1085.       fprintf(cfile, "};\n");
  1086.       exit(0);
  1087. }
  1088. EOF
  1089. if test `wc -c < mksignames.c` -ne 3662
  1090. then    echo 'mksignames.c is the wrong size'
  1091. fi
  1092. echo extracting mksyntax.c
  1093. cat > mksyntax.c <<\EOF
  1094. /*
  1095.  * This program creates syntax.h and syntax.c.
  1096.  *
  1097.  * Copyright (C) 1989 by Kenneth Almquist.  All rights reserved.
  1098.  * This file is part of ash, which is distributed under the terms specified
  1099.  * by the Ash General Public License.  See the file named LICENSE.
  1100.  */
  1101.  
  1102. #include <stdio.h>
  1103. #include "parser.h"
  1104.  
  1105.  
  1106. struct synclass {
  1107.       char *name;
  1108.       char *comment;
  1109. };
  1110.  
  1111. /* Syntax classes */
  1112. struct synclass synclass[] = {
  1113.       "CWORD",        "character is nothing special",
  1114.       "CNL",        "newline character",
  1115.       "CBACK",        "a backslash character",
  1116.       "CSQUOTE",    "single quote",
  1117.       "CDQUOTE",    "double quote",
  1118.       "CENDQUOTE",    "a terminating quote",
  1119.       "CBQUOTE",    "backwards single quote",
  1120.       "CVAR",        "a dollar sign",
  1121.       "CENDVAR",    "a '}' character",
  1122.       "CEOF",        "end of file",
  1123.       "CCTL",        "like CWORD, except it must be escaped",
  1124.       "CSPCL",        "these terminate a word",
  1125.       NULL, NULL
  1126. };
  1127.  
  1128.  
  1129. /*
  1130.  * Syntax classes for is_ functions.  Warning:  if you add new classes
  1131.  * you may have to change the definition of the is_in_name macro.
  1132.  */
  1133. struct synclass is_entry[] = {
  1134.       "ISDIGIT",    "a digit",
  1135.       "ISUPPER",    "an upper case letter",
  1136.       "ISLOWER",    "a lower case letter",
  1137.       "ISUNDER",    "an underscore",
  1138.       "ISSPECL",    "the name of a special parameter",
  1139.       NULL, NULL,
  1140. };
  1141.  
  1142. char writer[] = "\
  1143. /*\n\
  1144.  * This file was generated by the mksyntax program.\n\
  1145.  */\n\
  1146. \n";
  1147.  
  1148.  
  1149. FILE *cfile;
  1150. FILE *hfile;
  1151. char *syntax[513];
  1152. int base;
  1153. int size;        /* number of values which a char variable can have */
  1154. int nbits;        /* number of bits in a character */
  1155. int digit_contig;    /* true if digits are contiguous */
  1156.  
  1157.  
  1158. main() {
  1159.       char c;
  1160.       char d;
  1161.       int sign;
  1162.       int i;
  1163.       char buf[80];
  1164.       int pos;
  1165.       static char digit[] = "0123456789";
  1166.  
  1167.       /* Create output files */
  1168.       if ((cfile = fopen("syntax.c", "w")) == NULL) {
  1169.         perror("syntax.c");
  1170.         exit(2);
  1171.       }
  1172.       if ((hfile = fopen("syntax.h", "w")) == NULL) {
  1173.         perror("syntax.h");
  1174.         exit(2);
  1175.       }
  1176.       fputs(writer, hfile);
  1177.       fputs(writer, cfile);
  1178.  
  1179.       /* Determine the characteristics of chars. */
  1180.       c = -1;
  1181.       if (c < 0)
  1182.         sign = 1;
  1183.       else
  1184.         sign = 0;
  1185.       for (nbits = 1 ; ; nbits++) {
  1186.         d = (1 << nbits) - 1;
  1187.         if (d == c)
  1188.           break;
  1189.       }
  1190.       printf("%s %d bit chars\n", sign? "signed" : "unsigned", nbits);
  1191.       if (nbits > 9) {
  1192.         fputs("Characters can't have more than 9 bits\n", stderr);
  1193.         exit(2);
  1194.       }
  1195.       size = (1 << nbits) + 1;
  1196.       base = 1;
  1197.       if (sign)
  1198.         base += 1 << (nbits - 1);
  1199.       digit_contig = 1;
  1200.       for (i = 0 ; i < 10 ; i++) {
  1201.         if (digit[i] != '0' + i)
  1202.           digit_contig = 0;
  1203.       }
  1204.  
  1205.       /* Generate the #define statements in the header file */
  1206.       fputs("/* Syntax classes */\n", hfile);
  1207.       for (i = 0 ; synclass[i].name ; i++) {
  1208.         sprintf(buf, "#define %s %d", synclass[i].name, i);
  1209.         fputs(buf, hfile);
  1210.         for (pos = strlen(buf) ; pos < 32 ; pos = pos + 8 &~ 07)
  1211.           putc('\t', hfile);
  1212.         fprintf(hfile, "/* %s */\n", synclass[i].comment);
  1213.       }
  1214.       putc('\n', hfile);
  1215.       fputs("/* Syntax classes for is_ functions */\n", hfile);
  1216.       for (i = 0 ; is_entry[i].name ; i++) {
  1217.         sprintf(buf, "#define %s %#o", is_entry[i].name, 1 << i);
  1218.         fputs(buf, hfile);
  1219.         for (pos = strlen(buf) ; pos < 32 ; pos = pos + 8 &~ 07)
  1220.           putc('\t', hfile);
  1221.         fprintf(hfile, "/* %s */\n", is_entry[i].comment);
  1222.       }
  1223.       putc('\n', hfile);
  1224.       fprintf(hfile, "#define SYNBASE %d\n", base);
  1225.       fprintf(hfile, "#define PEOF %d\n\n", -base);
  1226.       putc('\n', hfile);
  1227.       fputs("#define BASESYNTAX (basesyntax + SYNBASE)\n", hfile);
  1228.       fputs("#define DQSYNTAX (dqsyntax + SYNBASE)\n", hfile);
  1229.       fputs("#define SQSYNTAX (sqsyntax + SYNBASE)\n", hfile);
  1230.       putc('\n', hfile);
  1231.       output_type_macros();        /* is_digit, etc. */
  1232.       putc('\n', hfile);
  1233.  
  1234.       /* Generate the syntax tables. */
  1235.       fputs("#include \"shell.h\"\n", cfile);
  1236.       fputs("#include \"syntax.h\"\n\n", cfile);
  1237.       init();
  1238.       fputs("/* syntax table used when not in quotes */\n", cfile);
  1239.       add("\n", "CNL");
  1240.       add("\\", "CBACK");
  1241.       add("'", "CSQUOTE");
  1242.       add("\"", "CDQUOTE");
  1243.       add("`", "CBQUOTE");
  1244.       add("$", "CVAR");
  1245.       add("}", "CENDVAR");
  1246.       add("<>();&| \t", "CSPCL");
  1247.       print("basesyntax");
  1248.       init();
  1249.       fputs("\n/* syntax table used when in double quotes */\n", cfile);
  1250.       add("\n", "CNL");
  1251.       add("\\", "CBACK");
  1252.       add("\"", "CENDQUOTE");
  1253.       add("`", "CBQUOTE");
  1254.       add("$", "CVAR");
  1255.       add("}", "CENDVAR");
  1256.       add("!*?[=", "CCTL");
  1257.       print("dqsyntax");
  1258.       init();
  1259.       fputs("\n/* syntax table used when in single quotes */\n", cfile);
  1260.       add("\n", "CNL");
  1261.       add("'", "CENDQUOTE");
  1262.       add("!*?[=", "CCTL");
  1263.       print("sqsyntax");
  1264.       filltable("0");
  1265.       fputs("\n/* character classification table */\n", cfile);
  1266.       add("0123456789", "ISDIGIT");
  1267.       add("abcdefghijklmnopqrstucvwxyz", "ISLOWER");
  1268.       add("ABCDEFGHIJKLMNOPQRSTUCVWXYZ", "ISUPPER");
  1269.       add("_", "ISUNDER");
  1270.       add("#?$!-*@", "ISSPECL");
  1271.       print("is_type");
  1272.       if (! digit_contig)
  1273.         digit_convert();
  1274.       exit(0);
  1275. }
  1276.  
  1277.  
  1278.  
  1279. /*
  1280.  * Clear the syntax table.
  1281.  */
  1282.  
  1283. filltable(dftval)
  1284.       char *dftval;
  1285.       {
  1286.       int i;
  1287.  
  1288.       for (i = 0 ; i < size ; i++)
  1289.         syntax[i] = dftval;
  1290. }
  1291.  
  1292.  
  1293. /*
  1294.  * Initialize the syntax table with default values.
  1295.  */
  1296.  
  1297. init() {
  1298.       filltable("CWORD");
  1299.       syntax[0] = "CEOF";
  1300.       syntax[base + CTLESC] = "CCTL";
  1301.       syntax[base + CTLVAR] = "CCTL";
  1302.       syntax[base + CTLENDVAR] = "CCTL";
  1303.       syntax[base + CTLBACKQ] = "CCTL";
  1304.       syntax[base + CTLBACKQ + CTLQUOTE] = "CCTL";
  1305. }
  1306.  
  1307.  
  1308. /*
  1309.  * Add entries to the syntax table.
  1310.  */
  1311.  
  1312. add(p, type)
  1313.       char *p, *type;
  1314.       {
  1315.       while (*p)
  1316.         syntax[*p++ + base] = type;
  1317. }
  1318.  
  1319.  
  1320.  
  1321. /*
  1322.  * Output the syntax table.
  1323.  */
  1324.  
  1325. print(name)
  1326.       char *name;
  1327.       {
  1328.       int i;
  1329.       int col;
  1330.  
  1331.       fprintf(hfile, "extern const char %s[];\n", name);
  1332.       fprintf(cfile, "const char %s[%d] = {\n", name, size);
  1333.       col = 0;
  1334.       for (i = 0 ; i < size ; i++) {
  1335.         if (i == 0) {
  1336.           fputs("      ", cfile);
  1337.         } else if ((i & 03) == 0) {
  1338.           fputs(",\n      ", cfile);
  1339.           col = 0;
  1340.         } else {
  1341.           putc(',', cfile);
  1342.           while (++col < 9 * (i & 03))
  1343.             putc(' ', cfile);
  1344.         }
  1345.         fputs(syntax[i], cfile);
  1346.         col += strlen(syntax[i]);
  1347.       }
  1348.       fputs("\n};\n", cfile);
  1349. }
  1350.  
  1351.  
  1352.  
  1353. /*
  1354.  * Output character classification macros (e.g. is_digit).  If digits are
  1355.  * contiguous, we can test for them quickly.
  1356.  */
  1357.  
  1358. char *macro[] = {
  1359.       "#define is_digit(c)\t((is_type+SYNBASE)[c] & ISDIGIT)",
  1360.       "#define is_alpha(c)\t((is_type+SYNBASE)[c] & (ISUPPER|ISLOWER))",
  1361.       "#define is_name(c)\t((is_type+SYNBASE)[c] & (ISUPPER|ISLOWER|ISUNDER))",
  1362.       "#define is_in_name(c)\t((is_type+SYNBASE)[c] & (ISUPPER|ISLOWER|ISUNDER|ISDIGIT))",
  1363.       "#define is_special(c)\t((is_type+SYNBASE)[c] & (ISSPECL|ISDIGIT))",
  1364.       NULL
  1365. };
  1366.  
  1367. output_type_macros() {
  1368.       char **pp;
  1369.  
  1370.       if (digit_contig)
  1371.         macro[0] = "#define is_digit(c)\t((unsigned)((c) - '0') <= 9)";
  1372.       for (pp = macro ; *pp ; pp++)
  1373.         fprintf(hfile, "%s\n", *pp);
  1374.       if (digit_contig)
  1375.         fputs("#define digit_val(c)\t((c) - '0')\n", hfile);
  1376.       else
  1377.         fputs("#define digit_val(c)\t(digit_value[c])\n", hfile);
  1378. }
  1379.  
  1380.  
  1381.  
  1382. /*
  1383.  * Output digit conversion table (if digits are not contiguous).
  1384.  */
  1385.  
  1386. digit_convert() {
  1387.       int maxdigit;
  1388.       static char digit[] = "0123456789";
  1389.       char *p;
  1390.       int i;
  1391.  
  1392.       maxdigit = 0;
  1393.       for (p = digit ; *p ; p++)
  1394.         if (*p > maxdigit)
  1395.           maxdigit = *p;
  1396.       fputs("extern const char digit_value[];\n", hfile);
  1397.       fputs("\n\nconst char digit_value[] = {\n", cfile);
  1398.       for (i = 0 ; i <= maxdigit ; i++) {
  1399.         for (p = digit ; *p && *p != i ; p++);
  1400.         if (*p == '\0')
  1401.           p = digit;
  1402.         fprintf(cfile, "      %d,\n", p - digit);
  1403.       }
  1404.       fputs("};\n", cfile);
  1405. }
  1406. EOF
  1407. if test `wc -c < mksyntax.c` -ne 7949
  1408. then    echo 'mksyntax.c is the wrong size'
  1409. fi
  1410. echo extracting mktokens
  1411. cat > mktokens <<\EOF
  1412. # Copyright (C) 1989 by Kenneth Almquist.  All rights reserved.
  1413. # This file is part of ash, which is distributed under the terms specified
  1414. # by the Ash General Public License.  See the file named LICENSE.
  1415.  
  1416. # The following is a list of tokens.  The second column is nonzero if the
  1417. # token marks the end of a list.  The third column is the name to print in
  1418. # error messages.
  1419.  
  1420. cat > /tmp/ka$$ <<\!
  1421. TEOF    1    end of file
  1422. TNL    0    newline
  1423. TSEMI    0    ";"
  1424. TBACKGND 0    "&"
  1425. TAND    0    "&&"
  1426. TOR    0    "||"
  1427. TPIPE    0    "|"
  1428. TLP    0    "("
  1429. TRP    1    ")"
  1430. TENDCASE 1    ";;"
  1431. TENDBQUOTE 1    "`"
  1432. TREDIR    0    redirection
  1433. TWORD    0    word
  1434. TIF    0    "if"
  1435. TTHEN    1    "then"
  1436. TELSE    1    "else"
  1437. TELIF    1    "elif"
  1438. TFI    1    "fi"
  1439. TWHILE    0    "while"
  1440. TUNTIL    0    "until"
  1441. TFOR    0    "for"
  1442. TDO    1    "do"
  1443. TDONE    1    "done"
  1444. TBEGIN    0    "{"
  1445. TEND    1    "}"
  1446. TCASE    0    "case"
  1447. TESAC    1    "esac"
  1448. !
  1449. nl=`wc -l /tmp/ka$$`
  1450. exec > token.def
  1451. awk '{print "#define " $1 " " NR-1}' /tmp/ka$$
  1452. echo '
  1453. /* Array indicating which tokens mark the end of a list */
  1454. const char tokendlist[] = {'
  1455. awk '{print "\t" $2 ","}' /tmp/ka$$
  1456. echo '};
  1457.  
  1458. char *const tokname[] = {'
  1459. sed -e 's/"/\\"/g' \
  1460.     -e 's/[^     ]*[     ][     ]*[^     ]*[     ][     ]*\(.*\)/    "\1",/' \
  1461.     /tmp/ka$$
  1462. echo '};
  1463. '
  1464. sed 's/"//g' /tmp/ka$$ | awk '
  1465. /TIF/{print "#define KWDOFFSET " NR-1; print ""; print "char *const parsekwd[] = {"}
  1466. /TIF/,/neverfound/{print "    \"" $3 "\","}'
  1467. echo '    0
  1468. };'
  1469.  
  1470. rm /tmp/ka$$
  1471. EOF
  1472. if test `wc -c < mktokens` -ne 1315
  1473. then    echo 'mktokens is the wrong size'
  1474. fi
  1475. chmod 755 mktokens
  1476. echo extracting myerrno.h
  1477. cat > myerrno.h <<\EOF
  1478. /*
  1479.  * Some versions of errno.h don't declare errno, so we do it ourself.
  1480.  *
  1481.  * Copyright (C) 1989 by Kenneth Almquist.  All rights reserved.
  1482.  * This file is part of ash, which is distributed under the terms specified
  1483.  * by the Ash General Public License.  See the file named LICENSE.
  1484.  */
  1485.  
  1486. #include <sys/errno.h>
  1487.  
  1488. extern int errno;
  1489. EOF
  1490. if test `wc -c < myerrno.h` -ne 331
  1491. then    echo 'myerrno.h is the wrong size'
  1492. fi
  1493. echo extracting mymalloc.c
  1494. cat > mymalloc.c <<\EOF
  1495. /*
  1496.  * First fit memory allocation.  (Generally uses memory pretty efficiently,
  1497.  * although it is slower than some other memory allocators.)
  1498.  *
  1499.  * Copyright (C) 1989 by Kenneth Almquist.  All rights reserved.
  1500.  * This file is part of ash, which is distributed under the terms specified
  1501.  * by the Ash General Public License.  See the file named LICENSE.
  1502.  */
  1503.  
  1504.  
  1505. #include "shell.h"
  1506. #include "machdep.h"
  1507. #include "mystring.h"
  1508. #include <sys/types.h>
  1509.  
  1510.  
  1511. /*
  1512.  * The free memory pool consists of a collection of contiguous blocks.
  1513.  * Each block has an integer at the beginning of it which specifies the
  1514.  * size of the block.  If the block is allocated, the integer contains
  1515.  * the negative of the size.  After the last block comes an integer with
  1516.  * a value of zero.
  1517.  *
  1518.  * To allocate a block, we want to scan the list of blocks starting with
  1519.  * the first block, merging adjacent free blocks, until we get a free
  1520.  * block which is large enough.  The actual implementation uses some
  1521.  * hacks to decrease the amount of scanning required.  Startfree always
  1522.  * points to the first free block or a block before it.  This keeps us
  1523.  * from repeatedly scanning allocated block at the start of the memory
  1524.  * pool.  In a similar vein, startbig points to what we believe is the
  1525.  * first free block whose size is >= BIG or a block before it.  Startbig
  1526.  * can actually point to some location after the first large free if the
  1527.  * first large free block was formed by freeing several small blocks
  1528.  * which have not yet been merged into a single free block.  To make this
  1529.  * less likely, the free routine will merge a freed block with any free
  1530.  * blocks after it, but the free routine cannot merge a freed block with
  1531.  * free blocks which precede it because there is no (efficient) way for
  1532.  * free to locate the preceding block.
  1533.  *
  1534.  * The variables lastsize and lastloc are used to implement one final
  1535.  * method to cut down on scanning.  When a malloc is performed, the
  1536.  * variable lastsize is set to the size of the largest block skipped
  1537.  * during the scan, and the variable lastloc is set to the end of the
  1538.  * scan.  The next call to malloc can start where the preceding one left
  1539.  * off if the number of bytes reqested is larger than the size of any
  1540.  * blocks skipped on the preceding malloc.  When a block is freed with a
  1541.  * lower address than lastloc, free assumes that the block is adjacent to
  1542.  * the largest free block skipped by malloc, and updates lastsize
  1543.  * accordingly.  This is necessary to ensure that starting at lastloc
  1544.  * will never cause a block that could be allocated to be skipped; a more
  1545.  * aggressive policy could be used.
  1546.  */
  1547.  
  1548.  
  1549.  
  1550. /*
  1551.  * Machine dependent stuff:
  1552.  *
  1553.  * PAGE_SIZE is the size of a page.  Malloc will try to keep the break
  1554.  * location on a page boundary to avoid wasting space (since the operating
  1555.  * system presumably has to allocate a whole page even if we only request
  1556.  * part of one).  PAGE_SIZE must be a power of 2.
  1557.  *
  1558.  * Head_t is a signed integer type that is capable of holding a value one
  1559.  * less than the maximum size of the pool.  Type int works fine on a VAX
  1560.  * because on a VAX processes only get 31 bits of address space.  In
  1561.  * practice most other 32 bit machines aren't going to allow processes to
  1562.  * allocate more that 2 gigabytes either.
  1563.  *
  1564.  * Machines generally have alignment restrictions which malloc must
  1565.  * obey.  ALIGN(n) returns the value of n rounded up to the minimum
  1566.  * value that malloc must allocate to keep things aligned.
  1567.  *
  1568.  * The code here assumes a linear address space, with sbrk allocating
  1569.  * successively higher addresses.
  1570.  */
  1571.  
  1572.  
  1573. #define PAGE_SIZE 1024
  1574. #define PAGE_MASK (PAGE_SIZE - 1)
  1575.  
  1576.  
  1577. #define head_t int
  1578. #define HEADSIZE ALIGN(sizeof (head_t))
  1579.  
  1580. #define DEREF(p)    (*(head_t *)(p))
  1581.  
  1582.  
  1583. #ifndef ALIGN
  1584. union align {
  1585.       long l;
  1586.       char *cp;
  1587. };
  1588.  
  1589. #define ALIGN(nbytes)    ((nbytes) + sizeof(union align) - 1 &~ (sizeof(union align) - 1))
  1590. #endif
  1591.  
  1592.  
  1593. /*
  1594.  * Tunable paramaters.  SLOP is the smallest free block that malloc or
  1595.  * realloc will create.  If they would have to create a smaller free
  1596.  * block to satisfy the caller's request, they allocate the extra bytes
  1597.  * to the caller rather than forming a free block.  BIG is the smallest
  1598.  * block size that will cause the scan to start at startbig; this is
  1599.  * used to keep requests for large blocks from scanning lots of small
  1600.  * blocks.  MINSBRK is the smallest number of pages that will be requested
  1601.  * from sbrk at a time.  A larger value can cut down the number of calls
  1602.  * to sbrk.  MINSBRK should be a multiple of PAGE_SIZE.
  1603.  */
  1604.  
  1605. #define SLOP 8
  1606. #define BIG 500
  1607. #define MINSBRK (2 * PAGE_SIZE)
  1608.  
  1609.  
  1610. pointer startfree;    /* where to start search for n < BIG */
  1611. pointer startbig;    /* where to start search for n >= BIG */
  1612. pointer lastloc;    /* where last search terminated */
  1613. head_t lastsize;    /* largest block skipped on last search */
  1614.  
  1615.  
  1616.  
  1617. pointer realloc();
  1618. void free();
  1619. caddr_t sbrk();
  1620.  
  1621.  
  1622.  
  1623. pointer
  1624. malloc(n)
  1625.       unsigned n;
  1626.       {
  1627.       return realloc((pointer)0, n);
  1628. }
  1629.  
  1630.  
  1631.  
  1632. pointer
  1633. realloc(old, nbytes)
  1634.       pointer old;
  1635.       unsigned nbytes;
  1636.       {
  1637.       head_t n = nbytes + HEADSIZE;
  1638.       pointer p, q;
  1639.       head_t i;
  1640.       head_t size;
  1641.       head_t largest;
  1642.       pointer next;
  1643.       head_t allocsize;
  1644.  
  1645.       if (n < 0)
  1646.         return NULL;    /* nbytes out of range */
  1647.       n = ALIGN(n);
  1648.       if (startfree == NULL) {    /* first time called */
  1649.         p = sbrk(0);
  1650.         allocsize = PAGE_SIZE - ((int)p & PAGE_MASK);
  1651.         if (allocsize < n + 2 * HEADSIZE)
  1652.           allocsize += MINSBRK;
  1653.         if (sbrk(allocsize) != p)
  1654.           return NULL;
  1655.         DEREF(p) = allocsize - HEADSIZE;
  1656.         startfree = startbig = lastloc = p;
  1657.         lastsize = 0;
  1658.       }
  1659.       if (old) {    /* it's a realloc; try resizing */
  1660.         p = old - HEADSIZE;
  1661.         q = p - DEREF(p);
  1662.         while (DEREF(q) > 0) {
  1663.           if (startbig == q)
  1664.             startbig = p;
  1665.           if (startfree == q)
  1666.             startfree = p;
  1667.           if (lastloc == q)
  1668.             lastloc = p;
  1669.           q += DEREF(q);
  1670.         }
  1671.         size = q - p;
  1672.         if (size >= n) {
  1673.           if (size - n <= SLOP) {
  1674.             DEREF(p) = -size;
  1675.           } else {
  1676.             next = p + n;
  1677.             DEREF(p) = -n;
  1678.             DEREF(next) = size - n;
  1679.           }
  1680.           return old;
  1681.         }
  1682.       }
  1683.       if (n > lastsize) {
  1684.         p = lastloc;
  1685.         largest = lastsize;
  1686.       } else {
  1687.         p = startfree;
  1688.         largest = 0;
  1689.       }
  1690.       if (n >= BIG && p < startbig) {
  1691.         p = startbig;
  1692.         largest = BIG - 1;
  1693.       }
  1694.       for (;;) {
  1695.         while ((size = DEREF(p)) < 0)
  1696.           p -= size;
  1697.         if (largest < BIG) {
  1698.           if (largest == 0)
  1699.             startfree = p;
  1700.           if (p > startbig)
  1701.             startbig = p;
  1702.         }
  1703.         q = p + size;
  1704.         if (DEREF(q) > 0) {
  1705.           do {
  1706.             if (startbig == q)
  1707.                   startbig = p;
  1708.             q += DEREF(q);
  1709.           } while (DEREF(q) > 0);
  1710.           size = q - p;
  1711.           DEREF(p) = size;
  1712.         }
  1713.         if (size >= n) {    /* found a block that's large enough */
  1714.           if (size - n <= SLOP) {
  1715.             DEREF(p) = -size;
  1716.             next = q;
  1717.           } else {
  1718.             next = p + n;
  1719.             DEREF(p) = -n;
  1720.             DEREF(next) = size - n;
  1721.           }
  1722.           if (next < startbig && size - n >= BIG)
  1723.             startbig = next;
  1724.           lastsize = largest;
  1725.           lastloc = next;
  1726.           break;
  1727.         }
  1728.         if (DEREF(q) == 0) { /* out of space; must get some from sbrk */
  1729.           if (old && old + DEREF(old - HEADSIZE) == p) {
  1730.             p = old - HEADSIZE;
  1731.             size += -DEREF(p);
  1732.             old = NULL;
  1733.           }
  1734.           allocsize = (n - size - 1 + PAGE_SIZE) &~ PAGE_MASK;
  1735.           if (allocsize < MINSBRK)
  1736.             allocsize = MINSBRK;
  1737.           if ((next = sbrk(allocsize)) == (caddr_t)-1)
  1738.             return NULL;
  1739.           if (next != q + HEADSIZE) {
  1740.             if (largest < size)
  1741.                   largest = size;
  1742.             if (allocsize < n + HEADSIZE) {
  1743.                   if (sbrk(PAGE_SIZE) == (caddr_t)-1) {
  1744.                     sbrk(-allocsize);
  1745.                     return NULL;
  1746.                   }
  1747.                   allocsize += PAGE_SIZE;
  1748.             }
  1749.             DEREF(q) = -(next - q);
  1750.             p = next;
  1751.           }
  1752.           q = next + allocsize - HEADSIZE;
  1753.           DEREF(q) = 0;            /* delete */
  1754.           next = p + n;
  1755.           DEREF(p) = -n;
  1756.           DEREF(next) = q - next;
  1757.           lastsize = largest;
  1758.           lastloc = next;
  1759.           break;
  1760.         }
  1761.         if (largest < size)
  1762.           largest = size;
  1763.         p = q;
  1764.       }
  1765.       /* allocated a block */
  1766.       p += HEADSIZE;
  1767.       if (old) {
  1768.         size = -DEREF(old - HEADSIZE);
  1769.         bcopy(old, p, size);
  1770.         free(old);
  1771.       }
  1772.       return p;
  1773. }
  1774.  
  1775.  
  1776.  
  1777. void
  1778. free(p)
  1779.       pointer p;
  1780.       {
  1781.       pointer q;
  1782.       head_t size;
  1783.  
  1784.       if (p == (pointer)0)
  1785.         return;
  1786.       p -= HEADSIZE;
  1787.       if (DEREF(p) >= 0)
  1788.         abort();
  1789.       q = p - DEREF(p);
  1790.       for (;;) {
  1791.         if (startbig == q)
  1792.           startbig = p;
  1793.         if (lastloc == q)
  1794.           lastloc = p;
  1795.         if (DEREF(q) <= 0)
  1796.           break;
  1797.         q += DEREF(q);
  1798.       }
  1799.       size = q - p;
  1800.       DEREF(p) = size;
  1801.       if (startfree > p)
  1802.         startfree = p;
  1803.       if (size >= BIG && startbig > p)
  1804.         startbig = p;
  1805.       if (p < lastloc)
  1806.         lastsize += size;
  1807. }
  1808. EOF
  1809. if test `wc -c < mymalloc.c` -ne 8670
  1810. then    echo 'mymalloc.c is the wrong size'
  1811. fi
  1812. echo extracting mystring.h
  1813. cat > mystring.h <<\EOF
  1814. /*
  1815.  * Copyright (C) 1989 by Kenneth Almquist.  All rights reserved.
  1816.  * This file is part of ash, which is distributed under the terms specified
  1817.  * by the Ash General Public License.  See the file named LICENSE.
  1818.  */
  1819.  
  1820. #ifndef SYSV
  1821. #define strchr mystrchr
  1822. #endif
  1823.  
  1824. #ifdef __STDC__
  1825. void scopyn(const char *, char *, int);
  1826. char *strchr(const char *, int);
  1827. void mybcopy(const pointer, pointer, int);
  1828. int prefix(const char *, const char *);
  1829. int number(const char *);
  1830. int is_number(const char *);
  1831. int strcmp(const char *, const char *);    /* from C library */
  1832. char *strcpy(char *, const char *);    /* from C library */
  1833. int strlen(const char *);        /* from C library */
  1834. char *strcat(char *, const char *);    /* from C library */
  1835. #else
  1836. void scopyn();
  1837. char *strchr();
  1838. void mybcopy();
  1839. int prefix();
  1840. int number();
  1841. int is_number();
  1842. int strcmp();
  1843. char *strcpy();
  1844. int strlen();
  1845. char *strcat();
  1846. #endif
  1847.  
  1848. #define equal(s1, s2)    (strcmp(s1, s2) == 0)
  1849. #define scopy(s1, s2)    ((void)strcpy(s2, s1))
  1850. #define bcopy(src, dst, n)    mybcopy((pointer)(src), (pointer)(dst), n)
  1851. EOF
  1852. if test `wc -c < mystring.h` -ne 1036
  1853. then    echo 'mystring.h is the wrong size'
  1854. fi
  1855. echo extracting mystring.c
  1856. cat > mystring.c <<\EOF
  1857. /*
  1858.  * String functions.
  1859.  *
  1860.  *    equal(s1, s2)        Return true if strings are equal.
  1861.  *    scopy(from, to)        Copy a string.
  1862.  *    scopyn(from, to, n)    Like scopy, but checks for overflow.
  1863.  *    strchr(s, c)        Find first occurance of c in s.
  1864.  *    bcopy(from, to, n)    Copy a block of memory.
  1865.  *    number(s)        Convert a string of digits to an integer.
  1866.  *    is_number(s)        Return true if s is a string of digits.
  1867.  *
  1868.  * Copyright (C) 1989 by Kenneth Almquist.  All rights reserved.
  1869.  * This file is part of ash, which is distributed under the terms specified
  1870.  * by the Ash General Public License.  See the file named LICENSE.
  1871.  */
  1872.  
  1873. #include "shell.h"
  1874. #include "syntax.h"
  1875. #include "error.h"
  1876. #include "mystring.h"
  1877.  
  1878.  
  1879. char nullstr[1];        /* zero length string */
  1880.  
  1881.  
  1882. /*
  1883.  * scopyn - copy a string from "from" to "to", truncating the string
  1884.  *        if necessary.  "To" is always nul terminated, even if
  1885.  *        truncation is performed.  "Size" is the size of "to".
  1886.  */
  1887.  
  1888. void
  1889. scopyn(from, to, size)
  1890.       register char const *from;
  1891.       register char *to;
  1892.       register int size;
  1893.       {
  1894.  
  1895.       while (--size > 0) {
  1896.             if ((*to++ = *from++) == '\0')
  1897.                   return;
  1898.       }
  1899.       *to = '\0';
  1900. }
  1901.  
  1902.  
  1903. /*
  1904.  * strchr - find first occurrence of a character in a string.
  1905.  */
  1906.  
  1907. #ifndef SYS5
  1908. char *
  1909. mystrchr(s, charwanted)
  1910.       char const *s;
  1911.       register char charwanted;
  1912.       {
  1913.       register char const *scan;
  1914.  
  1915.       /*
  1916.        * The odd placement of the two tests is so NUL is findable.
  1917.        */
  1918.       for (scan = s ; *scan != charwanted ; )    /* ++ moved down for opt. */
  1919.             if (*scan++ == '\0')
  1920.                   return NULL;
  1921.       return (char *)scan;
  1922. }
  1923. #endif
  1924.  
  1925.  
  1926.  
  1927. /*
  1928.  * bcopy - copy bytes
  1929.  *
  1930.  * This routine was derived from code by Henry Spencer.
  1931.  */
  1932.  
  1933. void
  1934. mybcopy(src, dst, length)
  1935.       pointer dst;
  1936.       const pointer src;
  1937.       register int length;
  1938.       {
  1939.       register char *d = dst;
  1940.       register char *s = src;
  1941.  
  1942.       while (--length >= 0)
  1943.             *d++ = *s++;
  1944. }
  1945.  
  1946.  
  1947. /*
  1948.  * prefix -- see if pfx is a prefix of string.
  1949.  */
  1950.  
  1951. int
  1952. prefix(pfx, string)
  1953.       register char const *pfx;
  1954.       register char const *string;
  1955.       {
  1956.       while (*pfx) {
  1957.         if (*pfx++ != *string++)
  1958.           return 0;
  1959.       }
  1960.       return 1;
  1961. }
  1962.  
  1963.  
  1964. /*
  1965.  * Convert a string of digits to an integer, printing an error message on
  1966.  * failure.
  1967.  */
  1968.  
  1969. int
  1970. number(s)
  1971.       const char *s;
  1972.       {
  1973.  
  1974.       if (! is_number(s))
  1975.         error2("Illegal number", (char *)s);
  1976.       return atoi(s);
  1977. }
  1978.  
  1979.  
  1980.  
  1981. /*
  1982.  * Check for a valid number.  This should be elsewhere.
  1983.  */
  1984.  
  1985. int
  1986. is_number(p)
  1987.       register const char *p;
  1988.       {
  1989.       do {
  1990.         if (! is_digit(*p))
  1991.           return 0;
  1992.       } while (*++p != '\0');
  1993.       return 1;
  1994. }
  1995. EOF
  1996. if test `wc -c < mystring.c` -ne 2651
  1997. then    echo 'mystring.c is the wrong size'
  1998. fi
  1999. echo extracting nodes.c.pat
  2000. cat > nodes.c.pat <<\EOF
  2001. /*
  2002.  * Routine for dealing with parsed shell commands.
  2003.  *
  2004.  * Copyright 1989 by Kenneth Almquist.  All rights reserved.
  2005.  *
  2006.  * This file is part of ash.  Ash is distributed under the terms specified
  2007.  * by the Ash General Public License.  See the file named LICENSE.
  2008.  */
  2009.  
  2010. #include "shell.h"
  2011. #include "nodes.h"
  2012. #include "memalloc.h"
  2013. #include "machdep.h"
  2014. #include "mystring.h"
  2015.  
  2016.  
  2017. int funcblocksize;        /* size of structures in function */
  2018. int funcstringsize;        /* size of strings in node */
  2019. pointer funcblock;        /* block to allocate function from */
  2020. char *funcstring;        /* block to allocate strings from */
  2021.  
  2022. %SIZES
  2023.  
  2024.  
  2025. #ifdef __STDC__
  2026. STATIC void calcsize(union node *);
  2027. STATIC void sizenodelist(struct nodelist *);
  2028. STATIC union node *copynode(union node *);
  2029. STATIC struct nodelist *copynodelist(struct nodelist *);
  2030. STATIC char *nodesavestr(char *);
  2031. #else
  2032. STATIC void calcsize();
  2033. STATIC void sizenodelist();
  2034. STATIC union node *copynode();
  2035. STATIC struct nodelist *copynodelist();
  2036. STATIC char *nodesavestr();
  2037. #endif
  2038.  
  2039.  
  2040.  
  2041. /*
  2042.  * Make a copy of a parse tree.
  2043.  */
  2044.  
  2045. union node *
  2046. copyfunc(n)
  2047.       union node *n;
  2048.       {
  2049.       if (n == NULL)
  2050.         return NULL;
  2051.       funcblocksize = 0;
  2052.       funcstringsize = 0;
  2053.       calcsize(n);
  2054.       funcblock = ckmalloc(funcblocksize + funcstringsize);
  2055.       funcstring = funcblock + funcblocksize;
  2056.       return copynode(n);
  2057. }
  2058.  
  2059.  
  2060.  
  2061. STATIC void
  2062. calcsize(n)
  2063.       union node *n;
  2064.       {
  2065.       %CALCSIZE
  2066. }
  2067.  
  2068.  
  2069.  
  2070. STATIC void
  2071. sizenodelist(lp)
  2072.       struct nodelist *lp;
  2073.       {
  2074.       while (lp) {
  2075.         funcblocksize += ALIGN(sizeof (struct nodelist));
  2076.         calcsize(lp->n);
  2077.         lp = lp->next;
  2078.       }
  2079. }
  2080.  
  2081.  
  2082.  
  2083. STATIC union node *
  2084. copynode(n)
  2085.       union node *n;
  2086.       {
  2087.       union node *new;
  2088.  
  2089.       %COPY
  2090.       return new;
  2091. }
  2092.  
  2093.  
  2094. STATIC struct nodelist *
  2095. copynodelist(lp)
  2096.       struct nodelist *lp;
  2097.       {
  2098.       struct nodelist *start;
  2099.       struct nodelist **lpp;
  2100.  
  2101.       lpp = &start;
  2102.       while (lp) {
  2103.         *lpp = funcblock;
  2104.         funcblock += ALIGN(sizeof (struct nodelist));
  2105.         (*lpp)->n = copynode(lp->n);
  2106.         lp = lp->next;
  2107.         lpp = &(*lpp)->next;
  2108.       }
  2109.       *lpp = NULL;
  2110.       return start;
  2111. }
  2112.  
  2113.  
  2114.  
  2115. STATIC char *
  2116. nodesavestr(s)
  2117.       char *s;
  2118.       {
  2119.       register char *p = s;
  2120.       register char *q = funcstring;
  2121.       char *rtn = funcstring;
  2122.  
  2123.       while (*q++ = *p++);
  2124.       funcstring = q;
  2125.       return rtn;
  2126. }
  2127.  
  2128.  
  2129.  
  2130. /*
  2131.  * Free a parse tree.
  2132.  */
  2133.  
  2134. void
  2135. freefunc(n)
  2136.       union node *n;
  2137.       {
  2138.       if (n)
  2139.         ckfree(n);
  2140. }
  2141. EOF
  2142. if test `wc -c < nodes.c.pat` -ne 2438
  2143. then    echo 'nodes.c.pat is the wrong size'
  2144. fi
  2145. echo extracting nodetypes
  2146. cat > nodetypes <<\EOF
  2147. # This file describes the nodes used in parse trees.  Unindented lines
  2148. # contain a node type followed by a structure tag.  Subsequent indented
  2149. # lines specify the fields of the structure.  Several node types can share
  2150. # the same structure, in which case the fields of the structure should be
  2151. # specified only once.
  2152. #
  2153. # A field of a structure is described by the name of the field followed
  2154. # by a type.  The currently implemented types are:
  2155. #    nodeptr - a pointer to a node
  2156. #    nodelist - a pointer to a list of nodes
  2157. #    string - a pointer to a nul terminated string
  2158. #    int - an integer
  2159. #    other - any type that can be copied by assignment
  2160. #    temp - a field that doesn't have to be copied when the node is copied
  2161. # The last two types should be followed by the text of a C declaration for
  2162. # the field.
  2163. #
  2164. #
  2165. # Copyright 1989 by Kenneth Almquist.  All rights reserved.
  2166. #
  2167. # This file is part of ash.  Ash is distributed under the terms specified
  2168. # by the Ash General Public License.  See the file named LICENSE.
  2169.  
  2170.  
  2171.  
  2172. NSEMI nbinary            # two commands separated by a semicolon
  2173.     type      int
  2174.     ch1      nodeptr        # the first child
  2175.     ch2      nodeptr        # the second child
  2176.  
  2177. NCMD ncmd            # a simple command
  2178.     type      int
  2179.     backgnd      int            # set to run command in background
  2180.     args      nodeptr        # the arguments
  2181.     redirect  nodeptr        # list of file redirections
  2182.  
  2183. NPIPE npipe            # a pipeline
  2184.     type      int
  2185.     backgnd      int            # set to run pipeline in background
  2186.     cmdlist      nodelist        # the commands in the pipeline
  2187.  
  2188. NREDIR nredir            # redirection (of a compex command)
  2189.     type      int
  2190.     n      nodeptr        # the command
  2191.     redirect  nodeptr        # list of file redirections
  2192.  
  2193. NBACKGND nredir            # run command in background
  2194. NSUBSHELL nredir        # run command in a subshell
  2195.  
  2196. NAND nbinary            # the && operator
  2197. NOR nbinary            # the || operator
  2198.  
  2199. NIF nif                # the if statement.  Elif clauses are handled
  2200.     type      int            # using multiple if nodes.
  2201.     test      nodeptr        # if test
  2202.     ifpart      nodeptr        # then ifpart
  2203.     elsepart  nodeptr        # else elsepart
  2204.  
  2205. NWHILE nbinary            # the while statement.  First child is the test
  2206. NUNTIL nbinary            # the until statement
  2207.  
  2208. NFOR nfor            # the for statement
  2209.     type      int
  2210.     args      nodeptr        # for var in args
  2211.     body      nodeptr        # do body; done
  2212.     var      string        # the for variable
  2213.  
  2214. NCASE ncase            # a case statement
  2215.     type      int
  2216.     expr      nodeptr        # the word to switch on
  2217.     cases      nodeptr        # the list of cases (NCLIST nodes)
  2218.  
  2219. NCLIST nclist            # a case
  2220.     type      int
  2221.     next      nodeptr        # the next case in list
  2222.     pattern      nodeptr        # list of patterns for this case
  2223.     body      nodeptr        # code to execute for this case
  2224.  
  2225.  
  2226. NDEFUN narg            # define a function.  The "next" field contains
  2227.                 # the body of the function.
  2228.  
  2229. NARG narg            # represents a word
  2230.     type      int
  2231.     next      nodeptr        # next word in list
  2232.     text      string        # the text of the word
  2233.     backquote nodelist        # list of commands in back quotes
  2234.  
  2235. NTO nfile            # fd> fname
  2236. NFROM nfile            # fd< fname
  2237. NAPPEND nfile            # fd>> fname
  2238.     type      int
  2239.     next      nodeptr        # next redirection in list
  2240.     fd      int            # file descriptor being redirected
  2241.     fname      nodeptr        # file name, in a NARG node
  2242.     expfname  temp    char *expfname    # actual file name
  2243.  
  2244. NTOFD ndup            # fd<&dupfd
  2245. NFROMFD ndup            # fd>&dupfd
  2246.     type      int
  2247.     next      nodeptr        # next redirection in list
  2248.     fd      int            # file descriptor being redirected
  2249.     dupfd      int            # file descriptor to duplicate
  2250.  
  2251. NHERE nhere            # fd<<\!
  2252. NXHERE nhere            # fd<<!
  2253.     type      int
  2254.     next      nodeptr        # next redirection in list
  2255.     fd      int            # file descriptor being redirected
  2256.     doc      nodeptr        # input to command (NARG node)
  2257. EOF
  2258. if test `wc -c < nodetypes` -ne 3482
  2259. then    echo 'nodetypes is the wrong size'
  2260. fi
  2261. echo extracting ocdecl.el
  2262. cat > ocdecl.el <<\EOF
  2263. (defun ocdecl ()
  2264.   "Update the old style C declarations from the new style ones.  This assumes
  2265. that you set up your declarations as follows:
  2266.     #ifdef __STDC__
  2267.     [ANSI style function prototypes]
  2268.     #else
  2269.     [Old style function prototypes]
  2270.     #endif
  2271. Then if you add or change a function, you can edit the ANSI style prototypes
  2272. and then run this function to make the old style prototypes match the new
  2273. style ones.  Normally bound to ESC D."
  2274.   (interactive)
  2275.   (let (ostart oend nstart nend+1 eol)
  2276.     (end-of-line)
  2277.     (search-backward "#ifdef __STDC__")
  2278.     (forward-line 1)
  2279.     (setq ostart (point))
  2280.     (search-forward "#else")
  2281.     (beginning-of-line)
  2282.     (setq oend (point))
  2283.     (forward-line 1)
  2284.     (setq nstart (point))
  2285.     (search-forward "#endif")
  2286.     (beginning-of-line)
  2287.     (setq nend+1 (make-marker))
  2288.     (set-marker nend+1 (1+ (point)))
  2289.     (goto-char nstart)
  2290.     (insert (buffer-substring ostart oend))
  2291.     (delete-region (point) (1- nend+1))
  2292.     (goto-char nstart)
  2293.     (while (< (point) (1- nend+1))
  2294.       (end-of-line)
  2295.       (setq eol (point))
  2296.       (beginning-of-line)
  2297.       (re-search-forward "[a-zA-Z0-9_] *(" eol)
  2298.       (setq ostart (point))
  2299.       (backward-char 1)
  2300.       (forward-sexp 1)
  2301.       (delete-region ostart (1- (point)))
  2302.       (forward-line 1))
  2303.     (set-marker nend+1 nil)
  2304.     nil))
  2305.  
  2306. (define-key esc-map "D" 'ocdecl)
  2307. EOF
  2308. if test `wc -c < ocdecl.el` -ne 1334
  2309. then    echo 'ocdecl.el is the wrong size'
  2310. fi
  2311. echo Archive 5 unpacked
  2312. exit
  2313.  
  2314.