/*
BEGIN DOCUMENTATION

Name: TCMWRD.C					Created: 02/07/84  DTS
					    Last Update: 05/03/84
Title: Text collection management word editing functions.

Index:

Abstract: Implements word orientated keypad functions of TCM system.  
	  All functions have same basic format.

Usage: coutptr = func(cinptr);

Parameters: cinptr  - pointer to current character in fixed line buffer.
    	    coutptr - pointer to new current character after function applied.

	    Note: Many routines use and change global editing parameters
		  defined in TCMPUBLIC.H.


Environment: DECUS C, RSX11M V4.0

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

Description: wordlf - Move cursor left word
	     wordrt - Move cursor right word
	     dewdlf - Delete word to the left of the cursor
	     dewdrt - Delete word right
	     deline - Delete line cursor is on
	     inline - Insert blank line at cursor line
	     undelt - Undelete last word or line deleted.

Example(s):

Uses:

Internal: Note: delbuf[] stores deleted line or word, '\r' indicates a
		line delete was done & '\n' marks a line break as part of
		a word or character delete.

Update History: 03/07/84 - DTS	Added call to padchr to instring.

END DOCUMENTATION
*/

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

/* external data references */

extern char wrddel[];		/* String of word terminating characters */
extern int linevir;		/* Displayable chars on current line (TCMSCRN) */

/* external function references */

extern char *index();
extern rfline();

extern charpointer csleft();
extern charpointer csdown();
extern charpointer dechrt();
extern charpointer inewln();

/* forward references */

extern boolean inword();	/* Returns true if character is not a word terminator */
extern delchrs();		/* Delete characters from current line */
extern instring();		/* Insert string in current line */

/***	WORDLF: Move cursor left word, if at start backup line    ***/

charpointer
wordlf(chr)
    register charpointer chr;
{
	iff chr-line > lin[0].len then	/* Beyond end of line */
	{
	    chr = &line[lin[0].len - 1];
	    *chr = eos;
	    bufcol = virlen(line) + 1;
	}
	else iff bufcol == 1 then
	    chr = csleft(chr);
	else
	{
	    bufcol--; chr--;	/* Backup char, assumes no enhancements */
	    while(! inword(*chr) and bufcol > 0)
		{ bufcol--; chr--; }	/* Backup until inword */
	    while( inword(*chr) and bufcol > 0)
		{ bufcol--; chr--; }	/* Backup until not inword */
	    bufcol++; chr++;		/* Advance to next character */
	}
	return(chr);
} /* end wordlf */



/***	WORDRT: Move cursor right word, if at end advance line    ***/

charpointer
wordrt(chr)
    register charpointer chr;
{
    register charpointer linend;

	linend = &line[lin[0].len - 1];
	while(inword(*chr) and chr < linend)
	    { chr++; bufcol++; }		/* Advance until not in word */
	iff chr >= linend then 			/* At or beyond end */
	{
	    iff bufline < curwin->botline then
		{ bufcol = 1; chr = csdown(chr); }	/* Advance to next line */
	}
	else
	{	/* Advance character, assumes no enhancements */
	    while(! inword(*chr) and chr < linend)
		{ chr++; bufcol++; }		/* Advance until in word */
	}
	return(chr);
} /* end wordrt */



/***	DEWDRT:  Delete word right    ***/

charpointer
dewdrt(chr)
    register charpointer chr;
{
    register charpointer nxt;
    register int	 oldcol;

	iff rdonly then
	{
	    tcmerr(TS_IKY);
	    return(chr);
	}
	iff (chr-line) >= (lin[0].len-1) then	/* At or beyond end of line */
	    { cpystr(delbuf,"\n"); chr = dechrt(chr); }
	else
	{
	    oldcol = bufcol;
	    nxt = wordrt(chr);		/* Point to start of next word */
	    iff bufcol == 1 then	/* Must have gone to next line */
		nxt = csleft(nxt);
	    bufcol = oldcol;
	    delchrs(chr,nxt-chr,delbuf); /* Remove from line, place in delbuf */
	}
	return(chr);
} /* end dewdrt */



/***     DEWDLF:  Delete word to the left of the cursor    ***/

charpointer
dewdlf(chr)
    register charpointer chr;
{
    register charpointer nxt;

	iff rdonly then
	{
	    tcmerr(TS_IKY);
	    return(chr);
	}
	iff bufcol == 1 then		/* At start of line */
	    nxt = deleft(chr);		/* Delete character left */
	else
	{
	    nxt = wordlf(chr);		/* Move word left first */
	    delchrs(nxt,chr-nxt,delbuf); /* Remove from line */
	}
	return(nxt);
} /* end dewdlf */



/***	DELINE: Delete line cursor is on    ***/

charpointer
deline(chr)
    register charpointer chr;
{
    register int oldcol;

	iff rdonly then
	{
	    tcmerr(TS_IKY);
	    return(chr);
	}
	chr = &line[lin[0].len-1];	/* Point to end */
	*chr++ = '\r';			/* Mark as a line */
	*chr = eos;
	cpystr(delbuf,line);		/* Save entire line to delete buffer */
	line[0] = eos;
	oldcol = bufcol;
	bufcol = lin[0].len = 1;	/* Kill entire line */
	linevir = 0;
	lin[0].fircol = newlin;
	iff curwin->botline > bufline then /* Stay here if last line */
	{
	    chr = csdown(line);
	    chr = deleft(line);
	    chr = deleft(chr);		/* Delete line in buffer */
	    bufcol = oldcol;
	}
	return(virchr(line,oldcol));
} /* end deline */



