
/*
 * TEXT1.C
 *
 *	(C)Copyright 1987 by Matthew Dillon,	All Rights Reserved
 */

#include "defs.h"

#define nomemory()  {memoryfail = 1;}

char RecallBuf[256];

text_init()
{
    register ED *e;
    long dirlock;

    text_switch(NULL);
    dirlock = E.dirlock;
    e = (ED *)allocb(sizeof(ED));
    if (e == NULL)
	return(0);
    bzero(&E, sizeof(E));
    E.Win = Win;
    if (Ep) {
	E.Insertmode = Ep->Insertmode;
	E.Tabstop    = Ep->Tabstop;
	E.Wordwrap   = Ep->Wordwrap;
    } else {
	E.Insertmode = 1;
	E.Tabstop = 4;
    }
    E.Lines = 1;
    E.Maxlines = 32;
    E.List = (ubyte **)allocl(E.Maxlines);
    E.List[0] = allocb(1);
    E.List[0][0] = Current[0] = Clen = 0;
    E.BSline = E.BEline = -1;
    E.IWiny = 16;
    E.dirlock = dirlock;	/* workbench support	*/
    *e = E;
    llink(&Base, e);
    strcpy(E.Name, "unnamed");
    Ep = e;
    text_cursor(1);
    return(1);
}


text_switch(win)
WIN *win;
{
    register ED *e;
    register ED *next, **prev;

    if (win)
	text_sync();
    if (Ep) {
	E.next = Ep->next;
	E.prev = Ep->prev;
	strcpy(E.Wtitle, Ep->Wtitle);
	*Ep = E;
    }
    if (win) {
	for (e = Base; e; e = e->next) {
	    if (e->Win == win) {
		Ep = e;
		Win = win;
		Rp = Win->RPort;
		E = *e;
		text_load();
		return(1);
	    }
	}
	return(0);
    }
}


text_sync()
{
    char redraw = 0;
    short len;
    ubyte *ptr;

    for (len = strlen(Current) - 1; len >= 0 && Current[len] == ' '; --len)
	Current[len] = '\0';
    Clen = len + 1;
    if (!Comlinemode) {
	if (strlen(E.List[E.Line]) != Clen) {
	    if (ptr = allocb(Clen+1)) {
		E.Modified = 1;
		Overide = 0;
		FreeMem(E.List[E.Line], strlen(E.List[E.Line])+1);
		E.List[E.Line] = ptr;
	    } else {
		nomemory();
		strcpy(Current, E.List[E.Line]);
		Clen = strlen(Current);
	    }
	} else {
	    if (strcmp(E.List[E.Line], Current)) {
		E.Modified = 1;
		Overide = 0;
	    }
	}
	strcpy(E.List[E.Line], Current);
    }
    if (Nsu == 0) {
	if (E.Column - E.Topcolumn >= Columns || E.Column < E.Topcolumn) {
	    redraw = 1;
	    E.Topcolumn = E.Column - (Columns>>1);
	    if (E.Topcolumn < 0)
		E.Topcolumn = 0;
	}
	if (E.Line - E.Topline >= Rows || E.Line < E.Topline) {
	    redraw = 1;
	    E.Topline = E.Line - (Rows>>1);
	    if (E.Topline < 0)
		E.Topline = 0;
	}
    }
    while (E.Column > Clen)
	Current[Clen++] = ' ';
    Current[Clen] = '\0';
    if (redraw)
	text_redisplay();
    return((int)redraw);
}

text_load()
{
    if (Comlinemode)
	return(0);
    strcpy(Current, E.List[E.Line]);
    Clen = strlen(Current);
    while (E.Column > Clen)
	Current[Clen++] = ' ';
    Current[Clen] = '\0';
}

text_colno()
{
    return(E.Column);
}

text_lineno()
{
    return(E.Line+1);
}

text_lines()
{
    return(E.Lines);
}

text_cols()
{
    return((int)Clen);
}

text_imode()
{
    return(E.Insertmode);
}

text_tabsize()
{
    return((int)E.Tabstop);
}

ubyte *
text_name()
{
    return(E.Name);
}


