
#include	"sysdef.h"
/*								*/
/*	Copyright Notice					*/
/*								*/
/*								*/
/*	C version Copyright (C) 1984 Change Software, Inc.	*/
/*	Copyright (C) 1978 1979 1980 1981 1982 1983 1984 by	*/
/*		      Change Software, Inc.			*/
/*								*/
/*								*/
/*	This software is furnished under a license and may	*/
/*	be  used  and  copied  only in accordance with the	*/
/*	terms of such license and with  the  inclusion  of	*/
/*	the  above copyright notice.  This software or any	*/
/*	other copies thereof may not be provided or other-	*/
/*	wise made available to any other person.  No title	*/
/*	to and ownership of the software is hereby  trans-	*/
/*	ferred.							*/
/*								*/
/*	The information in this  software  is  subject  to	*/
/*	change  without notice and should not be construed	*/
/*	as a commitment by the author.				*/
/*								*/
/*								*/

#include	"scterm.h"
#include	"tempio.h"
#include	"scerrd.h"
#include	"edswdf.h"

#define	CR	015
#define	LF	012

#define	INIT_SIZE	500
#if VAXVMS
#define	INCR_SIZE	1000
#else
#define	INCR_SIZE	300
#endif

/*
	 Modes in  which the tempfile updates routines can be in
	These modes control the 'dirtyness' of a tempfile buffer
	Stored in INT CURMODE, defined in TEMPIO.H

	ST_NORMAL_MODE_mode:	Do not update disk copy of text  window.
			Access is assumed to be readonly, wwhich
			for most accesses is true.
	ST_IFL:		Build index sequentially since the index
			will not be completed yet. Set when  the
			readonly copy of the input file is being
			read.
	ST_INSERT:	When adding lines, will force updates.
	ST_UPDATE:	Update the text window to the work file.
			this must be set  for any  module  which
			wants to alter text in a line.


	A note about temp file routines

	In general, the temp file handlers will abort on ANY fatal
	error.  While not terribly gracious, what else is there to
	do?


*/



/*	Globals that we really only need in this module, however, the
	structure  'WINDOW'  will be referenced just about everywhere
	we reference a line.
*/
  struct ctx	{
		int laddr ;
		int lc ;
		} ;


  char	 bigbuffer[_maxlen*2] ;

  static struct ctx	sccontext ;		/* for saving context	*/
  struct fswitch	inswitch ;		/* for input switches	*/
  struct textline	inline ;		/* a useful line	*/

  int    indexsize[NWINDOWS] ;			/* save size of virt mem */
  int	 w = 0  ;				/* current window number */

  int	 win_low[NWINDOWS] ;			/* save screen boundarys */
  int	 win_high[NWINDOWS] ;		/* same */
  int	 win_curline[NWINDOWS] ;		/* save current line number */
  struct textline	*w_l_address[_BCK_FIL];	/* pointer to current lines */
  struct tempindex	*win_workpt[NWINDOWS] ;	/* points to workfile index */
  struct tempindex	*workpt ;		/* point to workindex[]	    */
  struct textwindow	*windpt ;		/* pointer to current bucket */
  struct textwindow	window[NWINDOWS] ;	/* current view into workfile */
  struct tempblock	tempbuffer[NWINDOWS] ;	/* store the current bucket */
  struct stats		tempstat ;		/* update for cache hits */
  struct deltype	lastdeleted ;
  int tmpsiz  = _tmpsize  ;
  int bck_fil = _bck_fil  ;
  int bck_size= _bck_size ;
  int maxlen = _maxlen 	  ;
  int eoferror = ER_EOF	  ;

  int tty   =	_tty   ;
  int ansi  =	_ansi  ;
  int vt100 =	_vt100 ;
  int vt220 =	_vt220 ;

  int page_size[]={			/* size of the useable display	*/
		0		,	/* tty				*/
		22		,	/* ansi h19 style		*/
		20		,	/* vt100			*/
		20		,	/* vt220's			*/
		0			/* future?			*/
		  } ;


  int termtype = 0 	  ;
  int matchflag = 0	  ;
  int ffstop = 0	  ;
  int tempopen = 0	  ;

  int iniecho  = 0	 ;
  int escprint = 0	 ;
  int leftmargin  = 1	 ;
  int rightmargin = 72 	 ;
  int read_only = 0	 ;
  int infisize = 0	 ;
  static int ctx_valid = 0 ;
  int	curbucket[NWINDOWS]	 ;
  int	lstbucket[NWINDOWS]	 ;
  int	firbucket[NWINDOWS]	 ;	
  int	maxbucket[NWINDOWS]	 ;
  int	linecount[NWINDOWS]	 ;
  int	blkoffset[NWINDOWS]	 ;
  int	win_maxline[NWINDOWS]	 ;
  int   *maxline         ;
  int	lowlim		 ;
  int	highlim		 ;
  int	target		 ;
  int	trimarg		 ;
  int	filopen		 ;
  int	dovtedit	 ;
  int	argstat		 ;
  int	curmode[NWINDOWS];
  int	*loclow		 ;
  int	*lochigh	 ;
  int	*curline	 ;
  int	ttpsize		 ;
  int	verbose = 1	 ;
  int	kblun = kb_lun	 ;
  int	cmdlun= kb_lun	 ;
  int	inlun = in_lun	 ;
  int   outlun = out_lun ;
  int	indlun = ind_lun ;
  int	tmp1lun = tmp1_lun ;
  int	tmp2lun = tmp2_lun ;
  int	p_lines = 1	 ;
  int	oldstsone = 0	 ;
  int	sts_one = 0	 ;
  int	sts_two = 0	 ;
  char	argfile[_FILESIZE] ;
  char	insource[_FILESIZE];
  char  worddelim[32]	 ;
  int	dirindex = 0	 ;
  int	stvtedit = 0	 ;
  int	restart = 0	 ;
  int	waswild = 0	 ;
  int   maxfilesize = _FILESIZE ;
  int	filesize = 0 ;
  int	hlpctx[2] ;
  char	*hlbuffer ;
  int	nwindows = NWINDOWS ;


