///////////////////////////////////////////////////////////////////////
//                                                                   //
//      Title:     Edinburgh Compatible Context Editor               //
//      Author:    H.Whitfield                                       //
//      Date:      17 November 1985,    last modified 7 August 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;
enum {false, true};

typedef char string[256];

const string version = "Ecce editor v3.5";

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;

void openFiles(string InFileName, string OutFileName)
{
	// inFile.open(av[1], ios::in);
	
	inFile.open(InFileName, ios::in);
	if ( ! inFile )
	{
		halt("Open inFile failed");
	}

	// outFile.open(av[2],ios::out);

	outFile.open(OutFileName, ios::out);
	if ( ! outFile )
	{
		halt("Open outFile failed");
	}
}

boolean eofInFile()
{
	return inFile.eof();
}
		
char nextInFile()						// does not move past char
{
	char inFileBuffer;
	
	if ( inFile.eof() )
	{
		halt("Eof encountered on input file.");
	}
	else						
	{
		inFileBuffer = inFile.peek();
		if ( inFileBuffer == cr )		// map cr to nl on Macintosh
		{
			inFileBuffer = nl;
		}
	}
	return inFileBuffer;
}

void readInFile(char& c)				// gets and moves past char
{
	char inFileBuffer;
	
	if ( inFile.eof() )
	{
		halt("Eof encountered on input file.");
	}
	else						
	{
		inFile.get( inFileBuffer );
		if ( inFileBuffer == cr )		// map cr to nl on Macintosh
		{
			inFileBuffer = nl;
		}
	}
	c = inFileBuffer;
}

void putOutFile(char c)					// puts one char on output file
{
	if ( c == nl )						// map nl to cr on Macintosh
	{
		outFile << cr;
	}
	else
	{
		outFile << c;
	}
}
		
void closeFiles()						// closes files
{
	inFile.close();
	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 lastsym, prompt;					// prompt management variables
boolean prompted;

char nextsymbol()						// does not move past char
{
	char inputBuffer;
	
	if ( (lastsym == nl) && (! prompted) )
	{
		if ( prompt != ' ' )
		{
			write(prompt);
		}
		prompted = true;
	}
	
	if ( cin.eof() )
	{
		halt("Eof encountered on keyboard input.");
	}
	else
	{
		inputBuffer = cin.peek();
	}
	return inputBuffer;
}

char readsymbol()						// gets and moves past char
{
	char inputBuffer;
	
	lastsym = nextsymbol();				// get the next char
	if ( lastsym == nl  )
	{
		prompted = false;
	}
	cin.get( inputBuffer );				// move past char
	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;
		}
	}
}


void ecce(string InFileName, string OutFileName)
{
	int i, k;
	
	openFiles(InFileName, OutFileName);

	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;
						
					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

}


///////////////////////////////////////////////////////////////////////////
//                                                                       //
//  Interface to Macintosh OS Routines                                   //
//                                                                       //
//	Created: Saturday, September 29, 1990 at 10:18 						 //
//	Last Modified: Monday, August 5, 1996 at 09:30	   					 //
//																		 //
//	Copyright  ©  H.Whitfield 1990-1996 		 						 //
//    Copyright  © Apple Computer Inc.  1985-1990 						 //
//    All rights reserved 												 //
//																		 //
// Parts Derived from XFCNs  © 1989 by the Trustees of Dartmouth College //
// Written by Kevin Calhoun 											 //
//																		 //
///////////////////////////////////////////////////////////////////////////

#include <Types.h>
#include <Files.h>
#include <StandardFile.h>
#include <SegLoad.h>
#include <ToolUtils.h>

// typedef unsigned char string[256];

// typedef int boolean;
// enum {false, true};


///////////////////////////////////////////////////////////////////////////
//																		 //
//		String Conversion Routines 										 //
//																		 //
///////////////////////////////////////////////////////////////////////////

void cToPas(const string cstring, Str255 pstring)
{
	int  n = 0;
	char c = cstring[0];
	
	while ( ( c != char(0) ) && ( n < 255 ) )
	{
		n++;
		pstring[n] = c;
		c = cstring[n];
	}
	pstring[0] = n;
}

