[comp.sources.unix] v19i012: A command-line editor

rsalz@uunet.uu.net (Rich Salz) (06/01/89)

Submitted-by: ka@june.cs.washington.edu (Kenneth Almquist)
Posting-number: Volume 19, Issue 12
Archive-name: atty/part03

# This is part 3 of atty.  To unpack, feed it into the shell (not csh).
# The atty distribution consists of four pieces.  After you unpack everyting,
# read the file README.
cd atty
echo extracting kbind.c
cat > kbind.c <<\EOF
/*
 * The kbind program - compile .bind files.
 *
 * Copyright (C) 1989 by Kenneth Almquist.  All rights reserved.
 * This file is part of atty, which is distributed under the terms specified
 * by the Atty General Public License.  See the file named LICENSE.
 */

#include <stdio.h>
#include "bind.h"


#define VERSION 21	/* change if you change the .bindc format */


/*
 * List of commands.
 */

char *command[] = {
	"universal-argument",
	"digit-argument",
	"negative-argument",
	"self-insert",
	"quoted-insert",
	"newline",
	"end-of-file",
	"eof-or-delete-char",
	"newline-and-insert",
	"tty-intr",
	"tty-quit",
	"tty-susp",
	"delete-backward-char",
	"delete-char",
	"kill-word",
	"backward-kill-word",
	"kill-region",
	"kill-line",
	"kill-input",
	"copy-region-as-kill",
	"forward-char",
	"backward-char",
	"forward-word",
	"backward-word",
	"beginning-of-line",
	"end-of-line",
	"yank",
	"set-mark",
	"exchange-point-and-mark",
	"upcase-char",
	"upcase-word",
	"upcase-region",
	"gosling-transpose-chars",
	"transpose-chars",
	"transpose-words",
	"next-history",
	"previous-history",
	"beginning-of-history",
	"end-of-history",
	"re-search-forward",
	"re-search-backward",
	"file-complete",
	"list-file-completions",
	"get-history-word",
	"last-output-line",
	"mode-0",
	"mode-1",
	0
};



/* Token types */
#define TWORD	1	/* generic word */
#define TNL	2	/* newline */
#define TSTRING	3	/* quoted string */


#define C_UNSET 127	/* command is not set */


#define NMODES 2	/* maximum number of modes */
#define TBLSIZE 128	/* size of a key table */
#define MAXTBL 32	/* maximum number of key tables */
#define STRINGSPACE 5000 /* space for holding strings */
#define MAXABBREV 500	/* maximum number of abbreviations */


struct cmd {
      unsigned char type;	/* type of command */
      unsigned char index;	/* which command */
      int linno;		/* line where defined */
};


struct mode {
      int used;			/* set if mode is in use */
      struct cmd dft;		/* default binding */
      struct cmd *keytab;	/* base key table for this mode */
};


struct syntax {
      char *name;		/* name of this syntax class */
      int defined;		/* set if syntax defined */
      char bitmap[16];		/* bit map specifying which characters are
				   in the class */
};


struct abbrev {
      int fromlen;		/* length of "from" */
      char *from;		/* the abbreviation */
      int tolen;		/* length of "to" */
      char *to;			/* what it is defined as */
};


char *inputfile;		/* name of input file */
FILE *infp;			/* input file */
char outputfile[1024];		/* name of output file */
FILE *outfp;			/* output file */
struct mode mode[NMODES];	/* modes */
struct mode *curmode;		/* current mode */
int nmodes;			/* number of modes actually used */
struct cmd *keytab[MAXTBL];	/* key binding tables */
int nkeytab;			/* number of key tables */
struct syntax syntax[NSYNTAX];	/* syntax tables */
char stringspace[STRINGSPACE];	/* space for holding strings */
char *strnext;			/* next entry in string table */
int nstrings;			/* number of strings in string table */
int nabbrev;			/* number of abbreviations */
struct abbrev abbrev[MAXABBREV];/* abbreviations */
int abbrevsize;			/* total size of abbreviation table */
int mode_1_line;		/* line that mode-1 command occured on */
int lasttoken;			/* type of last token read */
int tokpushback;		/* set to push back token */
char toktext[1024];		/* text of last token read */
char tokstring[512];		/* input string */
char stringlen;			/* length of tokstring */
int linno;			/* current line of input */
int nerrors;			/* number of errors encountered */
int debug;			/* set for debugging info */


#ifdef __STDC__
void makefuncs(void);
char *cname(char *);
void parsefile(void);
void parseline(void);
void parsecmd(struct cmd *);
void setmode(int);
void bind(char *, int, struct cmd *);
struct cmd *newkeytab(void);
void defaultbind(void);
void setdftbind(struct cmd *, struct cmd *);
void setsyntax(char *, char *, int);
void chknl(void);
int gettoken(void);
int getstring(void);
void cvttext(int);
int ateof(void);
char *saveblock(char *, int);
void error(char *);
int writeout(void);
void putkeytab(struct cmd *);
void putsh(int, FILE *);
#else
void makefuncs();
char *cname();
void parsefile();
void parseline();
void parsecmd();
void setmode();
void bind();
struct cmd *newkeytab();
void defaultbind();
void setdftbind();
void setsyntax();
void chknl();
int gettoken();
int getstring();
void cvttext();
int ateof();
char *saveblock();
void error();
int writeout();
void putkeytab();
void putsh();
#endif

char *malloc();
#define equal(s1, s2)	(strcmp(s1, s2) == 0)



main(argc, argv)
      char **argv;
      {
      char **ap;
      int status;

      if (argc <= 1) {
	    fputs("Usage:  kbind file.bind ...\n", stderr);
	    exit(2);
      }
      if (argc == 2 && equal(argv[1], "-makefuncs")) {
	    makefuncs();
	    return 0;
      }
      if (equal(argv[1], "-d")) {
	    argv++;
	    debug = 1;
      }
      status = 0;
      for (ap = argv + 1 ; *ap ; ap++) {
	    inputfile = *ap;
	    if ((infp = fopen(inputfile, "r")) == NULL) {
		  fprintf(stderr, "Can't open %s\n", inputfile);
		  status = 2;
	    }
	    nerrors = 0;
	    parsefile();
	    if (nerrors != 0) {
		  if (status == 0)
			status = 1;
		  continue;
	    }
	    if (writeout() < 0)
		  status = 2;
      }
      exit(status);
}


/*
 * Generate function index to be compiled with atty.
 */

char head[] = "\
/*\n\
 * This file was created by the kbind program.\n\
 */\n\
\n";

void
makefuncs() {
      char **pp;

      if ((outfp = fopen("edfuncs.c", "w")) == NULL) {
	    fputs("Can't create edfuncs.c\n", stderr);
	    exit(2);
      }
      fputs(head, outfp);
      for (pp = command ; *pp ; pp++) {
	    fprintf(outfp, "int %s();\n", cname(*pp));
      }
      putc('\n', outfp);
      fputs("int (*edfunc[])() = {\n", outfp);
      for (pp = command ; *pp ; pp++) {
	    fprintf(outfp, "      %s,\n", cname(*pp));
      }
      fputs("};\n\n", outfp);
      fprintf(outfp, "int version = %d;\n", VERSION);
}


/*
 * Convert a function name to the way that it appears in C.
 */

