/******************************************************************************

    MODUL
	$Id: cursor.c 1.1 1994/08/09 15:55:36 digulla Exp digulla $

    DESCRIPTION
	All routines that only move the cursor.

    NOTES

    BUGS

    TODO

    EXAMPLES

    SEE ALSO

    INDEX

    HISTORY
	04. Oct 1992	ada created
	$Log: cursor.c $
 * Revision 1.1  1994/08/09  15:55:36  digulla
 * Initial revision
 *

******************************************************************************/

/**************************************
		Includes
**************************************/
#include <defs.h>


/**************************************
	    Globale Variable
**************************************/
Prototype void do_up		      (void);
Prototype void do_scrolldown	      (void);
Prototype void do_scrollup	      (void);
Prototype void do_down		      (void);
Prototype void do_page		      (void);
Prototype void do_downadd	      (void);
Prototype void do_left		      (void);
Prototype void do_right 	      (void);
Prototype void do_tab		      (void);
Prototype void do_backtab	      (void);
Prototype void do_top		      (void);
Prototype void do_bottom	      (void);
Prototype void do_firstcolumn	      (void);
Prototype void do_firstnb	      (void);
Prototype void do_lastcolumn	      (void);
Prototype void do_goto		      (void);
Prototype void do_screentop	      (void);
Prototype void do_screenbottom	      (void);
Prototype void do_wleft 	      (void);
Prototype void do_wright	      (void);
Prototype void do_col		      (void);
Prototype void do_scroll	      (int);
Prototype void do_match 	      (void);
Prototype void do_ping		      (void);
Prototype void do_pong		      (void);
Prototype void do_undo		      (void);
Prototype int  get_pong 	      (int);
Prototype void escapecomlinemode      (void);
Prototype void do_esc		      (void);
Prototype void do_recall	      (void);
Prototype void markerkill	      (ED *);

Prototype char	* HistoBuff[];
Prototype WORD	  NumHistoLines;
Prototype WORD	  HistoLine;


/**************************************
      Interne Defines & Strukturen
**************************************/


/**************************************
	    Interne Variable
**************************************/
static struct TextMarker marker[PINGDEPTH];

/* TODO: replace define by function for infinite history */

#define MaxHistoLines	    40

/* HistoBuff is filled [0..NumHistoLines-1], NumHistoLines is in
   [0..MaxHistoLines], HistoLine is in [0..NumHistoLines]. If NumHistoLines
   is 0, then the HistoryBuffer is empty. */

char * HistoBuff[MaxHistoLines];
WORD   NumHistoLines;
WORD   HistoLine;


/**************************************
	   Interne Prototypes
**************************************/



void do_up (void)
{
    ED * ep = Ep;

    if (!globalflags.Comlinemode)
    {
	if (ep->line)
	{
	    text_sync ();
	    ep->line --;
	    text_load ();

	    if (Ep->line < Ep->topline)
	    {
		ep->topline --;

		scroll_display (0, -1, ep->topcolumn, ep->topline,
			ep->topcolumn + Columns, ep->topline + Lines);
	    }
	} else
	{
	    globalflags.Abortcommand = 1;
	}
    } else
    {
	if (HistoLine)
	{
	    HistoLine --;

	    strcpy (Current, HistoBuff[HistoLine]);

	    ep->column = Clen = strlen (Current);
	    ep->topcolumn = ep->column - Columns + 1;

	    if (ep->topcolumn < 0)
		ep->topcolumn = 0;

	    text_redisplaycurrline ();
	}
    }
} /* do_up */


void do_scrolldown (void)
{
    ED * ep = Ep;

    if (ep->topline + Lines < ep->lines)
    {
	text_sync ();

	ep->topline ++;
	ep->line ++;

	text_load ();

	scroll_display (0, 1, ep->topcolumn, ep->topline,
		    ep->topcolumn + Columns - 1, ep->topline + Lines - 1);
    } else
	globalflags.Abortcommand = 1;
} /* do_scrolldown */


