rsalz@uunet.uu.net (Rich Salz) (05/31/89)
Submitted-by: ka@june.cs.washington.edu (Kenneth Almquist) Posting-number: Volume 19, Issue 5 Archive-name: ash/part05 # This is part 5 of ash. To unpack, feed it into the shell (not csh). # The ash distribution consists of eight pieces. Be sure you get them all. # After you unpack everything, read the file README. echo extracting mkinit.c cat > mkinit.c <<\EOF /* * Copyright (C) 1989 by Kenneth Almquist. All rights reserved. * This file is part of ash, which is distributed under the terms specified * by the Ash General Public License. See the file named LICENSE. * * Usage: mkinit command sourcefile... * * This program scans all the source files for code to handle various * special events and combines this code into one file. This (allegedly) * improves the structure of the program since there is no need for * anyone outside of a module to know that that module performs special * operations on particular events. The command is executed iff init.c * is actually changed. */ #include <stdio.h> #include <fcntl.h> /* * OUTFILE is the name of the output file. Output is initially written * to the file OUTTEMP, which is then moved to OUTFILE if OUTTEMP and * OUTFILE are different. */ #define OUTFILE "init.c" #define OUTTEMP "init.c.new" #define OUTOBJ "init.o" /* * A text structure is basicly just a string that grows as more characters * are added onto the end of it. It is implemented as a linked list of * blocks of characters. The routines addstr and addchar append a string * or a single character, respectively, to a text structure. Writetext * writes the contents of a text structure to a file. */ #define BLOCKSIZE 512 struct text { char *nextc; int nleft; struct block *start; struct block *last; }; struct block { struct block *next; char text[BLOCKSIZE]; }; /* * There is one event structure for each event that mkinit handles. */ struct event { char *name; /* name of event (e.g. INIT) */ char *routine; /* name of routine called on event */ char *comment; /* comment describing routine */ struct text code; /* code for handling event */ }; char writer[] = "\ /*\n\ * This file was generated by the mkinit program.\n\ */\n\ \n"; char init[] = "\ /*\n\ * Initialization code.\n\ */\n"; char reset[] = "\ /*\n\ * This routine is called when an error or an interrupt occurs in an\n\ * interactive shell and control is returned to the main command loop.\n\ */\n"; char shellproc[] = "\ /*\n\ * This routine is called to initialize the shell to run a shell procedure.\n\ */\n"; struct event event[] = { {"INIT", "init", init}, {"RESET", "reset", reset}, {"SHELLPROC", "initshellproc", shellproc}, {NULL, NULL} }; char *curfile; /* current file */ int linno; /* current line */ char *header_files[200]; /* list of header files */ struct text defines; /* #define statements */ struct text decls; /* declarations */ int amiddecls; /* for formatting */ void readfile(), doevent(), doinclude(), dodecl(), output(); void addstr(), addchar(), writetext(); #define equal(s1, s2) (strcmp(s1, s2) == 0) FILE *ckfopen(); char *savestr(); #ifdef __STDC__ void *ckmalloc(int); #else char *ckmalloc(); #endif void error(); main(argc, argv) char **argv; { char **ap; int fd; char c; if (argc < 2) error("Usage: mkinit command file..."); header_files[0] = "\"shell.h\""; header_files[1] = "\"mystring.h\""; for (ap = argv + 2 ; *ap ; ap++) readfile(*ap); output(); if (file_changed()) { unlink(OUTFILE); link(OUTTEMP, OUTFILE); unlink(OUTTEMP); } else { unlink(OUTTEMP); if (touch(OUTOBJ)) exit(0); /* no compilation necessary */ } printf("%s\n", argv[1]); execl("/bin/sh", "sh", "-c", argv[1], (char *)0); error("Can't exec shell"); } /* * Parse an input file. */ void readfile(fname) char *fname; { FILE *fp; char line[1024]; struct event *ep; fp = ckfopen(fname, "r"); curfile = fname; linno = 0; amiddecls = 0; while (fgets(line, sizeof line, fp) != NULL) { linno++; for (ep = event ; ep->name ; ep++) { if (line[0] == ep->name[0] && match(ep->name, line)) { doevent(ep, fp, fname); break; } } if (line[0] == 'I' && match("INCLUDE", line)) doinclude(line); if (line[0] == 'M' && match("MKINIT", line)) dodecl(line, fp); if (line[0] == '#' && gooddefine(line)) addstr(line, &defines); } fclose(fp); } int match(name, line) char *name; char *line; { register char *p, *q; p = name, q = line; while (*p) { if (*p++ != *q++) return 0; } if (*q != '{' && *q != ' ' && *q != '\t' && *q != '\n') return 0; return 1; } int gooddefine(line) char *line; { register char *p; if (! match("#define", line)) return 0; /* not a define */ p = line + 7; while (*p == ' ' || *p == '\t') p++; while (*p != ' ' && *p != '\t') { if (*p == '(') return 0; /* macro definition */ p++; } while (*p != '\n' && *p != '\0') p++; if (p[-1] == '\\') return 0; /* multi-line definition */ return 1; } void doevent(ep, fp, fname) register struct event *ep; FILE *fp; char *fname; { char line[1024]; int indent; char *p; sprintf(line, "\n /* from %s: */\n", fname); addstr(line, &ep->code); addstr(" {\n", &ep->code); for (;;) { linno++; if (fgets(line, sizeof line, fp) == NULL) error("Unexpected EOF"); if (equal(line, "}\n")) break; indent = 6; for (p = line ; *p == '\t' ; p++) indent += 8; for ( ; *p == ' ' ; p++) indent++; if (*p == '\n' || *p == '#') indent = 0; while (indent >= 8) { addchar('\t', &ep->code); indent -= 8; } while (indent > 0) { addchar(' ', &ep->code); indent--; } addstr(p, &ep->code); } addstr(" }\n", &ep->code); } void doinclude(line) char *line; { register char *p; char *name; register char **pp; for (p = line ; *p != '"' && *p != '<' && *p != '\0' ; p++); if (*p == '\0') error("Expecting '\"' or '<'"); name = p; while (*p != ' ' && *p != '\t' && *p != '\n') p++; if (p[-1] != '"' && p[-1] != '>') error("Missing terminator"); *p = '\0'; /* name now contains the name of the include file */ for (pp = header_files ; *pp && ! equal(*pp, name) ; pp++); if (*pp == NULL) *pp = savestr(name); } void dodecl(line1, fp) char *line1; FILE *fp; { char line[1024]; register char *p, *q; if (strcmp(line1, "MKINIT\n") == 0) { /* start of struct/union decl */ addchar('\n', &decls); do { linno++; if (fgets(line, sizeof line, fp) == NULL) error("Unterminated structure declaration"); addstr(line, &decls); } while (line[0] != '}'); amiddecls = 0; } else { if (! amiddecls) addchar('\n', &decls); q = NULL; for (p = line1 + 6 ; *p != '=' && *p != '/' ; p++); if (*p == '=') { /* eliminate initialization */ for (q = p ; *q && *q != ';' ; q++); if (*q == '\0') q = NULL; else { while (p[-1] == ' ') p--; *p = '\0'; } } addstr("extern", &decls); addstr(line1 + 6, &decls); if (q != NULL) addstr(q, &decls); amiddecls = 1; } } /* * Write the output to the file OUTTEMP. */ void output() { FILE *fp; char **pp; struct event *ep; fp = ckfopen(OUTTEMP, "w"); fputs(writer, fp); for (pp = header_files ; *pp ; pp++) fprintf(fp, "#include %s\n", *pp); fputs("\n\n\n", fp); writetext(&defines, fp); fputs("\n\n", fp); writetext(&decls, fp); for (ep = event ; ep->name ; ep++) { fputs("\n\n\n", fp); fputs(ep->comment, fp); fprintf(fp, "\nvoid\n%s() {\n", ep->routine); writetext(&ep->code, fp); fprintf(fp, "}\n"); } fclose(fp); } /* * Return true if the new output file is different from the old one. */ int file_changed() { register FILE *f1, *f2; register int c; if ((f1 = fopen(OUTFILE, "r")) == NULL || (f2 = fopen(OUTTEMP, "r")) == NULL) return 1; while ((c = getc(f1)) == getc(f2)) { if (c == EOF) return 0; } return 1; } /* * Touch a file. Returns 0 on failure, 1 on success. */ int touch(file) char *file; { int fd; char c; if ((fd = open(file, O_RDWR)) < 0) return 0; if (read(fd, &c, 1) != 1) { close(fd); return 0; } lseek(fd, 0L, 0); write(fd, &c, 1); close(fd); return 1; } /* * A text structure is simply a block of text that is kept in memory. * Addstr appends a string to the text struct, and addchar appends a single * character. */ void addstr(s, text) register char *s; register struct text *text; { while (*s) { if (--text->nleft < 0) addchar(*s++, text); else *text->nextc++ = *s++; } } void addchar(c, text) register struct text *text; { struct block *bp; if (--text->nleft < 0) { bp = ckmalloc(sizeof *bp); if (text->start == NULL) text->start = bp; else text->last->next = bp; text->last = bp; text->nextc = bp->text; text->nleft = BLOCKSIZE - 1; } *text->nextc++ = c; } /* * Write the contents of a text structure to a file. */ void writetext(text, fp) struct text *text; FILE *fp; { struct block *bp; if (text->start != NULL) { for (bp = text->start ; bp != text->last ; bp = bp->next) fwrite(bp->text, sizeof (char), BLOCKSIZE, fp); fwrite(bp->text, sizeof (char), BLOCKSIZE - text->nleft, fp); } } FILE * ckfopen(file, mode) char *file; char *mode; { FILE *fp; if ((fp = fopen(file, mode)) == NULL) { fprintf(stderr, "Can't open %s\n", file); exit(2); } return fp; } #ifdef __STDC__ void * #else char * #endif ckmalloc(nbytes) { register char *p; char *malloc(); if ((p = malloc(nbytes)) == NULL) error("Out of space"); return p; } char * savestr(s) char *s; { register char *p; p = ckmalloc(strlen(s) + 1); strcpy(p, s); return p; } void error(msg) char *msg; { if (curfile != NULL) fprintf(stderr, "%s:%d: ", curfile, linno); fprintf(stderr, "%s\n", msg); exit(2); } EOF if test `wc -c < mkinit.c` -ne 10550 then echo 'mkinit.c is the wrong size' fi echo extracting mknodes.c cat > mknodes.c <<\EOF /* * This program reads the nodetypes file and nodes.c.pat file. It generates * the files nodes.h and nodes.c. * * Copyright (C) 1989 by Kenneth Almquist. All rights reserved. * This file is part of ash, which is distributed under the terms specified * by the Ash General Public License. See the file named LICENSE. */ #include <stdio.h> #define MAXTYPES 50 /* max number of node types */ #define MAXFIELDS 20 /* max fields in a structure */ #define BUFLEN 100 /* size of character buffers */ /* field types */ #define T_NODE 1 /* union node *field */ #define T_NODELIST 2 /* struct nodelist *field */ #define T_STRING 3 #define T_INT 4 /* int field */ #define T_OTHER 5 /* other */ #define T_TEMP 6 /* don't copy this field */ struct field { /* a structure field */ char *name; /* name of field */ int type; /* type of field */ char *decl; /* declaration of field */ }; struct str { /* struct representing a node structure */ char *tag; /* structure tag */ int nfields; /* number of fields in the structure */ struct field field[MAXFIELDS]; /* the fields of the structure */ int done; /* set if fully parsed */ }; int ntypes; /* number of node types */ char *nodename[MAXTYPES]; /* names of the nodes */ struct str *nodestr[MAXTYPES]; /* type of structure used by the node */ int nstr; /* number of structures */ struct str str[MAXTYPES]; /* the structures */ struct str *curstr; /* current structure */ FILE *infp = stdin; char line[1024]; int linno; char *linep; char *savestr(); #define equal(s1, s2) (strcmp(s1, s2) == 0) main(argc, argv) char **argv; { if ((infp = fopen("nodetypes", "r")) == NULL) error("Can't open nodetypes"); while (readline()) { if (line[0] == ' ' || line[0] == '\t') parsefield(); else if (line[0] != '\0') parsenode(); } output(); } parsenode() { char name[BUFLEN]; char tag[BUFLEN]; struct str *sp; if (curstr && curstr->nfields > 0) curstr->done = 1; nextfield(name); if (! nextfield(tag)) error("Tag expected"); if (*linep != '\0') error("Garbage at end of line"); nodename[ntypes] = savestr(name); for (sp = str ; sp < str + nstr ; sp++) { if (equal(sp->tag, tag)) break; } if (sp >= str + nstr) { sp->tag = savestr(tag); sp->nfields = 0; curstr = sp; nstr++; } nodestr[ntypes] = sp; ntypes++; } parsefield() { char name[BUFLEN]; char type[BUFLEN]; char decl[2 * BUFLEN]; struct field *fp; if (curstr == NULL || curstr->done) error("No current structure to add field to"); if (! nextfield(name)) error("No field name"); if (! nextfield(type)) error("No field type"); fp = &curstr->field[curstr->nfields]; fp->name = savestr(name); if (equal(type, "nodeptr")) { fp->type = T_NODE; sprintf(decl, "union node *%s", name); } else if (equal(type, "nodelist")) { fp->type = T_NODELIST; sprintf(decl, "struct nodelist *%s", name); } else if (equal(type, "string")) { fp->type = T_STRING; sprintf(decl, "char *%s", name); } else if (equal(type, "int")) { fp->type = T_INT; sprintf(decl, "int %s", name); } else if (equal(type, "other")) { fp->type = T_OTHER; } else if (equal(type, "temp")) { fp->type = T_TEMP; } else { error("Unknown type %s", type); } if (fp->type == T_OTHER || fp->type == T_TEMP) { skipbl(); fp->decl = savestr(linep); } else { if (*linep) error("Garbage at end of line"); fp->decl = savestr(decl); } curstr->nfields++; } char writer[] = "\ /*\n\ * This file was generated by the mknodes program.\n\ */\n\ \n"; output() { FILE *hfile; FILE *cfile; FILE *patfile; int i; struct str *sp; struct field *fp; char *p; if ((patfile = fopen("nodes.c.pat", "r")) == NULL) error("Can't open nodes.c.pat"); if ((hfile = fopen("nodes.h", "w")) == NULL) error("Can't create nodes.h"); if ((cfile = fopen("nodes.c", "w")) == NULL) error("Can't create nodes.c"); fputs(writer, hfile); for (i = 0 ; i < ntypes ; i++) fprintf(hfile, "#define %s %d\n", nodename[i], i); fputs("\n\n\n", hfile); for (sp = str ; sp < &str[nstr] ; sp++) { fprintf(hfile, "struct %s {\n", sp->tag); for (i = sp->nfields, fp = sp->field ; --i >= 0 ; fp++) { fprintf(hfile, " %s;\n", fp->decl); } fputs("};\n\n\n", hfile); } fputs("union node {\n", hfile); fprintf(hfile, " int type;\n"); for (sp = str ; sp < &str[nstr] ; sp++) { fprintf(hfile, " struct %s %s;\n", sp->tag, sp->tag); } fputs("};\n\n\n", hfile); fputs("struct nodelist {\n", hfile); fputs("\tstruct nodelist *next;\n", hfile); fputs("\tunion node *n;\n", hfile); fputs("};\n\n\n", hfile); fputs("#ifdef __STDC__\n", hfile); fputs("union node *copyfunc(union node *);\n", hfile); fputs("void freefunc(union node *);\n", hfile); fputs("#else\n", hfile); fputs("union node *copyfunc();\n", hfile); fputs("void freefunc();\n", hfile); fputs("#endif\n", hfile); fputs(writer, cfile); while (fgets(line, sizeof line, patfile) != NULL) { for (p = line ; *p == ' ' || *p == '\t' ; p++); if (equal(p, "%SIZES\n")) outsizes(cfile); else if (equal(p, "%CALCSIZE\n")) outfunc(cfile, 1); else if (equal(p, "%COPY\n")) outfunc(cfile, 0); else fputs(line, cfile); } } outsizes(cfile) FILE *cfile; { int i; fprintf(cfile, "static const short nodesize[%d] = {\n", ntypes); for (i = 0 ; i < ntypes ; i++) { fprintf(cfile, " ALIGN(sizeof (struct %s)),\n", nodestr[i]->tag); } fprintf(cfile, "};\n"); } outfunc(cfile, calcsize) FILE *cfile; { struct str *sp; struct field *fp; int i; fputs(" if (n == NULL)\n", cfile); if (calcsize) fputs(" return;\n", cfile); else fputs(" return NULL;\n", cfile); if (calcsize) fputs(" funcblocksize += nodesize[n->type];\n", cfile); else { fputs(" new = funcblock;\n", cfile); fputs(" funcblock += nodesize[n->type];\n", cfile); } fputs(" switch (n->type) {\n", cfile); for (sp = str ; sp < &str[nstr] ; sp++) { for (i = 0 ; i < ntypes ; i++) { if (nodestr[i] == sp) fprintf(cfile, " case %s:\n", nodename[i]); } for (i = sp->nfields ; --i >= 1 ; ) { fp = &sp->field[i]; switch (fp->type) { case T_NODE: if (calcsize) { indent(12, cfile); fprintf(cfile, "calcsize(n->%s.%s);\n", sp->tag, fp->name); } else { indent(12, cfile); fprintf(cfile, "new->%s.%s = copynode(n->%s.%s);\n", sp->tag, fp->name, sp->tag, fp->name); } break; case T_NODELIST: if (calcsize) { indent(12, cfile); fprintf(cfile, "sizenodelist(n->%s.%s);\n", sp->tag, fp->name); } else { indent(12, cfile); fprintf(cfile, "new->%s.%s = copynodelist(n->%s.%s);\n", sp->tag, fp->name, sp->tag, fp->name); } break; case T_STRING: if (calcsize) { indent(12, cfile); fprintf(cfile, "funcstringsize += strlen(n->%s.%s) + 1;\n", sp->tag, fp->name); } else { indent(12, cfile); fprintf(cfile, "new->%s.%s = nodesavestr(n->%s.%s);\n", sp->tag, fp->name, sp->tag, fp->name); } break; case T_INT: case T_OTHER: if (! calcsize) { indent(12, cfile); fprintf(cfile, "new->%s.%s = n->%s.%s;\n", sp->tag, fp->name, sp->tag, fp->name); } break; } } indent(12, cfile); fputs("break;\n", cfile); } fputs(" };\n", cfile); if (! calcsize) fputs(" new->type = n->type;\n", cfile); } indent(amount, fp) FILE *fp; { while (amount >= 8) { putc('\t', fp); amount -= 8; } while (--amount >= 0) { putc(' ', fp); } } int nextfield(buf) char *buf; { register char *p, *q; p = linep; while (*p == ' ' || *p == '\t') p++; q = buf; while (*p != ' ' && *p != '\t' && *p != '\0') *q++ = *p++; *q = '\0'; linep = p; return (q > buf); } skipbl() { while (*linep == ' ' || *linep == '\t') linep++; } int readline() { register char *p; if (fgets(line, 1024, infp) == NULL) return 0; for (p = line ; *p != '#' && *p != '\n' && *p != '\0' ; p++); while (p > line && (p[-1] == ' ' || p[-1] == '\t')) p--; *p = '\0'; linep = line; linno++; if (p - line > BUFLEN) error("Line too long"); return 1; } error(msg, a1, a2, a3, a4, a5, a6) char *msg; { fprintf(stderr, "line %d: ", linno); fprintf(stderr, msg, a1, a2, a3, a4, a5, a6); putc('\n', stderr); exit(2); } char * savestr(s) char *s; { register char *p; char *malloc(); if ((p = malloc(strlen(s) + 1)) == NULL) error("Out of space"); strcpy(p, s); return p; } EOF if test `wc -c < mknodes.c` -ne 9481 then echo 'mknodes.c is the wrong size' fi echo extracting mksignames.c cat > mksignames.c <<\EOF /* * This program generates the signames.h and signames.c files. * * Copyright (C) 1989 by Kenneth Almquist. All rights reserved. * This file is part of ash, which is distributed under the terms specified * by the Ash General Public License. See the file named LICENSE. */ #include <stdio.h> #include <signal.h> struct sig { int signo; /* signal number */ char *name; /* signal name (without leading "SIG") */ char *mesg; /* description */ }; struct sig sigtab[] = { SIGHUP, "HUP", "Hangup", SIGINT, "INT", "Interrupt", /* normally don't print message */ SIGQUIT, "QUIT", "Quit", SIGILL, "ILL", "Illegal instruction", SIGTRAP, "TRAP", "Trace/BPT trap", #ifdef SIGABRT SIGABRT, "ABRT", "abort", #endif #if defined(SIGIOT) && (! defined(SIGABRT) || SIGABRT != SIGIOT) SIGIOT, "IOT", "abort", #endif #ifdef SIGEMT SIGEMT, "EMT", "EMT trap", #endif SIGFPE, "FPE", "Floating exception", SIGKILL, "KILL", "Killed", SIGBUS, "BUS", "Bus error", SIGSEGV, "SEGV", "Memory fault", SIGSYS, "SYS", "Bad system call", SIGPIPE, "PIPE", "Broken pipe", /* normally don't print message */ SIGALRM, "ALRM", "Alarm call", SIGTERM, "TERM", "Terminated", #ifdef SIGUSR1 SIGUSR1, "USR1", "User signal 1", #endif #ifdef SIGUSR2 SIGUSR2, "USR2", "User signal 2", #endif #ifdef SIGCLD SIGCLD, "CLD", NULL, #endif #if defined(SIGCHLD) && ! defined(SIGCLD) SIGCHLD, "CLD", NULL, #endif #ifdef SIGPWR SIGPWR, "PWR", "Power fail", #endif #ifdef SIGPOLL SIGPOLL, "POLL", "Poll", #endif /* Now for the BSD signals */ #ifdef SIGURG SIGURG, "URG", NULL, #endif #ifdef SIGSTOP SIGSTOP, "STOP", "Stopped", #endif #ifdef SIGTSTP SIGTSTP, "TSTP", "Stopped", #endif #ifdef SIGCONT SIGCONT, "CONT", NULL, #endif #ifdef SIGTTIN SIGTTIN, "TTIN", "Stopped (input)", #endif #ifdef SIGTTOU SIGTTOU, "TTOU", "Stopped (output)", #endif #ifdef SIGIO SIGIO, "IO", NULL, #endif #ifdef SIGXCPU SIGXCPU, "XCPU", "Time limit exceeded", #endif #ifdef SIGXFSZ SIGXFSZ, "XFSZ", NULL, #endif #ifdef SIGVTALARM SIGVTALARM, "VTALARM", "Virtual alarm", #endif #ifdef SIGPROF SIGPROF, "PROF", "Profiling alarm", #endif #ifdef SIGWINCH SIGWINCH, "WINCH", NULL, #endif 0, NULL, NULL }; #define MAXSIG 64 char *sigmesg[MAXSIG + 1]; char writer[] = "\ /*\n\ * This file was generated by the mksignames program.\n\ */\n\ \n"; main(argc, argv) char **argv; { FILE *cfile, *hfile; struct sig *sigp; int maxsig; int i; if ((cfile = fopen("signames.c", "w")) == NULL) { fputs("Can't create signames.c\n", stderr); exit(2); } if ((hfile = fopen("signames.h", "w")) == NULL) { fputs("Can't create signames.h\n", stderr); exit(2); } maxsig = 0; for (sigp = sigtab ; sigp->signo != 0 ; sigp++) { if (sigp->signo < 0 || sigp->signo > MAXSIG) continue; sigmesg[sigp->signo] = sigp->mesg; if (maxsig < sigp->signo) maxsig = sigp->signo; } fputs(writer, hfile); fprintf(hfile, "#define MAXSIG %d\n\n", maxsig); fprintf(hfile, "extern char *const sigmesg[MAXSIG+1];\n"); fputs(writer, cfile); fprintf(cfile, "#include \"shell.h\"\n\n"); fprintf(cfile, "char *const sigmesg[%d] = {\n", maxsig + 1); for (i = 0 ; i <= maxsig ; i++) { if (sigmesg[i] == NULL) { fprintf(cfile, " 0,\n"); } else { fprintf(cfile, " \"%s\",\n", sigmesg[i]); } } fprintf(cfile, "};\n"); exit(0); } EOF if test `wc -c < mksignames.c` -ne 3662 then echo 'mksignames.c is the wrong size' fi echo extracting mksyntax.c cat > mksyntax.c <<\EOF /* * This program creates syntax.h and syntax.c. * * Copyright (C) 1989 by Kenneth Almquist. All rights reserved. * This file is part of ash, which is distributed under the terms specified * by the Ash General Public License. See the file named LICENSE. */ #include <stdio.h> #include "parser.h" struct synclass { char *name; char *comment; }; /* Syntax classes */ struct synclass synclass[] = { "CWORD", "character is nothing special", "CNL", "newline character", "CBACK", "a backslash character", "CSQUOTE", "single quote", "CDQUOTE", "double quote", "CENDQUOTE", "a terminating quote", "CBQUOTE", "backwards single quote", "CVAR", "a dollar sign", "CENDVAR", "a '}' character", "CEOF", "end of file", "CCTL", "like CWORD, except it must be escaped", "CSPCL", "these terminate a word", NULL, NULL }; /* * Syntax classes for is_ functions. Warning: if you add new classes * you may have to change the definition of the is_in_name macro. */ struct synclass is_entry[] = { "ISDIGIT", "a digit", "ISUPPER", "an upper case letter", "ISLOWER", "a lower case letter", "ISUNDER", "an underscore", "ISSPECL", "the name of a special parameter", NULL, NULL, }; char writer[] = "\ /*\n\ * This file was generated by the mksyntax program.\n\ */\n\ \n"; FILE *cfile; FILE *hfile; char *syntax[513]; int base; int size; /* number of values which a char variable can have */ int nbits; /* number of bits in a character */ int digit_contig; /* true if digits are contiguous */ main() { char c; char d; int sign; int i; char buf[80]; int pos; static char digit[] = "0123456789"; /* Create output files */ if ((cfile = fopen("syntax.c", "w")) == NULL) { perror("syntax.c"); exit(2); } if ((hfile = fopen("syntax.h", "w")) == NULL) { perror("syntax.h"); exit(2); } fputs(writer, hfile); fputs(writer, cfile); /* Determine the characteristics of chars. */ c = -1; if (c < 0) sign = 1; else sign = 0; for (nbits = 1 ; ; nbits++) { d = (1 << nbits) - 1; if (d == c) break; } printf("%s %d bit chars\n", sign? "signed" : "unsigned", nbits); if (nbits > 9) { fputs("Characters can't have more than 9 bits\n", stderr); exit(2); } size = (1 << nbits) + 1; base = 1; if (sign) base += 1 << (nbits - 1); digit_contig = 1; for (i = 0 ; i < 10 ; i++) { if (digit[i] != '0' + i) digit_contig = 0; } /* Generate the #define statements in the header file */ fputs("/* Syntax classes */\n", hfile); for (i = 0 ; synclass[i].name ; i++) { sprintf(buf, "#define %s %d", synclass[i].name, i); fputs(buf, hfile); for (pos = strlen(buf) ; pos < 32 ; pos = pos + 8 &~ 07) putc('\t', hfile); fprintf(hfile, "/* %s */\n", synclass[i].comment); } putc('\n', hfile); fputs("/* Syntax classes for is_ functions */\n", hfile); for (i = 0 ; is_entry[i].name ; i++) { sprintf(buf, "#define %s %#o", is_entry[i].name, 1 << i); fputs(buf, hfile); for (pos = strlen(buf) ; pos < 32 ; pos = pos + 8 &~ 07) putc('\t', hfile); fprintf(hfile, "/* %s */\n", is_entry[i].comment); } putc('\n', hfile); fprintf(hfile, "#define SYNBASE %d\n", base); fprintf(hfile, "#define PEOF %d\n\n", -base); putc('\n', hfile); fputs("#define BASESYNTAX (basesyntax + SYNBASE)\n", hfile); fputs("#define DQSYNTAX (dqsyntax + SYNBASE)\n", hfile); fputs("#define SQSYNTAX (sqsyntax + SYNBASE)\n", hfile); putc('\n', hfile); output_type_macros(); /* is_digit, etc. */ putc('\n', hfile); /* Generate the syntax tables. */ fputs("#include \"shell.h\"\n", cfile); fputs("#include \"syntax.h\"\n\n", cfile); init(); fputs("/* syntax table used when not in quotes */\n", cfile); add("\n", "CNL"); add("\\", "CBACK"); add("'", "CSQUOTE"); add("\"", "CDQUOTE"); add("`", "CBQUOTE"); add("$", "CVAR"); add("}", "CENDVAR"); add("<>();&| \t", "CSPCL"); print("basesyntax"); init(); fputs("\n/* syntax table used when in double quotes */\n", cfile); add("\n", "CNL"); add("\\", "CBACK"); add("\"", "CENDQUOTE"); add("`", "CBQUOTE"); add("$", "CVAR"); add("}", "CENDVAR"); add("!*?[=", "CCTL"); print("dqsyntax"); init(); fputs("\n/* syntax table used when in single quotes */\n", cfile); add("\n", "CNL"); add("'", "CENDQUOTE"); add("!*?[=", "CCTL"); print("sqsyntax"); filltable("0"); fputs("\n/* character classification table */\n", cfile); add("0123456789", "ISDIGIT"); add("abcdefghijklmnopqrstucvwxyz", "ISLOWER"); add("ABCDEFGHIJKLMNOPQRSTUCVWXYZ", "ISUPPER"); add("_", "ISUNDER"); add("#?$!-*@", "ISSPECL"); print("is_type"); if (! digit_contig) digit_convert(); exit(0); } /* * Clear the syntax table. */ filltable(dftval) char *dftval; { int i; for (i = 0 ; i < size ; i++) syntax[i] = dftval; } /* * Initialize the syntax table with default values. */ init() { filltable("CWORD"); syntax[0] = "CEOF"; syntax[base + CTLESC] = "CCTL"; syntax[base + CTLVAR] = "CCTL"; syntax[base + CTLENDVAR] = "CCTL"; syntax[base + CTLBACKQ] = "CCTL"; syntax[base + CTLBACKQ + CTLQUOTE] = "CCTL"; } /* * Add entries to the syntax table. */ add(p, type) char *p, *type; { while (*p) syntax[*p++ + base] = type; } /* * Output the syntax table. */ print(name) char *name; { int i; int col; fprintf(hfile, "extern const char %s[];\n", name); fprintf(cfile, "const char %s[%d] = {\n", name, size); col = 0; for (i = 0 ; i < size ; i++) { if (i == 0) { fputs(" ", cfile); } else if ((i & 03) == 0) { fputs(",\n ", cfile); col = 0; } else { putc(',', cfile); while (++col < 9 * (i & 03)) putc(' ', cfile); } fputs(syntax[i], cfile); col += strlen(syntax[i]); } fputs("\n};\n", cfile); } /* * Output character classification macros (e.g. is_digit). If digits are * contiguous, we can test for them quickly. */ char *macro[] = { "#define is_digit(c)\t((is_type+SYNBASE)[c] & ISDIGIT)", "#define is_alpha(c)\t((is_type+SYNBASE)[c] & (ISUPPER|ISLOWER))", "#define is_name(c)\t((is_type+SYNBASE)[c] & (ISUPPER|ISLOWER|ISUNDER))", "#define is_in_name(c)\t((is_type+SYNBASE)[c] & (ISUPPER|ISLOWER|ISUNDER|ISDIGIT))", "#define is_special(c)\t((is_type+SYNBASE)[c] & (ISSPECL|ISDIGIT))", NULL }; output_type_macros() { char **pp; if (digit_contig) macro[0] = "#define is_digit(c)\t((unsigned)((c) - '0') <= 9)"; for (pp = macro ; *pp ; pp++) fprintf(hfile, "%s\n", *pp); if (digit_contig) fputs("#define digit_val(c)\t((c) - '0')\n", hfile); else fputs("#define digit_val(c)\t(digit_value[c])\n", hfile); } /* * Output digit conversion table (if digits are not contiguous). */ digit_convert() { int maxdigit; static char digit[] = "0123456789"; char *p; int i; maxdigit = 0; for (p = digit ; *p ; p++) if (*p > maxdigit) maxdigit = *p; fputs("extern const char digit_value[];\n", hfile); fputs("\n\nconst char digit_value[] = {\n", cfile); for (i = 0 ; i <= maxdigit ; i++) { for (p = digit ; *p && *p != i ; p++); if (*p == '\0') p = digit; fprintf(cfile, " %d,\n", p - digit); } fputs("};\n", cfile); } EOF if test `wc -c < mksyntax.c` -ne 7949 then echo 'mksyntax.c is the wrong size' fi echo extracting mktokens cat > mktokens <<\EOF # Copyright (C) 1989 by Kenneth Almquist. All rights reserved. # This file is part of ash, which is distributed under the terms specified # by the Ash General Public License. See the file named LICENSE. # The following is a list of tokens. The second column is nonzero if the # token marks the end of a list. The third column is the name to print in # error messages. cat > /tmp/ka$$ <<\! TEOF 1 end of file TNL 0 newline TSEMI 0 ";" TBACKGND 0 "&" TAND 0 "&&" TOR 0 "||" TPIPE 0 "|" TLP 0 "(" TRP 1 ")" TENDCASE 1 ";;" TENDBQUOTE 1 "`" TREDIR 0 redirection TWORD 0 word TIF 0 "if" TTHEN 1 "then" TELSE 1 "else" TELIF 1 "elif" TFI 1 "fi" TWHILE 0 "while" TUNTIL 0 "until" TFOR 0 "for" TDO 1 "do" TDONE 1 "done" TBEGIN 0 "{" TEND 1 "}" TCASE 0 "case" TESAC 1 "esac" ! nl=`wc -l /tmp/ka$$` exec > token.def awk '{print "#define " $1 " " NR-1}' /tmp/ka$$ echo ' /* Array indicating which tokens mark the end of a list */ const char tokendlist[] = {' awk '{print "\t" $2 ","}' /tmp/ka$$ echo '}; char *const tokname[] = {' sed -e 's/"/\\"/g' \ -e 's/[^ ]*[ ][ ]*[^ ]*[ ][ ]*\(.*\)/ "\1",/' \ /tmp/ka$$ echo '}; ' sed 's/"//g' /tmp/ka$$ | awk ' /TIF/{print "#define KWDOFFSET " NR-1; print ""; print "char *const parsekwd[] = {"} /TIF/,/neverfound/{print " \"" $3 "\","}' echo ' 0 };' rm /tmp/ka$$ EOF if test `wc -c < mktokens` -ne 1315 then echo 'mktokens is the wrong size' fi chmod 755 mktokens echo extracting myerrno.h cat > myerrno.h <<\EOF /* * Some versions of errno.h don't declare errno, so we do it ourself. * * Copyright (C) 1989 by Kenneth Almquist. All rights reserved. * This file is part of ash, which is distributed under the terms specified * by the Ash General Public License. See the file named LICENSE. */ #include <sys/errno.h> extern int errno; EOF if test `wc -c < myerrno.h` -ne 331 then echo 'myerrno.h is the wrong size' fi echo extracting mymalloc.c cat > mymalloc.c <<\EOF /* * First fit memory allocation. (Generally uses memory pretty efficiently, * although it is slower than some other memory allocators.) * * Copyright (C) 1989 by Kenneth Almquist. All rights reserved. * This file is part of ash, which is distributed under the terms specified * by the Ash General Public License. See the file named LICENSE. */ #include "shell.h" #include "machdep.h" #include "mystring.h" #include <sys/types.h> /* * The free memory pool consists of a collection of contiguous blocks. * Each block has an integer at the beginning of it which specifies the * size of the block. If the block is allocated, the integer contains * the negative of the size. After the last block comes an integer with * a value of zero. * * To allocate a block, we want to scan the list of blocks starting with * the first block, merging adjacent free blocks, until we get a free * block which is large enough. The actual implementation uses some * hacks to decrease the amount of scanning required. Startfree always * points to the first free block or a block before it. This keeps us * from repeatedly scanning allocated block at the start of the memory * pool. In a similar vein, startbig points to what we believe is the * first free block whose size is >= BIG or a block before it. Startbig * can actually point to some location after the first large free if the * first large free block was formed by freeing several small blocks * which have not yet been merged into a single free block. To make this * less likely, the free routine will merge a freed block with any free * blocks after it, but the free routine cannot merge a freed block with * free blocks which precede it because there is no (efficient) way for * free to locate the preceding block. * * The variables lastsize and lastloc are used to implement one final * method to cut down on scanning. When a malloc is performed, the * variable lastsize is set to the size of the largest block skipped * during the scan, and the variable lastloc is set to the end of the * scan. The next call to malloc can start where the preceding one left * off if the number of bytes reqested is larger than the size of any * blocks skipped on the preceding malloc. When a block is freed with a * lower address than lastloc, free assumes that the block is adjacent to * the largest free block skipped by malloc, and updates lastsize * accordingly. This is necessary to ensure that starting at lastloc * will never cause a block that could be allocated to be skipped; a more * aggressive policy could be used. */ /* * Machine dependent stuff: * * PAGE_SIZE is the size of a page. Malloc will try to keep the break * location on a page boundary to avoid wasting space (since the operating * system presumably has to allocate a whole page even if we only request * part of one). PAGE_SIZE must be a power of 2. * * Head_t is a signed integer type that is capable of holding a value one * less than the maximum size of the pool. Type int works fine on a VAX * because on a VAX processes only get 31 bits of address space. In * practice most other 32 bit machines aren't going to allow processes to * allocate more that 2 gigabytes either. * * Machines generally have alignment restrictions which malloc must * obey. ALIGN(n) returns the value of n rounded up to the minimum * value that malloc must allocate to keep things aligned. * * The code here assumes a linear address space, with sbrk allocating * successively higher addresses. */ #define PAGE_SIZE 1024 #define PAGE_MASK (PAGE_SIZE - 1) #define head_t int #define HEADSIZE ALIGN(sizeof (head_t)) #define DEREF(p) (*(head_t *)(p)) #ifndef ALIGN union align { long l; char *cp; }; #define ALIGN(nbytes) ((nbytes) + sizeof(union align) - 1 &~ (sizeof(union align) - 1)) #endif /* * Tunable paramaters. SLOP is the smallest free block that malloc or * realloc will create. If they would have to create a smaller free * block to satisfy the caller's request, they allocate the extra bytes * to the caller rather than forming a free block. BIG is the smallest * block size that will cause the scan to start at startbig; this is * used to keep requests for large blocks from scanning lots of small * blocks. MINSBRK is the smallest number of pages that will be requested * from sbrk at a time. A larger value can cut down the number of calls * to sbrk. MINSBRK should be a multiple of PAGE_SIZE. */ #define SLOP 8 #define BIG 500 #define MINSBRK (2 * PAGE_SIZE) pointer startfree; /* where to start search for n < BIG */ pointer startbig; /* where to start search for n >= BIG */ pointer lastloc; /* where last search terminated */ head_t lastsize; /* largest block skipped on last search */ pointer realloc(); void free(); caddr_t sbrk(); pointer malloc(n) unsigned n; { return realloc((pointer)0, n); } pointer realloc(old, nbytes) pointer old; unsigned nbytes; { head_t n = nbytes + HEADSIZE; pointer p, q; head_t i; head_t size; head_t largest; pointer next; head_t allocsize; if (n < 0) return NULL; /* nbytes out of range */ n = ALIGN(n); if (startfree == NULL) { /* first time called */ p = sbrk(0); allocsize = PAGE_SIZE - ((int)p & PAGE_MASK); if (allocsize < n + 2 * HEADSIZE) allocsize += MINSBRK; if (sbrk(allocsize) != p) return NULL; DEREF(p) = allocsize - HEADSIZE; startfree = startbig = lastloc = p; lastsize = 0; } if (old) { /* it's a realloc; try resizing */ p = old - HEADSIZE; q = p - DEREF(p); while (DEREF(q) > 0) { if (startbig == q) startbig = p; if (startfree == q) startfree = p; if (lastloc == q) lastloc = p; q += DEREF(q); } size = q - p; if (size >= n) { if (size - n <= SLOP) { DEREF(p) = -size; } else { next = p + n; DEREF(p) = -n; DEREF(next) = size - n; } return old; } } if (n > lastsize) { p = lastloc; largest = lastsize; } else { p = startfree; largest = 0; } if (n >= BIG && p < startbig) { p = startbig; largest = BIG - 1; } for (;;) { while ((size = DEREF(p)) < 0) p -= size; if (largest < BIG) { if (largest == 0) startfree = p; if (p > startbig) startbig = p; } q = p + size; if (DEREF(q) > 0) { do { if (startbig == q) startbig = p; q += DEREF(q); } while (DEREF(q) > 0); size = q - p; DEREF(p) = size; } if (size >= n) { /* found a block that's large enough */ if (size - n <= SLOP) { DEREF(p) = -size; next = q; } else { next = p + n; DEREF(p) = -n; DEREF(next) = size - n; } if (next < startbig && size - n >= BIG) startbig = next; lastsize = largest; lastloc = next; break; } if (DEREF(q) == 0) { /* out of space; must get some from sbrk */ if (old && old + DEREF(old - HEADSIZE) == p) { p = old - HEADSIZE; size += -DEREF(p); old = NULL; } allocsize = (n - size - 1 + PAGE_SIZE) &~ PAGE_MASK; if (allocsize < MINSBRK) allocsize = MINSBRK; if ((next = sbrk(allocsize)) == (caddr_t)-1) return NULL; if (next != q + HEADSIZE) { if (largest < size) largest = size; if (allocsize < n + HEADSIZE) { if (sbrk(PAGE_SIZE) == (caddr_t)-1) { sbrk(-allocsize); return NULL; } allocsize += PAGE_SIZE; } DEREF(q) = -(next - q); p = next; } q = next + allocsize - HEADSIZE; DEREF(q) = 0; /* delete */ next = p + n; DEREF(p) = -n; DEREF(next) = q - next; lastsize = largest; lastloc = next; break; } if (largest < size) largest = size; p = q; } /* allocated a block */ p += HEADSIZE; if (old) { size = -DEREF(old - HEADSIZE); bcopy(old, p, size); free(old); } return p; } void free(p) pointer p; { pointer q; head_t size; if (p == (pointer)0) return; p -= HEADSIZE; if (DEREF(p) >= 0) abort(); q = p - DEREF(p); for (;;) { if (startbig == q) startbig = p; if (lastloc == q) lastloc = p; if (DEREF(q) <= 0) break; q += DEREF(q); } size = q - p; DEREF(p) = size; if (startfree > p) startfree = p; if (size >= BIG && startbig > p) startbig = p; if (p < lastloc) lastsize += size; } EOF if test `wc -c < mymalloc.c` -ne 8670 then echo 'mymalloc.c is the wrong size' fi echo extracting mystring.h cat > mystring.h <<\EOF /* * Copyright (C) 1989 by Kenneth Almquist. All rights reserved. * This file is part of ash, which is distributed under the terms specified * by the Ash General Public License. See the file named LICENSE. */ #ifndef SYSV #define strchr mystrchr #endif #ifdef __STDC__ void scopyn(const char *, char *, int); char *strchr(const char *, int); void mybcopy(const pointer, pointer, int); int prefix(const char *, const char *); int number(const char *); int is_number(const char *); int strcmp(const char *, const char *); /* from C library */ char *strcpy(char *, const char *); /* from C library */ int strlen(const char *); /* from C library */ char *strcat(char *, const char *); /* from C library */ #else void scopyn(); char *strchr(); void mybcopy(); int prefix(); int number(); int is_number(); int strcmp(); char *strcpy(); int strlen(); char *strcat(); #endif #define equal(s1, s2) (strcmp(s1, s2) == 0) #define scopy(s1, s2) ((void)strcpy(s2, s1)) #define bcopy(src, dst, n) mybcopy((pointer)(src), (pointer)(dst), n) EOF if test `wc -c < mystring.h` -ne 1036 then echo 'mystring.h is the wrong size' fi echo extracting mystring.c cat > mystring.c <<\EOF /* * String functions. * * equal(s1, s2) Return true if strings are equal. * scopy(from, to) Copy a string. * scopyn(from, to, n) Like scopy, but checks for overflow. * strchr(s, c) Find first occurance of c in s. * bcopy(from, to, n) Copy a block of memory. * number(s) Convert a string of digits to an integer. * is_number(s) Return true if s is a string of digits. * * Copyright (C) 1989 by Kenneth Almquist. All rights reserved. * This file is part of ash, which is distributed under the terms specified * by the Ash General Public License. See the file named LICENSE. */ #include "shell.h" #include "syntax.h" #include "error.h" #include "mystring.h" char nullstr[1]; /* zero length string */ /* * scopyn - copy a string from "from" to "to", truncating the string * if necessary. "To" is always nul terminated, even if * truncation is performed. "Size" is the size of "to". */ void scopyn(from, to, size) register char const *from; register char *to; register int size; { while (--size > 0) { if ((*to++ = *from++) == '\0') return; } *to = '\0'; } /* * strchr - find first occurrence of a character in a string. */ #ifndef SYS5 char * mystrchr(s, charwanted) char const *s; register char charwanted; { register char const *scan; /* * The odd placement of the two tests is so NUL is findable. */ for (scan = s ; *scan != charwanted ; ) /* ++ moved down for opt. */ if (*scan++ == '\0') return NULL; return (char *)scan; } #endif /* * bcopy - copy bytes * * This routine was derived from code by Henry Spencer. */ void mybcopy(src, dst, length) pointer dst; const pointer src; register int length; { register char *d = dst; register char *s = src; while (--length >= 0) *d++ = *s++; } /* * prefix -- see if pfx is a prefix of string. */ int prefix(pfx, string) register char const *pfx; register char const *string; { while (*pfx) { if (*pfx++ != *string++) return 0; } return 1; } /* * Convert a string of digits to an integer, printing an error message on * failure. */ int number(s) const char *s; { if (! is_number(s)) error2("Illegal number", (char *)s); return atoi(s); } /* * Check for a valid number. This should be elsewhere. */ int is_number(p) register const char *p; { do { if (! is_digit(*p)) return 0; } while (*++p != '\0'); return 1; } EOF if test `wc -c < mystring.c` -ne 2651 then echo 'mystring.c is the wrong size' fi echo extracting nodes.c.pat cat > nodes.c.pat <<\EOF /* * Routine for dealing with parsed shell commands. * * Copyright 1989 by Kenneth Almquist. All rights reserved. * * This file is part of ash. Ash is distributed under the terms specified * by the Ash General Public License. See the file named LICENSE. */ #include "shell.h" #include "nodes.h" #include "memalloc.h" #include "machdep.h" #include "mystring.h" int funcblocksize; /* size of structures in function */ int funcstringsize; /* size of strings in node */ pointer funcblock; /* block to allocate function from */ char *funcstring; /* block to allocate strings from */ %SIZES #ifdef __STDC__ STATIC void calcsize(union node *); STATIC void sizenodelist(struct nodelist *); STATIC union node *copynode(union node *); STATIC struct nodelist *copynodelist(struct nodelist *); STATIC char *nodesavestr(char *); #else STATIC void calcsize(); STATIC void sizenodelist(); STATIC union node *copynode(); STATIC struct nodelist *copynodelist(); STATIC char *nodesavestr(); #endif /* * Make a copy of a parse tree. */ union node * copyfunc(n) union node *n; { if (n == NULL) return NULL; funcblocksize = 0; funcstringsize = 0; calcsize(n); funcblock = ckmalloc(funcblocksize + funcstringsize); funcstring = funcblock + funcblocksize; return copynode(n); } STATIC void calcsize(n) union node *n; { %CALCSIZE } STATIC void sizenodelist(lp) struct nodelist *lp; { while (lp) { funcblocksize += ALIGN(sizeof (struct nodelist)); calcsize(lp->n); lp = lp->next; } } STATIC union node * copynode(n) union node *n; { union node *new; %COPY return new; } STATIC struct nodelist * copynodelist(lp) struct nodelist *lp; { struct nodelist *start; struct nodelist **lpp; lpp = &start; while (lp) { *lpp = funcblock; funcblock += ALIGN(sizeof (struct nodelist)); (*lpp)->n = copynode(lp->n); lp = lp->next; lpp = &(*lpp)->next; } *lpp = NULL; return start; } STATIC char * nodesavestr(s) char *s; { register char *p = s; register char *q = funcstring; char *rtn = funcstring; while (*q++ = *p++); funcstring = q; return rtn; } /* * Free a parse tree. */ void freefunc(n) union node *n; { if (n) ckfree(n); } EOF if test `wc -c < nodes.c.pat` -ne 2438 then echo 'nodes.c.pat is the wrong size' fi echo extracting nodetypes cat > nodetypes <<\EOF # This file describes the nodes used in parse trees. Unindented lines # contain a node type followed by a structure tag. Subsequent indented # lines specify the fields of the structure. Several node types can share # the same structure, in which case the fields of the structure should be # specified only once. # # A field of a structure is described by the name of the field followed # by a type. The currently implemented types are: # nodeptr - a pointer to a node # nodelist - a pointer to a list of nodes # string - a pointer to a nul terminated string # int - an integer # other - any type that can be copied by assignment # temp - a field that doesn't have to be copied when the node is copied # The last two types should be followed by the text of a C declaration for # the field. # # # Copyright 1989 by Kenneth Almquist. All rights reserved. # # This file is part of ash. Ash is distributed under the terms specified # by the Ash General Public License. See the file named LICENSE. NSEMI nbinary # two commands separated by a semicolon type int ch1 nodeptr # the first child ch2 nodeptr # the second child NCMD ncmd # a simple command type int backgnd int # set to run command in background args nodeptr # the arguments redirect nodeptr # list of file redirections NPIPE npipe # a pipeline type int backgnd int # set to run pipeline in background cmdlist nodelist # the commands in the pipeline NREDIR nredir # redirection (of a compex command) type int n nodeptr # the command redirect nodeptr # list of file redirections NBACKGND nredir # run command in background NSUBSHELL nredir # run command in a subshell NAND nbinary # the && operator NOR nbinary # the || operator NIF nif # the if statement. Elif clauses are handled type int # using multiple if nodes. test nodeptr # if test ifpart nodeptr # then ifpart elsepart nodeptr # else elsepart NWHILE nbinary # the while statement. First child is the test NUNTIL nbinary # the until statement NFOR nfor # the for statement type int args nodeptr # for var in args body nodeptr # do body; done var string # the for variable NCASE ncase # a case statement type int expr nodeptr # the word to switch on cases nodeptr # the list of cases (NCLIST nodes) NCLIST nclist # a case type int next nodeptr # the next case in list pattern nodeptr # list of patterns for this case body nodeptr # code to execute for this case NDEFUN narg # define a function. The "next" field contains # the body of the function. NARG narg # represents a word type int next nodeptr # next word in list text string # the text of the word backquote nodelist # list of commands in back quotes NTO nfile # fd> fname NFROM nfile # fd< fname NAPPEND nfile # fd>> fname type int next nodeptr # next redirection in list fd int # file descriptor being redirected fname nodeptr # file name, in a NARG node expfname temp char *expfname # actual file name NTOFD ndup # fd<&dupfd NFROMFD ndup # fd>&dupfd type int next nodeptr # next redirection in list fd int # file descriptor being redirected dupfd int # file descriptor to duplicate NHERE nhere # fd<<\! NXHERE nhere # fd<<! type int next nodeptr # next redirection in list fd int # file descriptor being redirected doc nodeptr # input to command (NARG node) EOF if test `wc -c < nodetypes` -ne 3482 then echo 'nodetypes is the wrong size' fi echo extracting ocdecl.el cat > ocdecl.el <<\EOF (defun ocdecl () "Update the old style C declarations from the new style ones. This assumes that you set up your declarations as follows: #ifdef __STDC__ [ANSI style function prototypes] #else [Old style function prototypes] #endif Then if you add or change a function, you can edit the ANSI style prototypes and then run this function to make the old style prototypes match the new style ones. Normally bound to ESC D." (interactive) (let (ostart oend nstart nend+1 eol) (end-of-line) (search-backward "#ifdef __STDC__") (forward-line 1) (setq ostart (point)) (search-forward "#else") (beginning-of-line) (setq oend (point)) (forward-line 1) (setq nstart (point)) (search-forward "#endif") (beginning-of-line) (setq nend+1 (make-marker)) (set-marker nend+1 (1+ (point))) (goto-char nstart) (insert (buffer-substring ostart oend)) (delete-region (point) (1- nend+1)) (goto-char nstart) (while (< (point) (1- nend+1)) (end-of-line) (setq eol (point)) (beginning-of-line) (re-search-forward "[a-zA-Z0-9_] *(" eol) (setq ostart (point)) (backward-char 1) (forward-sexp 1) (delete-region ostart (1- (point))) (forward-line 1)) (set-marker nend+1 nil) nil)) (define-key esc-map "D" 'ocdecl) EOF if test `wc -c < ocdecl.el` -ne 1334 then echo 'ocdecl.el is the wrong size' fi echo Archive 5 unpacked exit -- Please send comp.sources.unix-related mail to rsalz@uunet.uu.net. Use a domain-based address or give alternate paths, or you may lose out.