From 05ddefad65531700058ef1e790249b7233fbeace Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 2 Jun 2018 18:02:51 +0200 Subject: [PATCH] Adopt a copy of Minix 2's ed; this allows the ACK's antiquated ed scripts to run with a minimum of tweaking. Rewriting them for modern ed looks really hard. Fixes: #84 --- lang/basic/src/build.lua | 1 + lang/basic/src/maketokentab | 3 +- mach/proto/fp/FP.script | 1 - mach/proto/fp/build.lua | 3 +- modules/src/em_code/build.lua | 5 +- modules/src/em_code/make.em.gen | 4 +- modules/src/em_data/build.lua | 3 +- modules/src/em_data/new_table | 25 +- modules/src/read_em/argtype | 2 +- modules/src/read_em/build.lua | 2 + modules/src/read_em/m_C_mnem | 5 +- modules/src/read_em/m_C_mnem_na | 6 +- util/cmisc/build.lua | 6 + util/cmisc/ed.c | 2199 +++++++++++++++++++++++++++++++ util/ncgg/build.lua | 3 +- util/ncgg/cvtkeywords | 7 +- 16 files changed, 2244 insertions(+), 31 deletions(-) create mode 100644 util/cmisc/ed.c diff --git a/lang/basic/src/build.lua b/lang/basic/src/build.lua index eff53d6e9..26e3074de 100644 --- a/lang/basic/src/build.lua +++ b/lang/basic/src/build.lua @@ -9,6 +9,7 @@ normalrule { name = "tokentab_h", ins = { "./maketokentab", + "util/cmisc+ed", matching(filenamesof("+llgen"), "/Lpars.h$"), }, outleaves = { "tokentab.h" }, diff --git a/lang/basic/src/maketokentab b/lang/basic/src/maketokentab index 777eb1402..c388c5d99 100755 --- a/lang/basic/src/maketokentab +++ b/lang/basic/src/maketokentab @@ -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 + diff --git a/mach/proto/fp/FP.script b/mach/proto/fp/FP.script index 22bda6b90..a8f12982a 100644 --- a/mach/proto/fp/FP.script +++ b/mach/proto/fp/FP.script @@ -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 diff --git a/mach/proto/fp/build.lua b/mach/proto/fp/build.lua index 62d0d8114..3dd62d56d 100644 --- a/mach/proto/fp/build.lua +++ b/mach/proto/fp/build.lua @@ -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 diff --git a/modules/src/em_code/build.lua b/modules/src/em_code/build.lua index a1316df2f..3a82234cb 100644 --- a/modules/src/em_code/build.lua +++ b/modules/src/em_code/build.lua @@ -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}" } } diff --git a/modules/src/em_code/make.em.gen b/modules/src/em_code/make.em.gen index 57553f841..d37d45638 100755 --- a/modules/src/em_code/make.em.gen +++ b/modules/src/em_code/make.em.gen @@ -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/ diff --git a/modules/src/em_data/build.lua b/modules/src/em_data/build.lua index 20312201d..d70369d06 100644 --- a/modules/src/em_data/build.lua +++ b/modules/src/em_data/build.lua @@ -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}" } } diff --git a/modules/src/em_data/new_table b/modules/src/em_data/new_table index c94958c8c..70d653989 100755 --- a/modules/src/em_data/new_table +++ b/modules/src/em_data/new_table @@ -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 >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 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/ diff --git a/modules/src/read_em/argtype b/modules/src/read_em/argtype index 57072fd50..8d77b9bb3 100755 --- a/modules/src/read_em/argtype +++ b/modules/src/read_em/argtype @@ -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 diff --git a/modules/src/read_em/build.lua b/modules/src/read_em/build.lua index 86794b036..c1c3c257a 100644 --- a/modules/src/read_em/build.lua +++ b/modules/src/read_em/build.lua @@ -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" }, diff --git a/modules/src/read_em/m_C_mnem b/modules/src/read_em/m_C_mnem index 67b6056b5..c7bbab2d3 100755 --- a/modules/src/read_em/m_C_mnem +++ b/modules/src/read_em/m_C_mnem @@ -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 diff --git a/modules/src/read_em/m_C_mnem_na b/modules/src/read_em/m_C_mnem_na index 07e80daad..7b663cb62 100755 --- a/modules/src/read_em/m_C_mnem_na +++ b/modules/src/read_em/m_C_mnem_na @@ -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 diff --git a/util/cmisc/build.lua b/util/cmisc/build.lua index 8bd0012f6..dec466279 100644 --- a/util/cmisc/build.lua +++ b/util/cmisc/build.lua @@ -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 index 000000000..e934be584 --- /dev/null +++ b/util/cmisc/ed.c @@ -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 +#include +#include +#include +#include +#include +#include + +/****************************/ + +/* 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='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 */ +/* #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 */ +/* #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 */ +#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 */ +/* #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 */ +/* #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 */ +/* #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 */ +/* #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 */ +/* #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 */ +/* #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 */ +/* #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 */ +/* #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 */ +/* #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 */ +/* #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 */ +/* #include */ +/* #include "tools.h" */ +/* #include "ed.h" */ +#include +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 */ +/* #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 */ +/* #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 */ +/* #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 */ +/* #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 */ +/* #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 */ +/* #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 */ +/* #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 */ +/* #include "tools.h" */ + +/* Translate arg into a TOKEN string */ +TOKEN * + getpat(arg) +char *arg; +{ + + return(makepat(arg, '\000')); +} + +/* getptr.c */ +/* #include */ +/* #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 */ +/* #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 */ +/* #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 */ +/* #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 */ +/* #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 */ +/* #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 */ +/* #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 */ +/* #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 */ +/* #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 */ +/* #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 */ +/* #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 */ +/* #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 */ +/* #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 */ +/* #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 */ +/* #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; + } + } +} diff --git a/util/ncgg/build.lua b/util/ncgg/build.lua index 20846f02d..9441e9f74 100644 --- a/util/ncgg/build.lua +++ b/util/ncgg/build.lua @@ -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]}" } } diff --git a/util/ncgg/cvtkeywords b/util/ncgg/cvtkeywords index a478b3f1a..54682d600 100755 --- a/util/ncgg/cvtkeywords +++ b/util/ncgg/cvtkeywords @@ -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