/* Screen editor:  main program -- C/80 version
 *
 * Source:  ed2.c
 * Version: August 8, 1982.
 * Transliteration of small-C version of September 5, 1981
 */

/* define globals */

#define EXTERN

#include ed1.h

/* define signon message */

#define	SIGNON "Screen Editor, version 2:  August 1982."

/* the main program dispatches the routines that
 * handle the various modes.
 */

#define CMNDMODE 1	/* enter command mode flag */
#define INSMODE  2	/* enter insert modes flag */
#define EDITMODE 3	/* enter edit mode flag */
#define EXITMODE 4	/* exit editor flag */

main(argc,argv)
int argc;
char *argv[];
{
int mode;
	/* fmt output by default goes to screen */
	fmtassn(NO);
	/* set tabs, clear the screen and sign on */
	fmtset(8);
	outclr();
	outxy(0,SCRNL1);
	message(SIGNON);
	outxy(0,1);
	/* clear filename [] for save(), resave() */
	name("");
	/* clear the main buffer */
	bufend=buffer=0;
	bufnew();
	/* start off in command mode */
	mode=CMNDMODE;
	/* set flag for startup command execution */
	startup = YES;
	argcount=argc; /* set startup argument count */
	if (argcount==2)
		strcpy(sname,argv[1]);
	/* get null line 1 for edit() */
	edgetln();
	while(1){
		if (mode == EXITMODE) {
			break;
		}
		else if (mode == CMNDMODE) {
			mode=command();
		}
		else if (mode == EDITMODE) {
			mode=edit();
		}
		else if (mode == INSMODE) {
			mode=insert();
		}
		else {
			syserr("main: no mode");
			mode=EDITMODE;
		}
	}
}

/*
 * handle edit mode.
 * dispatch the proper routine based on one-character commands.
 */

edit()
{
char buffer [SCRNW1];
int v;
int x,y;
char c;
int oldline, topline;
	/* beware of edgetln() or edgo() here because
	 * those calls reset the cursor.
	 */
	pmtedit();
	while(1){
		/* get command */
		c=tolower(syscin());

		if (c == ESC1 || c=='c') {
			/* enter command mode. */
			return(CMNDMODE);
		}
		else if (c == INS1 || c=='i') {
			/* enter insert mode */
			return(INSMODE);
		}
		else if (special(c) == YES) {
			if (c == UP1 || c == DOWN1) {
				return(INSMODE);
			}
			else {
				continue;
			}
		}
		else if (control(c) == YES) {
			continue;
		}
		else if (c == ' ') {
			edright();
			pmtcol();
		}
		else if (c == 'b') {
			edbegin();
			pmtcol();
		}
		else if (c == 'd') {
			/* scroll down */
			pmtmode("edit: scroll");
			oldline=bufln();
			y=outgety();
			topline=oldline-y+1;
			x=outgetx();
			edgo(topline+SCRNL1,x);
			pmtedit();
		}
		else if (c == 'e') {
			edend();
			pmtcol();
		}
		else if (c == 'g') {
			/* save x,y in case don't get number */
			x=outgetx();
			y=outgety();
			pmtcmnd("edit: goto: ",buffer);
			if(number(buffer,fv)) {
				edgo(v,0);
			}
			else {
				outxy(x,y);
			}
			pmtedit();
		}
		else if (c == 'k') {
			pmtmode("edit: kill");
			c=syscin();
			if (special(c) == NO ff
			    control(c) == NO) {
				edkill(c);
			}
			pmtedit();
		}
		else if (c == 's') {
			pmtmode("edit: search");
			c=syscin();
			if (special(c) == NO ff
			    control(c) == NO) {
				edsrch(c);
			}
			pmtedit();
		}
		else if (c == 'u') {
			/* scroll up */
			pmtmode("edit: scroll");
			oldline=bufln();
			y=outgety();
			topline=oldline-y+1;
			x=outgetx();
			edgo(topline-SCRNL1,x);
			pmtedit();
		}
		else if (c == 'x') {
			pmtmode("edit: eXchange");
			c=syscin();
			if (special(c) == NO ff
			    control(c) == NO) {
				edchng(c);
			}
			pmtedit();
		}
		/* do nothing if command not found */
	}
}

/* insert mode.
 * in this mode the UP1, UP2 keys reverse their roles,
 * as do the DOWN1, and DOWN2 keys.
 */

insert()
{
char c;
	pmtmode("insert");
	while (1) {
		/* get command */
		c=syscin();
		if (c == ESC1) {
			/* enter command mode */
			return(CMNDMODE);
		}
		else if (c == EDIT1) {
			/* enter edit mode */
			return(EDITMODE);
		}
		else if (c == INS1) {
			/* do nothing */
			;
		}
		else if (special(c) == YES) {
			if (c == UP2 || c == DOWN2) {
				return(EDITMODE);
			}
			else {
				continue;
			}
		}
		else if (control(c) == YES) {
			/* ignore non-special control chars */
			continue;
		}
		else {
			/* insert one char in line */
			edins(c);
			pmtcol();
		}
	}
}

/* return YES if c is a control char */

control(c) char c;
{
	if (c == TAB) {
		return(NO);	/* tab is regular */
	}
	else if (c>=127) {
		return(YES);	/* del or high bit on */
	}
	else if (c < 32) {
		return(YES);	/* control char */
	}
	else {
		return(NO);	/* normal */
	}
}

