
#include "vseeci.h"
#include <v/vcmdwin.h>
#include <v/vfilesel.h>
#include <fstream.h>

    static int filterIndex = 0;
    static char* filter[] =
      {
        "*",
        "*.txt",
        "*.c;*.cpp;*.cxx;*.h",
        0
      };

// ==================>>> vSeeCI::vSeeCI <<<=================
  vSeeCI::vSeeCI(vTextEditor* textEd, vCmdWindow* cw)
        : vTextEdCmdInterp(textEd, cw)
  {

    lex_def = 1;
    CmdCount = 1;
    param_count = 1;
    cmdmode = Cmd;
    countWait = 0;		// start in cmdmode
    slastl = savlen = nxtsav = 0;	// Save Buff stuff
    _SaveBuff  = new char*[SBAllocLines];	// build save in 500 line incrs.
    for (long lx = 0 ; lx < SBAllocLines ; ++lx)
        _SaveBuff[lx] = 0;

    _maxSBLines = SBAllocLines - 1;
  }

// ==================>>> vSeeCI::~vSeeCI <<<================
  vSeeCI::~vSeeCI()
  {
    if (_SaveBuff)
      {
	for (long lx = 0 ; lx < _maxSBLines ;++lx)	// delete contents
	  {
	    if (_SaveBuff[lx])
		delete [] _SaveBuff[lx];
	  }
	delete [] _SaveBuff;	// free SaveBuff	// delete line array
      }
  }

// =====================>>> vTextEdCmdInterp::InitCmdInterp <<<====================
  void vSeeCI::InitCmdInterp()
  {
    te()->ChangeInsMode(te()->GetEdState().ins_mode,"Command ");
  }

// =====================>>> vSeeCI::ProcessKey <<<====================
  int vSeeCI::ProcessKey(vKey key, unsigned int shift)
  {

    if (vk_IsModifier(key))             // ignore modifiers
	return -1;


//    return vTextEdCmdInterp::ProcessKey(key,shift);
    return edit(key,shift);
  }