char *
cname(s)
      char *s;
      {
      static char buf[128];
      char *p;

      strcpy(buf, s);
      for (p = buf ; *p ; p++) {
	    if (*p == '-')
		  *p = '_';
      }
      return buf;
}


void
parsefile() {
      int i;

      linno = 1;
      curmode = NULL;
      nkeytab = 0;
      nmodes = 0;
      strnext = stringspace;
      nstrings = 0;
      nabbrev = 0;
      syntax[0].name = "word";
      syntax[0].defined = 0;
      syntax[1].name = "filename";
      syntax[1].defined = 0;
      syntax[2].name = "abbrev";
      syntax[2].defined = 0;
      for (i = 0 ; i < NMODES ; i++) {
	    mode[i].used = 0;
	    mode[i].dft.type = C_UNSET;
	    mode[i]. keytab = NULL;
      }

      while (! ateof()) {
	    parseline();
      }
      for (i = 0 ; i < NSYNTAX ; i++) {
	    if (! syntax[i].defined)
		  setsyntax(syntax[i].bitmap, "^ \t", 3);
      }
      if (curmode == NULL) {
	    printf("%s:%d: No bindings specified\n", inputfile, linno);
	    nerrors++;
      } else if (mode[0].used == 0) {
	    printf("%s:%d: Mode zero not defined\n", inputfile, linno);
	    nerrors++;
      }
      if (mode_1_line != 0 && mode[1].used == 0) {
	    printf("%s:%d: Mode 1 referenced (line %d), but never defined\n",
		   inputfile, linno, mode_1_line);
	    nerrors++;
      }
      nmodes = 1;
      for (i = 1 ; i < NMODES ; i++) {
	    if (mode[i].used) {
		  if (! mode[i - 1].used) {
			printf("%s:%d: Mode %d is defined, but mode %d is not\n",
			      inputfile, linno, i, i - 1);
			nerrors++;
		  }
		  nmodes = i + 1;
	    }
      }
      defaultbind();
      abbrevsize = 0;
      for (i = 0 ; i < nabbrev ; i++) {
	    abbrevsize += abbrev[i].fromlen + abbrev[i].tolen + 2;
      }
}



void
parseline() {
      struct cmd cmd;
      char binding[128];
      int bindlen;
      int i;

      if (gettoken() == TNL)
	    goto out;
      if (lasttoken != TWORD) {
	    error("Expecting command");
	    goto out;
      }
      if (toktext[0] == '#') {
	    /* a comment, ignore it */
      } else if (equal(toktext, "b")) {
	    if (curmode == NULL) {
		  error("No mode specified");
		  setmode(0);
	    }
	    if (gettoken() != TWORD) {
		  error("Expecting key sequence for b command");
		  goto out;
	    }
	    cvttext(1);		/* parse and save value */
	    bindlen = stringlen;
	    bcopy(tokstring, binding, bindlen);
	    parsecmd(&cmd);
	    bind(binding, bindlen, &cmd);
	    chknl();
      } else if (equal(toktext, "mode")) {
	    if (gettoken() != TWORD || *toktext < '0'
	     || *toktext > '9' || toktext[1] != '\0') {
		  error("Expecting mode number");
		  goto out;
	    }
	    setmode(atoi(toktext));
	    chknl();
      } else if (equal(toktext, "default")) {
	    if (curmode == NULL) {
		  error("No mode specified");
		  setmode(0);
	    }
	    parsecmd(&cmd);
	    curmode->dft = cmd;
	    chknl();
      } else if (equal(toktext, "syntax")) {
	    if (gettoken() != TWORD) {
		  error("Expecting syntax class name");
		  goto out;
	    }
	    for (i = 0 ; ; i++) {
		  if (equal(toktext, syntax[i].name))
			break;
		  if (i == NSYNTAX - 1)
			error("Unimplemented syntax class");
	    }
	    if (syntax[i].defined)
		  error("Redefining syntax class");
	    if (getstring() < 0)
		  goto out;
	    cvttext(0);
	    setsyntax(syntax[i].bitmap, tokstring, stringlen);
	    syntax[i].defined = 1;
	    chknl();
      } else if (equal(toktext, "abbrev")) {
	    if (nabbrev >= MAXABBREV) {
		  error("Too many abbreviations");
		  nabbrev = 0;
	    }
	    if (getstring() < 0)
		  goto out;
	    cvttext(0);
	    if (stringlen == 0)
		  error("Can't define the null string to be an abbreviation");
	    abbrev[nabbrev].fromlen = stringlen;
	    abbrev[nabbrev].from = saveblock(tokstring, stringlen);
	    if (getstring() < 0)
		  goto out;
	    cvttext(0);
	    abbrev[nabbrev].tolen = stringlen;
	    abbrev[nabbrev].to = saveblock(tokstring, stringlen);
	    nabbrev++;
	    chknl();
      } else {
	    error("Unrecognized command");
      }
out:
      while (lasttoken != TNL)
	    gettoken();
}


void
parsecmd(cmdp)
      struct cmd *cmdp;
      {
      char **pp;

      cmdp->type = C_UNDEF;
      cmdp->linno = linno;
      if (gettoken() != TWORD) {
	    error("Expecting function name");	
	    return;
      }
      if (equal(toktext, "insert")) {
	    if (getstring() < 0)
		  return;
	    if (nstrings >= 255) {
		  error("Too many strings");
		  return;
	    }
	    cvttext(0);
	    if ((strnext - stringspace) + 1 + stringlen > STRINGSPACE) {
		  error("Out of space for string constants");
		  return;
	    }
	    *strnext++ = stringlen;
	    bcopy(tokstring, strnext, stringlen);
	    strnext += stringlen;
	    cmdp->type = C_INSERT;
	    cmdp->index = nstrings++;
      } else if (equal(toktext, "undefined")) {
	    cmdp->type = C_UNDEF;
	    cmdp->index = 0;
      } else {
	    for (pp = command ; *pp && ! equal(*pp, toktext) ; pp++);
	    if (*pp == NULL) {
		  error("Unrecognized function");
		  return;
	    }
	    if (equal(toktext, "mode-1"))
		  mode_1_line = linno;
	    cmdp->type = C_FUNC;
	    cmdp->index = pp - command;
      }
}


void
setmode(modenum) {
      if (modenum < 0 || modenum >= NMODES) {
	    error("Mode number out of range");
	    return;
      }
      curmode = &mode[modenum];
      curmode->used = 1;
      if (curmode->keytab == NULL)
	    curmode->keytab = newkeytab();
}


void
bind(keyseq, seqlen, cmdp)
      char *keyseq;
      int seqlen;
      struct cmd *cmdp;
      {
      struct cmd *k;
      struct cmd *cp;
      char *p;
      int lno;

      if (seqlen == 0) {			/* can't happen */
	    error("Empty binding sequence");
	    return;
      }
      if (curmode == NULL) {			/* can't happen */
	    error("No current mode");
	    setmode(0);
      }
      k = curmode->keytab;
      p = keyseq;
      while (--seqlen > 0) {
	    cp = &k[*p++ & 0177];
	    if (cp->type == C_UNSET) {
		  if (nkeytab >= MAXTBL) {
			error("Too many key tables required");
			return;
		  }
		  keytab[nkeytab++] = k = newkeytab();;
		  cp->type = C_PFXTBL;
		  cp->index = nkeytab - 1;
		  cp->linno = cmdp->linno;
	    } else if (cp->type == C_PFXTBL) {
		  k = keytab[cp->index];
	    } else {
		  goto redef;
	    }
      }
      cp = &k[*p & 0177];
      if (cp->type != C_UNSET) {
redef:
	    printf("%s:%d: Redefining key.  (Initial definition line %d)\n",
		   inputfile, cmdp->linno, cp->linno);
	    nerrors++;
	    return;
      }
      *cp = *cmdp;
}


