/* gcc -std=gnu89 */
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#define nl '\n'
char **_argv;
int _argc;
static FILE *_in[3];
static FILE *_out[3];
static int _init = 0;
static int _instream = 0;
static int _outstream = 0;
void _initstreams(void) {
if (_init != 1) return;
if (_argc != 4) {
fprintf(stderr, "syntax: %s infile secfile outfile\n", _argv[0]);
exit(1);
}
_in[0] = stdin;
_in[1] = fopen(_argv[1], "r");
_in[2] = fopen(_argv[2], "r");
_out[0] = stderr;
_out[1] = fopen(_argv[3], "w");
_out[2] = stdout;
_instream = 0; _outstream = 0;
}
void selectinput(int channel)
{
if (_init == 0) {
_init = 1;
_initstreams();
_init = 2;
}
if ((channel >= 0) && (channel < 3)) {
_instream = channel;
} else {
/* Error? */
fprintf(stderr, "selectinput(%d) \?\?\?\n", channel);
exit(1);
}
}
void selectoutput(int channel)
{
if (_init == 0) {
_init = 1;
_initstreams();
_init = 2;
}
if ((channel >= 0) && (channel < 3)) {
_outstream = channel;
} else {
/* Error? */
fprintf(stderr, "selectoutput(%d) \?\?\?\n", channel);
exit(1);
}
}
/* This version of ECCE, derived from a paper copy believed to */
/* date from 1975, removes PDP9/15 machine code, and other */
/* IMP9/15 system dependencies, and I'm hopeful that as a result */
/* it might well work if compiled with a generic Imp compiler. */
/* RWT Feb 2002 */
int main(int argc, char **argv) { /* edit15: ecce for pdp9/15 */
static int in = 1; /* current input stream */
#define min 1 /* main input stream */
#define mout 1 /* main output stream */
#define sin 2 /* secondary input stream */
#define sextra 122 /* extra buff for sin */
#define size 30000 /* of edit buffer (bytes) */
static int mon=0; /* monitor indic */
static int print1=0,print2=0; /* print indicators */
#define stop (-5000) /* loop stop (const) */
int i,j,k,pp1,sym;
int code; /* command code letter */
int text; /* text pointer */
int num; /* repetition number */
int *mainfp; /* == fp or mfp (for sin) */
#define cbase 1
#define tbase 120
static int *c; /* command -> <- text */
/* each command unit -- letter, parenthesis or comma -- is */
/* represented by a trio: code(+lim) text num */
/* in the case of parentheses and commas 'text' is a pointer */
/* to another command unit (not to a text string) */
int ci; /* command index (ad) */
int ti; /* text index (ad) */
static int cmax=0; /* command max (ad) */
int *stored;
/* defs of x,y,z */
static int pos1=0, pos2=0, pos3=0;
char *byte;
int top = 2; /* top of buff (index) */
int bot = size-sextra; /* bottom of buff (index) */
int lbeg; /* line start (index) */
int pp; /* previous pointer (index) */
static int fp=0; /* file pointer (index) */
int lend; /* line end (index) */
static int fend; /* end of file in buff (index)*/
static int ms=0; /* match start (index) */
static int ml=0; /* match limit (index) */
/* significance of file pointers: */
/* [nl] o n e nl t w . . . o nl n e x t nl . . nl l a s t nl [nl] */
/* ! ! ! ! ! ! */
/* t l p f l f */
/* o b p p e e */
/* p e n n */
/* g d d */
int type,chain; /* command input vars */
static int pend=0; /* ditto */
static void *t[12+1] = {
&&T0, &&T1, &&T2, &&T3, &&T4, &&T5, &&T6, NULL, &&T8, &&T9, &&T10, &&T11,
&&T12
}; /* http://gcc.gnu.org/onlinedocs/gcc-3.0.3/gcc_5.html#SEC70 */
static void *s['\\'+1] = {
/* 'A': */
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, &&S66, NULL, &&S68, &&S69, &&S70, &&S71,
NULL, &&S73, &&S74, &&S75, &&S76, &&S77, NULL, &&S79,
&&S80, NULL, &&S82, &&S83, &&S84, &&S85, &&S86, &&S87,
&&S88, &&S89, &&S90, NULL, &&S92
}; /* http://gcc.gnu.org/onlinedocs/gcc-3.0.3/gcc_5.html#SEC70 */
#ifdef NEVER
%on %event 9 %start /* needs manual rewrite using signal */
goto eof;
%finish
#endif
void loadpp(int k) { /* !!also increments pp */
byte[pp] = k; pp = pp+1;
}
void loadfp(int k) {
byte[fp] = k;
}
void leftstar(void) {
for (;;) {
if (pp == lbeg) return;
fp = fp-1; pp = pp-1;
loadfp(byte[pp]);
}
}
void rightstar(void) {
for (;;) {
if (fp == lend) return;
loadpp(byte[fp]);
fp = fp+1;
}
}
static int symtype[95+1] = {
/* 33: */ /* needs fixing */
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,
64, 3, 3, 3, 2, 3, 3,11, 9,64, 3,12, 2, 3, 3,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 3, 3, 3,64,
3, 2,10,18, 5, 8,52,10, 2, 6,10,10,10,56, 2, 2,
10,50,10,22, 5, 5, 6, 2,32,32,32, 3,10, 3, 3, 3
};
/* ! " # $ % & ' ( ) * + , - . / */
/* 0 1 2 3 4 5 6 7 8 9 : < = > ? */
/* @ A B C D E F G H I J K L M N O */
/* P Q R S T U V W X Y Z [ \ ] ^ _ */
void readsym(void) {
if (pend != 0) {sym=pend; pend=0; } else {
while (pos3 != 0) {
sym = stored[pos3]; pos3 = pos3+1;
if (!(sym = nl)) return;
pos3 = pos2; pos2 = pos1; pos1 = 0;
}
sym = fgetc(_in[_instream]);
}
}
void readitem(void) {
type = 1;
for (;;) {
do { readsym(); } while (!(sym != ' '));
if (sym < 32) return; /* nl */
if (sym >= 96) sym = sym-32; /* ensure upper case */
type = symtype[sym];
if (!((type&15) == 0)) return;
if (!(type==32)) break;
pos1 = pos2; pos2 = pos3;
pos3 = ((sym-'X')<<6)+1;
}
if (type == 0) {
num = sym-'0';
for (;;) {
pend = fgetc(_in[_instream]);
if (!(('0' <= pend) && (pend <= '9'))) break;
num = (((num<<2)+num)<<1)-'0'+pend;
}
} else {
type = 0;
num = 0; if (sym == '*') return;
num = stop+1; if (sym == '?') return;
num = stop; /* '!' */
}
}
void unchain(void) {
do {
text = chain; if (text == 0) return;
chain = c[text+1]; c[text+1] = ci;
} while (!(c[text] == 'X'));
}
void stack(int v) {
c[ci] = v; ci = ci+1;
}
void makespace(void) {
int k,p1,p2;
if ((*mainfp)-pp-240 > 0) return;
selectoutput(mout);
p1 = top; p2 = (p1+lbeg)>>1; /* ouptut about half */
if (code == 'C') p2 = lbeg; /* but all if closing */
assert (!(p2 == top)); /* !!logical error */
do {
k = byte[p1]; fputc(k, _out[_outstream]); p1 = p1+1;
} while (!((k == nl) && ((p1-p2) >= 0)));
selectoutput(0);
lbeg = top+lbeg-p1; p2 = pp; pp = top;
for (;;) {
if (p1 == p2) return;
loadpp(byte[p1]); p1 = p1+1;
}
}
void readline(void) {
int k;
#ifdef NEVER
%on %event 9 %start
goto eof;
%finish
#endif
if (fp != fend) {
lend = fp;
while (byte[lend] != nl) lend = lend+1;
return;
}
ms = 0; print1 = 0; print2 = 0;
selectinput(in);
fp = bot-sextra+1;
do {
if (fp != bot) k = fgetc(_in[_instream]); else k = nl;
if (k<0) goto eof;
loadfp(k); fp = fp+1;
} while (!(k == nl));
fend = fp; lend = fend-1;
fp = bot-sextra+1;
selectinput(0);
return;
eof:fp = bot; lend = fp; fend = lend;
loadfp(nl);
selectinput(0);
}
void switchinputs(void) {
static int mfp,mlend,mend,sfp,send;
if (in == min) {
leftstar();
in = sin;
mfp = fp; mlend = lend; mend = fend;
mainfp = &mfp;
bot = bot+sextra; fp = sfp; fend = send;
readline();
} else {
pp = lbeg;
in = min;
bot = bot-sextra; sfp = fp; send = fend;
fp = mfp; lend = mlend; fend = mend;
mainfp = &fp;
}
}
void printline(void) {
int p;
print1 = lend; print2 = fp+pp;
p = lbeg;
for (;;) {
if (p == pp) {
if ((p != lbeg) && (num == 0)) fputc('^', _out[_outstream]);
p = fp;
}
if (p == lend) break;
fputc(byte[p], _out[_outstream]);
p = p+1;
}
if (p == fend) fprintf(_out[_outstream], "%s", "**END**");
fputc(nl, _out[_outstream]);
}
int matched(void) {
int i,j,k,l,t1,fp1,lim;
lim = (c[ci-3])&(~127); t1 = c[text];
L1: pp1 = pp; fp1 = fp;
if (!((fp == ms) && ((code=='F') || (code=='U')))) goto L3;
k = byte[fp];
L2: loadpp(k); fp = fp+1;
L3: if (fp == lend) goto L10;
k = byte[fp];
if (!(k == t1)) goto L2;
i = fp; j = text;
L6: i = i+1; j = j-1;
l = c[j];
if (byte[i] == l) goto L6;
if (l != 0) goto L2;
ms = fp; ml = i;
return 1;
L10:lim = lim-128;
if ((lim != 0) && (fp != fend)) {
if (code != 'U') {
loadpp(nl); lbeg = pp;
} else pp = pp1;
fp = fp+1; makespace(); readline();
goto L1;
}
pp = pp1; fp = fp1;
return 0;
}
/* GENERATED SECTION */
_argv = argv; _argc = argc;
selectinput(0); selectoutput(0);
/* adjust base of array: */
c = (int *)malloc(sizeof(int) * (tbase-cbase+1)); c = c - cbase;
/* command -> <- text */
stored = (int *)malloc(sizeof(int) * (192-1+1)); stored = stored - 1;
byte = (char *)malloc(sizeof(char) * (size-1+1)); byte = byte - 1;
/* END OF GENERATED SECTION */
/* initialise */
pp = top-1; loadpp(nl); /* for bouncing off */
lbeg = pp; mainfp = &fp;
stored[1] = nl; stored[65] = nl; stored[129] = nl;
selectoutput(0); fprintf(_out[_outstream], "%s", "EDIT\n");
readline();
/* read command line */
L1: fprintf(stderr, "%s", ">");fflush(stderr);
readitem(); if (sym<0) goto eof; if (type == 1) goto L1;
ci = cbase; ti = tbase; chain = 0;
if ((type == 0) && (cmax != 0)) {
c[cmax+2] = num;
readitem(); if (type != 1) goto er2;
goto go;
}
if (sym == '%') {
readsym(); if (sym >= 96) sym = sym-32;
code = sym; if (code<=32) goto er5;
readitem();
goto *t[(symtype[code])>>4];
}
L2: i = type&15; if (i < 4) goto er2;
code = sym; text = 0; num = 1; /* default values */
readitem();
goto *t[i];
T2: /* %x, %y, %z */
if (sym != '=') goto er1;
i = (code-'X')<<6;
for (;;) {
readsym();
i = i+1; stored[i] = sym;
if (sym == nl) goto L1;
}
T3: /* %m, %f, %q */
mon = 'M'-code;
goto L1;
T4: /* find */
if (!(type == 0)) num = 0;
T5: /* +del,trav,uncover */
code = (num<<7)+code; num = 1;
if (type == 0) readitem();
T6: /* +insert,subst,verify */
if (type != 3) goto er4;
text = ti; i = sym;
L61:readsym();
if (sym != nl) {
if (sym != i) {
if (ti <= ci) goto er6;
c[ti] = sym; ti = ti-1;
goto L61;
}
} else {
pend = sym;
if (!((code == 'S') || (code == 'I'))) goto er4;
}
if ((ti == text) && (code != 'S')) goto er4;
c[ti] = 0; ti = ti-1;
goto L81;
T8: /* move,erase */
if (!(sym == '-')) goto L100;
code = code+10;
L81:readitem();
goto L101;
T9: /* close bracket */
unchain(); if (text == 0) goto er3;
code = 'Z'; c[text+2] = num;
text = text+3;
T10: /* +get,kill,etc. */
L100:if (type == 3) goto er1;
L101:if (type == 0) readitem();
goto put;
T11: /* open bracket */
code = 'X';
goto L121;
T12: /* comma */
code = 'Y';
if (type == 1) readitem();
L121:text = chain; chain = ci;
num = 0;
put:stack(code); stack(text); stack(num);
if (ci+4 >= ti) goto er6;
if (!(type == 1)) goto L2;
unchain(); if (text != 0) goto er3;
cmax = ci;
stack('Z'); stack(cbase); stack(1); /* extra close b */
stack(0);
goto go;
/* command input error reports */
er1:fputc(' ', _out[_outstream]); fputc(code, _out[_outstream]);
er2:code = sym;
goto er5;
er3:fprintf(_out[_outstream], "%s", " ()");
goto er7;
er4:fprintf(_out[_outstream], "%s", " TEXT FOR");
T0:
er5:fputc(' ', _out[_outstream]); fputc(code&127, _out[_outstream]);
goto er7;
er6:fprintf(_out[_outstream], "%s", " SIZE");
er7:fputc('?', _out[_outstream]);
fputc(nl, _out[_outstream]); if (ci != cbase) cmax = 0;
L10:if (sym<32) goto L1;
readsym();
goto L10;
/* execute command line */
go: ci = cbase;
get:code = (c[ci])&127; if (code == 0) goto L99;
text = c[ci+1];
num = c[ci+2];
ci = ci+3;
rep:num = num-1;
goto *s[code];
ok: if (!((num == 0) || (num == stop))) goto rep;
goto get;
S92: /* '\' */ /* invert */
no: if (num < 0) goto get;
if (c[ci] == '\\') {ci = ci+3; goto get;};
skp:i = c[ci]; if (i == 'X') ci = c[ci+1];
ci = ci+3;
if (i > 'X') {num = c[ci-1]-1; goto no;};
if (i != 0) goto skp;
/* execution error report */
fprintf(_out[_outstream], "%s", "FAILURE: ");
if ((code=='O') || (code=='W')) {
fputc(code-10, _out[_outstream]); code = '-';
}
fputc(code, _out[_outstream]);
if (text != 0) {
fputc('\'', _out[_outstream]);
while (c[text] != 0) {
fputc(c[text], _out[_outstream]);
text = text-1;
}
fputc('\'', _out[_outstream]);
}
fputc(nl, _out[_outstream]);
print1 = 0;
/* end of command line */
L99:if (sym != nl) goto L1;
if (!(((mon>=0) && (print1!=lend)) || ((mon>0) && (print2!=(fp+pp))))) goto L1;
num = 0; printline();
goto L1;
/* individual commands */
S88: /* 'X' */ /* open bracket */
c[text+2] = num+1;
goto get;
S90: /* 'Z' */ /* close bracket */
if ((num == 0) || (num == stop)) goto get;
c[ci-1] = num;
S89: /* 'Y' */ /* +comma */
ci = text;
goto get;
S82: /* 'R' */ /* right shift */
if (fp == lend) goto no;
loadpp(byte[fp]); fp = fp+1;
goto ok;
S76: /* 'L' */ /* left shift */
if ((in == sin) || (pp == lbeg)) goto no;
fp = fp-1; pp = pp-1; loadfp(byte[pp]);
ms = 0;
goto ok;
S69: /* 'E' */ /* erase */
if (fp == lend) goto no;
fp = fp+1;
goto ok;
S79: /* 'O' */ /* erase back */
if (pp == lbeg) goto no;
pp = pp-1;
goto ok;
S86: /* 'V' */ /* verify */
i = fp-1; j = text+1;
v1: i = i+1; j = j-1;
k = c[j];
if (byte[i] == k) goto v1;
if (k != 0) goto no;
ms = fp; ml = i;
goto ok;
S70: /* 'F' */ /* find */
if (matched() == 0) goto no;
goto ok;
S85: /* 'U' */ /* uncover */
if (matched() == 0) goto no; pp = pp1;
goto ok;
S68: /* 'D' */ /* delete */
if (matched() == 0) goto no; fp = ml;
goto ok;
S84: /* 'T' */ /* traverse */
if (matched() == 0) goto no;
S83: /* 'S' */ /* +substitute */
if (fp == ms) fp = ml;
S73: /* 'I' */ /* +insert */
makespace();
/* if ((pp-lbeg+lend-fp) > 80) goto no; */
i = text;
i1: if (c[i] == 0) goto ok;
loadpp(c[i]); i = i-1;
goto i1;
S71: /* 'G' */ /* get (line from tt) */
fprintf(stderr, "%s", ":");fflush(stderr);
/* makespace(); */
i = fgetc(_in[_instream]);
if (i == ':') goto no;
leftstar();
while (i != nl) {
loadpp(i);
i = fgetc(_in[_instream]);
}
S66: /* 'B' */ /* +break (insert newline) */
makespace();
loadpp(nl); lbeg = pp;
goto ok;
S80: /* 'P' */ /* print */
printline();
if (num == 0) goto get;
S77: /* 'M' */ /* +move */
rightstar();
if (fp == fend) goto no;
loadpp(nl); lbeg = pp;
m1: fp = fp+1; makespace(); readline();
goto ok;
S75: /* 'K' */ /* kill (line) */
pp = lbeg; fp = lend;
k1: if (fp == fend) goto no;
goto m1;
S74: /* 'J' */ /* join (delete newline) */
rightstar();
/* if (pp-lbeg > 80) goto no; */
goto k1;
S87: /* 'W' */ /* move back */
if (in == sin) goto no;
makespace();
if (lbeg == top) goto no;
lend = fp-pp+lbeg-1;
w1: k = byte[pp-1];
if ((k == nl) && (pp != lbeg)) goto w2;
fp = fp-1; pp = pp-1; loadfp(k);
goto w1;
w2: lbeg = pp; ms = 0;
goto ok;
T1: /* %s, %c */
if (code == 'C') goto eof;
switchinputs();
goto L99;
eof:code = 'C'; /* +eof on command stream */
if (in == sin) switchinputs();
for (;;) {
rightstar();
if (fp == fend) break;
loadpp(nl); lbeg = pp;
fp = fp+1; makespace(); readline();
}
selectoutput(mout);
while (top != pp) {
fputc(byte[top], _out[_outstream]); top = top+1;
}
/* GENERATED SECTION */
selectinput(0); selectoutput(0);
c = c + cbase; /* command -> <- text */
stored = stored + 1;
byte = byte + 1;
free(c); free(stored); free(byte);
exit(0);
/* END OF GENERATED SECTION */