v19i005: A reimplementation of the System V shell, Part05/08

Rich Salz rsalz at uunet.uu.net
Wed May 31 04:47:23 AEST 1989


Submitted-by: ka at 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 at uunet.uu.net.
Use a domain-based address or give alternate paths, or you may lose out.



More information about the Comp.sources.unix mailing list