// =============================>>> vSeeCI::edit   <<<==========================
  int vSeeCI::edit(vKey chr, unsigned int shift)
  {
    // Hard wired See command interp.

    int s_succ, retval;

    static int ins_set[] =		/* allowable commands for insert */
      {
	'i', 'o', 'X'-'@', 'T'-'@', 'g', 'Y'-'@', 'y', 0
      };

    static int jump_set[] =	/* commands to not reset jump memory */
      {
	'j', 'm', '?', 'n', 0
      };


    vKey lexval = chr; 		// @@ For now, simple translation

    if (cmdmode == Ins)		// in insert mode
      {
	// This code allows the keypad keys to still move
	// the cursor around while still staying in insert mode...
	retval = 1;
	switch (lexval)
	  {
	    case vk_BackSpace:		/* delete last character */
		retval = te()->charDelete(-CmdCount);
		break;

	    case vk_Delete:
	    case vk_KP_Delete:
	      {
		if (shift & VKM_Shift || shift & VKM_Ctrl)
		    te()->lineDelete(CmdCount);
		else
		    retval = te()->charDelete(CmdCount);
		break;
	      }

#ifdef CMDS_IN_INSERT
	    case vk_Home:
	    case vk_KP_Home:
	      {
		if (shift & VKM_Shift || shift & VKM_Ctrl)
		    retval = te()->lineGoto(1);
		else
		    te()->lineBeginning();
		break;
	      }

	    case vk_End:
	    case vk_KP_End:
	      {
		if (shift & VKM_Shift || shift & VKM_Ctrl)
		    te()->bufferBottom();
		else
		    te()->lineEnd();
		break;
	      }

	    case vk_Page_Up:
	    case vk_KP_Page_Up:
	      {
		if (shift & VKM_Ctrl)
		    te()->scrollDown(-CmdCount * te()->GetRows());
		else
		    retval = te()->lineDown((long)(-CmdCount * te()->GetRows()));
		break;
	      }

	    case vk_Up:
	    case vk_KP_Up:
	      {
		if (shift & VKM_Shift)
		    retval = te()->lineDownBeg(-CmdCount);
		else
		    retval = te()->lineDown(-CmdCount);
		break;
	      }

	    case vk_Page_Down:
	    case vk_KP_Page_Down:
	      {
		if (shift & VKM_Ctrl)
		    te()->scrollDown(CmdCount * te()->GetRows());
		else
		    retval = te()->lineDown(
		          (long) te()->minl((CmdCount * te()->GetRows()),
		          (long)(te()->GetLines() - te()->GetCurLine() + 1)));
		break;
	      }

	    case vk_KP_Down:
	    case vk_Down:
	      {
		if (shift & VKM_Shift)
		    retval = te()->lineDownBeg(CmdCount);
		else
		    retval = te()->lineDown(CmdCount);
		break;
	      }

	    case vk_Left:
	    case vk_KP_Left:
	      {
		if (shift & VKM_Ctrl || shift & VKM_Shift)
		    retval = te()->wordRight(-CmdCount);
		else
		    retval = te()->charRight(-CmdCount,1);
		break;
	      }

	    case vk_Right:
	    case vk_KP_Right:
	      {
		if (shift & VKM_Ctrl ||shift & VKM_Shift)
		    retval = te()->wordRight(CmdCount);
		else
		    retval = te()->charRight(CmdCount,1);
		break;
	      }
#endif

	    case vk_KP_Insert:
	    case vk_Insert:
	      {
		te()->SetInsMode(!(te()->GetEdState().ins_mode));
		break;
	      }

	    case vk_Escape:
	      {
		cmdmode = Cmd;
		te()->ChangeInsMode(te()->GetEdState().ins_mode,"Command ");
		return 1;		// done!
	      }

            case 'V'-'@':           // ^V: Paste
             {
		te()->EditPaste();
		break;
              }

	    default:
		retval = te()->defaultKeyIn(lexval, shift);
		break;
	  }

	return retval;
      }
    else if (cmdmode == Find)		// in Find pattern mode
      {
        char tmp[2] = "x";
        if (chr == vk_Escape)
          {
            cmdmode = Cmd;
            te()->ChangeInsMode(te()->GetEdState().ins_mode,"Command ");
            te()->SetFindPat(newFindPat);
	    return te()->EditCommand(edFindNext, CmdCount);
          }
        else if (chr == vk_BackSpace)
          {
            int pl = strlen(newFindPat);

            if (pl > 0)
              newFindPat[pl-1] = 0;	// wipe last char
            te()->StatusMessage(newFindPat);
            return 1;
          }
        tmp[0] = lexval;	// add to pattern
        if (strlen(newFindPat) < MAX_LINE)
          {
            strcat(newFindPat, tmp);
          }
        te()->StatusMessage(newFindPat);
        return 1;
      }

    te()->ChangeInsMode(te()->GetEdState().ins_mode,"Command ");

    if (lexval >= '0' && lexval <= '9' || lexval == '-')
      {
	if (countWait == 0)
	  {
	    countWait = 1;
	    if (lexval == '-')
	      {
		CmdCount = 1;	// - implies 1
		countWait = -1;
	      }
	    else
		CmdCount = lexval - '0';
	    return 1;
	  }
	else if (lexval == '-')
	  {
	    countWait = -1;
	    return 1;
	  }
	else if (lexval >= '0' && lexval <= '9')      // it is a count
	  {
	    if (countWait < 0 && CmdCount == 1)
		CmdCount = 0;			// user entering value
	    CmdCount = (CmdCount * 10) + (lexval - '0');
	    return 1;
	  }
      }

    if (countWait != 0)
      {
	CmdCount *= countWait;        // negative?
	countWait = 0;                      // done building count
      }


    s_succ = 1;

    if (te()->GetCurLine() < 1)	// make sure legal command for empty buffer
      {
	if (!inset(lexval,ins_set))
	  {
	    te()->StatusMessage("Can't, buffer empty. Insert 1st ");
	    return 1;
	  }
      }

//    if (did_insert)			/* was last command an insert? */
//      {
//	auto_tidy();			/* auto format text */
//	did_insert = 0;
//      }

    if (!inset(lexval,jump_set))
	te()->SetJLine(te()->GetCurLine()); // sets previous line for Jump

    switch (lexval)
      {
        case 'C'-'@':           // ^C : Copy ; Shift-^C: fold case
          {
            te()->EditCopy();
            break;
          }

	case 'D'-'@': 			/* down in column */
	case vk_KP_Down:
	case vk_Down:
	  {
	    if (shift & VKM_Shift)
		retval = te()->lineDownBeg(CmdCount);
	    else
		retval = te()->lineDown(CmdCount);
	    break;
	  }

	case 'E'-'@':			/* edit repeat buffer */
   //	    if (lex_def)		/* default 1 passed */
   //		CmdCount = rptuse + 1;	/* use current repeat loop */
    //	    retval = edit_rpt(CmdCount);	/* edit repeat buffer */
	    break;

	case 'F'-'@':           // ^F: find next, Shift-^F: find/replace
	  {
	    if (shift & VKM_Shift)      // Shift-^F
	      {
		retval = te()->EditCommand(edFindNext, CmdCount);
		//ED(target) = T_FIND_RPL;
		// (void) build_find(0,1,(int)CmdCount);	/* set up find build first */
	      }
	    else
	      {
		retval = te()->EditCommand(edFindNext, CmdCount);
	      }
	    break;
	  }

	case 'G'-'@':			/* unkill last line killed */
//@@	    retval = unkill();
	    break;

	case vk_BackSpace:		/* delete last character */
	    retval = te()->charDelete(-CmdCount);
	    break;

	case vk_Tab:
	  {
	    retval = te()->wordRight(CmdCount);
	  }

	case 'J'-'@':			/* set range by character */
//@@	    retval = add_to_range(CmdCount,0);
	    break;

	case 'K'-'@':           // ^K: Kill line
	  {
	    te()->lineDelete(CmdCount);
	    break;
	  }

	case 'L'-'@':			/* goto line */
	  {
	    retval = te()->lineGoto(CmdCount);
	    break;
	  }

	case 'M'-'@':			/* (RETURN) set range */
	    //	    retval = add_to_range(CmdCount,1);
	    break;

	case 'N'-'@':			/* return to noted location */
	  {
            retval = te()->EditCommand(edNoteGoto,CmdCount);
	    break;
	  }

	case 'P'-'@':			/* page up */
	  {
	    retval = te()->lineDown((long)(-CmdCount * te()->GetRows()));
	    break;
	  }

	case vk_Page_Up:
	case vk_KP_Page_Up:
	  {
	    if (shift & VKM_Ctrl)
		te()->scrollDown(-CmdCount * te()->GetRows());
	    else
		retval = te()->lineDown((long)(-CmdCount * te()->GetRows()));
	    break;
	  }

        case 'Q'-'@':			// ^Q - save/close this file
          {
            cmdWin()->WindowCommand(M_SaveClose,1,(CmdType)0);
            break;
          }

	case 'T'-'@':			/* abort */
//@@	    abort_session();
	    break;

	case 'U'-'@': 			/* up in column */
	case vk_Up:
	case vk_KP_Up:
	  {
	    if (shift & VKM_Shift)
		retval = te()->lineDownBeg(-CmdCount);
	    else
		retval = te()->lineDown(-CmdCount);
	    break;
	  }

        case 'V'-'@':           // ^V: Paste
          {
            te()->EditPaste();
            break;
          }

        case 'X'-'@':           // ^X : Cut
          {
            te()->EditCut();
            break;
          }

	case '"':			/* kill rest of line */
	  {
	    retval = te()->lineDeleteToEnd();
	    break;
	  }

	case '#':			/* ex. rpt k n times */
//@	    ED(target) = T_EXEC_RPT;	/* execute the repeat loop */
//@@	    param_count = CmdCount;	/* remember the count */
	    break;

	case '&':			/* execute repeat buffer again */
//&&	    if (CmdCount != 1)
//&&		ED(echof)=FALSE;	/* turn off echo */
//&&	    rptcnt[rptuse] = CmdCount > 0 ? CmdCount : (-CmdCount);
	    break;

	case '\'':			/* kill previous part of line */
	  {
	    retval = te()->lineDeleteFront();
	    break;
	  }

	case '*':			/* insert the find pattern */
//@@	    succ = ins_pat();
	    break;

	case '+':			/* insert counter value */
//@@	    ins_counter();
	    break;

	case ',':			/* move to beginning of line */
	  {
	    te()->lineBeginning();
	    break;
	  }

	case '.':			/* move to end of the line */
	  {
	    te()->lineEnd();
	    break;
	  }

	case '/':			/* delete last thing manipulated */
	    retval = RemoveLast();
	    break;

	case ';':			/* find again */
	  {
	    // @@ add code to handle Finds from repeat buffer
	    retval = te()->EditCommand(edFindNext, CmdCount);
	    break;
	  }

	case '<':			/* define/execute repeat loop */
//@@	    ED(target) = T_RPT;
//@@	    (void) rpt_build(0,1,CmdCount);
	    break;

	case '=':			/* remove last and enter insert mode */
	  {
	    if ((retval = RemoveLast()))
	      {
		cmdmode = Ins;
		te()->ChangeInsMode(te()->GetEdState().ins_mode);
	      }
	    break;
	  }

	case '@':			/* execute key macro */
//@@	    param_count = CmdCount;	/* remember the count */
//@@	    ED(target) = T_EXEC_KM;
	    break;

	case '[':			/* backwards jump over word */
	  {
	    retval = te()->wordRight(-CmdCount);
	    break;
	  }

	case '\\':			/* replace */
//@@	    succ = replace();
	    break;

	case ']':			/* balance match */
	  {
	    retval = te()->BalMatch(CmdCount);
	    break;
	  }

	case '^':			/* reverse find */
//@@	    ED(target) = T_FIND;
//@@	    (void) build_find(0,1,(int)(-CmdCount)); /* set up find build first */
	    break;

	case '_':			/* kill word */
//@@	    if (!(succ = wordr(CmdCount)))
//@@		break;
//@@	    retval = rmvlst();
	    break;

	case 'a':			/* append to save buffer */
	    retval = save(CmdCount,1);
	    break;

	case 'b':			/* goto top of page */
	  {
	    retval = te()->lineGoto(1);
	    break;
	  }

	case vk_Home:
	case vk_KP_Home:
	  {
	    if (shift & VKM_Shift || shift & VKM_Ctrl)
		retval = te()->lineGoto(1);
	    else
		te()->lineBeginning();
	    break;
	  }

	case 'c':			/* change characters */
	    if ((retval = te()->charDelete(CmdCount)) )
	      {
		cmdmode = Ins;
		te()->ChangeInsMode(te()->GetEdState().ins_mode);
	      }

	    break;

	case 'D':
	case 'd': 			/* down line */
	    retval = te()->lineDownBeg(CmdCount);
	    break;

	case 'e':			/* goto to bottom of page */
	    te()->bufferBottom();
	    break;

	case vk_End:
	case vk_KP_End:
	  {
	    if (shift & VKM_Shift || shift & VKM_Ctrl)
		te()->bufferBottom();
	    else
		te()->lineEnd();
	    break;
	  }

	case 'f':		// F: set find pattern only - unechoed
          {
            cmdmode = Find;
            te()->ChangeInsMode(te()->GetEdState().ins_mode,"Find Pat");
            newFindPat[0] = 0;	// no pattern yet
            break;
          }

	case 'F':		// f: find via dialog
	  {
	    // @@ add code to handle Finds from repeat buffer
            te()->SetFindPat("");	// new pattern each time!
	    retval = te()->EditCommand(edFind, CmdCount);
	    break;
	  }

	case 'g':			/* get move buffer */
	    retval = getsav();
	    break;

	case 'I':
	    if (CmdCount >= 1)
		retval = te()->charInsert(CmdCount);
	    break;

	case 'i': 			/* insert */
	    cmdmode = Ins;
	    te()->ChangeInsMode(te()->GetEdState().ins_mode);
	    break;

	case 'j':			/* jump back to last location */
	  {
	    long itmp = te()->GetCurLine();
	    retval = te()->lineGoto(te()->JLine());
	    te()->SetJLine(itmp);
	    break;
	  }

	case 'k': 			/* delete next character */
	    retval = te()->charDelete(CmdCount);
	    break;

	case vk_Delete:
	case vk_KP_Delete:
	  {
	    if (shift & VKM_Shift || shift & VKM_Ctrl)
		te()->lineDelete(CmdCount);
	    else
		retval = te()->charDelete(CmdCount);
	    break;
	  }

	case 'l': 			/* left */
	    retval = te()->charRight(-CmdCount,1);
	    break;

	case vk_Left:
	case vk_KP_Left:
	  {
	    if (shift & VKM_Ctrl || shift & VKM_Shift)
		retval = te()->wordRight(-CmdCount);
	    else
		retval = te()->charRight(-CmdCount,1);
	    break;
	  }

	case 'n':			/* save current location */
            retval = te()->EditCommand(edNoteLocation, CmdCount);
	    break;

	case 'o':			/* open new line */
	    retval = te()->lineOpen(CmdCount);
	    cmdmode = Ins;
	    te()->ChangeInsMode(te()->GetEdState().ins_mode);
	    break;

	case 'O':			/* overtype */
	case vk_KP_Insert:
	case vk_Insert:
	  {
	    te()->SetInsMode(!(te()->GetEdState().ins_mode));
	    break;
	  }

	case 'p':			/* page down screen */
	    retval = te()->lineDown(
		    (long) te()->minl((CmdCount * te()->GetRows()),
		    (long)(te()->GetLines() - te()->GetCurLine() + 1)));
	    break;

	case vk_Page_Down:
	case vk_KP_Page_Down:
	  {
	    if (shift & VKM_Ctrl)
		te()->scrollDown(CmdCount * te()->GetRows());
	    else
		retval = te()->lineDown(
	    	    (long) te()->minl((CmdCount * te()->GetRows()),
	    	    (long)(te()->GetLines() - te()->GetCurLine() + 1)));
	    break;
	  }

	case 'r': 			/* right */
	    retval = te()->charRight(CmdCount,1);
	    break;

	case vk_Right:
	case vk_KP_Right:
	  {
	    if (shift & VKM_Ctrl ||shift & VKM_Shift)
		retval = te()->wordRight(CmdCount);
	    else
		retval = te()->charRight(CmdCount,1);
	    break;
	  }

	case 's':			/* save lines in move buffer */
	    retval = save(CmdCount,0);
	    break;

	case 't':			/* tidy up screen */
	    retval = te()->formatC(CmdCount);
	    break;

	case 'U':
	case 'u': 			/* up line */
	    retval = te()->lineDownBeg(-CmdCount);
	    break;

	case 'v':			/* verify */
	    te()->Verify();
	    break;


	case 'Y'-'@':			/* append external file to save buffer */
	case 'y':			/* write save buffer to file */
	    retval = yankfile(CmdCount);
	    break;

	case '~':			/* '~': change case */
	    retval = te()->charFoldCase(CmdCount);
	    break;

//@@	case Cxa:		/* abandon file */
//@@	    clear_mark_range();		/* no range now */
//@@	    abandon_changes();
//@@	    break;

//@@	case Cxf:		/* copy selection to find */
//@@	    succ = copy_selection(1);
//@@	    break;

//@@	case Cxk:			/* define/execute key macro */
//@@	    ED(target) = T_BUILD_KM;
//@@	    (void) km_build(0);
//@@	    break;


//@@	case Cxr:		/* copy selection to replace */
//@@	    succ = copy_selection(0);
//@@	    break;

#ifdef XXXYYYX
	case Cxcf:		/* replace again */
	    if (s_succ = succ = do_find(1,1,1))	/* find first */
	      {
		succ = replace();			/* do the replacement */
	      }
	    break;
#endif

	default:
	    retval = 0;
	    break;
      }  			/* end of switch */

    if (! retval)		// handle repeat loops
	return 0;
    else
	oldlex = lexval;
    CmdCount = 1;

    return 1;
  }

