/*
BEGIN DOCUMENTATION

Name: TCMEDIT.C 				Created: 07/20/83  DTS.
					    Last Update: 05/21/84
Title: Text collection management edit subroutine.

Index:

Abstract: Implements "TCOLL" function of TCM system

Usage:

Parameters:


Environment: DECUS C, RSX11M V4.0

See Also: TCM.C, TCMTABLES.C, TCMEDFUNC.C, TCM.DOC

Description: Uses window buffer returned by fndwnd() to do editing in.
	     Loops adding characters & word - wrapping if nec. until
	     buffer is full or user presses a done editing key.

Example(s):

Uses:

Internal:

Update History: 01/19/84 DTS -	Changed use of srbuf fields including
				srbuf.opflag from single character
				to bit encoded character.
END DOCUMENTATION
*/

#include <clang.c>
#include <stdio.h>
#include <cx.h>
#include "tcmdefs.h"
#include "tcmerr.h"
#include "tcmpublic.h"
#include "tcmedopt.h"

/* External globals */

extern int timeout;	/* Defined in TCMINPUT module */
extern int linevir;	/* Defined in TCMSCRN module */

/* #define debug 0 */

/* Forward references */

extern padlin();

/***	Edit window on screen (TCOLL)    ***/

edit()
{
    register struct twindcb *win;
    register 	int c;
    register	char *nxt;
    boolean	funcall;
    funcpointer	edfun;

	/*** Initialize editing session ***/

	iff (win = fndwnd()) == NULL then	/* Set window from name */
	    { ret.cd = TE_NSW; return; }	/* exit edit if not found */
	curwin = win;
	c = (int) srbuf.opflag;
	coldisp = ifx (c & STATLIN) != 0 thenx true elsex false;
	rdonly = ifx (c & READOLY) != 0  thenx true elsex false;
	iff (c & INSRT) != 0 then insert = true;
	win->column = ifx srbuf.col > 0 thenx srbuf.col elsex win->width;
	c = ifx (srbuf.row > 0) and (srbuf.row < win->botline) thenx srbuf.row elsex win->botline;
	win->edline = fndlin(win->bufstart,win->bufend,c);
	iff (win->topline > c) or (win->topline + win->height <= c) then /* on screen */
	    win->topline = ifx (c -= win->height) > 0 thenx (c+1) elsex 1;
	c = virlen(win->edline) + 1;
	iff win->column > c then
	    win->column = c;
	errlvl = srbuf.virt_lines;
	timeout = srbuf.max_chars;
	attach(TLUN);			/* Attach terminal (TI:) for input */
	setout(win);			/* Init screen output */
	setscroll(top,bot);
	eddone = funcall = false;
	nxt = getlin(win->edline);	/* Init edit line */
	rdastinit(TLUN,RDFLAG);		/* Init read ast routine, input from TI: */

	/* Loop while editing window */

	/* Process all input before refreshing screen */
	repeat
	{
	    ret.cd = TS_SUC;
	    refresh();		/* Refresh screen if changed */
	    rfstat();
	    wtse(RDFLAG);	/* Wait for next input */
	    while((c = inchar()) != EOF)
	    {
		iff lin[vtlin].fircol == tempmsg then
		    lin[vtlin].fircol = newlin;
	    	ret.term = c;			/* Return last character */
		iff c == NULL then
		    { doo nothing; }
		else iff c >= 127 then
		{
		    funcall = true;		/* process function key */
		    edfun = edfunc[c-127];
		    nxt = (*edfun)(nxt);
		}
		else iff ! (rdonly) then
		{ /* Add character to line */
		    iff funcall != false then
		    {
			/*** commented out, not yet implemented
			nxt = insenhan(nxt);		* insert enhancements *
			***/
			funcall = false;		/* Once per line only */
		    }
		    rfline(bufcol,nxt-line,nxt-line);	/* Mark char on screen */
		    iff nxt >= &line[lin[0].len] then	/* pad with spaces */
			padlin(nxt);
		    iff insert then			/* make room for character */
		    {
			iff addchr() then
			    moveup(nxt,nxt+1, &line[lin[0].len]-nxt); 
			rfline(bufcol+1,nxt-line,lin[0].len - 1);	/* Redisplay to end */
		    }
		    else iff nxt == &line[lin[0].len-1] then
			addchr();			/* Increment line length */
		    iff ret.cd == TS_SUC then
		    	{ bufcol++; *nxt++ = c; }	/* not full, add char */ 
		    iff bufcol > (win->width + 1) then
		    	nxt = wdwrap(win);		/* Type past end, word wrap */
		    else iff linevir > win->width then
			nxt = inewln(nxt);		/* Insert overflow, insert new line */
		    iff linevir > win->width then	/* Must have filled buffer */
			nxt = deleft(nxt);		/* Undo character insert */
		}
		else tcmerr(TS_IKY);
	    }
	} untill(eddone));

	/* Terminate editing session */

	savlin(win);		/* Save current line */
	win->edlinnum = ret.bline = bufline;	/* Return line & column to caller */
	ret.bcol = bufcol;
	scerln(vtlin,1);