void pasToC(Str255 pstring, const string cstring)
{
	int i = 0;
	int n = pstring[0];
	
	if ( n < 0 )
	{
		n = n + 256;
	}
	
	while (i < n)
	{
		cstring[i] = pstring[i+1];
		i++;
	}
	cstring[i] = char(0);
}

void pAppend (Str255 pstring, const char c)
{
	// append char c to pascal string pstring
	
	int n = pstring[0];
	
	if ( n < 0 )
	{
		n = n + 256;
	}
	
	if ( n < 255 )
	{
		n++;
		pstring[n] = c;
		pstring[0] = n;
	}
}

void pConcat(Str255 a, Str255 b, Str255 c)
{
	// a = concat(b,c)   concatenate pascal style strings
	
	int i;
	
	int nb = b[0];
	if ( nb < 0 )
	{
		nb = nb + 256;
	}
	
	int nc = c[0];
	if ( nc < 0 )
	{
		nc = nc + 256;
	}
	
	Str255 temp;
	
	for ( i = 1 ; i <= nb ; i++ )
	{
		temp[i] = b[i];
	}
	
	int min;
		
	if ( nc < ( 255 - nb ) )
	{
		min = nc;
	}
	else
	{
		min = 255 - nb;
	}

	for ( i = 1 ; i <= min ; i++ )
	{
		temp[nb + i] = c[i];
	}
	
	int na = nb + min;
	
	temp[0] = na;
	
	for ( i = 0;  i <= na ; i++ )
	{
		a[i] = temp[i];
	}
}


///////////////////////////////////////////////////////////////////////////
//																		 //
//		Pathname Routines												 //
//																		 //
///////////////////////////////////////////////////////////////////////////

boolean AuxActive()

// Derived from XFCN AuxActive © 1989 by the Trustees of Dartmouth College
// Written by Kevin Calhoun
// if A/UX is active, bit 9 of the word at $B22 is set.
// if Mac OS is active, that bit is clear.

{
	const int HWCfgFlags = 0xB22;

	return BitTst(Ptr(HWCfgFlags), 6);
	
    // "6" is not a typo!  The toolbox BitTst routine takes
    // an offset from the high order bit of the byte pointed to
    // by the first param.
}

void PathNameFromDirID (int DirID, short vRefNum, string result)
{
	CInfoPBRec Block;
	// HFileInfo* HBlock = (HFileInfo*) &Block;
	DirInfo* DBlock = (DirInfo*) &Block;
	
	Str255 directoryName, FullPathName;
	OSErr err;
	boolean gHaveAUX;

	gHaveAUX = AuxActive();
	FullPathName[0] = char(0);

		DBlock->ioNamePtr = StringPtr(&directoryName);
		DBlock->ioDrParID = DirID;

	do
	{
		DBlock->ioVRefNum = vRefNum;
		DBlock->ioFDirIndex = -1;
		DBlock->ioDrDirID = DBlock->ioDrParID;

		err = PBGetCatInfo(&Block, false);
		
		if ( gHaveAUX )
		{
			if ( directoryName[1] != '/' )
			{
            	// if this isn't root (i.e. "/") append a slash ('/')
            	
				pAppend (directoryName, '/');
			}
		}
		else
		{
			pAppend (directoryName, ':');
		}
		
		pConcat(FullPathName, directoryName, FullPathName);
	}
	while ( ! (DBlock->ioDrDirID == fsRtDirID) );
	
	pasToC(FullPathName,result);
}

void PathNameFromWD (int vRefnum, string result)
{
	WDPBRec myBlock;
	OSErr err;
	boolean gHaveAUX;

	gHaveAUX = AuxActive();
	
    // PBGetWDInfo has a bug under A/UX 1.1.  if ( vRefNum is a real vRefNum
    // and not a wdRefNum , then it returns garbage . Since A / UX has only 1
    // volume ( in the Macintosh sense ) and only 1 root directory, //
    // this can occur only when a file has been selected in the root directory ( / ).
    // So we look for this and hard code the DirID and vRefNum .
    
	if ( (gHaveAUX) && (vRefnum == -1) )
	{
		PathNameFromDirID(2, -1, result);
	}
	else
	{
		myBlock.ioNamePtr = nil;
		myBlock.ioVRefNum = vRefnum;
		myBlock.ioWDIndex = 0;
		myBlock.ioWDProcID = 0;

		
        // Change the Working Directory number in vRefnum into
        // a real vRefnum and DirID. The real vRefnum is
        // returned in ioVRefnum, and the real DirID is
        // returned in ioWDDirID.
        
		err = PBGetWDInfo(&myBlock, false);
		PathNameFromDirID(myBlock.ioWDDirID, myBlock.ioWDVRefNum, result);
	}
}


