#include	"stdio.h"
#include	"ed.h"
/* ovudfb31.c: (read "up down forward back" for "udfb")
** overlay 31 source code.
** this large overlay is a portmanteau of frequently-used
** commands. One can hardly justify having some of them in
** overlays UNLESS the overlay in question is one which is
** likely to be in memory at all times -- so, this overlay 
** includes gobs of the most useful commands.
*/

extern int   wstyle;	/* Which kind of Word operations? */
extern int   currow;	/* set by update() */
extern int   tabsize;	/* if tabs are expanded to spaces. */
extern char *kbufp;	/* Kill buffer data */
extern int   kused;	/* # of bytes used in KB */
extern int   ksize;	/* # of bytes allocated in KB */

#define TABCASE 40	/* case TABCASE and above are special. */
	/* cases < TABCASE are numbered so that we can handle a negative
	** parameter with "casenumber ^= 1"
	*/

ovmain( x )
#define cmdflag (*(int *)0x102)
#define cmdparm (*(int *)0x104)
{
	register LINE	* mylp;
	register WINDOW * mywp;

#define temp_int (*(int *)0xc0)
#define mydoto   (*(int *)0xc2)
#define xbufchar (*(int *)0xc4)
#define limitp   (*(LINE **)0xc6)
#define localx   (*(int *)0xc8)
#define xinsct   (*(int *)0xca)
#define mylen    (*(int *)0xcc)
#define Wdoto    (*(int *)0xce)
	/* the above #defines are temporary variables, in effect:
	** the compiler generates much smaller code for specific addresses
	** than it does for stack variables.
	*/

	xinsct = 1;
	mywp = curwp;
	mylp = mywp->w_dotp;
	limitp = curbp->b_linep;
	temp_int = mydoto =  0;
	mylen = llength( mylp );
	Wdoto = mywp->w_doto;

	if ( ( localx = x ) < TABCASE )
	{	/* most commands here have negative-parameter counterparts. */

		if ( cmdparm < 0 )
		{	localx ^= 1;
			cmdparm = -cmdparm;
		}
	}

	switch ( localx )
	{
		case 13:	/* goto end of line. */
			mydoto = mylen;
			goto dotpset;
		case 12:	/* goto start of line. */
			if ( cmdflag && ( mydoto = cmdparm -1 ) > mylen )
				mydoto = mylen;
			goto dotpset;
		case 10:	/* page forwards */
		case 11:	/* page back. */
			cmdparm *= ( mywp->w_ntrows - 1 );
			goto linemotion;
		case 1:	/* up arrow.  */
			++cmdparm;
			goto linemo2;	/* backward goes n+1 lines! */
		case 9:	/* gotoeob */
			if ( cmdparm ) --cmdparm;
		case 8:	/* gotobob */
			mylp = curbp->b_linep;
linemotion:
			/* if ( localx & 1 ) */
			/* {	mylp = lforw( mylp ); */
			/* } */
			curgoal = curcol = 0;
			/* mywp->w_flag |= WFHARD; */
linemo2:		/* fall through. */
		case 0:	/* down arrow */
		{	/* up or down */
			if ( ! ( lastflag & CFCPCN ))
			{	/* Reset goal if last not up/down */
				curgoal = curcol;
			}
			thisflag |= CFCPCN;

			if ( localx & 1 )	/* backward */
			{	while ( decparm()
					&& ( mylp = lback( mylp )) != limitp
				);
			}
			else
			{	while ( decparm()
					&& ( mylp = lforw( mylp )) != limitp
				);
			}	/* "--n >= 0" for n+1 lines. */

			while ( mydoto != llength( mylp ))/* NOT mylen! */
			{	if ( ( xbufchar = lgetc( mylp, mydoto ))
					== '\t' )
						temp_int |= 0x07;
				else if ( ! isinsert( xbufchar ))
					plustemp();
				if ( ++temp_int > curgoal ) break;
				++mydoto;
			}
dotpmove:		wfmove();
dotpset:		mywp->w_dotp  = mylp;
			mywp->w_doto  = mydoto;
			goto rettrue;	/* return ( 1 ); */
		}	/* end case 0 or 1 */
		case 2:	/* word forward */
		case 4:	/* del word forward */
		{	/* mylp = curwp->w_dotp; at top (mylp) */
			mydoto = Wdoto;
			while ( decparm())
			{	if ( ! ( wstyle & 2 ) && ! fwx())
				{	goto retfalse;
				}
				while ( inword( ))
				{	fc1();
					/* assert the above cannot fail. */
					plustemp();
				}
				if ( wstyle & 2 && ! fwx())
				{	goto retfalse;
				}
			}
			if ( localx == 2 ) goto rettrue;
			mywp->w_dotp = mylp;
			mywp->w_doto = mydoto;
			goto retldel;	/* return ( ldelete( temp_int, 1 )); */
		}	/* end case 2 or 4 */
		case 3:	/* word backward */
		case 5:	/* del word backward */
		{
			if ( ! bc1( )) goto retfalse; /* TOF */
			/* temp_int++; */
			while ( decparm())
			{
				while ( ! inword( ))
				{	if ( ! bc1()) goto retfalse;
					plustemp();
				}
				while ( inword( ))
				{	if ( ! bc1())
					{	/* top of file. */
retfalse:					return ( 0 );
					}
					plustemp();
				}
			}
			/* temp_int--; */
			fc1();	/* can't fail. */
			if ( localx == 5 )
			{	/* delword. */
retldel:			cmdflag = 1;
ret2ldel:			return ( ldelete( temp_int, cmdflag ));
			}
rettrue:		return ( 1 );
		}	/* end case 3 or 5. */
		case 6:	/* forwdel() */
		case 7:	/* backdel() */
		{
			if ( cmdflag )
			{	/* Really a kill.	*/
				kdcheck();
			}
			if ( ( localx & 1 ) && ! backchar( cmdflag, cmdparm ))
				goto retfalse;
			temp_int = cmdparm;
			goto ret2ldel; /*return(ldelete(cmdparm,cmdflag));*/
		}	/* end cases 6 and 7 */
		case TABCASE:
		{	/* with no parameter, perform tab function;
			** with one, set tabsize.
			*/
			if ( cmdparm < 0 ) return ( 0 );
			if ( cmdparm != 1 )
			{	tabsize = cmdparm;
				return( 1 );
			}
			xbufchar = '\t';
			if ( tabsize )
			{	xinsct = tabsize - 
					( ( curcol + 1 ) % tabsize );
				xbufchar = ' ';
			}
			return( xlinsc( ));
		}	/* end case TABCASE */
		case TABCASE+1:	/* openline() */
		case TABCASE+2:	/* indent() */
		{	/* openline() keeps cursor in same place,
			** inserts arg newlines.
			** indent() moves forward with its newlines,
			** adds whitespace to match the current line.
			*/
			mylp = lback( mylp );
			mydoto = Wdoto;
			while ( decparm()) if ( ! lnewline()) goto retfalse;
			mylp = lforw( mylp );
				/* lnewline() may delete the original
				** target of mylp.
				*/
			if ( localx == ( TABCASE + 1 ))
			{	/* openline(), done. */
				goto dotpset;
			}
			while ( ( xbufchar = lgetc( mylp, ++cmdparm )) == ' '
				|| xbufchar == '\t' )
			{	xlinsc( );
			}
			if ( xbufchar == '{' )
			{	/* C indent */
				xbufchar = '\t';
				xlinsc();
			}
			goto rettrue;
		}	/* end case indent() and openline() */
		case TABCASE+7:	/* vi-style kill. */
			cmdflag = 1;
			mywp->w_doto = Wdoto = 0;	/* fall through. */
		case TABCASE+3:	/* kill() */
		{	kdcheck();
			mydoto = Wdoto;
			if ( ! cmdflag )
			{	temp_int = mylen - mydoto;
				if ( temp_int == 0 ) temp_int = 1;
			} else if ( ! cmdparm )
			{	temp_int = mydoto;
				mywp->w_doto = 0;
			} else if ( decparm())	/* "if n > 0" */
			{	temp_int = mylen - mydoto + 1;
				mylp = lforw( mylp );
				while (decparm()) /* while --n */
				{	if ( mylp == limitp )
					goto retfalse;
					temp_int += llength( mylp ) + 1;
					mylp = lforw( mylp );
				}
			} else
			{	/* mlwrite("neg kill"); */
				ctrlg();
				goto retfalse;
			}
			goto retldel; /*return(ldelete(temp_int,TRUE));*/
		}	/* end case "kill()" */
		case TABCASE+4:	/* yank() */
		{	if ( ! decparm()) goto retfalse;
			do	/* make cmdparm copies. */
			{	temp_int = 0;
				while ( temp_int < kused )
				{	if ( ( xbufchar = kbufp[ temp_int ])
						== '\n' )
					{	lnewline( );
					} else
					{	if ( ! xlinsc())
							goto retfalse;
					}
					plustemp();
				}
			} while ( decparm( ));
			goto rettrue;
		}	/* end case yank() */
		case TABCASE+5:	/* set mark */
		{	mlwrite("[Mark]");
markset:		mywp->w_markp = mylp;
			mywp->w_marko = Wdoto;
			goto rettrue;
		}	/* end case set mark */
		case TABCASE+6: /* exchange mark and cursor. */
		{	if ( mywp->w_markp == NULL )
			{	mlwrite("No mark");
				return ( 0 );
			}
			mywp->w_dotp  = mywp->w_markp;
			mywp->w_doto  = mywp->w_marko;
			wfmove();
			goto markset;
		}	/* end case ^X^X */
	}
}

fc1()	/* saves 10 bytes per call to it. */
{	return( forwchar( 0, 1 ));
}
bc1()	/* saves 10 bytes per call to it. */
{	return( backchar( 0, 1 ));
}
fwx()	/* loop used twice in forwword. */
{	while ( ! inword( ))
	{	if ( ! fc1( )) return ( 0 );
		plustemp();
	}
	return ( 1 );
}
plustemp()	/* temp_int++ : saves 2 bytes per call. */
{	++temp_int;
}
decparm()	/* --cmdparm >= 0 */
{	return ( --cmdparm >= 0 );
}
xlinsc()
{	return( linsert( xinsct, xbufchar ));
}
kdcheck()
{	if ( ! ( lastflag & CFKILL )) kdelete();
	thisflag |= CFKILL;
}
wfmove()
{	curwp->w_flag |= WFMOVE;
}