/*
 * Create a new key table.
 */

struct cmd *
newkeytab() {
      struct cmd *keytab;
      struct cmd *p;

      if ((keytab = (struct cmd *)malloc(TBLSIZE * sizeof *keytab)) == NULL) {
	    error("Out of space");
	    exit(2);
      }
      p = keytab + TBLSIZE;
      do {
	    (--p)->type = C_UNSET;
      } while (p > keytab);
      return keytab;
}


/*
 * Set the default bindings.
 */

void
defaultbind() {
      int tabno;
      struct cmd *cp;
      int i;
      static struct cmd dft = {C_UNDEF, 0, 0};

      for (tabno = 0 ; tabno < nmodes ; tabno++) {
	    if (mode[tabno].dft.type == C_UNSET)
		  setdftbind(mode[tabno].keytab, &dft);
	    else
		  setdftbind(mode[tabno].keytab, &mode[tabno].dft);
      }
      for (tabno = 0 ; tabno < nkeytab ; tabno++) {
	    setdftbind(keytab[tabno], &dft);
      }
}



void
setdftbind(tab, dft)
      struct cmd *tab;
      struct cmd *dft;
      {
      struct cmd *cp;
      int i;

      for (i = 128, cp = tab ; --i >= 0 ; cp++) {
	    if (cp->type == C_UNSET)
		  *cp = *dft;
      }
}



/*
 * Set up a syntax table.
 */

void
setsyntax(table, string, len)
      char table[16];
      char *string;
      {
      register char *p;
      int c;
      int invert;

      for (p = table ; p < table + 16 ; p++)
	    *p = 0;
      p = string;
      invert = 0;
      if (len > 0 && *p == '^') {
	    len--;
	    p++;
	    invert++;
      }
      while (--len >= 0) {
	    if (len >= 2 && p[1] == '-') {
		  for (c = p[0] ; c <= p[2] ; c++) {
			table[(c & 0177) >> 3] |= 1 << (c & 07);
		  }
		  p += 3;
		  len -= 2;
	    } else {
		  c = *p++;
		  table[(c & 0177) >> 3] |= 1 << (c & 07);
	    }
      }
      if (invert) {
	    for (p = table ; p < table + 16 ; p++)
		  *p = ~*p;
      }
}


/*
 * Be sure the next token is a newline.
 */

void
chknl() {
      if (gettoken() != TNL)
	    error("Expecting NEWLINE");
}


/*
 * Return the next input token.
 */

int
gettoken() {
      int c;
      char *p;

      if (tokpushback) {
	    tokpushback = 0;
	    return lasttoken;
      }
      lasttoken = 0;
      while ((c = getc(infp)) == ' ' || c == '\t');
      if (c == '\n') {
	    linno++;
	    return lasttoken = TNL;
      }
      p = toktext;
      do {
	    if (c == EOF) {
		  *p = '\0';
		  error("EOF in middle of line");
		  exit(2);
	    }
	    if (p >= toktext + sizeof toktext - 2) {
		  *p = '\0';
		  error("Input token too long");
		  p = toktext;
	    }
	    *p++ = c;
      } while ((c = getc(infp)) != ' ' && c != '\t' && c != '\n');
      ungetc(c, infp);
      *p = '\0';
      return lasttoken = TWORD;
}



/*
 * Parse a string.
 */

int
getstring() {
      int c;
      char *p;

      toktext[0] = '\0';
      lasttoken = 0;
      while ((c = getc(infp)) == ' ' || c == '\t');
      if (c == EOF) {
	    error("EOF in middle of line");
	    exit(2);
      }
      if (c != '"') {
	    ungetc(c, infp);
	    gettoken();
	    error("Expecting a quoted string");
	    return -1;
      }
      p = toktext;
      for (;;) {
	    c = getc(infp);
	    if (c == '"')
		  break;
	    if (c == '\\') {
		  *p++ = c;
		  c = getc(infp);
	    }
	    if (c == EOF) {
		  *p = '\0';
		  error("EOF in middle of line");
		  exit(2);
	    }
	    if (c == '\n') {
		  ungetc(c, infp);
		  error("Unterminated string");
		  return -1;
	    }
	    if (p >= toktext + sizeof toktext - 2) {
		  *p = '\0';
		  error("String too long");
		  p = toktext;
	    }
	    *p++ = c;
      }
      *p = '\0';
      lasttoken = TSTRING;
}


/*
 * Parse the text in the last token string.
 */


void
cvttext(doctl) {
      register char *p, *q;
      char *endp = toktext + strlen(toktext);
      int n;
      int c;

      q = tokstring;
      for (p = toktext ; p < endp ; p++) {
	    if (q >= tokstring + 127) {
		  error("String exceeds 127 characters");	
		  break;
	    }
	    if (*p == '\\') {
		  switch (*++p) {
		  case 'b':  *q++ = '\b';  break;
		  case 'e':  *q++ = '\033'; break;	/* escape */
		  case 'f':  *q++ = '\f';  break;
		  case 'n':  *q++ = '\n';  break;
		  case 'r':  *q++ = '\r';  break;
		  case 's':  *q++ = ' ';   break;
		  case 't':  *q++ = '\t';  break;
		  case '0': case '1': case '2': case '3':
		  case '4': case '5': case '6': case '7':
			c = *p - '0';
			n = 3;
			while (*++p >= '0' && *p <= '7' && --n > 0) {
			      c = (c << 3) + *p - '0';
			}
			*q++ = c;
			break;
		  default:
			*q++ = *p;
			break;
		  }
	    } else if (*p == '^' && doctl) {
		  if (*++p == '?')
			*q++ = '\177';
		  else
			*q++ = *p & 037;
	    } else {
		  *q++ = *p;
	    }
      }
      stringlen = q - tokstring;
}


int
ateof() {
      int c;

      if (feof(infp) || (c = getc(infp)) == EOF)
	    return 1;
      ungetc(c, infp);
      return 0;
}


char *
saveblock(block, len)
      char *block;
      int len;
      {
      char *p;

      if ((p = malloc(len)) == NULL) {
	    error("Out of space");
	    exit(2);
      }
      bcopy(block, p, len);
      return p;
}


void
error(msg)
      char *msg;
      {
      int lno;
      static int lasterror = -1;

      lno = (lasttoken == TNL)? linno - 1 : linno;
      if (lno != lasterror) {
	    lasterror = lno;
	    printf("%s:%d: %s", inputfile, lno, msg);
	    if (lasttoken == TNL)
		  printf(" (input token = NEWLINE)\n");
	    else
		  printf(" (input token = \"%s\")\n", toktext);
      }
      nerrors++;
}