text_uninit()
{
    register int i;
    register ED *e;

    for (i = 0; i < E.Lines; ++i)
	FreeMem(E.List[i], strlen(E.List[i])+1);
    FreeMem(E.List, E.Maxlines * sizeof(char *));

    lunlink(Ep);
    FreeMem(Ep, sizeof(ED));
    if (Base) {
	E = *Base;
	Ep= Base;
	text_load();
    } else {
	Ep = NULL;
    }
}

inversemode(n)
{
    if (n) {
	SetAPen(Rp, 3);
	SetDrMd(Rp, JAM2|INVERSVID);
    } else {
	SetAPen(Rp, 1);
	SetDrMd(Rp, JAM2);
    }
}

text_cursor(n)
{
    movetocursor();
    inversemode(n);
    if (Current[E.Column])
	Text(Rp, Current+E.Column, 1);
    else
	Text(Rp, " ", 1);
    inversemode(0);
}


text_position(col, row)
{
    text_sync();
    if (col == 0)
	col = -1;
    E.Column = E.Topcolumn + col;
    if (E.Column > 254)
	E.Column = 254;
    if (E.Column < 0)
	E.Column = 0;
    E.Line = E.Topline + row;
    if (E.Line >= E.Lines)
	E.Line = E.Lines - 1;
    if (E.Line < 0)
	E.Line = 0;
    text_load();
    text_sync();
}


text_displayseg(start, n)
{
    register short i, c;
    register ubyte *ptr;
    char ib;

    if (Nsu)
	return(0);
    for (i = start; i < start+n && E.Topline + i < E.Lines; ++i) {
	if (Comlinemode) {
	    if (E.Topline + i != E.Line)
		continue;
	    ptr = Current;
	} else {
	    ptr = E.List[E.Topline + i];
	}
	for (c = E.Topcolumn; c && *ptr; ++ptr, --c);
	c = strlen(ptr);
	if (c) {
	    Move(Rp, COLT(0), ROWT(i));
	    Text(Rp, ptr, (c > Columns) ? Columns : c);
	}
    }
}

text_redisplay()
{
    if (Nsu)
	return(0);
    SetAPen(Rp, 0);
    if (Comlinemode)
	RectFill(Rp, COL(0), ROW(Rows-1), Xbase+Xpixs, Ybase+Ypixs);
    else
	RectFill(Rp, Xbase, Ybase, Xbase + Xpixs, Ybase + Ypixs);
    SetAPen(Rp, 1);
    text_displayseg(0,Rows);
}

text_redisplaycurrline()
{
    int row = E.Line - E.Topline;

    if (Nsu)
	return(0);
    SetAPen(Rp, 0);
    RectFill(Rp, COL(0), ROW(row), Xbase+Xpixs, ROW(row+1)-1);
    SetAPen(Rp, 1);
    text_displayseg(row, 1);
}

text_write(str)
ubyte *str;
{
    short len = strlen(str);
    short i;

    if (Clen + len >= 255) {
	text_sync();
	text_load();
    }
    if (E.Insertmode == 0) {
	i = len;
	if (E.Column + len < 255) {
	    bmov(str, Current + E.Column, len);
	    if (E.Column + len >= Clen)
		Clen = E.Column + len;
	    Current[Clen] = 0;
	    goto bin;
	}
	goto ok;
    }
    if (Clen + len < 255) {
	bmov(Current + E.Column, Current + E.Column + len, Clen+1-E.Column);
	bmov(str, Current + E.Column, len);
	Clen += len;
	ScrollRaster(Rp, -len * Xsize, 0 ,
		COL(E.Column - E.Topcolumn), ROW(E.Line - E.Topline),
		COL(Columns) - 1, ROW(E.Line - E.Topline + 1) - 1
	);
	i = (E.Column - E.Topcolumn + len > Columns) ? Columns - E.Column + E.Topcolumn : len;
bin:
	Move(Rp, COLT(E.Column - E.Topcolumn), ROWT(E.Line - E.Topline));
	Text(Rp, str, i);
	E.Column += len;
	if (E.Column - E.Topcolumn >= Columns)
	    text_sync();
    }
ok:
    if (Comlinemode == 0 && E.Wordwrap)
	do_reformat(0);
}


