/*
 * Copyright (c) 1986, 1987, 1988 by The Trustees of Columbia University
 * in the City of New York.  Permission is granted to any individual or
 * institution to use, copy, or redistribute this software so long as it
 * is not sold for profit, provided this copyright notice is retained.
 */

#ifndef lint
static char *rcsid = "$Header: action.c,v 1.10 88/06/27 00:15:18 chris Exp $";
#endif

#include "mm.h"
#include "parse.h"
#include "cmfncs.h"

int (*(mmact[128]))();
extern int (*(stdact[128]))();
int mm_clsact(), fixact(), mm_abortact();
extern jmp_buf abortbuf;
int allow_aborts;

/*
 * set up special action characters for MM.
 */

typedef int (*(*acttab))();

acttab
mmactini()
{
    bcopy(stdact, mmact, sizeof(mmact));
    mmact[(int) '\f'] = mm_clsact;
    mmact[(int) '\016'] = mm_abortact; 
    return (mmact);
}

mm_clsact(fdblist,brk,deferred)
fdb *fdblist;
char brk;
int deferred;
{
  extern int control_l_confirm;

  if (control_l_confirm) {
      return ((*stdact[brk])(fdblist, brk, deferred));
  }
  cmxcls();	 	  	    	/* clear the screen for a formfeed */
  return(fixact(fdblist,brk,deferred));	/* refresh the line */
}
 
int
mm_abortact(fdblist,brk,deferred)
fdb *fdblist;
char brk;
int deferred;
{
    pval parseval;
    fdb *used;
    static fdb cfmfdb = { _CMCFM, 0, NULL, NULL, NULL, NULL, NULL };
    csb holdcsb;
    int cmdbuf[200];
    int cmerjnp();
    char atmbuf[200], wrkbuf[200];
    jmp_buf erbuf, rpbuf;
    extern int user_aborted;

    if (deferred)
	return(CMxDFR);

    if (!allow_aborts) {
	return(nextact(fdblist,brk,deferred));
    }

    if (control_n_abort == SET_ALWAYS) {
	user_aborted = true;
	longjmp (abortbuf, 1);
    }
    if (control_n_abort == SET_NEVER) {
	cmsti1 (brk, 0);
	return CMxOK;
    }
    else {				/* set control-n-abort ask */
	extern int user_aborted;
	csb oldcsb;
	save_parse_context();
	oldcsb = cmcsb;
	cmbufs (cmdbuf, sizeof cmdbuf, atmbuf, sizeof atmbuf,
		wrkbuf, sizeof wrkbuf);
	cmact (nil);
	user_aborted = yesno("Abort? ", "yes");
	cmcsb = oldcsb;
	cmcsb._cmcol = 0;
	restore_parse_context();
	if (user_aborted)
	    longjmp (abortbuf, 1);
	fixact (fdblist, brk, 0);
	return (CMxOK);
    }
}

/*
 * redisplay_line:
 * simulate a ^R
 */
redisplay_line ()
{
    fixact (NULL, NULL, NULL);		/* doesn't use any args */
}