int
writeout() {
      int i;
      int tabno;
      int stringno;
      int stringloc;
      struct abbrev *ap;

      if (debug)
	    return dbwriteout();
      strcpy(outputfile, inputfile);
      if ((i = strlen(inputfile)) < 5 || ! equal(inputfile + i - 5, ".bind"))
	    strcat(outputfile, ".bindc");
      else
	    strcat(outputfile, "c");
      if ((outfp = fopen(outputfile, "w")) == NULL) {
	    fprintf(stderr, "Can't create %s\n", outputfile);
	    return -1;
      }
      putsh(BINDMAGIC, outfp);
      putc(VERSION, outfp);
      putc(nmodes + nkeytab, outfp);
      putsh(strnext - stringspace, outfp);
      putsh(abbrevsize, outfp);
      for (tabno = 0 ; tabno < nmodes ; tabno++) {
	    putkeytab(mode[tabno].keytab);
      }
      for (tabno = 0 ; tabno < nkeytab ; tabno++) {
	    putkeytab(keytab[tabno]);
      }
      for (i = 0 ; i < NSYNTAX ; i++)
	    fwrite(syntax[i].bitmap, sizeof syntax[i].bitmap, 1, outfp);
      fwrite(stringspace, strnext - stringspace, 1, outfp);
      for (i = 0, ap = abbrev ; i < nabbrev ; i++, ap++) {
	    putc(ap->fromlen, outfp);	abbrevsize -= 1;
	    fwrite(ap->from, ap->fromlen, 1, outfp); abbrevsize -= ap->fromlen;
	    putc(ap->tolen, outfp);	abbrevsize -= 1;
	    fwrite(ap->to, ap->tolen, 1, outfp);  abbrevsize -= ap->tolen;
      }
      if (abbrevsize != 0)
	    abort();
      if (ferror(outfp) || fclose(outfp) == EOF) {
	    fprintf(stderr, "Write error on %s\n", outputfile);
	    return -1;
      }
      return 0;
}


void
putkeytab(tab)
      struct cmd *tab;
      {
      struct cmd *cp;
      int ch;

      cp = tab;
      for (ch = 0 ; ch <= 127 ; ch++) {
	    putc(cp->type, outfp);
	    cp++;
      }
      cp = tab;
      for (ch = 0 ; ch <= 127 ; ch++) {
	    if (cp->type == C_PFXTBL)
		  putc(cp->index + nmodes, outfp);
	    else
		  putc(cp->index, outfp);
	    cp++;
      }
}


void
putsh(i, fp)
      FILE *fp;
      {
      putc(i, fp);
      putc(i >> 8, fp);
}


#if 1
int
dbwriteout() {
      int i;
      int tabno;
      int stringno;
      int stringloc;
      struct abbrev *ap;
      char *p;

      strcpy(outputfile, inputfile);
      if ((i = strlen(inputfile)) < 5 || ! equal(inputfile + i - 5, ".bind"))
	    strcat(outputfile, ".bindc");
      else
	    strcat(outputfile, "c");
      if ((outfp = fopen(outputfile, "w")) == NULL) {
	    fprintf(stderr, "Can't create %s\n", outputfile);
	    return -1;
      }
      for (tabno = 0 ; tabno < nmodes ; tabno++) {
	    fprintf(outfp, "keytab for mode %d:\n", tabno);
	    dbputkeytab(mode[tabno].keytab);
      }
      for (tabno = 0 ; tabno < nkeytab ; tabno++) {
	    fprintf(outfp, "keytab %d:\n", tabno + nmodes);
	    dbputkeytab(keytab[tabno]);
      }
      for (i = 0 ; i < NSYNTAX ; i++)
	    dbputsyntax(syntax[i].name, syntax[i].bitmap);
      fprintf(outfp, "\nstrings:\n");
      stringloc = 0;
      for (stringno = 0 ; stringno < nstrings ; stringno++) {
	    fprintf(outfp, "%-4d ", i = stringspace[stringloc++]);
	    while (--i >= 0)
		  outchar(stringspace[stringloc++]);
	    putc('\n', outfp);
      }
      fprintf(outfp, "\nAbbreviations:\n");
      for (stringno = 0, ap = abbrev ; stringno < nabbrev ; stringno++, ap++) {
	    i = ap->fromlen, p = ap->from;
	    while (--i >= 0)
		  outchar(*p++);
	    fputs(": ", outfp);
	    i = ap->tolen, p = ap->to;
	    while (--i >= 0)
		  outchar(*p++);
	    putc('\n', outfp);
	    abbrevsize -= ap->fromlen + ap->tolen + 2;
      }
      if (abbrevsize != 0)
	    abort();
}



dbputkeytab(tab)
      struct cmd *tab;
      {
      struct cmd *cp;
      int ch;

      cp = tab;
      for (ch = 0 ; ch <= 127 ; ch++) {
	    outchar1(ch);
	    putc(' ', outfp);
	    if (cp->type == C_FUNC) {
		  fprintf(outfp, "%s\n", command[cp->index]);
	    } else if (cp->type == C_PFXTBL) {
		  fprintf(outfp, "keytab %d\n", cp->index + nmodes);
	    } else if (cp->type == C_INSERT) {
		  fprintf(outfp, "insert %d\n", cp->index);
	    } else if (cp->type == C_UNDEF) {
		  fprintf(outfp, "<undef>\n");
	    } else if (cp->type == C_UNSET) {
		  fprintf(outfp, "{}\n");
	    } else {
		  fprintf(outfp, "type = %d, index = %d\n", cp->type, cp->index);
	    }
	    cp++;
      }
      putc('\n', outfp);

}



dbputsyntax(name, syntax)
      char *name;
      char *syntax;
      {
      int c;
      int start;

      fprintf(outfp, "%s syntax: ", name);
      start = -1;
      for (c = 0 ; c <= 128 ; c++) {
	    if (c != 128 && syntax[c >> 3] & 1 << (c & 07)) {
		  if (start < 0) {
			start = c;
		  }
	    } else {
		  if (start >= 0) {
			outchar(start);
			if (start != c - 1) {
			      putc('-', outfp);
			      outchar(c - 1);
			}
			start = -1;
		  }
	    }
      }
      putc('\n', outfp);
}



outchar1(ch) {
      if (ch < ' ')
	    fprintf(outfp, "^%c", ch ^ 0100);
      else if (ch == ' ')
	    fprintf(outfp, "SP");
      else if (ch == '\177')
	    fprintf(outfp, "^?");
      else
	    fprintf(outfp, "%c ", ch);
}



outchar(ch) {
      if (ch < ' ')
	    fprintf(outfp, "^%c", ch ^ 0100);
      else if (ch == '\177')
	    fprintf(outfp, "^?");
      else
	    putc(ch, outfp);
}
#endif
EOF
if test `wc -c < kbind.c` -ne 23061
then	echo 'kbind.c is the wrong size'
fi
echo extracting makefile
cat > makefile <<\EOF
# Copyright (C) 1989 by Kenneth Almquist.

FILES=atty.o output.o ed.o edfuncs.o update.o dftbind.o regex.o

#CC=gcc
DEBUG=-g
CFLAGS=$(DEBUG)
LIBS=-ltermcap
#P=&	# for Sequent's parallel make

all:$P kbind atty fmatch atty.1 atty.bindc

clean:
	rm -f *.o

clobber:
	rm -f *.o atty kbind fmatch edfuncs.c dftbind.c atty.1 atty.bindc