do_up()
{
    if (E.Line) {
	text_sync();
	--E.Line;
	text_load();
	if (E.Line < E.Topline) {
	    if (Nsu == 0) {
		ScrollRaster(Rp,0,-Ysize,COL(0),ROW(0),COL(Columns)-1,ROW(Rows)-1);
		--E.Topline;
		text_displayseg(0, 1);
	    }
	}
    } else {
	Abortcommand = 1;
    }
}

do_scrolldown()
{
    if (E.Topline + Rows < E.Lines) {
	if (Nsu == 0) {
	    text_sync();
	    ScrollRaster(Rp,0,Ysize,COL(0),ROW(0),COL(Columns)-1,ROW(Rows)-1);
	    ++E.Topline;
	    ++E.Line;
	    text_load();
	    text_displayseg(Rows-1, 1);
	}
    } else {
	Abortcommand = 1;
    }
}

do_scrollup()
{
    if (E.Topline) {
	if (Nsu == 0) {
	    text_sync();
	    ScrollRaster(Rp,0,-Ysize,COL(0),ROW(0),COL(Columns)-1,ROW(Rows)-1);
	    --E.Topline;
	    --E.Line;
	    text_load();
	    text_displayseg(0, 1);
	}
    } else {
	Abortcommand = 1;
    }
}

do_down()
{
    if (E.Line + 1 < E.Lines) {
	text_sync();
	++E.Line;
	text_load();
	if (E.Line - E.Topline >= Rows) {
	    if (Nsu == 0) {
		ScrollRaster(Rp,0,Ysize,COL(0),ROW(0),COL(Columns)-1,ROW(Rows)-1);
		++E.Topline;
		text_displayseg(Rows-1, 1);
	    }
	}
    } else {
	Abortcommand = 1;
    }
}

/*
 *  PAGEUP
 *  PAGEDOWN
 *  PAGESET n	(n = 0 to 100 for percentage of #rows to scroll, minimum 1)
 *		can be > 100.
 */

do_page()
{
    register int n, multiplier = 1;
    static short pctg = 80;

    switch(av[0][4]) {
    case 'u':
	multiplier = -1;
    case 'd':
	n = multiplier * Rows * pctg / 100;
	if (!n)
	    n = multiplier;
	if (n > 0 && E.Topline >= E.Lines - Rows)
	    return(0);
	text_sync();
	E.Line += n;
	E.Topline += n;
	if (E.Line >= E.Lines)
	    E.Line = E.Lines - 1;
	if (E.Line < 0)
	    E.Line = 0;
	if (E.Topline >= E.Lines)
	    E.Topline = E.Lines - Rows - 1;
	if (E.Topline < 0)
	    E.Topline = 0;
	text_load();
	if (!text_sync())
	    text_redisplay();
	break;
    case 's':
	pctg = atoi(av[1]);
	break;
    }
}


do_downadd()
{
    ubyte *ptr;

    if (E.Line + 1 == E.Lines) {
	E.Modified = 1;
	if (makeroom(32) && (ptr = allocb(1))) {
	    E.List[E.Lines] = ptr;
	    *ptr = 0;
	    ++E.Lines;
	} else {
	    nomemory();
	}
    }
    do_down();
}


do_left()
{
    if (E.Column) {
	--E.Column;
	if (E.Column < E.Topcolumn)
	    text_sync();
    } else {
	Abortcommand = 1;
    }
}

do_right()
{
    if (E.Column != 254) {
	if (Current[E.Column] == 0) {
	    Current[E.Column] = ' ';
	    Current[E.Column+1]= '\0';
	    ++Clen;
	}
	++E.Column;
	if (E.Column - E.Topcolumn >= Columns)
	    text_sync();
    } else {
	Abortcommand = 1;
    }
}

do_tab()
{
    register short n;

    for (n = E.Tabstop-(E.Column % E.Tabstop); n > 0; --n)
	do_right();
}

do_backtab()
{
    register short n;

    n = E.Column % E.Tabstop;
    if (!n)
	n = E.Tabstop;
    for (; n > 0; --n)
	do_left();
}