/* =============================>>> vSeeCI::inset <<<============================= */
  int vSeeCI::inset(int val, int *set)
  {
     /* return true if val is in set set */

    while (*set)
	if (val == *set++)
	    return 1;
    return 0;
  }

/* =============================>>> vSeeCI::rmvlst <<<============================= */
  int vSeeCI::RemoveLast(void)
  {  /* RemoveLast - delete the previous thing found or manipulated
	length of oldlen is set by insert, find, and save
	may also use savlen if set by save */

    static int rmv_set[] =
      {
	'f', 'F' - '@', '^', 's', 'g', ';', 'a', 'I'-'@', '[', '_', 0
      };

    if (te()->RemoveMarkRange())	/* was a mark range to remove */
	return 1;			/* all done */

    if (!inset(oldlex,rmv_set))
	return 0;

    te()->ClearMarkRange();		/* no range now */

    if (savlen > 0)
      {
        int oldech = te()->GetEdState().echof;
        if (savlen > 1)
            te()->SetEchoF(0);
	if (te()->GetCurLine() == te()->GetLines()-1 && slastl != 0)
	  {
	    --savlen;	/* reduce the count */
	    if (savlen > 0)
	      {
		te()->lineDelete(-savlen);	/* kill off previous lines */
              }
	    te()->lineDelete((long) 1);		/* kill the last line */
            if (oldech)
                te()->SetEchoF(oldech);
            te()->Verify();
	  }
	else
          {
	    te()->lineDelete(-savlen);		/* kill off savlen lines */
            if (oldech)
                te()->SetEchoF(oldech);
            if (savlen > 1)
            	te()->Verify();
          }

      }
    else if (te()->OldLen() != 0)
      {
	if (! te()->charDelete((long)-te()->OldLen()) )
	    return 0;
      }
    te()->SetOldLen(0);			/* don't allow multiple deletes! */
    savlen = (-1);
    return 1;
  }