///////////////////////////////////////////////////////////////////////////
//																		 //
//		File Handling Routines											 //
//																		 //
///////////////////////////////////////////////////////////////////////////

// OSErr GetVol(StringPtr volName, short *vRefNum);
// OSErr GetFInfo(ConstStr255Param fileName, short vRefNum, FInfo *fndrInfo);
// OSErr SetFInfo(ConstStr255Param fileName, short vRefNum, const FInfo *fndrInfo);
// OSErr FSDelete(ConstStr255Param fileName, short vRefNum); 
// OSErr Rename(ConstStr255Param oldName, short vRefNum, ConstStr255Param newName); 

void DefaultVolume(string result)
{
	Str255 myStr;
	OSErr res;
	short vRefNum;

	res = GetVol(myStr, &vRefNum);
	PathNameFromWD(vRefNum, result);
}

boolean FileExists (string filename)
{
	const OSErr NoErr = 0;
	Str255 FName;
	Str255 myStr;
	OSErr res;
	short vRefNum;
	FInfo fndrInfo;

	cToPas(filename, FName);

	res = GetVol(myStr, &vRefNum);
	res = GetFInfo(FName, vRefNum, &fndrInfo);
	return (res == NoErr);
}

boolean FileDelete (string filename)
{
	const OSErr NoErr = 0;
	Str255 FName;
	Str255 myStr;
	OSErr res;
	short vRefNum;
	FInfo fndrInfo;

	cToPas(filename,FName);

	res = GetVol(myStr, &vRefNum);
	res = GetFInfo(FName, vRefNum, &fndrInfo);
	if ( res == NoErr )
	{
		res = FSDelete(FName, vRefNum);
	}
	return (res == NoErr);
}

void DeleteFile (string filename)
{
	const OSErr NoErr = 0;
	Str255 FName;
	Str255 myStr;
	OSErr res;
	short vRefNum;
	FInfo fndrInfo;

	cToPas(filename,FName);

	res = GetVol(myStr, &vRefNum);
	res = GetFInfo(FName, vRefNum, &fndrInfo);
	if ( res == NoErr )
	{
		res = FSDelete(FName, vRefNum);
	}
}

void RenameFile (string oldfilename, string newfilename)
{
	const OSErr NoErr = 0;
	Str255 oldName, newName;
	Str255 myStr;
	OSErr res;
	short vRefNum;
	FInfo fndrInfo;

	cToPas(oldfilename,oldName);
	cToPas(newfilename,newName);

	res = GetVol(myStr, &vRefNum);
	res = GetFInfo(oldName, vRefNum, &fndrInfo);
	if ( res == NoErr )
	{
		res = Rename(oldName, vRefNum, newName);
	}
}

void GetFileCreatorAndType (string filename, OSType& FCreator, OSType& FType)
{
	Str255 FName;
	Str255 myStr;
	OSErr res;
	short vRefNum;
	FInfo fndrInfo;
	
	cToPas(filename,FName);

	res = GetVol(myStr, &vRefNum);
	res = GetFInfo(FName, vRefNum, &fndrInfo);
	FCreator = fndrInfo.fdCreator;
	FType = fndrInfo.fdType;
}

void SetFileCreatorAndType (string filename, OSType FCreator, OSType FType)
{
	Str255 FName;
	Str255 myStr;
	OSErr res;
	short vRefNum;
	FInfo fndrInfo;

	cToPas(filename,FName);

	res = GetVol(myStr, &vRefNum);
	res = GetFInfo(FName, vRefNum, &fndrInfo);
	fndrInfo.fdCreator = FCreator;
	fndrInfo.fdType = FType;
	res = SetFInfo(FName, vRefNum, &fndrInfo);
}


///////////////////////////////////////////////////////////////////////////
//																		 //
//		Application File Routines										 //
//																		 //
///////////////////////////////////////////////////////////////////////////

// void CountAppFiles(short *message,short *count); 
// void GetAppFiles(short index,AppFile *theFile); 
// void ClrAppFiles(short index); 
// void GetAppParms(Str255 apName,short *apRefNum,Handle *apParam)