atty:$P $(FILES)
	$(CC) -o temp $(FILES) $(LIBS)
	mv -f temp $@

kbind: kbind.o
	$(CC) -o $@ kbind.o

edfuncs.c: kbind
	./kbind -makefuncs

dftbind.c:
	echo "char dftbind[] = \"`pwd`/atty.bindc\";" > $@

atty.bindc: atty.bind kbind
	./kbind atty.bind

fmatch: fmatch.o
	$(CC) -g -o $@ fmatch.o

atty.1: atty.1.mk
	sh atty.1.mk > atty.1

atty.o: atty.h attyed.h
ed.o: attyed.h ed.h bind.h regex.h
kbind.o: bind.h
output.o: atty.h attyed.h
update.o: attyed.h ed.h
EOF
if test `wc -c < makefile` -ne 794
then	echo 'makefile is the wrong size'
fi
echo extracting output.c
cat > output.c <<\EOF
/*
 * Copyright (C) 1989 by Kenneth Almquist.
 */

#include <stdio.h>
#include <sgtty.h>	/* for atty.h */
#include "atty.h"
#include "attyed.h"



int outstate;
int column;
char outline[COLUMNS];
char prompt[COLUMNS];
int promptlen;
int param[2];
char strparam[256];
int nparam;
char *strparamp;
char esccmd;
int *curnumber;
int promptcode;
int promptset;
char lastoutline[COLUMNS];
int lastoutlinelen;


/*
 * All output passes through the outchars routine.  The routine keeps
 * track of the current column and identifies escape sequences that
 * are interpreted by atty itself.
 */

outchars(p, n)
      char *p;
      int n;
      {
      char c;
      int newcol;
      int i;
      char *savep;
      char *q;
      int savecol = column;

      savep = p;
      switch (outstate) {
      case 0:
      state0:	/* base state */
	    while (--n >= 0) {
		  c = *p++;
		  if (c >= ' ' && c <= '~') {
			if (column < COLUMNS)
			      outline[column] = c;
			column++;
		  } else if (c == '\t') {
			newcol = (column + 8) &~ 07;
			while (column < newcol && column < COLUMNS)
			      outline[column++] = ' ';
			column = newcol;
		  } else if (c == '\r') {
			if ((lastoutlinelen = column) > COLUMNS)
				lastoutlinelen = COLUMNS;
			bcopy(outline, lastoutline, lastoutlinelen);
			column = 0;
		  } else if (c == '\033') {	/* ESCAPE */
			outstate = 1;
			goto state1;
		  } else if (c == '\b') {
			if (column > 0)
			      column--;
		  }
	    }
	    break;
      case 1:
      state1:	/* escape character seen */
	    if (--n < 0)
		  break;
	    c = *p++;
	    if (c == '[') {
		  outstate = 2;
		  nparam = 0;
		  param[0] = param[1] = 0;
		  curnumber = NULL;
		  goto state2;
	    } else if (c == ']') {
		  if (p - 2 > savep) {
			dispoff(savecol);
			outreal(savep, p - 2 - savep);
		  }
		  outstate = 3;
		  goto state3;
	    } else if (c == 'H') {	/* ESC H = home on some terminals */
		  column = 0;
		  outstate = 0;
		  goto state0;
	    } else {
		  outstate = 0;
		  goto state0;
	    }
      case 2:
      state2:	/* ESC [ seen */
	    while (--n >= 0) {
		  c = *p++;
		  if (c >= '0' && c <= '9') {
			if (curnumber != NULL) {
			      *curnumber = *curnumber * 10 + c - '0';
			} else if (nparam < 2) {
			      curnumber = &param[nparam++];
			      *curnumber = c - '0';
			}
		  } else if (c == '?') {
			/* ignore it for now */
		  } else if (c == ';') {
			curnumber = NULL;
		  } else {
			goto gotescape;
		  }
	    }
	    break;

gotescape:
	    /* got a complete escape sequence */
	    switch (c) {
		  case 'H':
			column = param[1] > 0? param[1] - 1 : 0;
			break;
		  case 'C':
			column += param[0];
			break;
		  case 'D':
			if ((column -= param[0]) < 0)
			      column = 0;
			break;
		  case 'L':  case'M':
			column = 0;
			break;
		  case 'J':
			if (param[0] == 1 || param[0] == 2) {
			      for (i = 0 ; i < column && i < COLUMNS; i++)
				    outline[i] = ' ';
			}
			break;
	    }
	    outstate = 0;
	    goto state0;
      case 3:
      state3:	/* got ESC ], which introduces an atty control sequence */
	    if (--n < 0)
		  break;
	    c = *p++;
	    if (c == 'P' || c == 'I' || c == 'D') {
		  esccmd = c;
		  strparamp = strparam;
		  outstate = 4;
		  goto state4;
	    } else {
		  dispoff(savecol);
		  ttyoutc('\033');
		  ttyoutc(']');
		  ttyoutc(c);
		  savep = p - 1;
		  outstate = 0;
		  goto state0;
	    }
	    break;
      case 4:
      state4:	/* reading prompt following ESC ] P */
	    while (--n >= 0) {
		  c = *p++;
		  if (c == '\n') {
			*strparamp = '\0';
			goto myesc;
		  }
		  if (c != '\r' && strparamp < &strparam[255]) {
			*strparamp++ = c;
		  }
	    }
	    break;

myesc:
	    /* got an ESC ] ... sequence */
	    switch (esccmd) {
	    case 'P':
		  if (promptset) {
			freezedisp(0);
#ifdef notdef
			if (column != 0) {
			      ttyoutc('\r');
			      ttyoutc('\n');
			}
			for (column = 0 ; prompt[column] ; column++)
			      ttyoutc(prompt[column]);
			bcopy(prompt, outline, column);
#endif
		  }
		  dispoff(savecol);
		  q = strparam;
		  i = 0;
		  while (*q >= '0' && *q <= '9') {
			i = 10 * i + *q - '0';
			q++;
		  }
		  if (*q == ';')
			q++;
		  promptcode = i;
		  if (strlen(q) > COLUMNS - 1)
      			q[COLUMNS - 1] = '\0';
		  strcpy(prompt, q);
		  promptset = 1;
		  break;
	    case 'D':
		  promptset = 0;
		  break;
	    case 'I':
		  insertchars(strparam, strlen(strparam));
		  break;
	    }
	    savep = p;
	    outstate = 0;
	    goto state0;
      }
      if (outstate < 3 && savep != p) {
	    dispoff(savecol);
	    outreal(savep, p - savep);
      }
}
EOF
if test `wc -c < output.c` -ne 4576
then	echo 'output.c is the wrong size'
fi
echo extracting update.c
cat > update.c <<\EOF
/*
 * Update the display of the line being edited on the screen.
 * Copyright (C) 1989 by Kenneth Almquist.
 */


#include "attyed.h"
#include "ed.h"
#include <ctype.h>

#ifndef NULL
#define NULL 0
#endif


struct displine {
      char *text;		/* text of line */
      int len;			/* length of line */
};