char	infi1[_FILESIZE] ;
char	infi2[_FILESIZE] ;
#if	NWINDOWS-3
char	infi3[2] ;
#else
char	infi3[_FILESIZE] ;
#endif

char	*infile[] = { infi1,infi2,infi3 } ;




/*	Define the mechanism for indexing into the window pointers	*/
/*	First, the fast way for virtual 32 bit systems like VMS.	*/

#if	VAXVMS
#define	_gworkpt(offset) workpt+offset
#endif


#if	RSX
extern struct tempindex *mapwin() ;
#define	_gworkpt mapwin
#endif


/*
#if	RSX
#define	_gworkpt workpt+
#endif
*/

/*	If we want to use a mapped dynamic region for memory management
	we can define _gworkpt as follows and write a function to check
	the mapping and appropiately remap if need be. Doing so will of
	course require mods to the way getvm is called.
	Additionally, the editor will run a bit slower due to the over-
	head involved with procedure calls and mapping the region. This
	alternative has been defined for possible use in the PDP-11 TED
	and has NO place being used on VMS (obviously).

#define	_gworkpt(offset) mapwork(offset)

static struct tempindex *mapwork(offset)
int offset ;
{
	return( workpt+offset ) ;
}

*/
	

/*	Procedure Ins_Line

	Ins_line  takes the line  passed to  it and  inserts it into the
	current workfile bucket. Obviously, if the current bucket should
	become full Ins_Line will process that. For insertions after the
	initial file load,  it is assumed that SAVELN has been called to
	setup the bucket split to handle this.
*/


ins_line( line ,size )

char 	*line;
int	size;

{
	struct textline detab_buffer ;	/* in case removing tabs and such */
	register char *lp,*dp ;		/* register pointer to the line	*/
	register int i ;
	int	more ;			/* some local things		*/
	extern  int checkindex();	/* check the index for room	*/

	lp = line ;
	if ( inswitch.tabxl )
	  then	{
		lp = detab_buffer.c ;
		size = detab( lp,line, size ) ;
		}
	if ( inswitch.casexl )
	  then	{
		dp = detab_buffer.c ;
		for (i=size; i > 0; i-- ) *dp++ = toupper(*lp++) ;
		lp = detab_buffer.c ;
		}
	more = true ;
	while (more) {
	  curbucket[w] = lstbucket[w] ;
	  if ( linecount[w] == 0 ) then blkoffset[w] = 0 ;
	  if ((linecount[w] == bck_fil) || (blkoffset[w]+size >= bck_size))
	    then {
		ins_block();
		ins_lnks();
		linecount[w] = 0 ;
		more = true ;
		 }
	    else more = false ;
	}
	if ( size != 0 ) then tempbuffer[w].rsize[linecount[w]++] = size ;
	dp = &tempbuffer[w].txt[blkoffset[w]] ;
	blkoffset[w] += size ;
	scopy(dp,lp,size) ;
	return(SYS_NORMAL) ;
}