/***	inline:  Insert blank line at cursor line    ***/

charpointer
inline(chr)
    register charpointer chr;
{
    register charpointer nchr;
    register int oldcol;

	iff rdonly then
	{
	    tcmerr(TS_IKY);
	    return(chr);
	}
	oldcol = bufcol;
	bufcol = 1;		/* Cursor at start of new line */
	nchr = inewln(line);
	iff ret.cd == TS_SUC then
	    return(nchr);
	else
	    { bufcol = oldcol; return(chr); }
} /* end inline */



/***	UNDELT:  Undelete last deleted word or line.    ***/

charpointer
undelt(chr)
    register charpointer chr;
{
    register charpointer linend;
    register int	 oldcol;

	iff rdonly then
	{
	    tcmerr(TS_IKY);
	    return(chr);
	}
	iff (linend = index(delbuf,'\r')) != NULL then	/* Undelete line */
	{
	    oldcol = bufcol;
	    *linend = eos;
	    iff (bufline < curwin->botline) or (lin[0].len > 1) then
	        chr = inline(chr);		/* Insert blank line */
	    else
	    {
		linevir = virlen(delbuf);
		lin[0].fircol = newlin;
	    }
	    iff ret.cd == TS_SUC then
	    {
		instring(line,delbuf);		/* Insert entire line */
		*linend = '\r';			/* Restore end marker */
		chr = virchr(line,oldcol);
	    }
	    bufcol = oldcol;
	}
	else iff delbuf[0] == '\n' then		/* Insert line break */
	    chr = inewln(chr);
	else
	{
	    instring(chr,delbuf);		/* Insert word at chr */
	    rfline(bufcol,chr-line,lin[0].len+1); /* Update screen pointers */
	}
	return(chr);
} /* end undelt */



/***	INWORD: Return false if character is a word terminator    ***/

inword(ch)
    register char ch;
{
    register charpointer ptr;

	for(ptr = wrddel; *ptr != eos; ptr++)
	    iff *ptr == ch then break;
	iff *ptr == eos then
	    return(true);
	else
	    return(false);
} /* end inword */



/***	INSTRING: Insert string into current line buffer    ***/
/*		  wrap if line is too long for margins	      */

instring(ptr,strg)
    register charpointer ptr,strg;
{
    register struct twindcb *win;
    register int slen;
    register charpointer linend;
	     char	 tempch;

	win = curwin;
	slen = strlen(strg);
	iff ptr >= &line[lin[0].len] then	/* pad with spaces */
	    padlin(ptr);
	iff ret.cd == TS_SUC then
	{
	    linend = &line[lin[0].len+1];
	    lin[0].len += slen;
	    linevir = virlen(strg) + virlen(line);
	    iff (linevir > win->width) and (win->botline+1 >= win->virt_lines) then
		tcmerr(TS_MCP);
	    else iff win->curmax + lin[0].len > win->max_chars then
		tcmerr(TS_BFP);
	    iff ret.cd != TS_SUC then	/* Undo everything */
	    {
		lin[0].len -= slen;
		linevir = virlen(line);
	    }
	    else
	    {
		moveup(ptr,ptr+slen,linend-ptr); /* Make room for string in line */
		tempch = *(ptr+slen);
		cpystr(ptr,strg);		 /* Insert string */
		*(ptr+slen) = tempch;
		iff virlen(line) > curwin->width then
		    wrapln(ptr);
	    }
	}
} /* end instring */



/***	DELCHRS: Remove characters from current line buffer    ***/

delchrs(ptr,cnt,cutptr)
    register charpointer ptr;		/* Pointer into line[] */
    charpointer cutptr;			/* Pointer to save buffer */
    register int cnt;			/* Number of actual chars to delete */
{	
    register charpointer linend,chrend;
    char	 tempch;

	linend = &line[lin[0].len-1];	/* End of line */
	iff linend - ptr < cnt then	/* Cnt is actual chars, not displayable only */
	    cnt = linend - ptr;
	iff cnt > 0 then
	{
	    chrend = ptr + cnt;
	    tempch = *chrend;
	    *chrend = eos;
	    cpystr(cutptr,ptr);		/* Save chars to delbuf */
	    *chrend = tempch;
	    movedn(chrend,ptr,linend-chrend);	/* Close line cnt characters */
	    rfline(bufcol,ptr-line,lin[0].len);	/* Update screen pointers */
	    lin[0].len -= cnt;
	    linevir -= virlen(cutptr);
	}
} /* end delchrs */



/***	WRAPLN: Wrap current line in line[] buffer, too long    ***/

wrapln(chr)
    register charpointer chr;
{
    register int oldcol;

	oldcol = bufcol;
	chr = inewln(chr);		/* Temporary call other functions */
	iff ret.cd == TS_SUC then
	    { bufcol = 1; chr = csdown(line); }
	iff ret.cd == TS_SUC then
	    chr = deleft(chr);
	bufcol = oldcol;
} /* end wrapln */