void do_scrollup (void)
{
    ED * ep = Ep;

    if (ep->topline)
    {
	text_sync ();

	ep->topline --;
	ep->line --;

	text_load ();

	scroll_display (0, -1, ep->topcolumn, ep->topline,
		    ep->topcolumn + Columns - 1, ep->topline + Lines - 1);
    } else
	globalflags.Abortcommand = 1;
} /* do_scrollup */


void do_down (void)
{
    ED * ep = Ep;

    if (!globalflags.Comlinemode)
    {
	if (ep->line + 1 < ep->lines)
	{
	    text_sync ();

	    ep->line ++;

	    text_load ();

	    if (ep->line - ep->topline >= Lines)
	    {
		ep->topline ++;

		scroll_display (0, 1, ep->topcolumn, ep->topline,
			    ep->topcolumn + Columns, ep->topline + Lines);
	    }
	} else
	    globalflags.Abortcommand = 1;
    } else
    { /* Comlinemode */
	if (HistoLine < NumHistoLines)
	{
	    HistoLine ++;

	    if (HistoLine != NumHistoLines)
		strcpy (Current, HistoBuff[HistoLine]);
	    else
		*Current = 0;

	    ep->column = Clen = strlen (Current);
	    ep->topcolumn = ep->column - Columns + 1;

	    if (ep->topcolumn < 0)
		ep->topcolumn = 0;

	    text_redisplaycurrline ();
	}
    } /* if (!Comlinemode) */
} /* do_down */


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

void do_page (void)
{
    ED	 * ep = Ep;
    UWORD n,
	   t;

    switch(av[0][4])
    {
	case 'u':
	    if (!ep->topline && !ep->line) return;

	    text_sync ();

	    if (ep->line != ep->topline)
	    {
		ep->line = ep->topline;

		text_load ();
		return;
	    }

	    n = Lines * PageJump / 100;

	    if (ep->topline < n)
		n = ep->topline;

	    ep->line -= n;
	    ep->topline -= n;

	    text_load ();

	    if (!Nsu)
		scroll_display (0, -n, 0, ep->topline, MAXLINELEN,
			ep->topline + Lines);
	    break;

	case 'd':
	    if (ep->topline + Lines >= ep->lines &&
			ep->line == ep->lines -1)
		return;

	    text_sync ();

	    if (ep->line != ep->topline + Lines -1)
	    {
		ep->line = ep->topline + Lines -1;

		if (ep->line >= ep->lines)
		    ep->line = ep->lines -1;

		text_load ();
		return;
	    }

	    n = Lines * PageJump / 100;

	    ep->line	+= n;
	    ep->topline += n;

	    if (ep->line >= ep->lines)
		ep->line = ep->lines - 1;

	    text_load ();

	    if (!Nsu)
		scroll_display (0, n, 0, ep->topline, MAXLINELEN,
			ep->topline + Lines);
	    break;

	case 'l':
	    if (!ep->topcolumn && !ep->column) return;

	    t = firstns (Current);

	    if (ep->column != ep->topcolumn)
	    {
		if (t > ep->topcolumn && ep->column != t)
		    ep->column = t;
		else
		    ep->column = ep->topcolumn;

		text_sync ();
		return;
	    }

	    n = Columns * PageJump / 100;

	    if (ep->topcolumn < n)
		n = ep->topcolumn;

	    if (t < ep->column && t > ep->column - n)
		ep->column = t;
	    else
		ep->column -= n;
	    ep->topcolumn -= n;

	    text_sync ();

	    if (!Nsu)
		scroll_display (-n, 0, 0, ep->topline, MAXLINELEN,
			ep->topline + Lines);
	    break;

	case 'r':
	    if (ep->topcolumn + Columns >= MAXLINELEN &&
			ep->column == MAXLINELEN-1)
		return;

	    text_sync ();

	    t = LINELEN(ep,ep->line);

	    if (ep->column != ep->topcolumn + Columns -1)
	    {
		if (t < ep->topcolumn + Columns && t != ep->column)
		    ep->column = t;
		else
		    ep->column = ep->topcolumn + Columns -1;

		if (ep->column >= MAXLINELEN)
		    ep->column = MAXLINELEN - 1;

		text_sync ();
		return;
	    }

	    n = Columns * PageJump / 100;

	    if (t > ep->column && t < ep->column + n)
		ep->column = t;
	    else
		ep->column    += n;
	    ep->topcolumn += n;

	    if (ep->column >= MAXLINELEN)
		ep->column = MAXLINELEN - 1;

	    text_sync ();

	    if (!Nsu)
		scroll_display (n, 0, 0, ep->topline, MAXLINELEN,
			ep->topline + Lines);
	    break;

	case 's':
	    PageJump = atoi ((char *)av[1]);

	    if (PageJump > 100)
		PageJump = 100;
	    else if (PageJump < 1)
		PageJump = 1;

	    break;
    }
} /* do_page */