putlast( line,size )

char	*line ;
int	size ;

{
	ins_block();
	ins_lnks();
	ins_line( line,size );
}


ins_block()

{
	register int nxtbucket,done,foundlink;

	lstbucket[w] = 0 ;
	if ( curmode[w] == ST_IFL )
	  then	{
		curbucket[w]++ ;
		lstbucket[w] = curbucket[w] ;
		(_gworkpt(lstbucket[w]))->link = lstbucket[w] + 1 ;
		}
	  else  {
		nxtbucket = 1 ;
		done = ( nxtbucket > maxbucket[w] ) ? true:false ;
		while (done == false )
		  {
		   lstbucket[w] = nxtbucket ;
		   if ( (_gworkpt(nxtbucket))->lcount != 0 )
		     then {
			nxtbucket++ ;
			foundlink = false ;
			done = ( nxtbucket > maxbucket[w] ) ? true:false ;
			  }
		     else {
			done = true ;
			foundlink = true ;
			  }
		   }
		if ( foundlink == false )
		  then {
			maxbucket[w] = nxtbucket ;
			lstbucket[w] = nxtbucket ;
		       }
		(_gworkpt(nxtbucket))->link=(_gworkpt(curbucket[w]))->link;
		(_gworkpt(curbucket[w]))->link = nxtbucket ;
		(_gworkpt(nxtbucket))->lcount = -1 ;

		}	/* end else */
}


ins_lnks()
{
	register int i,nchars,status ;

	(_gworkpt(curbucket[w]))->lcount = linecount[w] ;
	nchars = 0 ;
	for ( i=0; i<linecount[w]; i++ ) nchars +=tempbuffer[w].rsize[i] ;
#if CHARCOUNT
	(_gworkpt(curbucket[w]))->chcount = nchars ;
#endif
	status = checkindex(curbucket[w]) ;
	status = puttemp( &tempbuffer[w],curbucket[w],w ) ;
	tempstat.writes++ ;
	windpt->toplin = 0 ;
	if (linecount[w] == 0)
	  then	{
		if ( curbucket[w] == firbucket[w] )
		  then firbucket[w] = (_gworkpt(curbucket[w]))->link ;
		  else	{
			i = 1 ;
			while ( (_gworkpt(i))->link != curbucket[w] ) i++ ;
			(_gworkpt(i))->link = (_gworkpt(curbucket[w]))->link ;
			}
		(_gworkpt(curbucket[w]))->link = 0 ;
		}
}



dumpstats()
{
	xprintf("Accesses (r/w) %d %d\n",tempstat.reads,tempstat.writes);
	xprintf("Faults   (r/w) %d %d\n",tempstat.r_faults,tempstat.w_faults);
	xprintf("Cache hits     %d\n",   tempstat.hits) ;
	accstats() ;
}

dumpindex()
{
	long ccount ;
	register int st,i ;

	st = 1 ;
	ccount = 0 ;
	for (i=1;i<=maxbucket[w] && testcc() == 0;i++) {
#if CHARCOUNT
		decout((_gworkpt(i))->chcount) ;
#endif
		decout((_gworkpt(i))->lcount ) ;
		decout((_gworkpt(i))->link ) ;
		decout(st) ;
		st = st + (_gworkpt(i))->lcount ;
#if CHARCOUNT
		ccount = ccount + (_gworkpt(i))->chcount ;
#endif
		crlfout() ;
		}
	xprintf("\n Average characters/bucket %d\n",(i=ccount/maxbucket[w])) ;
	xprintf(" Average lines/bucket %d\n\n",st/maxbucket[w]) ;
}




/*	 FindLine looks through the resident index to locate the workfile
	bucket that has the desired line in it. If the workfile bucket is
	already resident on the current window, it will simply return the
	the index to it. If not resident, it will ask the workfile cacher
	to return the bucket containing the line and then update the win-
	dow to contain all the lines from that bucket, returing the index
	to the desired line.
*/


struct textline *textpointer(linenumber)
int linenumber ;
{
	return( w_l_address[ findline(linenumber) ] ) ;
/*	return( &windpt->lines[findline(linenumber)] );  */
}	