// =============================>>> vSeeCI::save   <<<=========================
  int vSeeCI::save(long cnt, int app)
  { /* save - save cnt lines in save buffer */

    long l, lend;

    int old_ef = te()->GetEdState().echof;   	// remember state of echo flag

    if (cnt < 0)
	return 0;

    if (te()->GetCurLine() == te()->GetLines()-1 && slastl != 0)
      {
	te()->ErrorMsg("Can't save last line twice! ");
	return 0;
      }

    te()->SetOldLen(0);			/* use savlin instead */

    if ((oldlex != 's' && !app) || cnt == 0)
      { 			/* if new save, cnt == 0 and not appending */
        // Clear old save buffer - delete storage for lines
        for (long lx = 0 ; lx < nxtsav ; ++lx)  // copy old lines
	    if (_SaveBuff[lx])
                delete [] _SaveBuff[lx];	// free space

        slastl = savlen = nxtsav = 0;	/* reset these guys */

	if (cnt == 0)
	  {
	    return 1;
	  }
      }

    if (oldlex != 'a' && app)	/* need to reset savlen for append */
	savlen = 0;

    if (cnt > 10)
	te()->SetEchoF(0);

    lend = (te()->GetCurLine()+cnt-1 < te()->GetLines()-1)
	    ? te()->GetCurLine()+cnt-1
	    : te()->GetLines()-1 ;

    for (l = te()->GetCurLine() ; l <= lend ; ++l)
      {
	if (nxtsav >= _maxSBLines)         // check for max lines
	  {
	    if (!reallocSaveBuff())
	      {
		if (cnt > 10)
		  {
		    te()->SetEchoF(old_ef);
		    te()->Verify();
		  }
		te()->ErrorMsg("Not enough memory for save ");
		return 0;
	      }
          }

        char line[MAX_LINE + 2];
        te()->getLine(line, MAX_LINE, l);	// fetch the line
        char* cp = new char[strlen(line) + 1];
        strcpy(cp, line);
        _SaveBuff[nxtsav++] = cp;	// copy the line to buffer

	++savlen;		/* savlen for rmvlst */
	if (te()->GetCurLine() == te()->GetLines()-1)	/* don't save last line twice! */
	  {
	    slastl = 1;
	    break;
	  }
        (void) te()->lineDownBeg(1);
      }

    if (cnt > 10)
      {
	te()->SetEchoF(old_ef);
	te()->Verify();
      }
    return 1;
  }