do_return()
{
    ubyte buf[256];
    char *partial;

    if (Comlinemode) {
	strcpy(buf, Current);
	strcpy(RecallBuf, Current);
	partial = Partial;
	Partial = NULL;
	escapecomlinemode();
	if (partial) {
	    if (do_command(buf))
		do_command(partial);
	    free(partial);
	} else {
	    do_command(buf);
	}
    } else {
	E.Column = 0;
	text_sync();
	do_downadd();
    }
}

do_bs()
{
    if (E.Column) {
	bmov(Current + E.Column, Current + E.Column - 1, Clen - E.Column + 1);
	--E.Column;
	--Clen;
	if (E.Column < E.Topcolumn) {
	    text_sync();
	} else {
	    ScrollRaster(Rp, Xsize, 0,
		COL(E.Column - E.Topcolumn),
		ROW(E.Line   - E.Topline),
		COL(Columns)-1,
		ROW(E.Line - E.Topline + 1)-1
	    );
	    if (Clen >= E.Topcolumn + Columns) {
		Move(Rp, COLT(Columns-1), ROWT(E.Line - E.Topline));
		Text(Rp, Current + E.Topcolumn + Columns - 1, 1);
	    }
	}
	if (Comlinemode == 0 && E.Wordwrap)
	    do_reformat(0);
    } else {
	Abortcommand = 1;
    }
}


/*
 * esc, escimm
 */

int Savetopline, Savecolumn, Savetopcolumn;

do_recall()
{
    av[0] = (ubyte *)"escimm";
    av[1] = (ubyte *)RecallBuf;
    do_esc();
}

do_esc()
{
    if (Comlinemode)
	return(escapecomlinemode());
    text_sync();
    if (av[0][3] == 'i')
	strcpy(Current, av[1]);
    else
	Current[0] = 0;
    Clen = strlen(Current);
    Comlinemode = 1;
    returnoveride(1);
    Savetopline = E.Topline;
    Savecolumn	= E.Column;
    Savetopcolumn = E.Topcolumn;
    E.Column	= Clen;
    E.Topcolumn = 0;
    E.Topline	= E.Line - Rows + 1;
    SetAPen(Rp, 0);
    RectFill(Rp, COL(0), ROW(Rows-1), Xbase+Xpixs, Ybase+Ypixs);
    SetAPen(Rp, 1);
    Move(Rp, COL(0), ROW(Rows-1) - 1);
    Draw(Rp, Xbase + Xpixs, ROW(Rows-1) - 1);
    text_displayseg(Rows-1,1);
}


escapecomlinemode()
{
    if (Partial) {
	free(Partial);
	Partial = NULL;
    }
    if (Comlinemode) {
	strcpy(RecallBuf, Current);
	Comlinemode = 0;
	returnoveride(0);
	E.Topline = Savetopline;
	E.Column  = Savecolumn;
	E.Topcolumn = Savetopcolumn;
	text_load();
	SetAPen(Rp, 0);
	RectFill(Rp, COL(0), ROW(Rows-1)-1, Xbase+Xpixs, Ybase+Ypixs);
	SetAPen(Rp, 1);
	text_displayseg(Rows-2,2);
    }
}


do_del()
{
    if (Current[E.Column]) {
	bmov(Current + E.Column + 1, Current + E.Column, Clen - E.Column);
	--Clen;
	ScrollRaster(Rp, Xsize, 0,
	    COL(E.Column - E.Topcolumn),
	    ROW(E.Line - E.Topline),
	    COL(Columns)-1,
	    ROW(E.Line - E.Topline + 1) - 1
	);
	if (Clen >= E.Topcolumn + Columns) {
	    Move(Rp, COLT(Columns-1), ROWT(E.Line-E.Topline));
	    Text(Rp, Current+E.Topcolumn+Columns-1, 1);
	}
	if (Comlinemode == 0 && E.Wordwrap)
	    do_reformat(0);
    }
}

do_top()
{
    text_sync();
    E.Line = 0;
    text_load();
    text_sync();
}

do_bottom()
{
    text_sync();
    E.Line = E.Lines - 1;
    text_load();
    text_sync();
}

do_firstcolumn()
{
    if (E.Column) {
	E.Column = 0;
	text_sync();
    }
}

do_firstnb()
{
    for (E.Column = 0; Current[E.Column] == ' '; ++E.Column);
    if (Current[E.Column] == 0)
	E.Column = 0;
    text_sync();
}