findline( lineno )
int lineno;
{

	int      temp,status,oldcurmode ;
	register int i,buffoffset,wline ;
	
	read_only = 0 ;
	if ( *maxline < 2 ) then error( ER_NOLINES ) ;
	if ( (lineno >= windpt->botlin) && (lineno <= windpt->toplin) )
	  then 	return(lineno - windpt->botlin) ;
	  else {
		if ((oldcurmode=curmode[w]) == ST_UPDATE) then putback();

/*		Desired line not found in current window, assume that	*/
/*		we are like searching for a pattern so try looking in	*/
/*		the next window. If its not in the next window,  then	*/
/*		start all over from the first link  to the end.  Also	*/
/*		check CTX_VALID to see if  next field can be invalid.	*/
/*		If CTX_VALID is zero then ignore the next  field  and	*/
/*		start at the top of the index to the end.		*/

		temp = 0 ;
		if (  (curbucket[w]=(_gworkpt(curbucket[w]))->link) != 0
		    && oldcurmode == ST_NORMAL_MODE
		    && ctx_valid )
		  then	{
		    windpt->botlin = windpt->toplin + 1 ;
		    windpt->toplin += (_gworkpt(curbucket[w]))->lcount ;
		    temp = ( ( lineno >= windpt->botlin ) && 
			     ( lineno <= windpt->toplin ) ) ;
			} ; 

		if ( temp == 0 )
		  then {		
		    curbucket[w] = firbucket[w] ;
		    windpt->botlin = 1 ;
		    windpt->toplin = (_gworkpt(curbucket[w]))->lcount ;
		
		    while (! (( lineno >= windpt->botlin ) && 
			      ( lineno <= windpt->toplin )) ) {
		      	windpt->botlin = windpt->toplin + 1 ;
			curbucket[w] = (_gworkpt(curbucket[w]))->link ;
			windpt->toplin += (_gworkpt(curbucket[w]))->lcount ;
			} ;
		    } ;
		status = gettemp( &tempbuffer[w],curbucket[w],w ) ;
		tempstat.reads++ ;
		lstbucket[w] = curbucket[w] ;
		ctx_valid = 1 ;

		buffoffset = 0 ;
		temp = (_gworkpt(curbucket[w]))->lcount ;
		for (wline=0; wline<temp; wline++ )
		  {
		   scopy( w_l_address[wline]->c ,
			  &tempbuffer[w].txt[buffoffset] ,
			  tempbuffer[w].rsize[wline] ) ;
		   w_l_address[wline]->len = tempbuffer[w].rsize[wline] ;
		   buffoffset += w_l_address[wline]->len ;

/*		   scopy( &windpt->lines[wline].c[0],			  */
/*			  &tempbuffer[w].txt[buffoffset],		  */
/*			  tempbuffer[w].rsize[wline] ) ;		  */
/*		   windpt->lines[wline].len = tempbuffer[w].rsize[wline] ;*/
/*		   buffoffset += windpt->lines[wline].len ;		  */

		  }
		curmode[w] = ST_NORMAL_MODE ;
		return( lineno - windpt->botlin );
	       }
}



putback()
{
	register int	i,nlines ;

	lstbucket[w] = curbucket[w] ;
	linecount[w] = 0 ;
	nlines = (_gworkpt(curbucket[w]))->lcount ;
	for ( i=0; i < nlines ; i++ ) 
		ins_line( &windpt->lines[i].c[0],windpt->lines[i].len );
	ins_lnks();
	if (curmode[w] != ST_SPECIAL) then curmode[w] = ST_NORMAL_MODE ;
	ctx_valid = 0 ;
	return(SYS_NORMAL);
}




/*	Procedure SAVELN

	SAVELN  takes the current window from the start  linenumber
	(relative to  the start of the window)  to the desired line
	and updates the index to make room for a new line. The line
	number are relative, in that they are number 1..WINDOWSIZE.
	Since offsets for array in 'C' start at zero, the reference
	to 'lineno-1' should be obvious.
*/


saveline(rel_start_line,rel_fin_line)
int	rel_start_line,rel_fin_line;
{
	register int lineno;

	for ( lineno = rel_start_line; lineno < rel_fin_line; lineno++ )
	  ins_line(windpt->lines[lineno].c,windpt->lines[lineno].len);
	return(SYS_NORMAL);
}



/*	Procedure CheckIndex

	Checkindex should check to see if there is sufficient  space in the
	workfile pointer index (which  is maintained in memory) to add ano-
	ther entry. If not, then it should do the equivalent of a EXTK$S to
	get the space needed and update the size.
*/