static int
fixact(fdblist,brk,deferred)
fdb *fdblist;
char brk;
int deferred;
{
  int *cp;				/* pointer into buffer */
  int cc;				/* character under examination */
  char c;
  int reflen;				/* # of chars refreshed */

  cp = cmcsb._cmptr + cmcsb._cminc; 	/* point to end of buffer */
  while (cp-- != cmcsb._cmbfp) { 	/* loop over all the chars */
    if ((*cp & CC_HID) == 0)
      break;				/* found a non-hidden character */
  }
  cp++;					/* point to last nonhidden char */

  if (cp != cmcsb._cmbfp)
    cp--;				/* refresh at least 1 nonhidden chr */
  while (cp-- != cmcsb._cmbfp) {	/* search for nonhidden newline */
    c = (cc = *cp) & CC_CHR;		/* get next char */
    if (((cc & CC_HID) == 0) && (c == NEWLINE)) /* nonhidden newline? */
      break;				/* yup, stop looking */
  }
  cp++;					/* point to char after break */

  reflen = (cmcsb._cmptr - cp) + cmcsb._cminc; /* get # of chars to refresh */

  if (cmcsb._cmflg & CM_CRT)
    cmcsb._cmcol = cmxera(reflen,TRUE); /* erase the characters from screen */
  else {
    cmxputs("^R");			/* signal line kill on hardcopy */
    cmxnl();				/* move to a new line */
    if (cp == cmcsb._cmbfp)		/* killed prompt line? */
      cmxputs(cmcsb._cmrty);		/* then reprompt */
  }
  while (reflen-- > 0) {		/* retype buffer contents */
    c = (cc = *cp++) & CC_CHR;		/* get next char */
    if ((cc & CC_NEC) == 0)		/* character originally echoed? */
      cmechx(c);			/* yup, do it again */
  }
}

static
nextact(fdblist,brk,deferred)
fdb *fdblist;
char brk;
int deferred;
{
    cmhist *h = cmcsb._cmhist;
    int i;
    int next;
    if (h == NULL || h->len == 0) {
	cmputc(BELL,cmcsb._cmoj);
	cmxflsh();
	return(CMxOK);
    }
    next = (h->current + h->len + 1) % h->len;
    if (h->bufs[next].buf == NULL || h->next == h->current) {
	cmputc(BELL,cmcsb._cmoj);
	cmxflsh();
	return(CMxOK);
    }
    h->current = next;
    begact(fdblist,brk,deferred);
    for( i= 0; i < h->bufs[next].len; i++)
	cmsti1(h->bufs[next].buf[i] & CC_CHR, h->bufs[next].buf[i] & ~CC_CHR);
    return(CMxOK);
}

static
begact(fdblist,brk,deferred)
fdb *fdblist;
char brk;
int deferred;
{
  int *cp;				/* pointer to deletion site */
  int cc;				/* character under examination */
  char c;
  int eralen;				/* # of chars erased */

  cp = cmcsb._cmptr + cmcsb._cminc; 	/* point to end of buffer */
  while (cp-- != cmcsb._cmbfp) { 	/* loop over all the chars */
    if ((*cp & CC_HID) == 0)
      break;				/* found a non-hidden character */
  }
  cp++;					/* point to last nonhidden char */

  if (cp != cmcsb._cmbfp)
    cp--;				/* erase at least 1 nonhidden char */
  while (cp-- != cmcsb._cmbfp) {	/* search for nonhidden newline */
    c = (cc = *cp) & CC_CHR;		/* get next char */
    if (((cc & CC_HID) == 0) && (c == NEWLINE)) /* nonhidden newline? */
      break;				/* yup, stop looking */
  }
  cp++;					/* point to char after break */

  eralen = (cmcsb._cmptr - cp) + cmcsb._cminc; /* get # of chars erased */

  if (cmcsb._cmflg & CM_CRT)
    cmcsb._cmcol = cmxera(eralen,TRUE); /* erase the characters */
  else {
    cmxputs("^U");			/* signal line kill on hardcopy */
    cmxnl();				/* move to a new line */
    if (cp == cmcsb._cmbfp)		/* killed prompt line? */
      cmxputs(cmcsb._cmrty);		/* then reprompt */
  }
  cmcsb._cminc -= eralen;		/* update CSB counters */
  cmcsb._cmcnt += eralen;
  if (cmcsb._cminc <= 0) {		/* erased back to parsed data? */
    cmcsb._cmptr += cmcsb._cminc;	/* yup, backup parsed pointer */
    cmcsb._cminc = 0;			/* no unparsed chars */
    return(CMxRPT);			/* and call for reparse */
  }
  else
   return(CMxOK);			/* else no reparse */
}
