#include <stdio.h>
#define FALSE	0
#define TRUE	1
#define NL	'\n'
#define MAXLINE 256
#define DEBUG(l, f, s)	if (Debug >= l) fprintf(stderr, f, s)

extern char buf[],file_name[],prompt[],tty_buf[];
extern char reqch;
extern char *gap_start, *gap_end, *buffer_end;
extern int  flsw, modified, skipline, untrusted, valid_path;
extern int  li,le,fli,fle,lli,lle,ti,te;
extern int  Debug;
/***
 *	quit ()
 *
 *	quits out of the editor
 *
 */
quit()
{
    if (reqch != 'Q' && modified && (buffer_end-buf) - (gap_end-gap_start) > 0) {
	printf ("Buffer is modified. Q forces.\n");
	skipline = TRUE;
	return;
    }

    if (flsw || tty_buf[ti] != NL) {
	printf ("Syntax error in quit request.\n");
	skipline = TRUE;
	return;
    }

    exit(0);
}
/***
 *	setprompt ()
 *
 *	sets the prompt from the rest of the line.
 *
 */
setprompt()
{
    if (te - ti > 15) {		/* check prompt size */
	tty_buf[ti+15] = '\0';	/* force length */
    }
    else {
	tty_buf[te] = '\0';	/* eliminate NL */
    }

    strcpy (prompt,&tty_buf[ti]);
    skipline = TRUE;
}
/***
 *	execute ()
 *
 *	execute a subcommand.
 *
 *
 */
execute()
{
    system (&tty_buf[ti]);
    skipline = TRUE;
}
/***
 *	print ()
 *
 *	prints out given lines.
 *
 */
print()
{
    register int i;
    register char *bp;

    if (!defaults(li,le)) return;

    bp = buf;

    if (gap_start - bp <= lle)
	move_gap (lle + 1);


    for (i=fli;i<=lle;i++)
	putchar (bp[i]);

    find_line (lle, &li, &le);
}
/***
 *	input ()
 *
 *	implements input commands (append, insert, or change)
 *
 */
input()
{
    if (tty_buf[ti] != NL && tty_buf[ti] != ' ') {
	printf ("Invalid syntax in input mode request.\n");
	skipline = TRUE;
	return;
    }

    if (reqch == 'a') {
	if (!flsw) fle = le;
	move_gap (fle + 1);
    }
    else if (reqch == 'i') {
	if (!flsw) fli = li;
	fle = fli - 1;
	move_gap (fle + 1);
    }
    else {			/* change request */
	if (!defaults (li, le)) return;
	modified = TRUE;
	move_gap (lle + 1);	/* gap after text */
	gap_start = buf + fli; 	/* delete text */
	if ((buffer_end - buf) - (gap_end - gap_start) <= 0) valid_path = FALSE;
    }

    if (tty_buf[ti] == NL) goto in_line;
    modified = TRUE;
    if (tty_buf[ti] == ' ') ti++;
    strcpy (tty_buf,&tty_buf[ti]);
in_loop:
    DEBUG(4,"Input - tty_buf = %s", tty_buf);
    if (gap_end - gap_start <= 512) goto in_ovfl;
    if (tty_buf[3] == '\0')
	if (strcmp (tty_buf, "\\f\n") == 0 || strcmp (tty_buf, "\\F\n") == 0) goto in_end;
    if (tty_buf[2] == '\0')
	if (tty_buf [0] == '.') goto in_end;
    modified = TRUE;
    strcpy (gap_start,tty_buf);
    gap_start=gap_start+strlen(tty_buf);
in_line:
    fgets(tty_buf, MAXLINE, stdin);
    goto in_loop;

in_ovfl:
    printf ("The buffer has overflowed.  Sorry...\n");

in_end:
    find_line (gap_start-buf-1, &li, &le);
    skipline = TRUE;
    return;
}
/***
 *	delete ()
 *
 *	deletes given lines.
 *
 */
delete()
{
    if (!defaults(li,le)) return;	/* default is .,. */

    modified = TRUE;
    move_gap (lle+1);
    gap_start = buf+fli;	/* gobble text into the gap */
    find_line(fli,&li,&le);	/* go to line after deleted text */

    if ((buffer_end - buf) - (gap_end - gap_start) <= 0)
	valid_path = FALSE;

    return;
}
/***
 *	linenum ()
 *
 *	linenum () - print out line number of addressed line.
 *
 */
linenum()
{
    register int j;
    register char *sp, *endp;

    if (!defaults(li,le)) return;	/* default is .,. */

    find_line(lle,&li,&le);
    if (gap_start <= buf+lle)
	move_gap (lle+1);		/* get gap out of the way */

    endp = buf + lle;
    for (j=0,sp=buf;sp<=endp;sp++) {
	if (*sp == NL)
	    j++;
    }

    printf ("%d\n", j);
    return;
}
/***
 *	nothing ()
 *
 *	nothing - Do nothing.  (used to set address only)
 *
 */