void do_downadd (void)
{
    ED	  * ep = Ep;
    UBYTE * ptr;

    if (ep->line + 1 == ep->lines)
    {
	ep->modified = 1;

	if (makeroom (32))
	{
	    ptr = allocline (1);

	    SETLINE(ep,ep->lines,ptr);
	    ep->lines ++;
	} else
	{
	    nomemory ();
	}
    }

    do_down ();
} /* do_downadd */


void do_left (void)
{
    ED * ep = Ep;

    if (ep->column)
    {
	ep->column --;

	if (ep->column < ep->topcolumn)
	    text_adjust (FALSE);
    } else
	globalflags.Abortcommand = 1;
} /* do_left */


void do_right (void)
{
    ED * ep = Ep;

    if (ep->column != 254)
    {
	if (Current[ep->column] == 0)
	{
	    Current[ep->column] = ' ';
	    Current[ep->column+1]= '\0';

	    Clen ++;
	}

	ep->column ++;

	if (ep->column - ep->topcolumn >= Columns)
	    text_adjust (FALSE);
    } else
	globalflags.Abortcommand = 1;
} /* do_right */


void do_tab (void)
{
    WORD  n;
    ED	* ep = Ep;

    /* TODO */
    for (n=ep->config.tabstop-(ep->column % ep->config.tabstop); n>0; n--)
	do_right ();
} /* do_tab */


void do_backtab (void)
{
    WORD  n;
    ED	* ep = Ep;

    n = ep->column % ep->config.tabstop;
    if (!n)
	n = ep->config.tabstop;

    /* TODO */
    for (; n > 0; --n)
	do_left ();
} /* do_backtab */


void do_top (void)
{
    text_sync ();

    Ep->line = 0;

    text_load ();
    text_adjust (FALSE);
} /* do_top */


void do_bottom (void)
{
    text_sync ();

    Ep->line = Ep->lines - 1;

    text_load ();
    text_adjust (FALSE);
} /* do_bottom */


void do_firstcolumn (void)
{
    if (Ep->column)
    {
	Ep->column = 0;
	text_adjust (FALSE);
    }
} /* do_firstcolumn */


void do_firstnb (void)
{
    for (Ep->column = 0; Current[Ep->column] == ' '; Ep->column ++);

    if (Current[Ep->column] == 0)
	Ep->column = 0;

    text_adjust (FALSE);
} /* do_firstnb */


void do_lastcolumn (void)
{
    WORD  i;

    text_sync ();

    i = (globalflags.Comlinemode) ? Clen : LINELEN(Ep,Ep->line);

    if (i != Ep->column)
    {
	Ep->column = i;
	text_adjust (FALSE);
    }
} /* do_lastcolumn */


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

void do_goto (void)
{
    Line   line;
    Column col;
    long   i;
    char * ptr = (char *)av[1];

    i	 = 0;
    line = -1;
    col  = -1;

    switch (*ptr)
    {
	case 'b':
	case 's':
	   if (ActualBlock.type != BT_NONE && Ep == ActualBlock.ep)
	   {
	       line = ActualBlock.start_line;

	       if (ActualBlock.type != BT_LINE)
		   col = ActualBlock.start_column;
	   }
	break;

	case 'e':
	    if (ActualBlock.type != BT_NONE && Ep == ActualBlock.ep)
	    {
		line = ActualBlock.end_line;

		if (ActualBlock.type != BT_LINE)
		    col = ActualBlock.end_column;
	    }
	break;

	case '+':
	    i = 1;

	case '-':
	    line = Ep->line;

	default:
	    line += atoi(ptr+i);
    } /* switch (*ptr) */

    if (line >= Ep->lines)
	line = Ep->lines - 1;

    if (line < 0)
	line = 0;

    text_sync ();

    Ep->line = line;
    if (col != -1)
	Ep->column = col;

    text_load ();
    text_adjust (FALSE);
} /* do_goto */