//========================>>> vSeeCI::reallocSaveBuff <<<======================
  int vSeeCI::reallocSaveBuff()
  {
    BUFFPTR* oldLines = _SaveBuff;

    _SaveBuff  = new char*[_maxSBLines + SBAllocLines];
    if (!_SaveBuff)
      {
	_SaveBuff = oldLines;              // failed to get more lines
	return 0;
      }

    long lx;
    for (lx = 0 ; lx <= _maxSBLines ; ++lx)  // copy old lines
	_SaveBuff[lx] = oldLines[lx];

    _maxSBLines = _maxSBLines + SBAllocLines - 1;       // safety factor

    for (; lx <= _maxSBLines ; ++lx)  // null new lines
	_SaveBuff[lx] = 0;


    delete [] oldLines;                 // free the old lines
    return 1;
  }

//=============================>>> vSeeCI::getsav <<<==========================
  int vSeeCI::getsav()
  { /* ## getsav - get text from save buffer */

    long lx;
    int ix;

    if (nxtsav <= 0)		/* nothing to get */
      {
	return 1;
      }

    int old_ef = te()->GetEdState().echof;
    te()->SetEchoF(0);

    te()->ClearMarkRange();		/* no range now */

    // If someday I want the insert to be allowed in the middle
    // of a line, then the easiest way is to insert the first line
    // of the save buffer char by char, then bulk insert the rest
    // after the next line. For now, just insert in front of current
    // line.

    te()->lineBeginning();			// force to beginning

    long curLine = te()->GetCurLine();		// find current line

    for (lx = nxtsav - 1 ; lx >= 0 ; --lx)
       te()->insertLine(_SaveBuff[lx], curLine);	// insert the lines backwards

    te()->lineDownBeg(nxtsav);			// go back down to where we were

    te()->IncChanges();				/* note changes */

    te()->SetOldLen(0);				// fix up this stuff
    te()->SetEchoF(1);
    te()->Verify();
    return 1;
  }