nothing()
{
    if (!flsw) return;		/* No addresses, forget it! */
    if (!defaults(li, le)) return; /* defaults to .,. */
    find_line (lle, &li, &le);
    return;
}
/***
 *	comment ()
 *
 *	comment request.  Do nothing and trash line.
 *
 */
comment()
{
    skipline = TRUE;		/* trash line */
    if (!flsw) return;
    if (!defaults(li, le)) return;
    find_line (lle, &li, &le);
    return;
}
/***
 *	status ()
 *
 *	status request.  Print out the buffer status.
 *
 */
status()
{
    if (valid_path)		/* pathname set? */
	printf ("Pathname: %s\n", file_name);
    else
        printf ("No pathname set.\n");

    if (modified)
        printf ("(Modified)\n");

    if (untrusted && valid_path)
	printf ("(Untrusted)\n");
    return;
}
/***
 *	db()
 *
 *	debug request.  Set debugging level.
 *
 */
db()
{
    Debug = atoi(&tty_buf[ti]);
    skipline = TRUE;
    if (Debug <= 0)
	Debug = 1;
}
/***
 *	readf ()
 *
 *	readf - read a file into buffer.
 *
 */
readf()
{
    FILE *fp;
    int ife, nread, rbufl;

    while (tty_buf[ti]== ' ')
	ti++;
    if (te - ti > 0) {		/* file name given? */
	if (te - ti > 167) {		/* check file name size */
	    tty_buf[ti+167] = '\0';	/* force length */
	}
	else {
	    tty_buf[te] = '\0';		/* eliminate NL */
	}
	strcpy (file_name,&tty_buf[ti]);
    }
    else {
	if (!valid_path) {
	    printf ("No pathname set.\n");
	    skipline = TRUE;
	    return;
	}
    }

    fp = fopen (file_name, "r");
    if (fp == NULL) {
	printf ("Unable to open %s\n", file_name);
	valid_path = FALSE;
	skipline = TRUE;
	return;
    }

    valid_path = TRUE;

    ife = (buffer_end - buf) - (gap_end - gap_start);
    if (ife <= 0) modified = FALSE;
    else modified = TRUE;

    if (!flsw) fle = ife-1;		/* r defaults to ($)r */

    move_gap (fle + 1);			/* put gap right after address */

    for (;;) {				/* read loop */
	rbufl = ((gap_end - gap_start) < 16384) ? gap_end - gap_start : 16384;	/* take min(16384, gap_end - gap_start) */
	if (rbufl < 512) goto read_overflow;
	if (fgets (gap_start, 512, fp) == NULL) goto reof;
	nread = strlen (gap_start);

	li = gap_start - buf;
	gap_start += nread;
	le = gap_start - buf;
    }

read_overflow:
    printf ("The buffer has overflowed.  Sorry...\n");
    valid_path = FALSE;

reof:
    fclose (fp);
    find_line (gap_start - buf - 1, &li, &le);
    if (modified) untrusted = TRUE;
    skipline = TRUE;
    return;
}
/***
 *	writef ()
 *
 *	writef - Write specified lines to file.
 *
 */
writef()
{
    register char *endp, *sp;
    FILE *fp;


    if (reqch == 'W') untrusted = FALSE;	/* force write request */

    if (!defaults (0, (buffer_end - buf) - (gap_end - gap_start)-1)) return;	/* defaults to (1,$) */

    while (tty_buf[ti] == ' ')
	ti++;
    if (te - ti > 0) {		/* file name given? */
	if (te - ti > 167) {		/* check file name size */
	    tty_buf[ti+167] = '\0';	/* force length */
	}
	else {
	    tty_buf[te] = '\0';		/* eliminate NL */
	}
	strcpy (file_name,&tty_buf[ti]);
    }
    else if (!valid_path) {
	printf ("No pathname set.\n");
	skipline = TRUE;
	return;
    }
    else if (untrusted) {
	printf ("Untrusted pathname.  W forces.\n");
	skipline = TRUE;
	return;
    }

    fp = fopen (file_name, "w");
    if (fp == NULL) {
	printf ("Cannot open file.\n");
	valid_path = FALSE;
	skipline = TRUE;
	return;
    }

    valid_path = TRUE;

    if (gap_start <= buf + lle) move_gap (lle+1);

    endp = buf + lle + 1;
    for (sp=buf+fli;sp <= buf+lle;)
	putc (*sp++,fp);

    fclose (fp);
    modified = FALSE;
    untrusted = FALSE;
    skipline = TRUE;
    return;

}
/***
 *	subst()
 *
 *	subst - implement substitute request.
 *
 */