void do_screentop (void)
{
    text_sync ();

    Ep->line = Ep->topline;

    text_load ();
    text_adjust (FALSE);
} /* do_screentop */


void do_screenbottom (void)
{
    text_sync ();

    Ep->line = Ep->topline + Lines - 1;

    if (Ep->line < 0 || Ep->line >= Ep->lines)
	Ep->line = Ep->lines - 1;

    text_load ();
    text_adjust (FALSE);
} /* do_screenbottom */


void do_wleft ()
{
    ED * ep = Ep;
    int  i;

    for (;;)
    {
	i = ep->column;

	if (i == 0)
	    goto prevline;

	i --;

	while (i && Current[i] == ' ')
	    i --;

	if (i == 0 && Current[0] == ' ')
	{
prevline:
	    if (globalflags.Comlinemode || ep->line == 0)
	    {
		i = ep->column;
		break;
	    }

	    text_sync ();

	    ep->line --;

	    text_load ();

	    ep->column = Clen;
	    continue;
	} /* while !SOL && isspace(Current[i]) */

	while (i && Current[i] != ' ')
	    i --;

	if (Current[i] == ' ')
	    i ++;

	break;
    } /* forever */

    ep->column = i;

    text_adjust (FALSE);
} /* do_wleft */


void do_wright()
{
    ED * ep = Ep;
    int  i;

    for (;;)
    {
	i = ep->column;

	if (i == Clen)
	    goto nextline;

	while (i != Clen && Current[i] != ' ')  /* skip past current word */
	    i ++;

	while (i != Clen && Current[i] == ' ')  /* to beg. of next word   */
	    i ++;

	if (i == Clen)
	{
nextline:
	    if (globalflags.Comlinemode || ep->line == ep->lines - 1)
	    {
		i = ep->column;
		break;
	    }

	    text_sync ();

	    ep->line ++;

	    text_load ();

	    ep->column = i = 0;

	    if (Current[0] != ' ')
		break;

	    continue;
	}

	break;
    } /* forever */

    ep->column = i;

    text_adjust (FALSE);
} /* do_wright() */


void do_col (void)
{
    int    col;
    char * ptr = (char *)av[1];

    switch(*ptr)
    {
	case '+':
	    col = text_colno() + atoi(ptr + 1);
	    if (col > 254)
		col = 254;
	break;

	case '-':
	    col = text_colno() + atoi(ptr);
	    if (col < 0)
		col = 0;
	break;

	default:
	    col = atoi(ptr) - 1;
	break;
    }

    if (col > 254 || col < 0)
    {
	globalflags.Abortcommand = 1;
	return;
    }

    while (Clen < col)
	Current[Clen ++] = ' ';

    Current[Clen] = 0;

    Ep->column = col;

    text_adjust (FALSE);
} /* do_col */


void do_scroll (int dir) /* SCROLLLEFT SCROLLRIGHT */
{
    ED	 * ep = Ep;
    UWORD step	  = 4;

    if (Nsu)
	return;

    if (dir == -1)
	if (av[0][6] == 'l')
	    dir = SCROLL_LEFT;
	else
	    dir = SCROLL_RIGHT;

    if (dir == SCROLL_LEFT)
    {
	if (!ep->topcolumn)
	{
	    globalflags.Abortcommand = 1;
	    return;
	}

	if (ep->topcolumn < step)
	    step = ep->topcolumn;
    } else if (dir == SCROLL_RIGHT)
    {
	if ((ep->topcolumn + Columns) >= MAXLINELEN)
	{
	    globalflags.Abortcommand = 1;
	    return;
	}

	if ((ep->topcolumn + Columns + step) >= MAXLINELEN)
	    step = MAXLINELEN - (ep->topcolumn + Columns);
    }

    if (dir == SCROLL_LEFT)
    {
	ep->topcolumn -= step;
	ep->column    -= step;
    } else
    {
	UWORD end;

	/* fill Current with spaces */
	end = ep->column + step;

	for ( ; Clen<end; Clen++)
	    Current[Clen] = ' ';

	Current[Clen] = 0;

	ep->topcolumn += step;
	ep->column    += step;
    }

    scroll_display ((dir == SCROLL_LEFT ? -step : step), 0,
	    ep->topcolumn, ep->topline,
	    ep->topcolumn + Columns, ep->topline + Lines);
} /* do_scroll */


