#include <stdio.h>

#define FALSE	0
#define TRUE	1
#define NULL_ADDRESS	0	/* get_addr return codes */
#define SINGLE_ADDRESS	1
#define COMMA_ADDRESS	2
#define SEMI_ADDRESS	3
#define REG_FAIL	4
#define ADDR_FAIL	5
#define MAXLINE		256
#define NL		'\n'
#define BUF_SIZE	4000000
#define DEBUG(l, f, s)	if (Debug >= l) fprintf(stderr, f, s)

/***
 *	ted - C version of Dave Warme's E editor.
 *
 *	This main program simply implements the read loop.
 *
 */

char buf[BUF_SIZE],		/* buffer */
     file_name[168],		/* remembered file name */
     prompt[16]="",		/* prompt */
     tty_buf[MAXLINE];		/* buffer for tty input */

char *buffer_end,		/* points to end of buffer */
     *gap_start,
     *gap_end,
     *the_bp;			/* external buffer point */

char reqch;			/* current request character */

int  ti,			/* tty buffer index */
     te,			/* tty buffer end index */
     li,			/* first char of current line */
     le,			/* last char of current line */
     lli,			/* index of first char on last line */
     lle,			/* index of last char on last line */
     fli,			/* first char of address area */
     fle;			/* last char of address area */

int  flsw,			/* 1st address present */
     llsw,			/* 2nd address present */
     modified,			/* buffer contents modified */
     untrusted,			/* file read into non-empty buffer */
     valid_path,		/* file name saved */
     skipline;			/* abort current line */


int  Debug = 0;
static eof = 0;

main (argc, argv)
int  argc;
char *argv[];
{

    char *bufp;
    int code;

    the_bp = bufp = buf;
    gap_start = buf;
    gap_end = buffer_end = buf + BUF_SIZE - 1;
    li = 0;
    le = -1;

    valid_path = untrusted = modified = FALSE;

    file_name[0] = '\0';

    if (argc > 1) {
	strcpy (file_name, argv[argc-1]);
	valid_path = TRUE;
	strcpy (tty_buf, "r\n");
	te = 1;
	goto process_line;
    }

    for (;;) {			/* line loop */
	printf ("%s", prompt);
        if (fgets (tty_buf, MAXLINE, stdin) == NULL) {
		eof++;
		if (eof > 20) 			/* in a loop */
			exit(1);		/* by guy */
	}
	else eof = 0;
	te = strlen (tty_buf) - 1;
        tty_buf[te+1] = '\0';
	if (te == 0) {
	    strcpy (tty_buf, ".1p\n");
	    te = 3;
	}

process_line:
	for (ti=0;ti<te;) {	/* process line */
	    DEBUG(4, "Find first - %s", &tty_buf[ti]);
	    get_addr (tty_buf, &ti, &te, &li, &le, &fli, &fle, &code);
	    if (code == NULL_ADDRESS) {
		flsw = FALSE;
		llsw = FALSE;
	    }
	    else if (code == SINGLE_ADDRESS) {
		flsw = TRUE;
		llsw = FALSE;
	    }
	    else if (code == COMMA_ADDRESS || code == SEMI_ADDRESS) {
		flsw = TRUE;
		llsw = TRUE;
		DEBUG(4,"Find second - %s", &tty_buf[ti]);
		get_addr (tty_buf, &ti, &te, (code == COMMA_ADDRESS) ? &li : & fli, (code == COMMA_ADDRESS) ? &le : &fle, &lli, &lle, &code);
		if (code == REG_FAIL) goto reg_err;
		if (code == ADDR_FAIL) break;
	    }
	    else if (code == REG_FAIL) {
reg_err:
		printf ("Search failed.\n");
		break;
	    }
	    else break;

	    skipline = FALSE;
	    reqch = tty_buf[ti++];
	    DEBUG(4,"reqch = %c\n",reqch);
	    if (reqch == NL)
		if (flsw) {
		    print();
		    break;
		}
		else
		    break;

	    switch (reqch) {
		case 'p':
		    print();
		    break;
		case 'S':
		case 's':
		    subst();
		    break;
		case 'a':
		case 'i':
		case 'c':
		    input();
		    break;
		case 'd':
		    delete();
		    break;
		case 'q':
		case 'Q':
		    quit();
		    break;
		case 'x':
		    status();
		    break;
		case 'r':
		    readf();
		    break;
		case 'w':
		case 'W':
		    writef();
		    break;
		case '=':
		    linenum();
		    break;
		case 'g':
		case 'v':
		    global();
		    break;
		case 'z':
		    setprompt();
		    break;
		case 'n':
		    nothing();
		    break;
		case '"':
		    comment();
		    break;
		case '%':
		    db();
		    break;
		case '!':
		case 'e':
		    execute();
		    break;
		default:
		    printf ("edit: %c is not recognized as a request.\n", reqch);
		    skipline = TRUE;
		    break;
	    }

	    DEBUG(7,"End command - gap_start = %d", gap_start-buf);
	    DEBUG(7,"  gap_end = %d", gap_end - buf);
	    DEBUG(7,"  buffer_end = %d\n", buffer_end - buf);
	    if (skipline)
		break;
	}
    }
}

/***
 *	move_gap (dest)
 *	int dest;
 *
 *	moves gap to gap independent position.
 *
 */
move_gap(dest)
int dest;
{
    char *bp;
    register int l;
    register char *sp, *dp;
    int i;

    DEBUG(7,"Moving gap - dest = %d", dest);
    DEBUG(7,"  current = %d\n", gap_start-buf);
    bp = buf;

    if (bp+dest == gap_start) return;

    if (bp+dest < gap_start) {
	for (i=l=(gap_start-bp)-dest,sp=gap_start,dp=gap_end;*(--dp)= *(--sp),l--;)
	    ;
	gap_start -= i;
	gap_end -= i;
    }
    else {
        dest = dest + (gap_end - gap_start);
	for (i=l=(dest+bp)-gap_end,sp=gap_end,dp=gap_start;*(dp++)= *(sp++),l--;)
	    ;
	gap_start += i;
	gap_end += i;
    }
}

/***
 *	defaults (fli, lle)
 *	int fli, lle;
 *
 *	defaults - easy procedure to set defaults, where the
 *	arguments are the defaults.  it checks to see what was
 *	on the input and defaults the rest.
 *
 */
defaults(afli,alle)
int afli,alle;
{
    int ife;

    if (!flsw) {
	fli = afli;
	lli = afli;
	fle = alle;
	lle = alle;
    }
    else if (!llsw) {
	lli = fli;
	lle = fle;
    }

    ife = (buffer_end - buf) - (gap_end - gap_start);
    if (ife <= 0) {
	printf ("Buffer empty.\n");
	return (FALSE);
    }

    if (fli < 0 || lle < 0 || fli >= ife) {
	printf ("Address out of buffer.\n");
	return (FALSE);
    }

    if (fli > lle) {
	printf ("Address wrap-around.\n");
	return (FALSE);
    }

    return (TRUE);
}
