/* 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 */