struct pos
{
    UBYTE * ptr;
    ULONG   len;
    Line    lin;
    Column  col;
};


Prototype int get_char (ED * ep, struct pos * curr, int dir);

int get_char (ED * ep, struct pos * curr, int dir)
{
    int c;

    if (dir == 0)
    {
	curr->ptr = CONTENTS(Current);
	curr->len = strlen (curr->ptr);
	curr->lin = Ep->line;
	curr->col = Ep->column;

	if (curr->col > curr->len)
	    curr->col = curr->len - 1;

	c = curr->ptr[curr->col];
    }
    else if (dir < 0)
    {
	if (curr->col < 0)
	{
	    do
	    {
		curr->lin --;

		if (curr->lin < 0)
		    return (-1);

		curr->ptr = GETTEXT(ep,curr->lin);
		curr->len = strlen (curr->ptr);
	    } while (!curr->len);

	    curr->col = curr->len-1;
	} /* col out of range */

	c = curr->ptr[curr->col];

	curr->col --;
    }
    else
    {
	if (curr->col > curr->len)
	{
	    do
	    {
		curr->lin ++;

		if (curr->lin >= ep->lines)
		    return (-1);

		curr->ptr = GETTEXT(ep,curr->lin);
		curr->len = strlen (curr->ptr);
	    } while (!curr->len);

	    curr->col = 0;
	} /* col out of range */

	c = curr->ptr[curr->col];

	curr->col ++;
    }

    return (c);
}

void do_match (void)
{
    char   dec, 	/* char that indicates a "level_down"   */
	   inc; 	/*	    -""-         "level_up"     */
    WORD   dir; 	/* direction of search			*/
    WORD   level;	/* "level"                              */
    int    c;
    struct pos curr;	/* current position */

    /* set start values */
    inc = get_char (Ep, &curr, 0);

    /* Check for a known paren and select the search-direction accordingly. */
    switch (inc)
    {
	case '{':
	    dir = 1;
	    dec = '}';
	break;

	case '}':
	    dir = -1;
	    dec = '{';
	break;

	case '[':
	    dir = 1;
	    dec = ']';
	break;

	case ']':
	    dir = -1;
	    dec = '[';
	break;

	case '(':
	    dir = 1;
	    dec = ')';
	break;

	case ')':
	    dir = -1;
	    dec = '(';
	break;

	case '`':
	    dir = 1;
	    dec = '\'';
	break;

	case '\'':
	    dir = -1;
	    dec = '`';
	break;

	case '*':
	case '/': {
	    int ln, nested;

	    {
		int pre, next;

		pre = next = 0;

		if (curr.col)
		    pre = curr.ptr[curr.col-1];

		if (curr.col != curr.len-1)
		    next = curr.ptr[curr.col+1];

		if (inc == '*')
		{
		    if (pre == '/')
		    {
			if (next == '/')
			{
			    warn ("match: ambigous comment");
			    return;
			}
			else
			    dir = 1;	/* / * x */
		    }
		    else
		    {
			if (next == '/')
			    dir = -1;	/* x * / */
			else
			    return;	/* x * x */
		    }

		    /* skip '*' */
		    /* c = dead assign */ get_char (Ep, &curr, dir);
		}
		else /* inc == '/' */
		{
		    if (pre == '*')
		    {
			if (next == '*')
			{
			    warn ("match: ambigous comment");
			    return;
			}
			else
			    dir = -1;	/* * / x */
		    }
		    else
		    {
			if (next == '*')
			    dir = 1;	/* x / * */
			else
			    return;	/* x / x */
		    }

		    /* skip '/' */
		    /* c = dead assign */ get_char (Ep, &curr, dir);
		    /* skip '*' */
		    /* c = dead assign */ get_char (Ep, &curr, dir);
		}
	    } /* block */

	    nested = FALSE;
	    level = 1;		/* we _are_ inside the comment */

	    /* now look for the first * /-sequence (get_char returns
	       the next char in the specified direction and from within
	       the comment, * / always terminates it */
	    for (;;)
	    {
		ln = curr.lin;
		c = get_char (Ep, &curr, dir);

		if (c == -1)
		    goto not_found;

		/* Zeilenwechsel ? -> Trenner */
		if (ln != curr.lin)
		    continue;

		while (c == '/')
		{
		    c = get_char (Ep, &curr, dir);

		    if (c == -1)
			goto not_found;

		    if (c == '*')
		    {
			level ++;
			nested = TRUE;
		    }
		}

		while (c == '*')
		{
		    c = get_char (Ep, &curr, dir);

		    if (c == -1)
			goto not_found;

		    if (c == '/')
		    {
			level --;

			if (!level)
			    goto found;
		    }
		}
	    }

	    if (nested)
		warn ("match: nested commend");
	break; }

	default:
	    dir = 0;
	break;
    }

    /* if there is no known paren, just return */
    if (!dir)
	return;

    /* we start with level 0. Since we ARE on a paren, this is increased soon */
    level = 0;

    for (;;)
    {
	c = get_char (Ep, &curr, dir);

	if (c == -1)
	{
not_found:
	    warn ("match: No matching paren");
	    return;
	}

	if (c == inc)
	{ /* check for "inc-char" */
	    level ++;
	} else
	{
	    if (c == dec)
	    { /* dito */
		level --;

		/* if we have reached the start-level, we are through */
		if (!level)
		    break;
	    }
	}
    }

found:
    text_sync ();

    if (curr.lin >= Ep->lines)
	curr.lin = Ep->lines - 1;

    Ep->line   = curr.lin;
    Ep->column = curr.col - dir;    /* undo last oper. in get_char() */

    text_load ();
    text_adjust (FALSE);
} /* do_match */