do_lastcolumn()
{
    short i;

    text_sync();
    i = (Comlinemode) ? Clen : strlen(E.List[E.Line]);
    if (i != E.Column) {
	E.Column = i;
	text_sync();
    }
}

/*
 * GOTO [+/-]N
 * GOTO BLOCK	start of block
 * GOTO START	start of block
 * GOTO END	end of block
 */

do_goto()
{
    register short n, i;
    register ubyte *ptr = av[1];

    i = 0;
    n = -1;

    switch(*ptr) {
    case 'b':
    case 's':
    case 'B':
    case 'S':
	n = E.BSline;
	break;
    case 'e':
    case 'E':
	n = E.BEline;
	break;
    case '+':
	i = 1;
    case '-':
	n = E.Line;
    default:
	n += atoi(ptr+i);
    }
    if (n >= E.Lines)
	n = E.Lines - 1;
    if (n < 0)
	n = 0;
    text_sync();
    E.Line = n;
    text_load();
    text_sync();
}

do_screentop()
{
    text_sync();
    E.Line = E.Topline;
    text_load();
    text_sync();
}

do_screenbottom()
{
    text_sync();
    E.Line = E.Topline + Rows - 1;
    if (E.Line < 0 || E.Line >= E.Lines)
	E.Line = E.Lines - 1;
    text_load();
    text_sync();
}

static ubyte Fstr[256];
static ubyte Rstr[256];
static short Srch_sign;
static char Doreplace;

/*
 * findstr, repstr
 */

do_findstr()
{
    if (av[0][0] == 'f')
	strcpy(Fstr, av[1]);
    else
	strcpy(Rstr, av[1]);
}

/*
 * findr, nextr, prevr
 */

do_findr()
{
    Doreplace = 1;
    Srch_sign = 1;
    switch(av[0][0]) {
    case 'f':
	strcpy(Fstr, av[1]);
	strcpy(Rstr, av[2]);
	break;
    case 'p':
	Srch_sign = -1;
	break;
    }
    search_operation();
}

/*
 * find, next, prev
 */

do_find()
{
    Doreplace = 0;
    Srch_sign = 1;
    switch(av[0][0]) {
    case 'f':
	strcpy(Fstr, av[1]);
	break;
    case 'p':
	Srch_sign = -1;
	break;
    }
    search_operation();
}


void
search_operation()
{
    int flen = strlen(Fstr);
    int rlen = strlen(Rstr);
    char senabled = 0;
    register ubyte *ptr;
    register int i, col;

    text_sync();
    if (!flen) {
	title("No find pattern");
	Abortcommand = 1;
	return;
    }

    col = E.Column;
    if (col >= strlen(E.List[E.Line]))
	col = strlen(E.List[E.Line]);
    for (i = E.Line;;) {
	ptr = E.List[i];
	if (Srch_sign > 0) {
	    while (ptr[col]) {
		if (Fstr[0] == ptr[col] &&
		strncmp(Fstr,ptr+col,flen) == 0 &&
		senabled) {
		    goto found;
		}
		senabled = 1;
		++col;
	    }
	    senabled = 1;
	    if (++i >= E.Lines)
		break;
	    col = 0;
	} else {
	    while (col >= 0) {
		if (Fstr[0] == ptr[col] &&
		strncmp(Fstr,ptr+col,flen) == 0 &&
		senabled) {
		    goto found;
		}
		senabled = 1;
		--col;
	    }
	    senabled = 1;
	    if (--i < 0)
		break;
	    col = strlen(E.List[i]);
	}
    }
    title("Pattern Not Found");
    Abortcommand = 1;
    return;

found:
    E.Line = i;
    E.Column = col;

    text_load();
    if (Doreplace) {
	if (rlen > flen && rlen-flen+strlen(ptr) > 254) {
	    title("Replace: Line Too Long");
	    Abortcommand = 1;
	    return;
	}
	if (Clen-col-flen >= 0) {
	    bmov(Current+col+flen, Current+col+rlen, Clen-col-flen+1);
	    bmov(Rstr, Current+col, rlen);
	    Clen += rlen-flen;
	}
	text_sync();
	text_redisplaycurrline();
    } else {
	text_sync();
    }
}


