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