///////////////////////////////////////////////////////////////////////
// //
// Title: Edinburgh Compatible Context Editor //
// Author: H.Whitfield //
// Date: 17 November 1985, last modified 29 July 1996 //
// Copyright (c) H.Whitfield 1985-1996 //
// //
///////////////////////////////////////////////////////////////////////
#include <iostream.h>
#include <fstream.h>
#include <stdlib.h>
typedef char * PtrChar;
typedef PtrChar * PtrPtrChar;
typedef int boolean;
typedef char string[256];
const string version = "Ecce editor v3.3";
const int amax = 16384; // size of internal text buffer
const int argmax = 64;
const int cmax = 121;
const int stop = -5000;
const int inv = -5001;
const int lmax = 2048; // maximum line length
const int firstcol = 1;
const int lastcol = 160;
const int linelength = 160;
const int parslength = 20;
const int tbase = 1;
const char nl = char(10); // Unix eol
const char cr = char(13); // Macintosh eol
const char tab = char(9); // Ascii tab
int top, pe, pp, fp, bottom, pp1, ms, ml, lim, p, ci, ti, txt, clim;
int num, codelim, matchlim, arg, mon, itype, chain;
char code, last, term, ch, sym, quote;
boolean printed, okok, done, failed, detab, again, errorFlag;
char a[amax+1];
int c[cmax+1];
void halt (const string s); // prototypes
void writestring(const string s);
void writeln();
///////////////////////////////////////////////////////////////////////
// //
// I/O Interface Functions File I/O //
// //
///////////////////////////////////////////////////////////////////////
ifstream inFile;
ofstream outFile;
char inFileBuffer; // one char look-ahead buffer
boolean inFileEmpty = true;
void openFiles(const PtrPtrChar av)
{
inFile.open(av[1], ios::in);
if ( ! inFile )
{
halt("Open inFile failed");
}
outFile.open(av[2],ios::out);
if ( ! outFile )
{
halt("Open outFile failed");
}
}
boolean eofInFile()
{
if ( inFileEmpty ) // if look-ahead buffer empty
{
return inFile.eof(); // return the real eof
}
return false; // else return false
}
char nextInFile() // does not move past char
{
if ( inFileEmpty ) // if look-ahead buffer empty
{ // try to get the next char
if ( inFile.eof() )
{
halt("Eof encountered on input file.");
}
else
{
inFile.get( inFileBuffer );
inFileEmpty = false; // look-ahead buffer now full
}
}
return inFileBuffer;
}
void readInFile(char& c) // gets and moves past char
{
c = nextInFile(); // get the next char
inFileEmpty = true; // empty the look-ahead buffer
}
void putOutFile(char c) // puts one char on output file
{
outFile << c;
}
void closeFiles() // closes output file
{
outFile.close();
}
///////////////////////////////////////////////////////////////////////
// //
// I/O Interface Functions Program Control //
// //
///////////////////////////////////////////////////////////////////////
void halt (const string s)
{
writestring(s);
writeln();
closeFiles();
exit(0); // stop the program
}
///////////////////////////////////////////////////////////////////////
// //
// I/O Interface Functions Keyboard/Screen //
// //
///////////////////////////////////////////////////////////////////////
void write(const char c)
{
cout << c;
}
void writeln()
{
cout << endl;
}
void writestring(const string s)
{
cout << s;
}
char inputBuffer; // one char look-ahead buffer
boolean inputEmpty = true;
char lastsym, prompt; // prompt management variables
boolean prompted;
char nextsymbol() // does not move past char
{
if ( (lastsym == nl) && (! prompted) )
{
if ( prompt != ' ' )
{
write(prompt);
}
prompted = true;
}
if ( inputEmpty ) // if look-ahead buffer empty
{ // try to get the next char
if ( cin.eof() )
{
halt("Eof encountered on keyboard input.");
}
else
{
cin.get( inputBuffer );
inputEmpty = false; // look-ahead buffer now full
}
}
return inputBuffer;
}
char readsymbol() // gets and moves past char
{
lastsym = nextsymbol(); // get the next char
if ( lastsym == nl )
{
prompted = false;
}
inputEmpty = true; // empty the look-ahead buffer
return lastsym;
}
///////////////////////////////////////////////////////////////////////
// //
// Body of Ecce Editor //
// //
///////////////////////////////////////////////////////////////////////
char lower (char ch)
{
if ( ('A' <= ch) && (ch <= 'Z') )
{
return char(int(ch) - int('A') + int('a'));
}
else if ( ch == '`' )
{
return '@';
}
else if ( ch == '{' )
{
return '[';
}
else if ( ch == '|' )
{
return '\\';
}
else if ( ch == '}' )
{
return ']';
}
else if ( ch == '~' )
{
return '^';
}
else
{
return ch;
}
}
void readnum()
{
char ch, junk;
num = int(sym) - int('0');
ch = nextsymbol();
while ( ('0' <= ch) && (ch <= '9') )
{
num = 10 * num + int(ch) - int('0');
junk = readsymbol();
ch = nextsymbol();
}
}
int nextitemtype()
{
int result;
char junk;
do
{
sym = readsymbol();
} while ( ! ( sym != ' ' ) );
sym = lower(sym);
if ( sym < ' ' )
{
result = 1;
}
else
{
switch ( sym )
{
case ';':
result = 1;
break;
case '(':
result = 2;
break;
case ',':
if ( nextsymbol() == nl )
{
junk = readsymbol();
};
result = 3;
break;
case ')':
result = 4;
break;
case 'i':
case 's':
result = 5;
break;
case 'd':
result = 6;
break;
case 'f':
case 't':
case 'u':
result = 7;
break;
case 'v':
result = 8;
break;
case 'e':
case 'm':
if ( nextsymbol() == '-' )
{
junk = readsymbol();
if ( sym == 'e' )
{
sym = 'o';
}
else
{
sym = 'w';
}
};
result = 9;
break;
case 'b':
case 'g':
case 'j':
case 'k':
case 'l':
case 'p':
case 'r':
result = 9;
break;
case 'a':
case 'c':
case 'h':
case 'n':
case 'o':
case 'q':
case '-':
case 'w':
case 'x':
case 'y':
case 'z':
result = 10;
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
readnum();
result = 0;
break;
case '*':
num = 0;
result = 0;
break;
case '?':
num = stop + 1;
result = 0;
break;
case '\\':
case '^':
num = inv + 1;
result = 0;
break;
default:
// '!', '"', '#', '$', '%', '&', '''', '+', '.', '/', ':', '<', '=', '>', '@', '[', ']', '_':
result = -1;
break;
} // switch
} // else
return result;
}
void unchain()
{
boolean finished;
txt = chain;
if ( txt != 0 )
{
finished = false;
do
{
chain = c[txt];
c[txt] = ci;
if ( c[txt + 1] != int('y') )
{
txt = chain;
}
else
{
finished = true;
}
} while ( ! ( (txt == 0) || finished ) );
}
}
void stack (int v)
{
ci = ci - 1;
c[ci] = v;
}
void push()
{
stack(256 * matchlim + int(code));
stack(txt);
stack(num);
}
void procerror (int n)
{
if ( n != 6 )
{
switch ( n )
{
case 0:
write(' ');
write(code);
code = sym;
break;
case 1:
code = sym;
break;
case 2:
code = '(';
break;
case 3:
writestring(" text for");
break;
case 5:
break;
}
write(' ');
write(code);
write('?');
writeln();
}
else
{
writestring(" too long");
writeln();
};
if ( ci != cmax )
{
clim = 0;
}
while ( sym != nl )
{
sym = readsymbol();
}
errorFlag = true;
}
void qstring()
{
if ( (itype >= 0) || (txt != 0) )
{
procerror(3);
}
else
{
quote = sym;
txt = ti;
while ( (nextsymbol() != quote) && (nextsymbol() != nl) && (! errorFlag) )
{
sym = readsymbol();
if ( detab )
{
if ( sym == tab )
{
sym = ' ';
}
}
c[ti] = int(sym);
ti = ti + 1;
if ( ti == ci )
{
procerror(6);
}
}
if ( ! errorFlag )
{
if ( nextsymbol() == nl )
{
if ( (code != 'i') && (code != 's') )
{
procerror(3);
}
}
else
{
sym = readsymbol();
}
if ( ! errorFlag )
{
if ( (ti == txt) && (code != 's') )
{
procerror(3);
}
else
{
c[ti] = 0;
ti = ti + 1;
itype = nextitemtype();
if ( itype == 0 )
{
itype = nextitemtype();
}
push();
}
}
}
}
}
void readcommand()
{
int i;
done = false;
do
{
again = false;
errorFlag = false;
prompt = '>';
do
{
itype = nextitemtype();
} while ( ! ( itype != 1 ) );
ci = cmax;
ti = tbase;
chain = 0;
if ( (itype == 0) && (clim != 0) ) // repeat last command
{
c[clim] = num;
if ( nextitemtype() == 1 )
{
done = true;
}
else
{
procerror(1);
}
}
else if ( sym == '%')
{
sym = lower(readsymbol());
code = sym;
matchlim = 0;
num = 0;
txt = 0;
itype = nextitemtype();
if ( itype != 1 )
{
procerror(1);
}
else if ( code == 'c' )
{
push();
}
else if ( (code == 'q') || (code == 'm') || (code == 'f') )
{
mon = int('m') - int(code);
again = true;
switch ( code )
{
'q'case:
writestring("quiet mode");
writeln();
break;
case 'm':
writestring("normal mode");
writeln();
break;
case 'f':
writestring("full mode");
writeln();
break;
}
}
else if ( code == 't' )
{
detab = ! detab;
if ( detab )
{
writestring("detab on");
writeln();
}
else
{
writestring("detab off");
writeln();
}
}
else
{
procerror(1);
}
}
else
{
do
{
if ( itype <= 0 )
{
procerror(1);
}
else if ( ci - 4 <= ti )
{
procerror(6);
}
else
{
code = sym;
matchlim = 0;
txt = 0;
if ( code == 'f' )
{
num = 0;
}
else
{
num = 1;
}
i = itype;
itype = nextitemtype();
switch ( i )
{
case 2: // left bracket
code = 'y';
txt = chain;
chain = ci - 2;
push();
break;
case 3: // comma
num = inv;
code = 'z';
txt = chain;
chain = ci - 2;
push();
break;
case 4: // right bracket
unchain();
if ( txt == 0 )
{
procerror(5);
}
else
{
c[txt] = ci - 3;
txt = txt - 1;
c[txt] = num;
code = 'z';
if ( itype == 0 )
{
itype = nextitemtype();
}
push();
}
break;
case 5: // insert,substitute
qstring();
break;
case 6: // delete
case 7: // find,traverse,uncover
matchlim = num;
num = 1;
if ( itype == 0 )
{
itype = nextitemtype();
}
qstring();
break;
case 8: // verify
qstring();
break;
case 9:
if ( itype < 0 )
{
procerror(0);
}
else // all the others
{
if ( itype == 0 )
{
itype = nextitemtype();
}
push();
}
break;
case 10: // invalid letters
procerror(5);
break;
} // switch
} // else
} while ( ! ( (itype == 1) || errorFlag ) );
}
if ( (! done) && (! again) && (! errorFlag) )
{
unchain();
if ( txt != 0 )
{
procerror(2);
}
else
{
stack(int('z'));
stack(cmax);
stack(1);
clim = ci;
stack(0);
done = true;
}
}
} while ( ! ( done ) );
}
void makespace()
{
char k;
int p1, p2;
if ( fp - pp - 240 <= 0 )
{
p1 = top;
if ( code == 'c' )
{
p2 = pe;
}
else
{
p2 = (p1 + pe) / 2;
}
if ( p2 == top )
{
halt("Fatal error in makespace.");
}
do
{
do
{
k = a[p1];
putOutFile(k);
p1 = p1 + 1;
} while ( ! ( (k == nl) ) );
} while ( ! ( (p1 - p2 >= 0) ) );
pe = top + pe - p1;
p2 = pp;
pp = top;
while ( p1 != p2 )
{
a[pp] = a[p1];
pp = pp + 1;
p1 = p1 + 1;
}
}
}
void printline()
{
int p;
printed = true;
if ( fp == bottom )
{
writestring("**end**");
writeln();
}
else
{
if ( pe == pp )
{
p = fp;
}
else
{
p = pe;
}
if ( a[p] != nl )
{
write(a[p]);
}
else
{
writeln();
}
while ( a[p] != nl )
{
p = p + 1;
if ( (p == pp) && (num == 0) )
{
write('^');
}
if ( p == pp )
{
p = fp;
}
if ( a[p] != nl )
{
write(a[p]);
}
else
{
writeln();
}
}
}
}
void readline()
{
char k;
printed = false;
if ( fp == bottom )
{
fp = lim - lmax;
ms = 0;
if ( eofInFile() )
{
fp = lim;
bottom = fp;
a[fp] = nl;
}
else
{
do
{
readInFile(k);
if ( detab )
{
if ( k == tab )
{
k = ' ';
}
}
a[fp] = k;
fp = fp + 1;
} while ( ! ( (k == nl) || eofInFile() || (fp == lim) ) );
if ( k == nl )
{
bottom = fp;
fp = lim - lmax;
}
else if ( eofInFile() ) // unexpected eof before eoln
{
a[fp] = nl;
fp = fp + 1;
bottom = fp;
fp = lim - lmax;
}
else
{
if ( nextInFile() == nl )
{
readInFile(k);
}
a[fp] = nl;
fp = fp + 1;
bottom = fp;
fp = lim - lmax;
}
}
}
}
void lefttab()
{
while ( pp != pe )
{
fp = fp - 1;
pp = pp - 1;
a[fp] = a[pp];
}
}
void move()
{
char k;
makespace();
do
{
k = a[fp];
a[pp] = k;
pp = pp + 1;
fp = fp + 1;
} while ( ! ( k == nl ) );
pe = pp;
readline();
}
void moveback()
{
char k;
k = a[pp - 1];
while ( (k != nl) || (pp == pe) )
{
fp = fp - 1;
pp = pp - 1;
a[fp] = k;
k = a[pp - 1];
};
pe = pp;
ms = 0;
printed = false;
}
boolean matched()
{
int i, l, ind, t1;
char k;
int fp1;
pp1 = pp;
fp1 = fp;
ind = matchlim;
t1 = c[txt];
if ( (fp != ms) || ((code != 'f') && (code != 'u')) )
{
goto L2;
}
k = a[fp];
L1:
a[pp] = k;
pp = pp + 1;
fp = fp + 1;
L2:
k = a[fp];
if ( k == char(t1) )
{
goto L5;
}
if ( k != nl )
{
goto L1;
}
else
{
goto L10;
}
L5:
l = 1;
L6:
i = c[txt + l];
if ( i == 0 )
{
goto L7;
}
if ( a[fp + l] != char(i) )
{
goto L1;
}
l = l + 1;
goto L6;
L7:
ms = fp;
ml = fp + l;
return true;
L10:
ind = ind - 1;
if ( ind == 0 )
{
goto L15;
}
if ( fp == bottom )
{
goto L16;
}
if ( code != 'u' )
{
a[pp] = k;
pp = pp + 1;
pe = pp;
}
else
{
pp = pp1;
}
fp = fp + 1;
makespace();
readline();
pp1 = pp;
fp1 = fp;
goto L2;
L15:
pp = pp1;
fp = fp1;
L16:
return false;
}
void fail()
{
writestring("failure: ");
if ( code == 'o' )
{
write('e');
code = '-';
}
else if ( code == 'w' )
{
write('m');
code = '-';
}
if ( code != 'z' )
{
write(code);
if ( txt > 0 )
{
write('\'');
while ( c[txt] != 0 )
{
write(char(c[txt]));
txt = txt + 1;
}
write('\'');
}
}
if ( num == inv )
{
write('\\');
}
writeln();
}
void insert()
{
int i;
makespace();
if ( (pp - pe > linelength) || (fp == bottom) )
{
okok = false;
}
else
{
i = txt;
while ( c[i] != 0 )
{
a[pp] = char(c[i]);
pp = pp + 1;
i = i + 1;
}
}
}
int main(const int ac, const PtrPtrChar av)
{
int i, k;
if ( ac == 3 )
{
openFiles(av);
}
else
{
halt("Wrong number of parameters -- ecce1 f1 f2");
}
lastsym = char(0);
prompted = false;
mon = 0;
detab = false;
printed = false;
fp = 0;
bottom = 0;
ms = 0;
ml = 0;
top = 1;
lim = amax;
clim = 0;
pp = top - 1;
a[pp] = nl;
pp = pp + 1;
pe = pp;
writestring(version);
writeln();
write('>');
readline();
do
{
failed = false;
readcommand();
term = sym;
ci = cmax;
last = char(0);
codelim = c[ci - 1];
while ( (codelim != 0) && (! failed) )
{
code = char(codelim & 255);
matchlim = codelim / 256;
txt = c[ci - 2];
num = c[ci - 3];
ci = ci - 3;
done = false;
okok = true;
do
{
num = num - 1;
switch ( code ) // 'a' to 'z'
{
case 'a':
break; // dummy
case 'b':
a[pp] = nl;
pp = pp + 1;
pe = pp;
break;
case 'c':
while ( fp != bottom )
{
move();
}
while ( top != pp )
{
putOutFile(a[top]);
top = top + 1;
};
closeFiles();
return 0;
case 'd':
okok = matched();
if ( okok )
{
fp = ml;
}
break;
case 'e':
if ( a[fp] == nl )
{
okok = false;
}
else
{
fp = fp + 1;
}
break;
case 'f':
okok = matched();
break;
case 'g':
if ( prompt == '>' )
{
prompt = ':';
}
else
{
prompt = ' ';
}
makespace();
sym = readsymbol();
if ( detab )
{
if ( sym == tab )
{
sym = ' ';
}
}
if ( sym == ':' )
{
okok = false;
}
else
{
lefttab();
a[pp] = sym;
pp = pp + 1;
pe = pp;
while ( sym != nl )
{
sym = readsymbol();
a[pp] = sym;
pp = pp + 1;
pe = pp;
}
}
break;
case 'h':
break; // dummy
case 'i':
insert();
break;
case 'j':
if ( fp == bottom )
{
okok = false;
}
else
{
do
{
ch = a[fp];
a[pp] = ch;
pp = pp + 1;
fp = fp + 1;
} while ( ! ( ch == nl ) );
readline();
pp = pp - 1;
if ( (pp - pe > linelength) || ((fp == bottom) && (pp != pe)) )
{
pp = pp + 1;
pe = pp;
okok = false;
}
}
break;
case 'k':
if ( fp == bottom )
{
okok = false;
}
else
{
pp = pe;
do
{
fp = fp + 1;
} while ( ! ( a[fp - 1] == nl ) );
readline();
}
break;
case 'l':
if ( pp == pe )
{
okok = false;
}
else
{
fp = fp - 1;
pp = pp - 1;
a[fp] = a[pp];
ms = 0;
}
break;
case 'm':
if ( fp == bottom )
{
okok = false;
}
else
{
move();
}
break;
case 'n':
break; // dummy
case 'o':
if ( pp == pe )
{
okok = false;
}
else
{
pp = pp - 1;
}
break;
case 'p':
if ( last != 'p' )
{
printline();
}
else if ( fp == bottom )
{
okok = false;
}
else
{
move();
printline();
}
break;
case 'q':
break; // dummy
case 'r':
ch = a[fp];
if ( ch == nl )
{
okok = false;
}
else
{
a[pp] = ch;
pp = pp + 1;
fp = fp + 1;
}
break;
case 's':
if ( fp != ms )
{
okok = false;
}
else
{
fp = ml;
insert();
}
break;
case 't':
if ( ! matched() )
{
okok = false;
}
else
{
fp = ml;
insert();
}
break;
case 'u':
if ( ! matched() )
{
okok = false;
}
else
{
pp = pp1;
}
break;
case 'v':
p = fp;
i = txt;
k = c[i];
while ( (k != 0) && okok )
{
if ( a[p] != char(k) )
{
okok = false;
}
else
{
p = p + 1;
i = i + 1;
k = c[i];
}
}
if ( okok )
{
ms = fp;
ml = p;
}
break;
case 'w':
makespace();
if ( pe == top )
{
okok = false;
}
else
{
moveback();
}
break;
case 'x':
break; // dummy
case 'y':
c[txt] = num + 1;
done = true;
break;
case 'z':
if ( num == inv )
{
okok = false;
}
else
{
if ( (num != 0) && (num != stop) )
{
c[ci] = num;
ci = txt;
}
}
done = true;
break;
}; // switch
if ( okok && (! done) )
{
last = code;
}
} while ( ! ( (num == 0) || (num == stop) || (num == inv) || done || ! okok) );
if ( ((okok != done) && (num == inv)) || ! (done || okok || (num < 0)) )
{
do
{
k = c[ci - 1];
ci = ci - 3;
if ( char(k) == 'y' )
{
ci = c[ci + 1];
}
} while ( ! ( (k == 0) || ((char(k) == 'z') && (c[ci] <= 0)) ) );
if ( k == 0 )
{
fail();
failed = true;
}
};
if ( ! failed )
{
codelim = c[ci - 1];
}
};
if ( term == nl )
{
num = 0;
if ( ((mon == 0) && (! printed)) || ((mon > 0) && (last != 'p')) )
{
printline();
}
}
} while ( ! ( false ) ); // forever
}