Adopt a copy of Minix 2's ed; this allows the ACK's antiquated ed scripts to
authorDavid Given <dg@cowlark.com>
Sat, 2 Jun 2018 16:02:51 +0000 (18:02 +0200)
committerDavid Given <dg@cowlark.com>
Sat, 2 Jun 2018 16:02:51 +0000 (18:02 +0200)
run with a minimum of tweaking. Rewriting them for modern ed looks really hard.

Fixes: #84

16 files changed:
lang/basic/src/build.lua
lang/basic/src/maketokentab
mach/proto/fp/FP.script
mach/proto/fp/build.lua
modules/src/em_code/build.lua
modules/src/em_code/make.em.gen
modules/src/em_data/build.lua
modules/src/em_data/new_table
modules/src/read_em/argtype
modules/src/read_em/build.lua
modules/src/read_em/m_C_mnem
modules/src/read_em/m_C_mnem_na
util/cmisc/build.lua
util/cmisc/ed.c [new file with mode: 0644]
util/ncgg/build.lua
util/ncgg/cvtkeywords

index eff53d6..26e3074 100644 (file)
@@ -9,6 +9,7 @@ normalrule {
        name = "tokentab_h",
        ins = {
                "./maketokentab",
+               "util/cmisc+ed",
                matching(filenamesof("+llgen"), "/Lpars.h$"),
        },
        outleaves = { "tokentab.h" },
index 777eb14..c388c5d 100755 (executable)
@@ -1,6 +1,6 @@
 #!/bin/sh
 
-ed -s "${1:-Lpars.h}" > $2 <<'+'
+$1 -s "${2:-Lpars.h}" > $3 <<'+'
 1d
 1,$s/# *define //
 1,$s/ ...$//
@@ -14,5 +14,4 @@ $a
 };
 .
 1,$p
-q
 +
index 22bda6b..a8f1298 100644 (file)
@@ -38,4 +38,3 @@ g/_b64_sft/s//.b64_sft/g
 g/_b64_rsft/s//.b64_rsft/g
 g/_b64_lsft/s//.b64_lsft/g
 1,$p
-q
index 62d0d81..3dd62d5 100644 (file)
@@ -29,11 +29,12 @@ for _, plat in ipairs({"cpm"}) do
                        name = "ed_"..plat.."/"..n,
                        ins = {
                                "./FP.script",
+                               "util/cmisc+ed",
                                assembly,
                        },
                        outleaves = { n..".s" },
                        commands = {
-                               "ed -s %{ins[2]} <%{ins[1]} >%{outs}"
+                               "%{ins[2]} -s %{ins[3]} <%{ins[1]} >%{outs}"
                        }
                }
        end
index a1316df..3a82234 100644 (file)
@@ -2,13 +2,14 @@ normalrule {
        name = "em_code_ek_h",
        ins = {
                "./make.em.gen",
+               "util/cmisc+ed",
                "./em.nogen",
                "h/em_table"
        },
        outleaves = { "em_codeEK.h" },
        commands = {
-               "%{ins[1]} %{ins[3]} > %{outs}",
-               "cat %{ins[2]} >> %{outs}"
+               "%{ins[1]} %{ins[2]} %{ins[4]} > %{outs}",
+               "cat %{ins[3]} >> %{outs}"
        }
 }
 
index 57553f8..d37d456 100755 (executable)
@@ -1,6 +1,6 @@
 #!/bin/sh
-echo "/* this part is generated from $1 at: " `date` "*/"
-ed -s $1 <<'EOI' 
+echo "/* this part is generated from $2 at: " `date` "*/"
+$1 -s $2 <<'EOI' 
 1,/^$/d
 1,/^$/d
 1,$s/^\(...\)  \(.\).*/\1:\2/