void do_ping (void)
{
    UWORD num = atoi (av[1]);

    if (num >= PINGDEPTH)
    {
	error ("ping:\n%ld out of range\n(max %ld)", num, PINGDEPTH);
	return;
    }

    marker[num].ep     = Ep;
    marker[num].column = Ep->column;
    marker[num].line   = Ep->line;

    title ("Position marked");
} /* do_ping */


void do_pong (void)
{
    WORD  num = atoi (av[1]);

    text_sync ();

    if (num < 0 || num >= PINGDEPTH || !marker[num].ep)
    {
	error ("pong:\nrange error or\nyet nothing marked");
	return;
    }

    text_cursor (1);
    switch_ed (marker[num].ep);
    text_cursor (0);

    if (IntuitionBase->ActiveWindow != Ep->win)
    {
	WindowToFront (Ep->win);
	ActivateWindow (Ep->win);
    }

    if ((Ep->line = marker[num].line) >= Ep->lines)
    {
	marker[num].line = Ep->line = Ep->lines - 1;
    }

    Ep->column = marker[num].column;

    text_load ();
    text_adjust (FALSE);
} /* do_pong */


int get_pong (int num)
{
     if (num < 0 || num >= PINGDEPTH || !marker[num].ep)
     {
	  return (-1);
     }

     if (marker[num].line >= Ep->lines)
	  return (marker[num].line = Ep->lines-1);

     return (marker[num].line);
} /* get_pong */


/*
 * esc, escimm
 */

int Savetopline, Savecolumn, Savetopcolumn;

void do_recall (void)
{
    av[0] = "escimm";

    /* Copy last Histoline if possible */
    if (NumHistoLines)
	av[1] = HistoBuff[NumHistoLines - 1];
    else
	av[1] = "";

    do_esc ();

    if (NumHistoLines)
	HistoLine --;
} /* do_recall */