#ifdef debug
	sprintf(&temp,"Line = %d, Column = %d, Terminator = %d.",ret.bline,ret.bcol,ret.term);
	scout(vtlin,1,temp);
	scout(curline,curcol,NULL);
#endif
	rstout(win);		/* Clear output buffer */
	curwin = NULL;
	errlvl = 0;		/* Restored for other routines */
	detach(TLUN);		/* Detach terminal */
} /* end edit */



/***	Wrap last word on line to next line    ***/
    /*	Returns pointer to end of new line */
    /*	Changes curline, bufline, & bufcol globals */

charpointer
wdwrap(win)
    register struct twindcb *win;
{
    register charpointer cptr;
    register int c,i;

	for(c=0,cptr=line,i=-1; c < lin[0].len; c++)
	    iff *cptr++ == ' ' then i = c;
	cptr -= 2;				/* Last char on line */
	iff i < 0 then				/* Word too long for line */
	{
	    tcmerr(TS_WTL);
	    subchr(); bufcol--;			/* Delete added character */
	    *cptr = eos;
	    return(cptr);
	}
	iff !addlin() then
	{
	    subchr(); bufcol--;			/* buffer full, delete char */
	    *cptr = eos;
	    return(cptr);
	}
	line[i] = '\r';				/* mark end of first line */
	savlin(win);		/* Move line & partial word into buffer */
	iff i > lin[curline].len then
	    i = lin[curline].len;		/* (Should not happen!) Must be in current line */
	cptr =  win->edline + i;
	*cptr = eos;				/* Break line in two */
	lin[curline].len = strlen(win->edline) + 1;
	lin[curline].laschr = win->width;
	lin[curline].fircol = bufcol;
	lin[curline].firchr = lin[curline].len - 1;
	win->edline = ++cptr;
	iff curline < bot then
	{
	    curline++; 				/* Advance to new line */
	    inslin();				/* Insert line on screen */
	}
	else
	{
	    win->topline++;
	    scrlup();				/* scroll current window up */
	}
	bufline++;
	bufcol = virlen(win->edline) + 1;	/* Doesn't count enhanced chars */
	return(getlin(win->edline));		/* Restore 2nd half as new line */
} /* end wdwrap */



/***	PADLIN: When beyond end, Pad current line with spaces, extend to pointer    ***/

padlin(nxt)
    register charpointer nxt;
{
    register charpointer lnend;

	rfline(linevir+1,lin[0].len-1,lin[0].len);	/* Show new spaces on screen */
	lnend = &line[lin[0].len]; lnend--;
	while((nxt > lnend) and addchr())		/* pad with spaces */
	    *lnend++ = ' ';
	line[lin[0].len - 1] = eos;			/* Mark end of line */
} /* end padlin */