int scrnwidth;			/* width of screen */
int eddisplay;			/* if nonzero, editor display is valid */
int needbeep;			/* if nonzero, beep on next refresh */
struct displine virtscrn[60];	/* what the screen should look like */
struct displine realscrn[60];	/* what the screen does look like */
int vslines;			/* number of lines on virtual screen */
int rslines;			/* number of lines on real screen */
int virtline;			/* cursor position in virtscrn */
int virtcol;			/* cursor position in virtscrn */
char *virtptr;			/* &virtscrn[virtline].text[virtcol] */
int *virtlen;			/* &virtscrn[virtline].len */
int realline;			/* position of cursor on real screen */
int realcol;			/* position of cursor on real screen */
int lastrealline;		/* last real line on the screen */
int startline;			/* end of prompt */
int startcol;			/* end of prompt */
char tcspace[120];		/* strings from termcap are stored here */
int tc_am;			/* cursor wraps around at right of screen */
char *tc_bc;			/* backspace */
char *tc_bl;			/* bell */
int tc_bs;			/* if set, terminal can backspace */
char *tc_ce;			/* clear to end of line */
int tc_co;			/* default width of screen */
char *tc_do;			/* cursor down one line */
char *tc_nc;			/* cursor right on column */
char *tc_up;			/* cursor up one line */
int tc_xn;			/* a newline is ignored after wrap around */
char PC;			/* pad character (for termcap routines) */
extern int errno;


#ifdef __STDC__
void virtgoto(int, int);
void drawch(int);
void realgoto(int, int);
void copytoreal(int, int);
void allocline(struct displine *);
#else
void virtgoto();
void drawch();
void realgoto();
void copytoreal();
void allocline();
#endif

#ifdef __STDC__
void ttyoutc(int);
char *getenv(char *);
int tgetent(char *, char *);
int tgetnum(char *);
int tgetflag(char *);
char *tgetstr(char *, char **);
void tputs(char *, int, void (*)(int));
char *malloc(unsigned);
#else
void ttyoutc();
char *getenv();
int tgetent();
int tgetnum();
int tgetflag();
char *tgetstr();
void tputs();
char *malloc();
#endif



/*
 * Read the termcap entry for this terminal.
 */

void
gettermcap() {
      char *termtype;
      char buffer[1024];
      char *tcp = tcspace;
      char *tc_pc;

      errno = 0;
      if ((termtype = getenv("TERM")) == NULL)
	    badinit("$TERM not set");
      if (tgetent(buffer, termtype) <= 0)
	    badinit("Termcap entry not found");
      tc_am = tgetflag("am");
      tc_bs = tgetflag("bs");
      tc_bc = tgetstr("bc", &tcp);
      tc_bl = tgetstr("bl", &tcp);
      tc_ce = tgetstr("ce", &tcp);
      tc_co = tgetnum("co");
      tc_do = tgetstr("do", &tcp);
      tc_nc = tgetstr("nc", &tcp);
      tc_pc = tgetstr("pc", &tcp);
      tc_up = tgetstr("up", &tcp);
      tc_xn = tgetflag("xn");
      PC = (tc_pc != NULL)? *tc_pc : '\0';
      if (tc_up == NULL)
	    badinit("Atty can only run a terminal with a cursor-up escape sequence");
      scrnwidth = tc_co;
}



void
newscrnwidth(width) {
      struct displine *lp;
      int disp = eddisplay;

      if (width <= 1)
	    width = tc_co;
      if (width == scrnwidth)
	    return;
      if (disp)
	    dispoff(column);
      for (lp = virtscrn ; lp->text ; lp++) {
	    free(lp->text);
	    lp->text = NULL;
      }
      vslines = 0;
      for (lp = realscrn ; lp->text ; lp++) {
	    free(lp->text);
	    lp->text = NULL;
      }
      scrnwidth = width;
      if (disp)
	    refresh();
}



void
refresh() {
      struct displine *lp;
      char *p;
      int pointline, pointcol;

      if (eddisplay == 0) {
	    if (realscrn[0].text == NULL)
		  allocline(&realscrn[0]);
	    if (virtscrn[0].text == NULL)
		  allocline(&virtscrn[0]);
	    for (lp = realscrn ; lp->text != NULL ; lp++)
		  lp->len = 0;
	    startcol = column % scrnwidth;
	    startline = 0;
	    realcol = startcol;
	    realline = 0;
	    if (column != 0) {
		  bcopy(outline, realscrn[0].text, realcol);
		  realscrn[0].len = realcol;
		  bcopy(outline, virtscrn[0].text, realcol);
		  virtscrn[0].len = realcol;
		  if (promptset) {
			startcol = 0;
			startline = 1;
		  }
	    }
	    if (promptset) {
		  virtgoto(startline, startcol);
		  for (p = prompt ; *p ; p++)
			drawch(*p);
		  startline = virtline;
		  startcol = virtcol;
	    }
	    lastrealline = 0;
	    eddisplay = 1;
      }
      /* erase everything following the prompt from the virtual screen */
      virtgoto(startline, startcol);
      lp = &virtscrn[startline];
      lp->len = startcol;
      while ((++lp)->text != NULL)
	    lp->len = 0;
      if (editprompt)
	    drawch(editprompt);
      pointcol = -1;
      if (ttymode.echo) {
	    for (p = curline ; p < endcurline ; p++) {
		  if (p == point) {
			pointline = virtline;
			pointcol = virtcol;
		  }
		  drawch(*p);
	    }
      }
      if (pointcol < 0) {
	    pointline = virtline;
	    pointcol = virtcol;
      }
      copytoreal(pointline, pointcol);
}


/*
 * Copy the virtual screen to the real screen.
 */

void
copytoreal(pointline, pointcol) {
      char *p;
      char *r;
      int line;
      int len;
      int limit;
      int col;

      for (line = 0 ; line <= virtline ; line++) {
	    len = virtscrn[line].len;
	    p = virtscrn[line].text;
	    limit = realscrn[line].len;
	    r = realscrn[line].text;
	    if (r == NULL) {
		  allocline(&realscrn[line]);
		  r = realscrn[line].text;
	    }
	    if (limit > len)
		  limit = len;
	    for (col = 0 ; col < limit ; col++) {
		  if (*p != *r) {
			if (realline != line || realcol != col)
			      realgoto(line, col);
			ttyoutc(*p);
			realcol++;
			*r = *p;
		  }
		  p++;
		  r++;
	    }
	    for ( ; col < len ; col++) {
		  if (*p != ' ') {
			if (realline != line || realcol != col)
			      realgoto(line, col);
			ttyoutc(*p);
			realcol++;
		  }
		  *r++ = *p++;
	    }
	    limit = realscrn[line].len;
	    if (col < limit) {
		  if (tc_ce == NULL || limit - col == 1) {
			for ( ; col < limit ; col++) {
			      if (*r++ != ' ') {
				    if (realline != line || realcol != col)
					  realgoto(line, col);
				    ttyoutc(' ');
				    realcol++;
			      }
			}
		  } else {
			realgoto(line, col);
			tputs(tc_ce, 1, ttyoutc);
		  }
	    }
	    if (realcol >= scrnwidth) {
		  if (tc_xn || ! tc_am)
			outreal("\r\n", 2);
		  realcol = 0;
		  realline++;
	    }
	    realscrn[line].len = virtscrn[line].len;
      }
      while (line <= lastrealline) {
	    if (realscrn[line].len > 0) {
		  if (tc_ce) {
			realgoto(line, 0);
			tputs(tc_ce, 1, ttyoutc);
		  } else {
			r = realscrn[line].text;
			limit = realscrn[line].len;
			for (col = 0 ; col < limit ; col++) {
			      if (*r++ != ' ') {
				    if (realline != line || realcol != col)
					  realgoto(line, col);
				    ttyoutc(' ');
				    realcol++;
			      }
			}
			if (realcol >= scrnwidth) {
			      if (tc_xn || ! tc_am)
				    outreal("\r\n", 2);
			      realcol = 0;
			      realline++;
			}
		  }
		  realscrn[line].len = 0;
	    }
	    line++;
      }
      realgoto(pointline, pointcol);
      if (needbeep) {
	    if (tc_bl)
		  tputs(tc_bl, 1, ttyoutc);
	    needbeep = 0;
      }
      lastrealline = virtline;
}



