#include "config.h"
/*
 * Copyright (c) 1986, 2014 by The Trustees of Columbia University in
 * the City of New York.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *  + Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 *  + Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 *  + Neither the name of Columbia University nor the names of its
 *    contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.

 Authors: Howie Kaye
*/

/*
 * cursor control
 * handle cursor motion and line updating for command line editing.
 */

#include "ccmdlib.h"
#include "cmfncs.h"

int *
#if HAVE_STDC
go_from(int *p1, int *p2)
#else /* K&R style */
go_from(p1,p2)
int *p1, *p2;
#endif /* HAVE_STDC */
{
    int l,c;

    if (p1 != p2) {
	relcharpos(&l,&c,p1,p2);
	if (l > 0)
	    go_down_line(l);
	else
	    go_up_line(-l);
	if (c > 0)
	    go_forward(c);
	else
	    go_backward(-c);
    }
    return(p2);
}

int *
goto_end_of_line(VOID)
{
  int *p = cmcsb._cmcur;
  int i=0;

  while(p < cmcsb._cmptr + cmcsb._cminc && ((*p & CC_CHR) != '\n')) {
    if (!(*p & (CC_NEC|CC_HID))) i++;
    p++;
  }
  go_from(cmcsb._cmcur, p);
  return(p);
}


int *
goto_beginning_of_line(VOID)
{
    int *bp;

    for(bp = cmcsb._cmcur-1; bp > cmcsb._cmbfp; bp--)
	if ((*bp & CC_CHR) == NEWLINE) {
	    bp++;
	    break;
	}
    go_from(cmcsb._cmcur, bp);
    return(bp);
}

void
goto_current_pos(VOID)
{
  int *p;

  goto_beginning_of_line();
  for(p = cmcsb._cmbfp; p < cmcsb._cmcur; p++) {
    if (!(*p & (CC_NEC|CC_HID)))
      cmechx(*p & CC_CHR);
  }
}


void
#if HAVE_STDC
go_up_line(int n)
#else /* K&R style */
go_up_line(n)
int n;
#endif /* HAVE_STDC */
{
    for(; n > 0; n--)
	if (!cmupl()) {			/* then move up to next line */
	    cmcr(cmcsb._cmoj);
	    cmputc(BS,cmcsb._cmoj);	/* no luck.. try backspace-return */
	    cmcr(cmcsb._cmoj);
	}
}

void
#if HAVE_STDC
go_down_line(int n)
#else /* K&R style */
go_down_line(n)
int n;
#endif /* HAVE_STDC */
{
    for(; n > 0; n--)
	cmdownl();
}

int *
#if HAVE_STDC
go_forward_char(int n)
#else /* K&R style */
go_forward_char(n)
int n;
#endif /* HAVE_STDC */
{
    go_from(cmcsb._cmcur, cmcsb._cmcur + n);
    return(cmcsb._cmcur + n);
}

int *
#if HAVE_STDC
go_backward_char(int n)
#else /* K&R style */
go_backward_char(n)
int n;
#endif /* HAVE_STDC */
{
    go_from(cmcsb._cmcur, cmcsb._cmcur - n);
    return(cmcsb._cmcur - n);
}


void
#if HAVE_STDC
go_backward(int n)
#else /* K&R style */
go_backward(n)
int n;
#endif /* HAVE_STDC */
{
    if (n == cmcsb._cmcol) {
	cmputc('\r', cmcsb._cmoj);
	cmcsb._cmcol = 0;
    }
    else {
	for(; n > 0; n--)
	    cmleft();
    }
}

void
#if HAVE_STDC
go_forward(int n)
#else /* K&R style */
go_forward(n)
int n;
#endif /* HAVE_STDC */
{
    for(; n > 0; n--)
	cmright();
}

void
refresh_eol(VOID)
{
    int *cp;
    int lines = 0;

/*
 * output the line.  If we wrap, must fix subsequent lines.
 * if we hit a '\n' or the end of the buffer, we can stop.
 */
    for(cp = cmcsb._cmcur; cp< cmcsb._cmptr + cmcsb._cminc; cp++) {
	if (!(*cp & (CC_NEC|CC_HID))) {
	    if ((*cp & CC_CHR) == NEWLINE && lines == 0)
		break;
	    cmechx(*cp);
	    if (cmcsb._cmcol == 0) {	/* wrap point? */
		lines++;		/* count the line */
	    }
	}
    }
    go_from(cp, cmcsb._cmcur);
}


/* relcharpos
**
** Purpose:
**   Compute line and column position of end, relative to start.
**   if start is cmcsb._cmbfp, include the prompt.
**
** Input parameters:
**   start, end: start and endpoints of the search
**
** Output parameters:
**   lpos - Number of lines from the one containing the beginning of the
**     prompt string.
**   cpos - Column position (0 = left edge of screen).
**/
void
#if HAVE_STDC
relcharpos(int *lpos, int *cpos, int *start, int *end)
#else /* K&R style */
relcharpos(lpos,cpos,start,end)
int *lpos,*cpos,*start,*end;
#endif /* HAVE_STDC */
{
    int sl, sc, el, ec;

    if (cmcsb._cmoj == NULL) {		/* not outputting anyway */
	*lpos = *cpos = 0;		/* so don't do anything */
    }
    else {
	abscharpos(start, &sl, &sc);
	abscharpos(end, &el, &ec);
	*lpos = el - sl;
	*cpos = ec - sc;
    }
}

void
#if HAVE_STDC
abscharpos(int *ptr, int *lpos, int *cpos)
#else /* K&R style */
abscharpos(ptr, lpos, cpos)
int *ptr;
int *lpos, *cpos;
#endif /* HAVE_STDC */
{
  int count;				/* counts characters */
  int *cp,cc;				/* for scanning buffer characters */
  char c;

  count = (int)strlen(cmcsb._cmrty);	/* get length of prompt string */
  *lpos = count / (cmcsb._cmcmx);	/* compute prompt end coordinates */
  *cpos = count % (cmcsb._cmcmx);
					/* get # of buffer chars to count */
  cp = cmcsb._cmbfp;			/* point to buffer start */
  while (cp < ptr) {			/* loop through chars */
    c = (cc = *cp++) & CC_CHR;		/* get next char */
    if (cc & CC_NEC)
      continue;				/* non-echoed char... no count */
    else if (c == NEWLINE) {
      (*lpos)++;			/* newline... move to next line */
      *cpos = 0;			/* and reset column counter */
    }
    else if (c == TAB) {		/* TAB character */
      *cpos = 8 + 8*(*cpos / 8);	/* move col to next multiple of 8 */
    }
    else {
      if ((c == DELETE) || (c < SPACE)) /* other control char */
        *cpos += 2;			/* count up-arrow and print char */
      else				/* normal printing char */
        (*cpos)++;			/* count it */
    }
    if (*cpos >= cmcsb._cmcmx) {	/* wrap if necessary */
      (*lpos)++;			/* to next line */
      *cpos = 0;			/* column zero */
    }
  }
}

int*
#if HAVE_STDC
disp_forward_char(int n)
#else /* K&R style */
disp_forward_char(n)
int n;
#endif /* HAVE_STDC */
{
    int *p = cmcsb._cmcur;

    for(; n > 0; n--,p++)
	if (!(*p & (CC_NEC | CC_HID)))
	    cmechx(*p & CC_CHR);
    return(p);
}