index 2031220..d70369d 100644 (file)
@@ -2,6 +2,7 @@ local generated = normalrule {
        name = "generated",
        ins = {
                "./new_table",
+               "util/cmisc+ed",
                "h/em_table", -- relative to root, which is a bit evil
        },
        outleaves = {
@@ -16,7 +17,7 @@ local generated = normalrule {
                "h+emheaders"
        },
        commands = {
-               "%{ins[1]} %{ins[2]} %{dir} %{dir}"
+               "%{ins[1]} %{ins[2]} %{ins[3]} %{dir} %{dir}"
        }
 }
 
index c94958c..70d6539 100755 (executable)
@@ -1,25 +1,26 @@
 #!/bin/sh
 set -e
 
-em_table=$1
-h=${2-.}
-d=${3-.}
+ed=$1
+em_table=$2
+h=${3-.}
+d=${4-.}
 
 set `grep fpseu $em_table`
 p=$2
 set `grep fmnem $em_table`
 m=$2
 
-ed - $em_table <<'A' > X
+$ed - $em_table <<'A' > X
 1,/^$/g/       /s// /gp
 A
 
-ed - $em_table <<'A' | awk '{$2=$2+'$p'; print}' > Y
+$ed - $em_table <<'A' | awk '{$2=$2+'$p'; print}' > Y
 1,/^$/d
 1,/^$/g/       /s// /gp
 A
 
-ed - $em_table <<'A' | awk '{print $0,'$m'+i++}' > Z
+$ed - $em_table <<'A' | awk '{print $0,'$m'+i++}' > Z
 1,/^$/d
 1,/^$/d
 1,/^$/g/       /s// /gp
@@ -30,23 +31,23 @@ echo 'lpseu' `expr $i + $p - 1` >>X
 i=`wc -l <Z`
 echo 'lmnem' `expr $i + $m - 1` >>X
 
-ed - X <<'A' > $h/em_spec.h
+$ed - X <<'A' > $h/em_spec.h
 g/^/s//#define sp_/p
 A
 
-ed - Y <<'A' > $h/em_pseu.h
+$ed - Y <<'A' > $h/em_pseu.h
 g/ \(.*\) .*/s// \1/
 g/\(.*\) \(.*\)/s//#define ps_\1 \2/p
 A
 
-ed - Z <<'A' > $h/em_mnem.h
+$ed - Z <<'A' > $h/em_mnem.h
 g/ .* /s// /
 g/\(.*\) \(.*\)/s//#define op_\1 \2/p
 A
 
 (
 echo 'char em_pseu[][4] = {'
-ed - Y <<'A'
+$ed - Y <<'A'
 g/\(...\).*/s//        "\1",/p
 A
 echo '};'
@@ -54,7 +55,7 @@ echo '};'
 
 (
 echo 'char em_mnem[][4] = {'
-ed - Z <<'A'
+$ed - Z <<'A'
 g/\(...\).*/s//        "\1",/p
 A
 echo '};'
@@ -63,7 +64,7 @@ echo '};'
 (
 echo '#include <em_flag.h>
 char em_flag[] = {'
-ed - Z <<'A' | tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ
+$ed - Z <<'A' | tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ
 g/^... /s///
 g/ .*/s///
 g/\(.\)\(.\)/s//PAR_\1 | FLO_\2/
index 57072fd..8d77b9b 100755 (executable)
@@ -8,7 +8,7 @@ case x$# in
                exit 1
                ;;
 esac
-ed -s $2 << A
+$ED -s $2 << A
 1,/^\$/d
 1,/^\$/d
 1,/^\$/g/^\(...\)      [$1].*/s//\\1/gp
index 86794b0..c1c3c25 100644 (file)
@@ -2,6 +2,7 @@ normalrule {
        name = "c_mnem_narg_h",
        ins = {
                "./m_C_mnem_na",
+               "util/cmisc+ed",
                "h/em_table",
                "./argtype"
        },
@@ -15,6 +16,7 @@ normalrule {
        name = "c_mnem_h",
        ins = {
                "./m_C_mnem",
+               "util/cmisc+ed",
                "h/em_table",
                "./argtype"
        },
index 67b6056..c7bbab2 100755 (executable)
@@ -1,7 +1,8 @@
 #!/bin/sh
 
-EM_TABLE=$1
-ARGTYPE=$2
+export ED=$1
+EM_TABLE=$2
+ARGTYPE=$3
 echo "switch(p->em_opcode) {"
 for i in - cdflnorswz p b
 do
index 07e80da..7b663cb 100755 (executable)
@@ -1,5 +1,7 @@
-EM_TABLE=$1
-ARGTYPE=$2
+#!/bin/sh
+export ED=$1
+EM_TABLE=$2
+ARGTYPE=$3
 list=`$ARGTYPE w $EM_TABLE`
 echo "switch(p->em_opcode) {"
 for i in $list
index 8bd0012..dec4662 100644 (file)
@@ -23,3 +23,9 @@ definerule("tabgen",
                }
        end
 )
+
+cprogram {
+       name = "ed",
+       srcs = { "./ed.c" }
+}
+
diff --git a/util/cmisc/ed.c b/util/cmisc/ed.c
new file mode 100644 (file)
index 0000000..e934be5
--- /dev/null
@@ -0,0 +1,2199 @@
+/* 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;
+       }
+  }
+}
index 20846f0..9441e9f 100644 (file)
@@ -14,12 +14,13 @@ normalrule {
        name = "keywords",
        ins = {
                "./cvtkeywords",
+               "util/cmisc+ed",
                "./keywords",
                matching(filenamesof(cggparser), "%.h$")
        },
        outleaves = { "enterkeyw.c" },
        commands = {
-               "%{ins[1]} %{ins[2]} %{ins[3]} %{outs[1]}"
+               "%{ins[1]} %{ins[2]} %{ins[3]} %{ins[4]} %{outs[1]}"
        }
 }
 
index a478b3f..54682d6 100755 (executable)
@@ -1,8 +1,8 @@
 #!/bin/sh
 : '$Id$'
 
-grep '^#' $2 >tokendefs
-ed -s $1 > $3 <<'!Funky!Stuff!'
+grep '^#' $3 >tokendefs
+$1 -s $2 > $4 <<'!Funky!Stuff!'
 g/^#/d
 1,$s/\([^      ]*\)[   ][      ]*\(.*\)/       sy_p=lookup("\1",symkeyw,newsymbol);sy_p->sy_value.syv_keywno=\2;/
 1i
@@ -18,8 +18,7 @@ enterkeyw() {
 $a
 }
 .
-,p
-q
+1,$p
 !Funky!Stuff!
 rm tokendefs