short AppFileCount()
{
	short message, count;

	CountAppFiles(&message, &count);
	if ( message == appOpen )
	{
		return count;
	}
	else
	{
		return 0;
	}
}

void AppName(string res)
{
	Str255 apName;
	short apRefNum;
	Handle apParam;

	GetAppParms(apName, &apRefNum, &apParam);
	pasToC(apName,res);
}

void AppFileName (short n, OSType fType, string fileName, string result)
{
	short message, count;
	AppFile reply;
	Str255 pathname;
	string cstring;

	CountAppFiles(&message, &count);
	if ( (0 < n) && (n <= count) && (message == appOpen) )
	{
		GetAppFiles(n, &reply);
		if ( (fType == 0x3f3f3f3f) || (fType == reply.fType) )
		{
			PathNameFromWD(reply.vRefNum, cstring);
			cToPas(cstring, pathname);
			pasToC(reply.fName,fileName);
			pConcat(pathname, pathname, reply.fName);
			pasToC(pathname, result);
		}
		else
		{
			fileName[0]  = char(0);
			result[0] = char(0);
		}
		ClrAppFiles(n);
	}
	else
	{
		fileName[0]  = char(0);
		result[0] = char(0);
	}
}


///////////////////////////////////////////////////////////////////////////
//																		 //
//		StandardFile Routines 	    									 //
//																		 //
///////////////////////////////////////////////////////////////////////////

// void SFGetFile(Point where, ConstStr255Param prompt, FileFilterUPP fileFilter,
// short numTypes, ConstSFTypeListPtr typeList, DlgHookUPP dlgHook, SFReply *reply)

void OldFileName (OSType fType, string fileName, string result)
{
	Point where;
	SFTypeList flist;
	SFReply reply;
	Str255 pathname;
	Str255 prompt;
	short numTypes;
	string cstring;

	where.h = 100;
	where.v = 50;
	flist[0] = fType;
	if ( fType == 0x3f3f3f3f )
	{
		numTypes = -1;
	}
	else
	{
		numTypes = 1;
	}
	prompt[0] = char(0);
	
	SFGetFile(where, prompt, nil, numTypes, flist, nil, &reply);
	if ( reply.good )
	{
		PathNameFromWD(reply.vRefNum, cstring);
		cToPas(cstring, pathname);
		pasToC(reply.fName,fileName);
		pConcat(pathname, pathname, reply.fName);
		pasToC(pathname, result);
	}
	else
	{
		fileName[0]  = char(0);
		result[0] = char(0);
	}
}

// void SFPutFile(Point where, ConstStr255Param prompt, ConstStr255Param origName,
// DlgHookUPP dlgHook, SFReply *reply)

void NewFileName (string cPrompt, string fileName, string result)
{
	Point where;
	SFReply reply;
	Str255 pathname, prompt, fName;
	string cstring;
	
	cToPas(fileName, fName);
	cToPas(cPrompt, prompt);

	where.h = 100;
	where.v = 50;
	SFPutFile(where, prompt, fName, nil, &reply);
	if ( reply.good )
	{
		PathNameFromWD(reply.vRefNum, cstring);
		cToPas(cstring, pathname);
		pasToC(reply.fName,fileName);
		pConcat(pathname, pathname, reply.fName);
		pasToC(pathname, result);
	}
	else
	{
		fileName[0]  = char(0);
		result[0] = char(0);
	}
}

void main()
{
	string InFileName, fileName, OutFileName;
	Str255 pstring;
	OSType FCreator, FType;

	cout << endl;					// open console window
	
	if ( AppFileCount() != 0 )
	{
		AppFileName(1, 'TEXT', fileName, InFileName);
	}
	else
	{
		OldFileName('TEXT', fileName, InFileName);
	}
	
	if ( InFileName[0] != 0 )
	{
		cToPas(InFileName, pstring);
		pAppend(pstring, '!');
		pasToC(pstring, OutFileName);
		GetFileCreatorAndType (InFileName,  FCreator, FType);
		
		ecce(InFileName, OutFileName);
		
		SetFileCreatorAndType(OutFileName, FCreator, FType);
		DeleteFile(InFileName);
		RenameFile(OutFileName, InFileName);
	}
}