// =============================>>> vSeeCI::yankfile   <<<=========================
  int vSeeCI::yankfile(long cnt)
  { 	// yank file to or from save bufer

    long l, lend;

    int old_ef = te()->GetEdState().echof;   	// remember state of echo flag

    char buff[MAX_LINE+2];
    vFileSelect fsel(cmdWin());

    if (cnt < 0)		// write save buffer
      {
	buff[0] = 0;
	int ians = fsel.FileSelectSave("Write save buffer to file",
		buff, MAX_LINE, filter, filterIndex);
	if (!ians)
	    return 0;

	ofstream fout(buff);		// open the file to yank
 	if (!fout)
	    return 0;

	for (long lx = 0; lx < nxtsav ; ++lx)
	    fout << _SaveBuff[lx] << endl;
	fout.close();
	return 1;
      }
    else
      {
	buff[0] = 0;
	int ians = fsel.FileSelect("Yank file to save buffer",
		buff, MAX_LINE, filter, filterIndex);
	if (!ians)
	    return 0;

	ifstream fin(buff);		// open the file to yank
 	if (!fin)
	    return 0;

        // Clear old save buffer - delete storage for lines
        for (long lx = 0 ; lx < nxtsav ; ++lx)  // copy old lines
	    if (_SaveBuff[lx])
                delete [] _SaveBuff[lx];	// free space

        slastl = savlen = nxtsav = 0;	/* reset these guys */

	while (fin.getline(buff,511))
	  {
	    if (nxtsav >= _maxSBLines)         // check for max lines
	      {
		if (!reallocSaveBuff())
		  {
		    te()->ErrorMsg("File too big -- only partially read ");
		    fin.close();
		    return 0;
		  }
	      }
	    // have a line to add
	    char* cp = new char[strlen(buff) + 1];
	    strcpy(cp, buff);
	    _SaveBuff[nxtsav++] = cp;	// copy the line to buffer

	  }
	fin.close();
      }
    return 1;
  }

#ifdef XXYYXX
//=============================>>> vSeeCI::ins_pat  <<<=============================
#ifdef ANSI_C
  int ins_pat(void)
#else
  int ins_pat()
#endif
  {
    char *chrp;

    if (!*pat_buff)
	return 0;

    for (chrp = pat_buff ; *chrp ; )	/* simply insert pattern buffer */
      {
	if (!ins_chr((int)*chrp++))	/* make sure it works */
	    return 0;
      }

    return 1;
  }
#endif