subst()
{
    char ch;
    int i,l,l1,l2,l3,l4,len;
    char *sp, *dp;
    int code, uparrow_flag, dollar_flag, subst_flag;

    if (!defaults (li, le)) return;
    ch = tty_buf[ti++];
    for (i=ti;i<=te;i++) {
	if (tty_buf[i] == ch) goto subst_found;
	if (tty_buf[i] == '\\') i++;
    }

s_err:
    printf ("Invalid syntax in substitute request.\n");
    skipline = TRUE;
    return;

subst_found:
    l = i - ti;				/* length of search string */
    l3 = i + 1;				/* start of replacement. */

    for (l4=l3;l4<=te;l4++) {
	if (tty_buf[l4] == ch) goto last_delim;
	if (tty_buf[l4] == '\\') l4++;
    }
    goto s_err;

last_delim:
    subst_flag = FALSE;			/* no substitutes yet */

    for (;;) {				/* substitute loop */
	search_file (tty_buf, ti, l, fli, lle, &l1, &l2, &uparrow_flag, &dollar_flag, &code);
	l = 0;				/* use canned exp next time */
	if (code != 0) break;

	modified = TRUE;
	move_gap (l1);			/* put gap before match */
	for (i=l3;i < l4;i++) {
	    if (tty_buf[i] == '&') {
		if ((gap_end - gap_start) - (l2 - l1 + 1) < 512) goto sub_ovfl;
		for (len=l2-l1+1,sp=gap_end,dp=gap_start;len-- > 0;sp++,dp++)
			*dp = *sp;				/* move old string */
		gap_start += l2 - l1 + 1;
		lle += l2 - l1 + 1;
	    }
	    else {
		if (tty_buf[i]=='\\') i++;
		*gap_start++ = tty_buf[i];
		if (gap_end - gap_start < 512) goto sub_ovfl;
		lle++;
	    }
	}
	gap_end += l2 - l1 + 1;
	lle -= l2 - l1 + 1;
	fli = gap_start - buf;

	if (uparrow_flag) {
		if (fli <= 1 || buf[fli-1] == NL) fli++;	/* skip newline */
	}
	else if (dollar_flag) {
	    fli++;
	}
	else if (l2 < l1) {
	    fli++;
	}

	subst_flag = TRUE;
    }

    if (code == 2) {
	skipline = TRUE;
	return;
    }

    if (!subst_flag) {
	if (reqch != 'S')
		printf ("Substitute failed.\n");
	skipline = TRUE;
	return;
    }

    ti = l4 + 1;
    find_line (lle, &li, &le);
    return;

sub_ovfl:
    printf ("The buffer has overflowed.  Sorry...\n");
    skipline = TRUE;
    return;
}
/***
 *	global ()
 *
 *	global - Perform an action on a selection of lines
 *
 */
global()
{
    int i,j,l,l1,l2,l3;
    int uparrow_flag,dollar_flag,code;
    char ch, delim;

    if (!defaults (0, (buffer_end - buf) - (gap_end - gap_start)- 1)) return;
    ch = tty_buf[ti++];

    if (ch != 'p' && ch != 'd' && ch != '=') {
gb_err:
	printf ("Syntax error in global request.\n");
	skipline = TRUE;
	return;
    }

    delim = tty_buf[ti++];
    if (delim == NL) goto gb_err;

    for (l3=ti; ti<=te; ti++) {
	if (tty_buf[ti] == delim) goto gb_found;
	if (tty_buf[ti] == '\\') ti++;
    }

    goto gb_err;

gb_found:
    l = ti - l3;
    ti++;
    j = 1;		/* line counter */
    if (ch != 'd') {	/* move gap at only one place */
	move_gap (lle+1);

	if (ch == '=') {
	    for (i=0;i < fli;i++)
		if (buf[i] == NL) j++;
	}
    }

    while (fli <= lle) {
	le = index_nl (fli, (lle-fli+1));
	if (le == -1) le = lle;
	else le = fli + le;

	search_file (tty_buf, l3, l, fli, le, &l1, &l2, &uparrow_flag, &dollar_flag, &code);
	l = 0;					/* use default next time */
	if (code > 1) goto gb_quit;
	if ((reqch == 'g' && code == 0) || (reqch == 'v' && code != 0)) {
	     if (ch == 'p') {
		while (fli <= le) {
		   putchar (buf[fli++]);
		}
	    }
	    else if (ch == 'd') {
		move_gap (le + 1);
		lle -= (gap_start - buf - fli);
		gap_start = fli + buf;			/* gobble up text */
		modified = TRUE;
	    }
	    else {
		printf ("%d\n", j);
	        fli = le + 1;
	    }
	}
	else {
	   fli = le + 1;
	}

	j++;
    }

gb_quit:
    find_line (lle, &li, &le);

    if (buffer_end - buf - (gap_end - gap_start) <= 0) valid_path = FALSE;
    return;
}