/*
 * Move to beyond the end of the edited stuff, and turn the display off.
 */

void
movetoend() {
      realgoto(lastrealline, 0);
      ttyoutc('\n');
      eddisplay = 0;
      column = 0;
      promptset = 0;
}


/*
 * Output the line being edited to the display, and freeze it there.
 * If the data flag is zero, only freeze the prompt.
 */

void
freezedisp(data) {
      int i;
      struct displine *lp;
      int save_echo;

      save_echo = ttymode.echo;
      ttymode.echo = data;
      refresh();
      ttymode.echo = save_echo;
      eddisplay = 0;
      column = realcol;
      lp = &realscrn[realline];
      for (i = 0 ; i < column ; i++) {
	    outline[i] = (i < lp->len)? lp->text[i] : ' ';
      }
      promptset = 0;
}



/*
 * Turn display off.
 */

void
dispoff(col) {
      int line;

      if (eddisplay == 0)
	    return;
      col = col % scrnwidth;
      virtscrn[0].len = col;
      for (line = 1 ; line <= lastrealline ; line++)
	    virtscrn[line].len = 0;
      copytoreal(0, col);
      eddisplay = 0;
}



void
virtgoto(line, col) {
      struct displine *lp;
      char *p;

      while (vslines <= line) {
	    allocline(&virtscrn[vslines]);
	    vslines++;
      }
      lp = &virtscrn[line];
      if (lp->len < col) {
	    p = &lp->text[lp->len];
	    do *p++ = ' ';
	    while (++lp->len < col);
      }
      virtline = line;
      virtcol = col;
      virtptr = &lp->text[col];
      virtlen = &lp->len;
}


void
drawch(c)
      char c;
      {
      if (! isprint(c)) {
	    if (c == '\t') {
		  do drawch(' ');
		  while ((virtcol & 07) != 0);
		  return;
	    } else {
		  drawch('^');
		  c ^= 0100;
	    }
      }
      *virtptr++ = c;
      virtcol++;
      if (*virtlen < virtcol)
	    *virtlen = virtcol;
      if (virtcol >= scrnwidth) {
	    virtgoto(virtline + 1, 0);
      }
}


/*
 * Goto the specified location on the real screen.  Note that we may
 * scroll the screen, so we must use line feed rather than do for
 * downward motion.
 */

void
realgoto(line, col) {
      char *text;
      int len;

      while (realline > 0 && realline > line) {
	    tputs(tc_up, 1, ttyoutc);
	    realline--;
      }
      while (realline < line) {
#ifdef notdef
	    tputs(tc_do, 1, ttyoutc);
#else
	    ttyoutc('\n');
#endif
	    realline++;
      }
      if (col < realcol - col) {
	    ttyoutc('\r');
	    realcol = 0;
      }
      if (realcol > col) {
	    if (tc_bc) {
		  do {
			tputs(tc_bc, 1, ttyoutc);
		  } while (--realcol > col);
	    } else {
		  do {
			ttyoutc('\b');
		  } while (--realcol > col);
	    }
      }
      if (realcol < col) {
	    text = realscrn[realline].text;
	    len = realscrn[realline].len;
	    do {
		  ttyoutc(realcol < len? text[realcol] : ' ');
	    } while (++realcol < col);
      }
      if (line == 0 && realline > 0) {
	    tputs(tc_up, 1, ttyoutc);
	    realline--;
      }
}



void
allocline(lp)
      struct displine *lp;
      {
      char *p;

      if (lp->text != NULL)
	    return;
      if ((p = malloc(scrnwidth)) == NULL)
	    fatal("Malloc line failed");
      lp->text = p;
      lp->len = 0;
}
EOF
if test `wc -c < update.c` -ne 10496
then	echo 'update.c is the wrong size'
fi
echo extracting vi.bind
cat > vi.bind <<\EOF
# A very half-hearted attempt at a vi mode.