checkindex( rnum )
int rnum ;
{
	register struct tempindex *status ;
	extern   struct tempindex *getvm() ;
	int temp ;

	if ( rnum < indexsize[w]-10 )
	  then	return( SYS_NORMAL ) ;
	  else	{
		if ( (status=getvm(indexsize[w]+INCR_SIZE,w,&temp)) == 0 )
		  then	{
			tederror("Failure to extend index, please finish") ;
			return(0) ;
			}
		  else	{
			indexsize[w] = indexsize[w] + temp ;
			win_workpt[w] = status ;
			workpt = win_workpt[w] ;
			return( SYS_NORMAL ) ;
			}
		}
}



/*	SCLOADLINE()		load workbuffer with desired line	*/
/*	SCUNLOADLINE()		unload desired line from workbuffer	*/
/*	TEXTMODIFY()		mark text window as being dirty		*/


scunloadline()
{
	extern int loaded,laddr,worklength ;
	extern char workbuffer[] ;
	register char *wp,*cp;
	register int i;

	if ( loaded == 0 ) then return(1) ;
	loaded = 0 ;
	wp = workbuffer ;
	if (worklength == 0) then worklength = 1 ;
	windpt->lines[sccontext.laddr].len = worklength ;
	cp = windpt->lines[sccontext.laddr].c ;
	for (i=0;i<worklength;i++) *cp++ = *wp++ ;
	read_only = 0 ;
	return(1) ;
}
	
scloadline()
{	
	extern int *curline,loaded,laddr,worklength ;
	extern char workbuffer[] ;
	register char *wp,*cp;
	register int i;
	
	loaded = 1 ;
	if (*curline == 0) then *curline = 1 ;
	if (*curline >= *maxline ) then *curline = *maxline - 1 ;
	i = findline( *curline ) ;
	sccontext.laddr = i ;
	wp = workbuffer ;
	cp = windpt->lines[i].c ;
	worklength = windpt->lines[i].len ;
	scopy(workbuffer,windpt->lines[i].c,worklength) ;
	read_only = 0 ;
	if ( *curline == *maxline-1 ) then read_only = 1 ;
	return(1) ;
}



	
txtmod()
{
	extern int *curline,inmode ;

	if ( (sts_one & _vtedit) == 0 )
	  then	curmode[w] = ST_UPDATE ;
	  else	if ( *curline != *maxline ) then curmode[w] = ST_UPDATE ;

	
}	


ins_scline()
{
	savectx() ;
	rstctx() ;
}

savectx()
{
	extern int *curline ;

	sccontext.laddr = findline(*curline) ;
	linecount[w] = 0 ;
	curmode[w] = ST_INSERT ;
	sccontext.lc = (_gworkpt(curbucket[w]))->lcount ;
	saveline(0,sccontext.laddr) ;
}


rstctx()
{
	extern char workbuffer[];
	extern int worklength ;

	ins_line(workbuffer,worklength) ;
	(*maxline)++ ;
	saveline(sccontext.laddr,sccontext.lc) ;
	ins_lnks() ;
}






/*	switch to a new editing window	*/

wptset()
{
	register int i ;
	for ( i = 0 ; i < _BCK_FIL; i++ )
	  w_l_address[i] = &windpt->lines[i] ;
}


vtswindow(new_w)
int new_w ;
{
	int temp_w ;

#if	NWINDOWS-1

	temp_w = w ;
	if ( new_w == -1 )
	  then	temp_w = ( temp_w == 0 ) ?1:0 ;
	  else	temp_w = new_w ;
	if ( temp_w > NWINDOWS-1 )
	  then	{
		scwarning(w_badwin) ;
		return(0) ;
		} ;
	scunloadline() ;
	w = temp_w ;
	workpt   = win_workpt[w] ;
	maxline  = &win_maxline[w] ;
	windpt = &window[w] ;
	wptset() ;
	loclow   = &win_low[w] ;
	lochigh  = &win_high[w] ;
	curline  = &win_curline[w] ;
	if ( *curline == 0 )
	  then	{
		inseofmark() ;
		*loclow = 1 ;
		*curline = *loclow ;
		}
	putbin("\015\012",2) ;
	scloadline() ;
	scmove() ;
	newpage(*curline) ;
	sctopline() ;
	scloadline() ;
	scmove() ;
	return(1) ;
#else
	scwarning(w_badwin) ;
	return(0) ;
#endif
}
	