void do_esc (void)
{
    ED	* ep = Ep;
    RP	* rp = ep->win->RPort;
    WORD  y;

    if (globalflags.Comlinemode)
    {
	escapecomlinemode ();
	return;
    } else
    {			 /* PATCH_NULL added */
	esc_partial = Partial;	/* PATCH_NULL added */
	Partial = NULL; 	/* PATCH_NULL added */
    }

    text_sync ();

    if (av[0][3] == 'i')
	strcpy ((char *)Current, (char *)av[1]);
    else
	Current[0] = 0;

    Clen = strlen ((char *)Current);
    globalflags.Comlinemode = 1;

    /* returnoveride (1); */            /* PATCH_NULL [25 Jan 1993] : commented out */

    Savetopline   = ep->topline;
    Savecolumn	  = ep->column;
    Savetopcolumn = ep->topcolumn;

    ep->column = Clen;
    ep->topcolumn = ep->column - Columns + 1;

    if (ep->column < Lines)
	ep->topcolumn = 0;
    else
    {
	ep->topcolumn = Clen - Lines;
    }

    ep->topline   = ep->line - Lines + 1;

    y = ROW (Lines-1);
    SetAPen (rp, TEXT_BPEN);
    SetWrMsk (rp, 0xFF);
    RectFill (rp, COL(0), y, Xpixs, Ypixs);

    y --;
    SetAPen (rp, TEXT_FPEN);
    RectFill (rp, COL(0), y, Xpixs, y);

    text_displayseg (Lines - 1, 1);

    text_cursor (1);

    HistoLine = NumHistoLines;
} /* do_esc */


void escapecomlinemode (void)
{
    ED	 * ep = Ep;
    RP	 * rp = ep->win->RPort;
    char * ptr;

    if (esc_partial)
    {	   /* PATCH_NULL P -> esc_p */
	free(esc_partial);  /* PATCH_NULL P -> esc_p */
	esc_partial = NULL; /* PATCH_NULL P -> esc_p */
    }

    if (globalflags.Comlinemode)
    {
	/* Don't add empty lines */
	if (*Current)
	{
	    ptr = Current + strlen (Current) -1;

	    while (*ptr == ' ' && ptr != (char *)Current)
		ptr --;

	    /* Set string-end after last char. Note that this code
	       removes histo-lines with length 1 (single chars) */
	    if (ptr != (char *)Current)
		ptr ++;

	    *ptr = 0;
	}

	/* If we are somewhere above and we didn't change anything,
	   we won't add a new history-line */
	/* If there is something to add */
	if (!(HistoLine != NumHistoLines && !strcmp (Current,
		HistoBuff[HistoLine])) && *Current)
		{
	    /* Check if buffer is full */
	    if (NumHistoLines == MaxHistoLines)
	    {
		/* Free oldest line and shift buffer */
		free (HistoBuff[0]);

		movmem (HistoBuff + 1, HistoBuff,
			sizeof (char *) * (MaxHistoLines - 1));

		/* We have now space for one line */
		NumHistoLines --;
	    }

	    /* Allocate new line */
	    ptr = malloc (strlen (Current) + 1);

	    /* Copy new line if possible. Note that even if malloc()
	       failed we don't loose information. */
	    if (ptr)
	    {
		strcpy (ptr, (char *)Current);

		/* Add line. At this point, NumHistoLines is ALWAYS
		   less than MaxHistoLines ! */
		HistoBuff[NumHistoLines ++] = ptr;
	    }
	}

	globalflags.Comlinemode = 0;

	/* returnoveride (0); */        /* PATCH_NULL [25 Jan 1993] : commented out */

	ep->topline   = Savetopline;
	ep->column    = Savecolumn;
	ep->topcolumn = Savetopcolumn;

	text_load ();

	SetAPen (rp, TEXT_BPEN);
	SetWrMsk (rp, 0xFF);
	RectFill (rp, COL(0), ROW(Lines-1)-1, Xpixs, Ypixs);

	SetAPen (rp, TEXT_FPEN);
	text_displayseg (Lines - 2, 2);
    }
} /* escapecomlinemode */


void markerkill (ED * ep)
{
    WORD  i;

    for (i = 0; i < PINGDEPTH; ++i)
    {	    /*	remove ping-pong marks	*/
	if (marker[i].ep == ep)
	    marker[i].ep = NULL;
    }
} /* markerkill */


/******************************************************************************
*****  ENDE cursor.c
******************************************************************************/
