--- /dev/null
+/* Copyright 1987 Brian Beattie Rights Reserved.
+ *
+ * Permission to copy and/or distribute granted under the
+ * following conditions:
+ *
+ * 1). No charge may be made other than resonable charges
+ * for reproduction.
+ *
+ * 2). This notice must remain intact.
+ *
+ * 3). No further restrictions may be added.
+ *
+ */
+
+/* This program used to be in many little pieces, with this makefile:
+.SUFFIXES: .c .s
+
+CFLAGS = -F
+
+OBJS = append.s catsub.s ckglob.s deflt.s del.s docmd.s doglob.s\
+ doprnt.s doread.s dowrite.s ed.s egets.s find.s getfn.s getlst.s\
+ getnum.s getone.s getptr.s getrhs.s gettxt.s ins.s join.s maksub.s\
+ move.s optpat.s set.s setbuf.s subst.s getpat.s matchs.s amatch.s\
+ unmkpat.s omatch.s makepat.s bitmap.s dodash.s esc.s System.s
+
+ed: $(OBJS)
+ cc -T. -i -o ed $(OBJS)
+*/
+
+#include <sys/types.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <stdio.h>
+
+/****************************/
+
+/* tools.h */
+/*
+ * #defines for non-printing ASCII characters
+ */
+
+#define NUL 0x00 /* ^@ */
+#define EOS 0x00 /* end of string */
+#define SOH 0x01 /* ^A */
+#define STX 0x02 /* ^B */
+#define ETX 0x03 /* ^C */
+#define EOT 0x04 /* ^D */
+#define ENQ 0x05 /* ^E */
+#define ACK 0x06 /* ^F */
+#define BEL 0x07 /* ^G */
+#define BS 0x08 /* ^H */
+#define HT 0x09 /* ^I */
+#define LF 0x0a /* ^J */
+#define NL '\n'
+#define VT 0x0b /* ^K */
+#define FF 0x0c /* ^L */
+#define CR 0x0d /* ^M */
+#define SO 0x0e /* ^N */
+#define SI 0x0f /* ^O */
+#define DLE 0x10 /* ^P */
+#define DC1 0x11 /* ^Q */
+#define DC2 0x12 /* ^R */
+#define DC3 0x13 /* ^S */
+#define DC4 0x14 /* ^T */
+#define NAK 0x15 /* ^U */
+#define SYN 0x16 /* ^V */
+#define ETB 0x17 /* ^W */
+#define CAN 0x18 /* ^X */
+#define EM 0x19 /* ^Y */
+#define SUB 0x1a /* ^Z */
+#define ESC 0x1b /* ^[ */
+#define FS 0x1c /* ^\ */
+#define GS 0x1d /* ^] */
+#define RS 0x1e /* ^^ */
+#define US 0x1f /* ^_ */
+#define SP 0x20 /* space */
+#define DEL 0x7f /* DEL */
+
+
+#define TRUE 1
+#define FALSE 0
+#define ERR -2
+
+
+/* Definitions of meta-characters used in pattern matching
+ * routines. LITCHAR & NCCL are only used as token identifiers;
+ * all the others are also both token identifier and actual symbol
+ * used in the regular expression.
+ */
+
+
+#define BOL '^'
+#define EOL '$'
+#define ANY '.'
+#define LITCHAR 'L'
+#define ESCAPE '\\'
+#define CCL '[' /* Character class: [...] */
+#define CCLEND ']'
+#define NEGATE '^'
+#define NCCL '!' /* Negative character class [^...] */
+#define CLOSURE '*'
+#define OR_SYM '|'
+#define DITTO '&'
+#define OPEN '('
+#define CLOSE ')'
+
+/* Largest permitted size for an expanded character class. (i.e. the class
+ * [a-z] will expand into 26 symbols; [a-z0-9] will expand into 36.)
+ */
+#define CLS_SIZE 128
+
+/*
+ * Tokens are used to hold pattern templates. (see makepat())
+ */
+typedef char BITMAP;
+
+typedef struct token {
+ char tok;
+ char lchar;
+ BITMAP *bitmap;
+ struct token *next;
+} TOKEN;
+
+#define TOKSIZE sizeof (TOKEN)
+
+/*
+ * An absolute maximun for strings.
+ */
+
+#define MAXSTR 132 /* Maximum numbers of characters in a line */
+
+
+/* Macros */
+#define max(a,b) ((a>b)?a:b)
+#define min(a,b) ((a<b)?a:b)
+#define toupper(c) (c>='a'&&c<='z'?c-32:c)
+
+/* ed.h */
+#define FATAL (ERR-1)
+struct line {
+ int l_stat; /* empty, mark */
+ struct line *l_prev;
+ struct line *l_next;
+ char l_buff[1];
+};
+
+typedef struct line LINE;
+
+#define LINFREE 1 /* entry not in use */
+#define LGLOB 2 /* line marked global */
+
+ /* max number of chars per line */
+#define MAXLINE (sizeof(int) == 2 ? 256 : 8192)
+#define MAXPAT 256 /* max number of chars per replacement
+ * pattern */
+ /* max file name size */
+#define MAXFNAME (sizeof(int) == 2 ? 256 : 1024)
+
+extern LINE line0;
+extern int curln, lastln, line1, line2, nlines;
+extern int nflg; /* print line number flag */
+extern int lflg; /* print line in verbose mode */
+extern char *inptr; /* tty input buffer */
+extern char linbuf[], *linptr; /* current line */
+extern int truncflg; /* truncate long line flag */
+extern int eightbit; /* save eighth bit */
+extern int nonascii; /* count of non-ascii chars read */
+extern int nullchar; /* count of null chars read */
+extern int truncated; /* count of lines truncated */
+extern int fchanged; /* file changed */
+
+#define nextln(l) ((l)+1 > lastln ? 0 : (l)+1)
+#define prevln(l) ((l)-1 < 0 ? lastln : (l)-1)
+
+/* amatch.c */
+/* #include <stdio.h> */
+/* #include "tools.h" */
+
+#define _PROTOTYPE(a, b) a b
+_PROTOTYPE(int main, (int argc, char **argv));
+_PROTOTYPE(static char *match, (char *lin, TOKEN *pat, char *boln));
+_PROTOTYPE(char *amatch, (char *lin, TOKEN *pat, char *boln));
+_PROTOTYPE(int append, (int line, int glob));
+_PROTOTYPE(BITMAP *makebitmap, (unsigned size));
+_PROTOTYPE(int setbit, (unsigned c, char *map, unsigned val));
+_PROTOTYPE(int testbit, (unsigned c, char *map));
+_PROTOTYPE(char *catsub, (char *from, char *to, char *sub, char *new, char *newend));
+_PROTOTYPE(int ckglob, (void));
+_PROTOTYPE(int deflt, (int def1, int def2));
+_PROTOTYPE(int del, (int from, int to));
+_PROTOTYPE(int docmd, (int glob));
+_PROTOTYPE(int dolst, (int line1, int line2));
+_PROTOTYPE(char *dodash, (int delim, char *src, char *map));
+_PROTOTYPE(int doglob, (void));
+_PROTOTYPE(int doprnt, (int from, int to));
+_PROTOTYPE(void prntln, (char *str, int vflg, int lin));
+_PROTOTYPE(void putcntl, (int c, FILE *stream));
+_PROTOTYPE(int doread, (int lin, char *fname));
+_PROTOTYPE(int dowrite, (int from, int to, char *fname, int apflg));
+_PROTOTYPE(void intr, (int sig));
+_PROTOTYPE(int egets, (char *str, int size, FILE *stream));
+_PROTOTYPE(int esc, (char **s));
+_PROTOTYPE(int find, (TOKEN *pat, int dir));
+_PROTOTYPE(char *getfn, (void));
+_PROTOTYPE(int getlst, (void));
+_PROTOTYPE(int getnum, (int first));
+_PROTOTYPE(int getone, (void));
+_PROTOTYPE(TOKEN *getpat, (char *arg));
+_PROTOTYPE(LINE *getptr, (int num));
+_PROTOTYPE(int getrhs, (char *sub));
+_PROTOTYPE(char *gettxt, (int num));
+_PROTOTYPE(int ins, (char *str));
+_PROTOTYPE(int System, (char *c));
+_PROTOTYPE(int join, (int first, int last));
+_PROTOTYPE(TOKEN *makepat, (char *arg, int delim));
+_PROTOTYPE(char *maksub, (char *sub, int subsz));
+_PROTOTYPE(char *matchs, (char *line, TOKEN *pat, int ret_endp));
+_PROTOTYPE(int move, (int num));
+_PROTOTYPE(int transfer, (int num));
+_PROTOTYPE(int omatch, (char **linp, TOKEN *pat, char *boln));
+_PROTOTYPE(TOKEN *optpat, (void));
+_PROTOTYPE(int set, (void));
+_PROTOTYPE(int show, (void));
+_PROTOTYPE(void relink, (LINE *a, LINE *x, LINE *y, LINE *b));
+_PROTOTYPE(void clrbuf, (void));
+_PROTOTYPE(void set_buf, (void));
+_PROTOTYPE(int subst, (TOKEN *pat, char *sub, int gflg, int pflag));
+_PROTOTYPE(void unmakepat, (TOKEN *head));
+
+/* Scans throught the pattern template looking for a match
+ * with lin. Each element of lin is compared with the template
+ * until either a mis-match is found or the end of the template
+ * is reached. In the former case a 0 is returned; in the latter,
+ * a pointer into lin (pointing to the character following the
+ * matched pattern) is returned.
+ *
+ * "lin" is a pointer to the line being searched.
+ * "pat" is a pointer to a template made by makepat().
+ * "boln" is a pointer into "lin" which points at the
+ * character at the beginning of the line.
+ */
+
+char *paropen[9], *parclose[9];
+int between, parnum;
+
+char *amatch(lin, pat, boln)
+char *lin;
+TOKEN *pat;
+char *boln;
+{
+ between = 0;
+ parnum = 0;
+
+ lin = match(lin, pat, boln);
+
+ if (between) return 0;
+
+ while (parnum < 9) {
+ paropen[parnum] = parclose[parnum] = "";
+ parnum++;
+ }
+ return lin;
+}
+
+static char *match(lin, pat, boln)
+char *lin;
+TOKEN *pat;
+char *boln;
+{
+ register char *bocl, *rval, *strstart;
+
+ if (pat == 0) return 0;
+
+ strstart = lin;
+
+ while (pat) {
+ if (pat->tok == CLOSURE && pat->next) {
+ /* Process a closure: first skip over the closure
+ * token to the object to be repeated. This object
+ * can be a character class. */
+
+ pat = pat->next;
+
+ /* Now match as many occurrences of the closure
+ * pattern as possible. */
+ bocl = lin;
+
+ while (*lin && omatch(&lin, pat, boln));
+
+ /* 'Lin' now points to the character that made made
+ * us fail. Now go on to process the rest of the
+ * string. A problem here is a character following
+ * the closure which could have been in the closure.
+ * For example, in the pattern "[a-z]*t" (which
+ * matches any lower-case word ending in a t), the
+ * final 't' will be sucked up in the while loop.
+ * So, if the match fails, we back up a notch and try
+ * to match the rest of the string again, repeating
+ * this process recursively until we get back to the
+ * beginning of the closure. The recursion goes, at
+ * most two levels deep. */
+
+ if (pat = pat->next) {
+ int savbtwn = between;
+ int savprnm = parnum;
+
+ while (bocl <= lin) {
+ if (rval = match(lin, pat, boln)) {
+ /* Success */
+ return(rval);
+ } else {
+ --lin;
+ between = savbtwn;
+ parnum = savprnm;
+ }
+ }
+ return(0); /* match failed */
+ }
+ } else if (pat->tok == OPEN) {
+ if (between || parnum >= 9) return 0;
+ paropen[parnum] = lin;
+ between = 1;
+ pat = pat->next;
+ } else if (pat->tok == CLOSE) {
+ if (!between) return 0;
+ parclose[parnum++] = lin;
+ between = 0;
+ pat = pat->next;
+ } else if (omatch(&lin, pat, boln)) {
+ pat = pat->next;
+ } else {
+ return(0);
+ }
+ }
+
+ /* Note that omatch() advances lin to point at the next character to
+ * be matched. Consequently, when we reach the end of the template,
+ * lin will be pointing at the character following the last character
+ * matched. The exceptions are templates containing only a BOLN or
+ * EOLN token. In these cases omatch doesn't advance.
+ *
+ * A philosophical point should be mentioned here. Is $ a position or a
+ * character? (i.e. does $ mean the EOL character itself or does it
+ * mean the character at the end of the line.) I decided here to
+ * make it mean the former, in order to make the behavior of match()
+ * consistent. If you give match the pattern ^$ (match all lines
+ * consisting only of an end of line) then, since something has to be
+ * returned, a pointer to the end of line character itself is
+ * returned. */
+
+ return((char *) max(strstart, lin));
+}
+
+/* append.c */
+/* #include <stdio.h> */
+/* #include "tools.h" */
+/* #include "ed.h" */
+
+int append(line, glob)
+int line, glob;
+{
+ int stat;
+ char lin[MAXLINE];
+
+ if (glob) return(ERR);
+ curln = line;
+ while (1) {
+ if (nflg) printf("%6d. ", curln + 1);
+
+ if (fgets(lin, MAXLINE, stdin) == NULL) return(EOF);
+ if (lin[0] == '.' && lin[1] == '\n') return (0);
+ stat = ins(lin);
+ if (stat < 0) return(ERR);
+
+ }
+}
+
+/* bitmap.c */
+/*
+ * BITMAP.C - makebitmap, setbit, testbit
+ * bit-map manipulation routines.
+ *
+ * Copyright (c) Allen I. Holub, all rights reserved. This program may
+ * for copied for personal, non-profit use only.
+ *
+ */
+
+#ifdef DEBUG
+/* #include <stdio.h> */
+#endif
+
+/* #include "tools.h" */
+
+
+BITMAP *makebitmap(size)
+unsigned size;
+{
+ /* Make a bit map with "size" bits. The first entry in the map is an
+ * "unsigned int" representing the maximum bit. The map itself is
+ * concatenated to this integer. Return a pointer to a map on
+ * success, 0 if there's not enough memory. */
+
+ unsigned *map, numbytes;
+
+ numbytes = (size >> 3) + ((size & 0x07) ? 1 : 0);
+
+#ifdef DEBUG
+ printf("Making a %d bit map (%d bytes required)\n", size, numbytes);
+#endif
+
+ if (map = (unsigned *) malloc(numbytes + sizeof(unsigned))) {
+ *map = size;
+ memset(map + 1, 0, numbytes);
+ }
+
+ return((BITMAP *) map);
+}
+
+int setbit(c, map, val)
+unsigned c, val;
+char *map;
+{
+ /* Set bit c in the map to val. If c > map-size, 0 is returned, else
+ * 1 is returned. */
+
+ if (c >= *(unsigned *) map) /* if c >= map size */
+ return 0;
+
+ map += sizeof(unsigned); /* skip past size */
+
+ if (val)
+ map[c >> 3] |= 1 << (c & 0x07);
+ else
+ map[c >> 3] &= ~(1 << (c & 0x07));
+
+ return 1;
+}
+
+int testbit(c, map)
+unsigned c;
+char *map;
+{
+ /* Return 1 if the bit corresponding to c in map is set. 0 if it is not. */
+
+ if (c >= *(unsigned *) map) return 0;
+
+ map += sizeof(unsigned);
+
+ return(map[c >> 3] & (1 << (c & 0x07)));
+}
+
+/* catsub.c */
+/* #include <stdio.h> */
+/* #include "tools.h" */
+/* #include "ed.h" */
+
+extern char *paropen[9], *parclose[9];
+
+char *catsub(from, to, sub, new, newend)
+char *from, *to, *sub, *new, *newend;
+{
+ char *cp, *cp2;
+
+ for (cp = new; *sub != EOS && cp < newend;) {
+ if (*sub == DITTO) for (cp2 = from; cp2 < to;) {
+ *cp++ = *cp2++;
+ if (cp >= newend) break;
+ }
+ else if (*sub == ESCAPE) {
+ sub++;
+ if ('1' <= *sub && *sub <= '9') {
+ char *parcl = parclose[*sub - '1'];
+
+ for (cp2 = paropen[*sub - '1']; cp2 < parcl;) {
+ *cp++ = *cp2++;
+ if (cp >= newend) break;
+ }
+ } else
+ *cp++ = *sub;
+ } else
+ *cp++ = *sub;
+
+ sub++;
+ }
+
+ return(cp);
+}
+
+/* ckglob.c */
+/* #include <stdio.h> */
+/* #include "tools.h" */
+/* #include "ed.h" */
+
+int ckglob()
+{
+ TOKEN *glbpat;
+ char c, delim;
+ char lin[MAXLINE];
+ int num;
+ LINE *ptr;
+
+ c = *inptr;
+
+ if (c != 'g' && c != 'v') return(0);
+
+ if (deflt(1, lastln) < 0) return(ERR);
+
+ delim = *++inptr;
+ if (delim <= ' ') return(ERR);
+
+ glbpat = optpat();
+
+ if (*inptr == delim) inptr++;
+
+ ptr = getptr(1);
+ for (num = 1; num <= lastln; num++) {
+ ptr->l_stat &= ~LGLOB;
+ if (line1 <= num && num <= line2) {
+ strcpy(lin, ptr->l_buff);
+ strcat(lin, "\n");
+ if (matchs(lin, glbpat, 0)) {
+ if (c == 'g') ptr->l_stat |= LGLOB;
+ } else {
+ if (c == 'v') ptr->l_stat |= LGLOB;
+ }
+ }
+ ptr = ptr->l_next;
+ }
+ return(1);
+}
+
+/* deflt.c */
+/* #include <stdio.h> */
+/* #include "tools.h" */
+/* #include "ed.h" */
+
+int deflt(def1, def2)
+int def1, def2;
+{
+ if (nlines == 0) {
+ line1 = def1;
+ line2 = def2;
+ }
+ if (line1 > line2 || line1 <= 0) return(ERR);
+ return(0);
+}
+
+/* del.c */
+/* #include <stdio.h> */
+/* #include "tools.h" */
+/* #include "ed.h" */
+
+int del(from, to)
+int from, to;
+{
+ LINE *first, *last, *next, *tmp;
+
+ if (from < 1) from = 1;
+ first = getptr(prevln(from));
+ last = getptr(nextln(to));
+ next = first->l_next;
+ while (next != last && next != &line0) {
+ tmp = next->l_next;
+ free((char *) next);
+ next = tmp;
+ }
+ relink(first, last, first, last);
+ lastln -= (to - from) + 1;
+ curln = prevln(from);
+ return(0);
+}
+
+/* docmd.c */
+/* #include <stdio.h> */
+/* #include "tools.h" */
+/* #include "ed.h" */
+
+char fname[MAXFNAME];
+int fchanged;
+extern int nofname;
+
+extern int mark[];
+
+int docmd(glob)
+int glob;
+{
+ static char rhs[MAXPAT];
+ TOKEN *subpat;
+ int c, err, line3;
+ int apflg, pflag, gflag;
+ int nchng;
+ char *fptr;
+
+ pflag = FALSE;
+ while (*inptr == SP && *inptr == HT) inptr++;
+
+ c = *inptr++;
+
+ switch (c) {
+ case NL:
+ if (nlines == 0) {
+ if ((line2 = nextln(curln)) == 0) return(ERR);
+ }
+ curln = line2;
+ return(1);
+ break;
+
+ case '=': printf("%d\n", line2); break;
+
+ case 'a':
+ if (*inptr != NL || nlines > 1) return(ERR);
+
+ if (append(line1, glob) < 0) return(ERR);;
+ fchanged = TRUE;
+ break;
+
+ case 'c':
+ if (*inptr != NL) return(ERR);
+
+ if (deflt(curln, curln) < 0) return(ERR);
+
+ if (del(line1, line2) < 0) return(ERR);
+ if (append(curln, glob) < 0) return (ERR);
+ fchanged = TRUE;
+ break;
+
+ case 'd':
+ if (*inptr != NL) return(ERR);
+
+ if (deflt(curln, curln) < 0) return(ERR);
+
+ if (del(line1, line2) < 0) return(ERR);
+ if (nextln(curln) != 0) curln = nextln(curln);
+ fchanged = TRUE;
+ break;
+
+ case 'e':
+ if (nlines > 0) return(ERR);
+ if (fchanged) {
+ fchanged = FALSE;
+ return(ERR);
+ }
+
+ /* FALL THROUGH */
+ case 'E':
+ if (nlines > 0) return(ERR);
+
+ if (*inptr != ' ' && *inptr != HT && *inptr != NL) return(ERR);
+
+ if ((fptr = getfn()) == NULL) return(ERR);
+
+ clrbuf();
+ if ((err = doread(0, fptr)) < 0) return(err);
+
+ strcpy(fname, fptr);
+ fchanged = FALSE;
+ break;
+
+ case 'f':
+ if (nlines > 0) return(ERR);
+
+ if (*inptr != ' ' && *inptr != HT && *inptr != NL) return(ERR);
+
+ if ((fptr = getfn()) == NULL) return(ERR);
+
+ if (nofname)
+ printf("%s\n", fname);
+ else
+ strcpy(fname, fptr);
+ break;
+
+ case 'i':
+ if (*inptr != NL || nlines > 1) return(ERR);
+
+ if (append(prevln(line1), glob) < 0) return(ERR);
+ fchanged = TRUE;
+ break;
+
+ case 'j':
+ if (*inptr != NL || deflt(curln, curln + 1) < 0) return(ERR);
+
+ if (join(line1, line2) < 0) return(ERR);
+ break;
+
+ case 'k':
+ while (*inptr == ' ' || *inptr == HT) inptr++;
+
+ if (*inptr < 'a' || *inptr > 'z') return ERR;
+ c = *inptr++;
+
+ if (*inptr != ' ' && *inptr != HT && *inptr != NL) return(ERR);
+
+ mark[c - 'a'] = line1;
+ break;
+
+ case 'l':
+ if (*inptr != NL) return(ERR);
+ if (deflt(curln, curln) < 0) return (ERR);
+ if (dolst(line1, line2) < 0) return (ERR);
+ break;
+
+ case 'm':
+ if ((line3 = getone()) < 0) return(ERR);
+ if (deflt(curln, curln) < 0) return (ERR);
+ if (move(line3) < 0) return (ERR);
+ fchanged = TRUE;
+ break;
+
+ case 'P':
+ case 'p':
+ if (*inptr != NL) return(ERR);
+ if (deflt(curln, curln) < 0) return (ERR);
+ if (doprnt(line1, line2) < 0) return (ERR);
+ break;
+
+ case 'q':
+ if (fchanged) {
+ fchanged = FALSE;
+ return(ERR);
+ }
+
+ /* FALL THROUGH */
+ case 'Q':
+ if (*inptr == NL && nlines == 0 && !glob)
+ return(EOF);
+ else
+ return(ERR);
+
+ case 'r':
+ if (nlines > 1) return(ERR);
+
+ if (nlines == 0) line2 = lastln;
+
+ if (*inptr != ' ' && *inptr != HT && *inptr != NL) return(ERR);
+
+ if ((fptr = getfn()) == NULL) return(ERR);
+
+ if ((err = doread(line2, fptr)) < 0) return(err);
+ fchanged = TRUE;
+ break;
+
+ case 's':
+ if (*inptr == 'e') return(set());
+ while (*inptr == SP || *inptr == HT) inptr++;
+ if ((subpat = optpat()) == NULL) return (ERR);
+ if ((gflag = getrhs(rhs)) < 0) return (ERR);
+ if (*inptr == 'p') pflag++;
+ if (deflt(curln, curln) < 0) return (ERR);
+ if ((nchng = subst(subpat, rhs, gflag, pflag)) < 0) return (ERR);
+ if (nchng) fchanged = TRUE;
+ break;
+
+ case 't':
+ if ((line3 = getone()) < 0) return(ERR);
+ if (deflt(curln, curln) < 0) return (ERR);
+ if (transfer(line3) < 0) return (ERR);
+ fchanged = TRUE;
+ break;
+
+ case 'W':
+ case 'w':
+ apflg = (c == 'W');
+
+ if (*inptr != ' ' && *inptr != HT && *inptr != NL) return(ERR);
+
+ if ((fptr = getfn()) == NULL) return(ERR);
+
+ if (deflt(1, lastln) < 0) return(ERR);
+ if (dowrite(line1, line2, fptr, apflg) < 0) return (ERR);
+ fchanged = FALSE;
+ break;
+
+ case 'x':
+ if (*inptr == NL && nlines == 0 && !glob) {
+ if ((fptr = getfn()) == NULL) return(ERR);
+ if (dowrite(1, lastln, fptr, 0) >= 0) return (EOF);
+ }
+ return(ERR);
+
+ case 'z':
+ if (deflt(curln, curln) < 0) return(ERR);
+
+ switch (*inptr) {
+ case '-':
+ if (doprnt(line1 - 21, line1) < 0) return(ERR);
+ break;
+
+ case '.':
+ if (doprnt(line1 - 11, line1 + 10) < 0) return(ERR);
+ break;
+
+ case '+':
+ case '\n':
+ if (doprnt(line1, line1 + 21) < 0) return(ERR);
+ break;
+ }
+ break;
+
+ default: return(ERR);
+}
+ return(0);
+}
+
+int dolst(line1, line2)
+int line1, line2;
+{
+ int oldlflg = lflg, p;
+
+ lflg = 1;
+ p = doprnt(line1, line2);
+ lflg = oldlflg;
+
+ return p;
+}
+
+/* dodash.c */
+/* #include <stdio.h> */
+/* #include "tools.h" */
+
+/* Expand the set pointed to by *src into dest.
+ * Stop at delim. Return 0 on error or size of
+ * character class on success. Update *src to
+ * point at delim. A set can have one element
+ * {x} or several elements ( {abcdefghijklmnopqrstuvwxyz}
+ * and {a-z} are equivalent ). Note that the dash
+ * notation is expanded as sequential numbers.
+ * This means (since we are using the ASCII character
+ * set) that a-Z will contain the entire alphabet
+ * plus the symbols: [\]^_`. The maximum number of
+ * characters in a character class is defined by maxccl.
+ */
+char *dodash(delim, src, map)
+int delim;
+char *src, *map;
+{
+
+ register int first, last;
+ char *start;
+
+ start = src;
+
+ while (*src && *src != delim) {
+ if (*src != '-') setbit(esc(&src), map, 1);
+
+ else if (src == start || *(src + 1) == delim)
+ setbit('-', map, 1);
+ else {
+ src++;
+
+ if (*src < *(src - 2)) {
+ first = *src;
+ last = *(src - 2);
+ } else {
+ first = *(src - 2);
+ last = *src;
+ }
+
+ while (++first <= last) setbit(first, map, 1);
+
+ }
+ src++;
+ }
+ return(src);
+}
+
+/* doglob.c */
+/* #include <stdio.h> */
+/* #include "tools.h" */
+/* #include "ed.h" */
+
+int doglob()
+{
+ int lin, stat;
+ char *cmd;
+ LINE *ptr;
+
+ cmd = inptr;
+
+ while (1) {
+ ptr = getptr(1);
+ for (lin = 1; lin <= lastln; lin++) {
+ if (ptr->l_stat & LGLOB) break;
+ ptr = ptr->l_next;
+ }
+ if (lin > lastln) break;
+
+ ptr->l_stat &= ~LGLOB;
+ curln = lin;
+ inptr = cmd;
+ if ((stat = getlst()) < 0) return(stat);
+ if ((stat = docmd(1)) < 0) return (stat);
+ }
+ return(curln);
+}
+
+/* doprnt.c */
+/* #include <stdio.h> */
+/* #include "tools.h" */
+/* #include "ed.h" */
+
+int doprnt(from, to)
+int from, to;
+{
+ int i;
+ LINE *lptr;
+
+ from = from < 1 ? 1 : from;
+ to = to > lastln ? lastln : to;
+
+ if (to != 0) {
+ lptr = getptr(from);
+ for (i = from; i <= to; i++) {
+ prntln(lptr->l_buff, lflg, (nflg ? i : 0));
+ lptr = lptr->l_next;
+ }
+ curln = to;
+ }
+ return(0);
+}
+
+void prntln(str, vflg, lin)
+char *str;
+int vflg, lin;
+{
+ if (lin) printf("%7d ", lin);
+ while (*str && *str != NL) {
+ if (*str < ' ' || *str >= 0x7f) {
+ switch (*str) {
+ case '\t':
+ if (vflg)
+ putcntl(*str, stdout);
+ else
+ putc(*str, stdout);
+ break;
+
+ case DEL:
+ putc('^', stdout);
+ putc('?', stdout);
+ break;
+
+ default:
+ putcntl(*str, stdout);
+ break;
+ }
+ } else
+ putc(*str, stdout);
+ str++;
+ }
+ if (vflg) putc('$', stdout);
+ putc('\n', stdout);
+}
+
+void putcntl(c, stream)
+char c;
+FILE *stream;
+{
+ putc('^', stream);
+ putc((c & 31) | '@', stream);
+}
+
+/* doread.c */
+/* #include <stdio.h> */
+/* #include "tools.h" */
+/* #include "ed.h" */
+
+extern int diag;
+
+int doread(lin, fname)
+int lin;
+char *fname;
+{
+ FILE *fp;
+ int err;
+ long bytes;
+ int lines;
+ static char str[MAXLINE];
+
+ err = 0;
+ nonascii = nullchar = truncated = 0;
+
+ if (diag) printf("\"%s\" ", fname);
+ if ((fp = fopen(fname, "r")) == NULL) {
+ printf("file open err\n");
+ return(ERR);
+ }
+ curln = lin;
+ for (lines = 0, bytes = 0; (err = egets(str, MAXLINE, fp)) > 0;) {
+ bytes += strlen(str);
+ if (ins(str) < 0) {
+ printf("file insert error\n");
+ err++;
+ break;
+ }
+ lines++;
+ }
+ fclose(fp);
+ if (err < 0) return(err);
+ if (diag) {
+ printf("%d lines %ld bytes", lines, bytes);
+ if (nonascii) printf(" [%d non-ascii]", nonascii);
+ if (nullchar) printf(" [%d nul]", nullchar);
+ if (truncated) printf(" [%d lines truncated]", truncated);
+ printf("\n");
+ }
+ return(err);
+}
+
+/* dowrite.c */
+/* #include <stdio.h> */
+/* #include "tools.h" */
+/* #include "ed.h" */
+
+int dowrite(from, to, fname, apflg)
+int from, to;
+char *fname;
+int apflg;
+{
+ FILE *fp;
+ int lin, err;
+ int lines;
+ long bytes;
+ char *str;
+ LINE *lptr;
+
+ err = 0;
+
+ lines = bytes = 0;
+ if (diag) printf("\"%s\" ", fname);
+ if ((fp = fopen(fname, (apflg ? "a" : "w"))) == NULL) {
+ printf("file open error\n");
+ return(ERR);
+ }
+ lptr = getptr(from);
+ for (lin = from; lin <= to; lin++) {
+ str = lptr->l_buff;
+ lines++;
+ bytes += strlen(str) + 1;
+ if (fputs(str, fp) == EOF) {
+ printf("file write error\n");
+ err++;
+ break;
+ }
+ fputc('\n', fp);
+ lptr = lptr->l_next;
+ }
+ if (diag) printf("%d lines %ld bytes\n", lines, bytes);
+ fclose(fp);
+ return(err);
+}
+
+/* ed.c */
+/* Copyright 1987 Brian Beattie Rights Reserved.
+ *
+ * Permission to copy and/or distribute granted under the
+ * following conditions:
+ *
+ * 1). No charge may be made other than resonable charges
+ * for reproduction.
+ *
+ * 2). This notice must remain intact.
+ *
+ * 3). No further restrictions may be added.
+ *
+ */
+/* #include <stdio.h> */
+/* #include <signal.h> */
+/* #include "tools.h" */
+/* #include "ed.h" */
+#include <setjmp.h>
+jmp_buf env;
+
+LINE line0;
+int curln = 0;
+int lastln = 0;
+char *inptr;
+static char inlin[MAXLINE];
+int nflg, lflg;
+int line1, line2, nlines;
+extern char fname[];
+int version = 1;
+int diag = 1;
+
+void intr(sig)
+int sig;
+{
+ printf("?\n");
+ longjmp(env, 1);
+}
+
+int main(argc, argv)
+int argc;
+char **argv;
+{
+ int stat, i, doflush;
+
+ set_buf();
+ doflush = isatty(1);
+
+ if (argc > 1 && (strcmp(argv[1], "-") == 0 || strcmp(argv[1], "-s") == 0)) {
+ diag = 0;
+ argc--;
+ argv++;
+ }
+ if (argc > 1) {
+ for (i = 1; i < argc; i++) {
+ if (doread(0, argv[i]) == 0) {
+ curln = 1;
+ strcpy(fname, argv[i]);
+ break;
+ }
+ }
+ }
+ while (1) {
+ setjmp(env);
+ if (signal(SIGINT, SIG_IGN) != SIG_IGN) signal(SIGINT, intr);
+
+ if (doflush) fflush(stdout);
+
+ if (fgets(inlin, sizeof(inlin), stdin) == NULL) {
+ break;
+ }
+ for (;;) {
+ inptr = strchr(inlin, EOS);
+ if (inptr >= inlin+2 && inptr[-2] == '\\' && inptr[-1] == NL) {
+ inptr[-1] = 'n';
+ if (fgets(inptr, sizeof(inlin) - (inptr - inlin),
+ stdin) == NULL) break;
+ } else {
+ break;
+ }
+ }
+ if (*inlin == '!') {
+ if ((inptr = strchr(inlin, NL)) != NULL) *inptr = EOS;
+ System(inlin + 1);
+ continue;
+ }
+ inptr = inlin;
+ if (getlst() >= 0)
+ if ((stat = ckglob()) != 0) {
+ if (stat >= 0 && (stat = doglob()) >= 0) {
+ curln = stat;
+ continue;
+ }
+ } else {
+ if ((stat = docmd(0)) >= 0) {
+ if (stat == 1) doprnt(curln, curln);
+ continue;
+ }
+ }
+ if (stat == EOF) {
+ exit(0);
+ }
+ if (stat == FATAL) {
+ fputs("FATAL ERROR\n", stderr);
+ exit(1);
+ }
+ printf("?\n");
+ }
+ return(0);
+}
+
+/* egets.c */
+/* #include <stdio.h> */
+/* #include "tools.h" */
+/* #include "ed.h" */
+
+int eightbit = 1; /* save eight bit */
+int nonascii, nullchar, truncated;
+int egets(str, size, stream)
+char *str;
+int size;
+FILE *stream;
+{
+ int c, count;
+ char *cp;
+
+ for (count = 0, cp = str; size > count;) {
+ c = getc(stream);
+ if (c == EOF) {
+ *cp++ = '\n';
+ *cp = EOS;
+ if (count) {
+ printf("[Incomplete last line]\n");
+ }
+ return(count);
+ }
+ if (c == NL) {
+ *cp++ = c;
+ *cp = EOS;
+ return(++count);
+ }
+ if (c > 127) {
+ if (!eightbit) /* if not saving eighth bit */
+ c = c & 127; /* strip eigth bit */
+ nonascii++; /* count it */
+ }
+ if (c) {
+ *cp++ = c; /* not null, keep it */
+ count++;
+ } else
+ nullchar++; /* count nulls */
+ }
+ str[count - 1] = EOS;
+ if (c != NL) {
+ printf("truncating line\n");
+ truncated++;
+ while ((c = getc(stream)) != EOF)
+ if (c == NL) break;
+ }
+ return(count);
+}
+
+/* esc.c */
+/* #include <stdio.h> */
+/* #include "tools.h" */
+
+/* Map escape sequences into their equivalent symbols. Returns the
+ * correct ASCII character. If no escape prefix is present then s
+ * is untouched and *s is returned, otherwise **s is advanced to point
+ * at the escaped character and the translated character is returned.
+ */
+int esc(s)
+char **s;
+{
+ register int rval;
+
+
+ if (**s != ESCAPE) {
+ rval = **s;
+ } else {
+ (*s)++;
+
+ switch (toupper(**s)) {
+ case '\000': rval = ESCAPE; break;
+ case 'S': rval = ' '; break;
+ case 'N': rval = '\n'; break;
+ case 'T': rval = '\t'; break;
+ case 'B': rval = '\b'; break;
+ case 'R': rval = '\r'; break;
+ default: rval = **s; break;
+ }
+ }
+
+ return(rval);
+}
+
+/* find.c */
+/* #include <stdio.h> */
+/* #include "tools.h" */
+/* #include "ed.h" */
+
+int find(pat, dir)
+TOKEN *pat;
+int dir;
+{
+ int i, num;
+ char lin[MAXLINE];
+ LINE *ptr;
+
+ num = curln;
+ ptr = getptr(curln);
+ num = (dir ? nextln(num) : prevln(num));
+ ptr = (dir ? ptr->l_next : ptr->l_prev);
+ for (i = 0; i < lastln; i++) {
+ if (num == 0) {
+ num = (dir ? nextln(num) : prevln(num));
+ ptr = (dir ? ptr->l_next : ptr->l_prev);
+ }
+ strcpy(lin, ptr->l_buff);
+ strcat(lin, "\n");
+ if (matchs(lin, pat, 0)) {
+ return(num);
+ }
+ num = (dir ? nextln(num) : prevln(num));
+ ptr = (dir ? ptr->l_next : ptr->l_prev);
+ }
+ return(ERR);
+}
+
+/* getfn.c */
+/* #include <stdio.h> */
+/* #include "tools.h" */
+/* #include "ed.h" */
+
+extern char fname[MAXFNAME];
+int nofname;
+
+char *getfn()
+{
+ static char file[256];
+ char *cp;
+
+ if (*inptr == NL) {
+ nofname = TRUE;
+ strcpy(file, fname);
+ } else {
+ nofname = FALSE;
+ while (*inptr == SP || *inptr == HT) inptr++;
+
+ cp = file;
+ while (*inptr && *inptr != NL && *inptr != SP && *inptr != HT) {
+ *cp++ = *inptr++;
+ }
+ *cp = '\0';
+
+ if (strlen(file) == 0) {
+ printf("bad file name\n");
+ return(NULL);
+ }
+ }
+
+ if (strlen(file) == 0) {
+ printf("no file name\n");
+ return(NULL);
+ }
+ return(file);
+}
+
+/* getlst.c */
+/* #include <stdio.h> */
+/* #include "tools.h" */
+/* #include "ed.h" */
+
+int getlst()
+{
+ int num;
+
+ line2 = 0;
+ for (nlines = 0; (num = getone()) >= 0;) {
+ line1 = line2;
+ line2 = num;
+ nlines++;
+ if (*inptr != ',' && *inptr != ';') break;
+ if (*inptr == ';') curln = num;
+ inptr++;
+ }
+ nlines = min(nlines, 2);
+ if (nlines == 0) line2 = curln;
+ if (nlines <= 1) line1 = line2;
+
+ if (num == ERR)
+ return(num);
+ else
+ return(nlines);
+}
+
+/* getnum.c */
+/* #include <stdio.h> */
+/* #include "tools.h" */
+/* #include "ed.h" */
+
+int mark['z' - 'a' + 1];
+
+int getnum(first)
+int first;
+{
+ TOKEN *srchpat;
+ int num;
+ char c;
+
+ while (*inptr == SP || *inptr == HT) inptr++;
+
+ if (*inptr >= '0' && *inptr <= '9') { /* line number */
+ for (num = 0; *inptr >= '0' && *inptr <= '9';) {
+ num = (num * 10) + *inptr - '0';
+ inptr++;
+ }
+ return num;
+ }
+ switch (c = *inptr) {
+ case '.':
+ inptr++;
+ return(curln);
+
+ case '$':
+ inptr++;
+ return(lastln);
+
+ case '/':
+ case '?':
+ srchpat = optpat();
+ if (*inptr == c) inptr++;
+ return(find(srchpat, c == '/' ? 1 : 0));
+
+ case '-':
+ case '+':
+ return(first ? curln : 1);
+
+ case '\'':
+ inptr++;
+ if (*inptr < 'a' || *inptr > 'z') return(EOF);
+
+ return mark[*inptr++ - 'a'];
+
+ default:
+ return(first ? EOF : 1);/* unknown address */
+ }
+}
+
+/* getone.c */
+/* #include <stdio.h> */
+/* #include "tools.h" */
+/* #include "ed.h" */
+
+#define FIRST 1
+#define NOTFIRST 0
+
+int getone()
+{
+ int c, i, num;
+
+ if ((num = getnum(FIRST)) >= 0) {
+ while (1) {
+ while (*inptr == SP || *inptr == HT) inptr++;
+
+ if (*inptr != '+' && *inptr != '-') break;
+ c = *inptr++;
+
+ if ((i = getnum(NOTFIRST)) < 0) return(i);
+
+ if (c == '+') {
+ num += i;
+ } else {
+ num -= i;
+ }
+ }
+ }
+ return(num > lastln ? ERR : num);
+}
+
+/* getpat.c */
+/* #include <stdio.h> */
+/* #include "tools.h" */
+
+/* Translate arg into a TOKEN string */
+TOKEN *
+ getpat(arg)
+char *arg;
+{
+
+ return(makepat(arg, '\000'));
+}
+
+/* getptr.c */
+/* #include <stdio.h> */
+/* #include "tools.h" */
+/* #include "ed.h" */
+
+LINE *
+ getptr(num)
+int num;
+{
+ LINE *ptr;
+ int j;
+
+ if (2 * num > lastln && num <= lastln) { /* high line numbers */
+ ptr = line0.l_prev;
+ for (j = lastln; j > num; j--) ptr = ptr->l_prev;
+ } else { /* low line numbers */
+ ptr = &line0;
+ for (j = 0; j < num; j++) ptr = ptr->l_next;
+ }
+ return(ptr);
+}
+
+/* getrhs.c */
+/* #include <stdio.h> */
+/* #include "tools.h" */
+/* #include "ed.h" */
+
+int getrhs(sub)
+char *sub;
+{
+ if (inptr[0] == NL || inptr[1] == NL) /* check for eol */
+ return(ERR);
+
+ if (maksub(sub, MAXPAT) == NULL) return(ERR);
+
+ inptr++; /* skip over delimter */
+ while (*inptr == SP || *inptr == HT) inptr++;
+ if (*inptr == 'g') {
+ inptr++;
+ return(1);
+ }
+ return(0);
+}
+
+/* gettxt.c */
+/* #include <stdio.h> */
+/* #include "tools.h" */
+/* #include "ed.h" */
+
+char *
+ gettxt(num)
+int num;
+{
+ LINE *lin;
+ static char txtbuf[MAXLINE];
+
+ lin = getptr(num);
+ strcpy(txtbuf, lin->l_buff);
+ strcat(txtbuf, "\n");
+ return(txtbuf);
+}
+
+/* ins.c */
+/* #include <stdio.h> */
+/* #include "tools.h" */
+/* #include "ed.h" */
+
+int ins(str)
+char *str;
+{
+ char buf[MAXLINE], *cp;
+ LINE *new, *cur, *nxt;
+
+ cp = buf;
+ while (1) {
+ if ((*cp = *str++) == NL) *cp = EOS;
+ if (*cp) {
+ cp++;
+ continue;
+ }
+ if ((new = (LINE *) malloc(sizeof(LINE) + strlen(buf))) == NULL)
+ return(ERR); /* no memory */
+
+ new->l_stat = 0;
+ strcpy(new->l_buff, buf); /* build new line */
+ cur = getptr(curln); /* get current line */
+ nxt = cur->l_next; /* get next line */
+ relink(cur, new, new, nxt); /* add to linked list */
+ relink(new, nxt, cur, new);
+ lastln++;
+ curln++;
+
+ if (*str == EOS) /* end of line ? */
+ return(1);
+
+ cp = buf;
+ }
+}
+
+/* join.c */
+/* #include <stdio.h> */
+/* #include "tools.h" */
+/* #include "ed.h" */
+
+extern int fchanged;
+
+int join(first, last)
+int first, last;
+{
+ char buf[MAXLINE];
+ char *cp = buf, *str;
+ int num;
+
+ if (first <= 0 || first > last || last > lastln) return(ERR);
+ if (first == last) {
+ curln = first;
+ return 0;
+ }
+ for (num = first; num <= last; num++) {
+ str = gettxt(num);
+
+ while (*str != NL && cp < buf + MAXLINE - 1) *cp++ = *str++;
+
+ if (cp == buf + MAXLINE - 1) {
+ printf("line too long\n");
+ return(ERR);
+ }
+ }
+ *cp++ = NL;
+ *cp = EOS;
+ del(first, last);
+ curln = first - 1;
+ ins(buf);
+ fchanged = TRUE;
+ return 0;
+}
+
+/* makepat.c */
+/* #include <stdio.h> */
+/* #include "tools.h" */
+
+/* Make a pattern template from the strinng pointed to by arg. Stop
+ * when delim or '\000' or '\n' is found in arg. Return a pointer to
+ * the pattern template.
+ *
+ * The pattern template used here are somewhat different than those
+ * used in the "Software Tools" book; each token is a structure of
+ * the form TOKEN (see tools.h). A token consists of an identifier,
+ * a pointer to a string, a literal character and a pointer to another
+ * token. This last is 0 if there is no subsequent token.
+ *
+ * The one strangeness here is caused (again) by CLOSURE which has
+ * to be put in front of the previous token. To make this insertion a
+ * little easier, the 'next' field of the last to point at the chain
+ * (the one pointed to by 'tail) is made to point at the previous node.
+ * When we are finished, tail->next is set to 0.
+ */
+TOKEN *
+ makepat(arg, delim)
+char *arg;
+int delim;
+{
+ TOKEN *head, *tail, *ntok;
+ int error;
+
+ /* Check for characters that aren't legal at the beginning of a template. */
+
+ if (*arg == '\0' || *arg == delim || *arg == '\n' || *arg == CLOSURE)
+ return(0);
+
+ error = 0;
+ tail = head = NULL;
+
+ while (*arg && *arg != delim && *arg != '\n' && !error) {
+ ntok = (TOKEN *) malloc(TOKSIZE);
+ ntok->lchar = '\000';
+ ntok->next = 0;
+
+ switch (*arg) {
+ case ANY: ntok->tok = ANY; break;
+
+ case BOL:
+ if (head == 0) /* then this is the first symbol */
+ ntok->tok = BOL;
+ else
+ ntok->tok = LITCHAR;
+ ntok->lchar = BOL;
+ break;
+
+ case EOL:
+ if (*(arg + 1) == delim || *(arg + 1) == '\000' ||
+ *(arg + 1) == '\n') {
+ ntok->tok = EOL;
+ } else {
+ ntok->tok = LITCHAR;
+ ntok->lchar = EOL;
+ }
+ break;
+
+ case CLOSURE:
+ if (head != 0) {
+ switch (tail->tok) {
+ case BOL:
+ case EOL:
+ case CLOSURE:
+ return(0);
+
+ default:
+ ntok->tok = CLOSURE;
+ }
+ }
+ break;
+
+ case CCL:
+
+ if (*(arg + 1) == NEGATE) {
+ ntok->tok = NCCL;
+ arg += 2;
+ } else {
+ ntok->tok = CCL;
+ arg++;
+ }
+
+ if (ntok->bitmap = makebitmap(CLS_SIZE))
+ arg = dodash(CCLEND, arg, ntok->bitmap);
+ else {
+ fprintf(stderr, "Not enough memory for pat\n");
+ error = 1;
+ }
+ break;
+
+ default:
+ if (*arg == ESCAPE && *(arg + 1) == OPEN) {
+ ntok->tok = OPEN;
+ arg++;
+ } else if (*arg == ESCAPE && *(arg + 1) == CLOSE) {
+ ntok->tok = CLOSE;
+ arg++;
+ } else {
+ ntok->tok = LITCHAR;
+ ntok->lchar = esc(&arg);
+ }
+ }
+
+ if (error || ntok == 0) {
+ unmakepat(head);
+ return(0);
+ } else if (head == 0) {
+ /* This is the first node in the chain. */
+
+ ntok->next = 0;
+ head = tail = ntok;
+ } else if (ntok->tok != CLOSURE) {
+ /* Insert at end of list (after tail) */
+
+ tail->next = ntok;
+ ntok->next = tail;
+ tail = ntok;
+ } else if (head != tail) {
+ /* More than one node in the chain. Insert the
+ * CLOSURE node immediately in front of tail. */
+
+ (tail->next)->next = ntok;
+ ntok->next = tail;
+ } else {
+ /* Only one node in the chain, Insert the CLOSURE
+ * node at the head of the linked list. */
+
+ ntok->next = head;
+ tail->next = ntok;
+ head = ntok;
+ }
+ arg++;
+ }
+
+ tail->next = 0;
+ return(head);
+}
+
+/* maksub.c */
+/* #include <stdio.h> */
+/* #include "tools.h" */
+/* #include "ed.h" */
+
+char *
+ maksub(sub, subsz)
+char *sub;
+int subsz;
+{
+ int size;
+ char delim, *cp;
+
+ size = 0;
+ cp = sub;
+
+ delim = *inptr++;
+ for (size = 0; *inptr != delim && *inptr != NL && size < subsz; size++) {
+ if (*inptr == '&') {
+ *cp++ = DITTO;
+ inptr++;
+ } else if ((*cp++ = *inptr++) == ESCAPE) {
+ if (size >= subsz) return(NULL);
+
+ switch (toupper(*inptr)) {
+ case NL: *cp++ = ESCAPE; break;
+ break;
+ case 'S':
+ *cp++ = SP;
+ inptr++;
+ break;
+ case 'N':
+ *cp++ = NL;
+ inptr++;
+ break;
+ case 'T':
+ *cp++ = HT;
+ inptr++;
+ break;
+ case 'B':
+ *cp++ = BS;
+ inptr++;
+ break;
+ case 'R':
+ *cp++ = CR;
+ inptr++;
+ break;
+ case '0':{
+ int i = 3;
+ *cp = 0;
+ do {
+ if (*++inptr < '0' || *inptr > '7')
+ break;
+
+ *cp = (*cp << 3) | (*inptr - '0');
+ } while (--i != 0);
+ cp++;
+ } break;
+ default: *cp++ = *inptr++; break;
+ }
+ }
+ }
+ if (size >= subsz) return(NULL);
+
+ *cp = EOS;
+ return(sub);
+}
+
+/* matchs.c */
+/* #include <stdio.h> */
+/* #include "tools.h" */
+
+/* Compares line and pattern. Line is a character string while pat
+ * is a pattern template made by getpat().
+ * Returns:
+ * 1. A zero if no match was found.
+ *
+ * 2. A pointer to the last character satisfing the match
+ * if ret_endp is non-zero.
+ *
+ * 3. A pointer to the beginning of the matched string if
+ * ret_endp is zero.
+ *
+ * e.g.:
+ *
+ * matchs ("1234567890", getpat("4[0-9]*7), 0);
+ * will return a pointer to the '4', while:
+ *
+ * matchs ("1234567890", getpat("4[0-9]*7), 1);
+ * will return a pointer to the '7'.
+ */
+char *
+ matchs(line, pat, ret_endp)
+char *line;
+TOKEN *pat;
+int ret_endp;
+{
+
+ char *rval, *bptr;
+ char *line2;
+ TOKEN *pat2;
+ char c;
+ short ok;
+
+ bptr = line;
+
+ while (*line) {
+
+ if (pat && pat->tok == LITCHAR) {
+ while (*line) {
+ pat2 = pat;
+ line2 = line;
+ if (*line2 != pat2->lchar) {
+ c = pat2->lchar;
+ while (*line2 && *line2 != c) ++line2;
+ line = line2;
+ if (*line2 == '\0') break;
+ }
+ ok = 1;
+ ++line2;
+ pat2 = pat2->next;
+ while (pat2 && pat2->tok == LITCHAR) {
+ if (*line2 != pat2->lchar) {
+ ok = 0;
+ break;
+ }
+ ++line2;
+ pat2 = pat2->next;
+ }
+ if (!pat2) {
+ if (ret_endp)
+ return(--line2);
+ else
+ return(line);
+ } else if (ok)
+ break;
+ ++line;
+ }
+ if (*line == '\0') return(0);
+ } else {
+ line2 = line;
+ pat2 = pat;
+ }
+ if ((rval = amatch(line2, pat2, bptr)) == 0) {
+ if (pat && pat->tok == BOL) break;
+ line++;
+ } else {
+ if (rval > bptr && rval > line)
+ rval--; /* point to last char matched */
+ rval = ret_endp ? rval : line;
+ break;
+ }
+ }
+ return(rval);
+}
+
+/* move.c */
+/* #include <stdio.h> */
+/* #include "tools.h" */
+/* #include "ed.h" */
+
+int move(num)
+int num;
+{
+ LINE *k0, *k1, *k2, *k3;
+
+ if (line1 <= 0 || line2 < line1 || (line1 <= num && num <= line2))
+ return(ERR);
+ k0 = getptr(prevln(line1));
+ k1 = getptr(line1);
+ k2 = getptr(line2);
+ k3 = getptr(nextln(line2));
+
+ relink(k0, k3, k0, k3);
+ lastln -= line2 - line1 + 1;
+
+ if (num > line1) num -= line2 - line1 + 1;
+
+ curln = num + (line2 - line1 + 1);
+
+ k0 = getptr(num);
+ k3 = getptr(nextln(num));
+
+ relink(k0, k1, k2, k3);
+ relink(k2, k3, k0, k1);
+ lastln += line2 - line1 + 1;
+
+ return(1);
+}
+
+int transfer(num)
+int num;
+{
+ int mid, lin, ntrans;
+
+ if (line1 <= 0 || line1 > line2) return(ERR);
+
+ mid = num < line2 ? num : line2;
+
+ curln = num;
+ ntrans = 0;
+
+ for (lin = line1; lin <= mid; lin++) {
+ ins(gettxt(lin));
+ ntrans++;
+ }
+ lin += ntrans;
+ line2 += ntrans;
+
+ for (; lin <= line2; lin += 2) {
+ ins(gettxt(lin));
+ line2++;
+ }
+ return(1);
+}
+
+/* omatch.c */
+/* #include <stdio.h> */
+/* #include "tools.h" */
+
+/* Match one pattern element, pointed at by pat, with the character at
+ * **linp. Return non-zero on match. Otherwise, return 0. *Linp is
+ * advanced to skip over the matched character; it is not advanced on
+ * failure. The amount of advance is 0 for patterns that match null
+ * strings, 1 otherwise. "boln" should point at the position that will
+ * match a BOL token.
+ */
+int omatch(linp, pat, boln)
+char **linp;
+TOKEN *pat;
+char *boln;
+{
+
+ register int advance;
+
+ advance = -1;
+
+ if (**linp) {
+ switch (pat->tok) {
+ case LITCHAR:
+ if (**linp == pat->lchar) advance = 1;
+ break;
+
+ case BOL:
+ if (*linp == boln) advance = 0;
+ break;
+
+ case ANY:
+ if (**linp != '\n') advance = 1;
+ break;
+
+ case EOL:
+ if (**linp == '\n') advance = 0;
+ break;
+
+ case CCL:
+ if (testbit(**linp, pat->bitmap)) advance = 1;
+ break;
+
+ case NCCL:
+ if (!testbit(**linp, pat->bitmap)) advance = 1;
+ break;
+ }
+ }
+ if (advance >= 0) *linp += advance;
+
+ return(++advance);
+}
+
+/* optpat.c */
+/* #include <stdio.h> */
+/* #include "tools.h" */
+/* #include "ed.h" */
+
+TOKEN *oldpat;
+
+TOKEN *
+ optpat()
+{
+ char delim, str[MAXPAT], *cp;
+
+ delim = *inptr++;
+ cp = str;
+ while (*inptr != delim && *inptr != NL) {
+ if (*inptr == ESCAPE && inptr[1] != NL) *cp++ = *inptr++;
+ *cp++ = *inptr++;
+ }
+
+ *cp = EOS;
+ if (*str == EOS) return(oldpat);
+ if (oldpat) unmakepat(oldpat);
+ oldpat = getpat(str);
+ return(oldpat);
+}
+
+/* set.c */
+/* #include <stdio.h> */
+/* #include "tools.h" */
+/* #include "ed.h" */
+
+struct tbl {
+ char *t_str;
+ int *t_ptr;
+ int t_val;
+} *t, tbl[] = {
+
+ "number", &nflg, TRUE,
+ "nonumber", &nflg, FALSE,
+ "list", &lflg, TRUE,
+ "nolist", &lflg, FALSE,
+ "eightbit", &eightbit, TRUE,
+ "noeightbit", &eightbit, FALSE,
+ 0
+};
+
+int set()
+{
+ char word[16];
+ int i;
+
+ inptr++;
+ if (*inptr != 't') {
+ if (*inptr != SP && *inptr != HT && *inptr != NL) return(ERR);
+ } else
+ inptr++;
+
+ if (*inptr == NL) return(show());
+ /* Skip white space */
+ while (*inptr == SP || *inptr == HT) inptr++;
+
+ for (i = 0; *inptr != SP && *inptr != HT && *inptr != NL;)
+ word[i++] = *inptr++;
+ word[i] = EOS;
+ for (t = tbl; t->t_str; t++) {
+ if (strcmp(word, t->t_str) == 0) {
+ *t->t_ptr = t->t_val;
+ return(0);
+ }
+ }
+ return(0);
+}
+
+int show()
+{
+ extern int version;
+
+ printf("ed version %d.%d\n", version / 100, version % 100);
+ printf("number %s, list %s\n", nflg ? "ON" : "OFF", lflg ? "ON" : "OFF");
+ return(0);
+}
+
+/* setbuf.c */
+/* #include <stdio.h> */
+/* #include "tools.h" */
+/* #include "ed.h" */
+
+void relink(a, x, y, b)
+LINE *a, *x, *y, *b;
+{
+ x->l_prev = a;
+ y->l_next = b;
+}
+
+void clrbuf()
+{
+ del(1, lastln);
+}
+
+void set_buf()
+{
+ relink(&line0, &line0, &line0, &line0);
+ curln = lastln = 0;
+}
+
+/* subst.c */
+/* #include <stdio.h> */
+/* #include "tools.h" */
+/* #include "ed.h" */
+
+int subst(pat, sub, gflg, pflag)
+TOKEN *pat;
+char *sub;
+int gflg, pflag;
+{
+ int lin, chngd, nchngd;
+ char *txtptr, *txt;
+ char *lastm, *m, *new, buf[MAXLINE];
+
+ if (line1 <= 0) return(ERR);
+ nchngd = 0; /* reset count of lines changed */
+ for (lin = line1; lin <= line2; lin++) {
+ txt = txtptr = gettxt(lin);
+ new = buf;
+ chngd = 0;
+ lastm = NULL;
+ while (*txtptr) {
+ if (gflg || !chngd)
+ m = amatch(txtptr, pat, txt);
+ else
+ m = NULL;
+ if (m != NULL && lastm != m) {
+ chngd++;
+ new = catsub(txtptr, m, sub, new,
+ buf + MAXLINE);
+ lastm = m;
+ }
+ if (m == NULL || m == txtptr) {
+ *new++ = *txtptr++;
+ } else {
+ txtptr = m;
+ }
+ }
+ if (chngd) {
+ if (new >= buf + MAXLINE) return(ERR);
+ *new++ = EOS;
+ del(lin, lin);
+ ins(buf);
+ nchngd++;
+ if (pflag) doprnt(curln, curln);
+ }
+ }
+ if (nchngd == 0 && !gflg) {
+ return(ERR);
+ }
+ return(nchngd);
+}
+
+/* System.c */
+#define SHELL "/bin/sh"
+#define SHELL2 "/usr/bin/sh"
+
+int System(c)
+char *c;
+{
+ int pid, status;
+
+ switch (pid = fork()) {
+ case -1:
+ return -1;
+ case 0:
+ execl(SHELL, "sh", "-c", c, (char *) 0);
+ execl(SHELL2, "sh", "-c", c, (char *) 0);
+ exit(-1);
+ default: while (wait(&status) != pid);
+}
+ return status;
+}
+
+/* unmkpat.c */
+/* #include <stdio.h> */
+/* #include "tools.h" */
+
+/* Free up the memory usde for token string */
+void unmakepat(head)
+TOKEN *head;
+{
+
+ register TOKEN *old_head;
+
+ while (head) {
+ switch (head->tok) {
+ case CCL:
+ case NCCL:
+ free(head->bitmap);
+ /* Fall through to default */
+
+ default:
+ old_head = head;
+ head = head->next;
+ free((char *) old_head);
+ break;
+ }
+ }
+}