mode 0
default		self-insert
b	^H	delete-backward-char
b	^J	newline-and-insert
b	\r	newline
b	^V	quoted-insert
b	^W	backward-kill-word
b	^X	kill-input
b	^Z	tty-susp
b	^[	mode-1
b	\034	tty-quit
b	\037	end-of-file
b	\177	tty-intr

mode 1
default		undefined
b	^H	backward-char
b	^J	newline-and-insert
b	\r	newline
b	^Z	tty-susp
b	\034	tty-quit
b	\037	end-of-file
b	\s	forward-char
b	+	next-history
b	-	previous-history
b	0	digit-argument
b	1	digit-argument
b	2	digit-argument
b	3	digit-argument
b	4	digit-argument
b	5	digit-argument
b	6	digit-argument
b	7	digit-argument
b	8	digit-argument
b	9	digit-argument
b	/	re-search-forward
b	?	re-search-backward
b	B	backward-word
b	W	forward-word
b	a	mode-0
b	b	backward-word
b	e	forward-word
b	h	backward-char
b	i	mode-0
b	j	previous-history
b	k	next-history
b	l	forward-char
b	w	forward-word
b	x	delete-backward-char
b	\177	tty-intr

b	db	backward-kill-word
b	dd	kill-input
b	dw	kill-word
EOF
if test `wc -c < vi.bind` -ne 974
then	echo 'vi.bind is the wrong size'
fi
echo extracting regex.h
cat > regex.h <<\EOF
/* Definitions for data structures callers pass the regex library.
   Copyright (C) 1985 Free Software Foundation, Inc.

		       NO WARRANTY

  BECAUSE THIS PROGRAM IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY
NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW.  EXCEPT
WHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC,
RICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE THIS PROGRAM "AS IS"
WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY
AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE PROGRAM PROVE
DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR
CORRECTION.

 IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M.
STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., AND/OR ANY OTHER PARTY
WHO MAY MODIFY AND REDISTRIBUTE THIS PROGRAM AS PERMITTED BELOW, BE
LIABLE TO YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR
OTHER SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR
DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR
A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) THIS
PROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY.

		GENERAL PUBLIC LICENSE TO COPY

  1. You may copy and distribute verbatim copies of this source file
as you receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy a valid copyright notice "Copyright
(C) 1985 Free Software Foundation, Inc."; and include following the
copyright notice a verbatim copy of the above disclaimer of warranty
and of this License.  You may charge a distribution fee for the
physical act of transferring a copy.

  2. You may modify your copy or copies of this source file or
any portion of it, and copy and distribute such modifications under
the terms of Paragraph 1 above, provided that you also do the following:

    a) cause the modified files to carry prominent notices stating
    that you changed the files and the date of any change; and

    b) cause the whole of any work that you distribute or publish,
    that in whole or in part contains or is a derivative of this
    program or any part thereof, to be licensed at no charge to all
    third parties on terms identical to those contained in this
    License Agreement (except that you may choose to grant more extensive
    warranty protection to some or all third parties, at your option).

    c) You may charge a distribution fee for the physical act of
    transferring a copy, and you may at your option offer warranty
    protection in exchange for a fee.

Mere aggregation of another unrelated program with this program (or its
derivative) on a volume of a storage or distribution medium does not bring
the other program under the scope of these terms.

  3. You may copy and distribute this program (or a portion or derivative
of it, under Paragraph 2) in object code or executable form under the terms
of Paragraphs 1 and 2 above provided that you also do one of the following:

    a) accompany it with the complete corresponding machine-readable
    source code, which must be distributed under the terms of
    Paragraphs 1 and 2 above; or,

    b) accompany it with a written offer, valid for at least three
    years, to give any third party free (except for a nominal
    shipping charge) a complete machine-readable copy of the
    corresponding source code, to be distributed under the terms of
    Paragraphs 1 and 2 above; or,

    c) accompany it with the information you received as to where the
    corresponding source code may be obtained.  (This alternative is
    allowed only for noncommercial distribution and only if you
    received the program in object code or executable form alone.)

For an executable file, complete source code means all the source code for
all modules it contains; but, as a special exception, it need not include
source code for modules which are standard libraries that accompany the
operating system on which the executable file runs.

  4. You may not copy, sublicense, distribute or transfer this program
except as expressly provided under this License Agreement.  Any attempt
otherwise to copy, sublicense, distribute or transfer this program is void and
your rights to use the program under this License agreement shall be
automatically terminated.  However, parties who have received computer
software programs from you with this License Agreement will not have
their licenses terminated so long as such parties remain in full compliance.

  5. If you wish to incorporate parts of this program into other free
programs whose distribution conditions are different, write to the Free
Software Foundation at 675 Mass Ave, Cambridge, MA 02139.  We have not yet
worked out a simple rule that can be stated here, but we will often permit
this.  We will be guided by the two goals of preserving the free status of
all derivatives of our free software and of promoting the sharing and reuse of
software.


In other words, you are welcome to use, share and improve this program.
You are forbidden to forbid anyone else to use, share and improve
what you give them.   Help stamp out software-hoarding!  */


#ifndef RE_NREGS
#define RE_NREGS 10
#endif

/* This data structure is used to represent a compiled pattern. */

struct re_pattern_buffer
  {
    char *buffer;	/* Space holding the compiled pattern commands. */
    int allocated;	/* Size of space that  buffer  points to */
    int used;		/* Length of portion of buffer actually occupied */
    char *fastmap;	/* Pointer to fastmap, if any, or zero if none. */
			/* re_search uses the fastmap, if there is one,
			   to skip quickly over totally implausible characters */
    char *translate;	/* Translate table to apply to all characters before comparing.
			   Or zero for no translation.
			   The translation is applied to a pattern when it is compiled
			   and to data when it is matched. */
    char fastmap_accurate;
			/* Set to zero when a new pattern is stored,
			   set to one when the fastmap is updated from it. */
    char can_be_null;   /* Set to one by compiling fastmap
			   if this pattern might match the null string.
			   It does not necessarily match the null string
			   in that case, but if this is zero, it cannot.
			   2 as value means can match null string
			   but at end of range or before a character
			   listed in the fastmap.  */
  };

/* Structure to store "register" contents data in.

   Pass the address of such a structure as an argument to re_match, etc.,
   if you want this information back.

   start[i] and end[i] record the string matched by \( ... \) grouping i,
   for i from 1 to RE_NREGS - 1.
   start[0] and end[0] record the entire string matched. */

struct re_registers
  {
    int start[RE_NREGS];
    int end[RE_NREGS];
  };

/* These are the command codes that appear in compiled regular expressions, one per byte.
  Some command codes are followed by argument bytes.
  A command code can specify any interpretation whatever for its arguments.
  Zero-bytes may appear in the compiled regular expression. */

enum regexpcode
  {
    unused,
    exactn,    /* followed by one byte giving n, and then by n literal bytes */
    begline,   /* fails unless at beginning of line */
    endline,   /* fails unless at end of line */
    jump,	 /* followed by two bytes giving relative address to jump to */
    on_failure_jump,	 /* followed by two bytes giving relative address of place
		            to resume at in case of failure. */
    finalize_jump,	 /* Throw away latest failure point and then jump to address. */
    maybe_finalize_jump, /* Like jump but finalize if safe to do so.
			    This is used to jump back to the beginning
			    of a repeat.  If the command that follows
			    this jump is clearly incompatible with the
			    one at the beginning of the repeat, such that
			    we can be sure that there is no use backtracking
			    out of repetitions already completed,
			    then we finalize. */
    dummy_failure_jump,  /* jump, and push a dummy failure point.
			    This failure point will be thrown away
			    if an attempt is made to use it for a failure.
			    A + construct makes this before the first repeat.  */
    anychar,	 /* matches any one character */
    charset,     /* matches any one char belonging to specified set.
		    First following byte is # bitmap bytes.
		    Then come bytes for a bit-map saying which chars are in.
		    Bits in each byte are ordered low-bit-first.
		    A character is in the set if its bit is 1.
		    A character too large to have a bit in the map
		    is automatically not in the set */
    charset_not, /* similar but match any character that is NOT one of those specified */
    start_memory, /* starts remembering the text that is matched
		    and stores it in a memory register.
		    followed by one byte containing the register number.
		    Register numbers must be in the range 0 through NREGS. */
    stop_memory, /* stops remembering the text that is matched
		    and stores it in a memory register.
		    followed by one byte containing the register number.
		    Register numbers must be in the range 0 through NREGS. */
    duplicate,    /* match a duplicate of something remembered.
		    Followed by one byte containing the index of the memory register. */
    before_dot,	 /* Succeeds if before dot */
    at_dot,	 /* Succeeds if at dot */
    after_dot,	 /* Succeeds if after dot */
    begbuf,      /* Succeeds if at beginning of buffer */
    endbuf,      /* Succeeds if at end of buffer */
    wordchar,    /* Matches any word-constituent character */
    notwordchar, /* Matches any char that is not a word-constituent */
    wordbeg,	 /* Succeeds if at word beginning */
    wordend,	 /* Succeeds if at word end */
    wordbound,   /* Succeeds if at a word boundary */
    notwordbound, /* Succeeds if not at a word boundary */
    syntaxspec,  /* Matches any character whose syntax is specified.
		    followed by a byte which contains a syntax code, Sword or such like */
    notsyntaxspec /* Matches any character whose syntax differs from the specified. */
  };

extern char *re_compile_pattern ();
/* Is this really advertised? */
extern void re_compile_fastmap ();
extern int re_search (), re_search_2 ();
extern int re_match (), re_match_2 ();

/* 4.2 bsd compatibility (yuck) */
extern char *re_comp ();
extern int re_exec ();

#ifdef SYNTAX_TABLE
extern char *re_syntax_table;
#endif
EOF
if test `wc -c < regex.h` -ne 10736
then	echo 'regex.h is the wrong size'
fi
echo Archive 3 unpacked
exit

-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.