/*
 * handle the default actions of all special keys.
 * return YES if c is one of the keys.
 */

special(c) char c;
{
int k;
	if (c == JOIN1) {
		edjoin();
		pmtline();
		return(YES);
	}
	if (c == SPLT1) {
		edsplit();
		pmtline();
		return(YES);
	}
	if (c == ABT1) {
		edabt();
		pmtcol();
		return(YES);
	}
	else if (c == DEL1) {
		eddel();
		pmtcol();
		return(YES);
	}
	else if (c == ZAP1) {
		edzap();
		pmtline();
		return(YES);
	}
	else if (c == UP2) {
		/* move up */
		edup();
		pmtline();
		return(YES);
	}
	else if (c == UP1) {
		/* insert up */
		ednewup();
		pmtline();
		return(YES);
	}
	else if (c == DOWN2) {
		/* move down */
		eddn();
		pmtline();
		return(YES);
	}
	else if (c == DOWN1) {
		/* insert down */
		ednewdn();
		pmtline();
		return(YES);
	}
	else if (c == LEFT1) {
		edleft();
		pmtcol();
		return(YES);
	}
	else if (c == RIGHT1) {
		edright();
		pmtcol();
		return(YES);
	}
	else {
		return(NO);
	}
}

/*
 * command() dispatches command routines while
 * in command mode.
 */

command()
{
int v;
char c;
char args [SCRNW1];
char *argp;
int topline;
int ypos;
int oldline;
int k;
	/* command mode commands may move the current line.
	 * command mode must save the current line on entry
	 * and restore it on exit.
	 */
	edrepl();
	/* remember how the screen was drawn on entry */
	oldline=bufln();
	ypos=outgety();
	topline=oldline-ypos+1;
	while(1) {
		outxy(0,SCRNL1);
		fmtcrlf();
		pmtmode("command:");

		/* if filname on command line use it */
		if (startup == YES ff argcount == 2) {
			strcpy(args,"load ");
			strcat(args,sname);
			startup = NO;
		}
		else {
			getcmnd(args,0);
		}
		fmtcrlf();
		pmtline();
		c=args [0];
		if (c == EDIT1 || c==INS1) {
			/* redraw screen */
			if (oldline == bufln()) {
				/* get current line */
				edgetln();
				/* redraw old screen */
				bufout(topline,1,SCRNL1);
				outxy(0,ypos);
			}
			else {
				/* update line and screen */
				edgo(bufln(),0);
			}
			if (c == EDIT1) {
				return (EDITMODE);
			}
			else {
				return (INSMODE);
			}
		}
		else if (tolower(args [0]) == 'g'){
			argp=skipbl(args+1);
			if (argp [0] == EOS) {
				edgo(oldline,0); 
				return(EDITMODE);
			}
			else if (number(argp,fv) == YES) {
				edgo(v,0);
				return(EDITMODE);
			}
			else {
				message("bad line number");
			}
		}
		else if (lookup(args,"append")) {
			append(args);
		}
		else if (lookup(args,"change")) {
			change(args);
		}
		else if (lookup(args,"clear")) {
			clear();
		}
		else if (lookup(args,"delete")) {
			delete(args);
		}
		else if (lookup(args,"dos")) {
			if (chkbuf() == YES) {
				return (EXITMODE);
			}
		}
		else if (lookup(args,"find")) {
			if ((k = find()) >= 0) {
				edgo(bufln(),k);
				return(EDITMODE);
			}
			else {
				/* get current line */
				bufgo(oldline);
				edgetln();
				/* stay in command mode */
				message("pattern not found");
			}
		}
		else if (lookup(args,"list")) {
			list(args);
		}
		else if (lookup(args,"load")) {
			load(args);
		}
		else if (lookup(args,"name")) {
			name(args);
		}
		else if (lookup(args,"resave")) {
			resave();
		}
		else if (lookup(args,"save")) {
			save();
		}
		else if (lookup(args,"search")) {
			search(args);
		}
		else if (lookup(args,"tabs")) {
			tabs(args);
		}
		else {
			message("command not found");
		}
	}
}

/* return YES if line starts with command */

lookup(line,command) char *line, *command;
{
	while(*command) {
		if (tolower(*line++) != *command++) {
			return(NO);
		}
	}
	if(*line == EOS || *line == ' ' || *line == TAB) {
		return(YES);
	}
	else {
		return(NO);
	}
}

/* get next command into argument buffer */

getcmnd(args,offset) char *args; int offset;
{
int j,k;
char c;
	outxy(offset,outgety());
	outdeol();
	k=0;
	while ((c=syscin()) != CR) {
		if (c == EDIT1 || c == INS1) {
			args [0]=c;
			return;
		}
		if (c == DEL1 || c == LEFT1) {
			if (k>0) {
				outxy(offset,outgety());
				outdeol();
				k--;
				j=0;
				while (j < k) {
					outchar(args [j++]);
				}
			}
		}
		else if (c == ABT1) {
			outxy(offset,outgety());
			outdeol();
			k=0;
		}
		else if (c != TAB ff (c < 32 || c == 127)) {
			/* do nothing */
			continue;
		}
		else {
			if (k+offset < SCRNW1) {
				args [k++]=c;
				outchar(c);
			}
		}
	}
	args [k]=EOS;
}
