/*	mark saeger,	msaeger@cse.unl.edu				*/
/*	process.c							*/
/*	Copyright 1995 Mark Saeger.					*/
/*									*/
/*	Permission is granted to any individual or instituition to use,	*/
/*	copy, or redistribute this executable so long as it is not	*/
/*	modified and that it is not sold for profit.			*/
/*									*/
/*	LIKE ANYTHING THAT IS FREE, MORE IS PROVIDED AS IS AND COMES	*/
/*	WITH NO	WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED.	*/
/*	IN NO EVENT WILL THE COPYRIGHT HOLDER BE LIABLE FOR ANY DAMAGES	*/
/*	RESULTING FROM THE USE OF THIS SOFTWARE.			*/
#include "more.h"

/***********************/

#ifdef MINT
#include <termcap.h>
#endif

#ifdef UNIX
#include <curses.h>
#include <term.h>
#endif

/***********************/

void filler(int *mlcounter, int mlines, int mccounter);
char *conv_xl_to_string(int top_of_form);

int test_top_of_form;

/***********************/

/*when viewing more than one file, or with the command line option '-w',
prints the tilde character on an blank line at the end of the file, this 
way, '--more--' appears in the correct place*/
void filler(int *mlcounter, int mlines, int mccounter)
{
	extern char *cleod, *cleol;

	tputs(cleod,1,putch);
	while(*mlcounter < mlines-1)
	{
		if(mccounter==0)
			printf("~");
		tputs(cleol,1,putch);
		printf("\n");
		mccounter=0;	/*reset*/
		(*mlcounter)++;
	}
}

/* converts an integer to a string of characters with a '+' prefix*/
char *conv_xl_to_string(int top_of_form)
{
	int x=0;
	static char result[10];	/*finished product*/
	int divisor=1;		/*used to determine how big it is*/

/*we now find largest multiple that fits*/
	while((top_of_form/divisor) > /*10*/9)
		divisor*=10;

	result[x++]='+';

	while(divisor>=1)
	{
		result[x]=(top_of_form/divisor)+'0';/*store digits l->r*/
		top_of_form=top_of_form-((result[x]-'0') * divisor);
		x++;
		divisor/=10;
	}
	result[x]='\0';	/*and add \0*/

	return(result);
}

/*The user interaction point.  At the end of displaying a whole page this
routine is called to display the correct '--more--...' prompt.  It then
handles the users keypresses*/
int do_prompt(FILE *tty, int *qmore, int *mlcounter, int *poffset,int pipe,
	       long countlines, long totallines, int longlines[],
	       int xlonglines, int flag, int doing, node *llist)
{
	/*doing - flag to determine if we want keyboard input after prompt*/
	extern char *bold, *norm, *cleol, *cls, *curson, *cursoff;
	extern char **nextfile;
	extern int optc, optw, optd;
	extern int testvalue;
	extern int retflag;
	extern char **currfile;
	extern char *prog_name;	/*used in :p routine*/
	extern int optpl;
	extern rgx *globrgx;
	extern int mlines;
	extern int global_out_of_here;
	int	c,		/*hold return value from fgetc*/
		number,		/*hold option <#> before a command*/
		dum1,		/*dummy*/
		xxx,		/*dummy*/
		top_of_form,	/*the line that is the top of the page*/
		localflag,
		xl=0;		/*offset to adjust for longlines before top_of_form*/
	char	*editor,
		*shell,
		*commandline;
	char **prevfile;	/*to store the prev. file in command line(:p)*/
/*	int id;*/
	int savec;
	static int	last_number,	/*to store last # for the . command*/
			last_command,	/*used to store last keypress for . */
			space_number,	/* to handle <#><sp>*/
			d_number,	/* to handle <#> ^D */
			cr_number,	/* to handle <#><cr>*/
			save_rgx_pos;	/*to store # for ' to work*/
	extern int global_skipper;	/*pass value to main.c for next file*/
	extern test_top_of_form;	/*TEST-used in file.c*/

/******************************************************/
/*here we determine if lines wrapped or not and set top_of_form to the
correct value*/
	dum1=0;

/*this tells how many longlines weve had to the current point*/
	for(xxx=0;xxx<xlonglines;xxx++)
		if(longlines[xxx] <= countlines)
			xl++;

/*now check and see if we have longlines on the current "page"*/
	for(xxx=0;xxx<xlonglines;xxx++)
		if((longlines[xxx] >= countlines-(*mlcounter)+xl-xxx+1) && (longlines[xxx] <= countlines))
			dum1++;
	
	top_of_form=countlines-(*mlcounter)+dum1+1+testvalue;

	if(top_of_form<1)	/*cant be negative*/
		top_of_form=1;

	test_top_of_form=top_of_form;
/********************************************************/
/*leave dum1 alone since use it below....*/

	if(top_of_form<mlines)
		dum1=0;/*no offset when up at the top*/

/********************************************************/
	pcr();
	tputs(bold,1,putch);

	testvalue=0;
	switch (flag)
	{
		case PROMPTNORMAL:
			if(pipe)
				printf("Line %ld",top_of_form);
			else
				printf("--more-- (%ld/%ld)",top_of_form,totallines);
			if(!pipe)
				printf(" [%ld%%]",((countlines*100)/totallines));
			break;
		case PROMPTEND:
			if (optw)
			{
				if(!pipe)
				{
					if(*nextfile != NULL)
						printf("(END) Next file: %s",*nextfile);
					else
						printf("(END)");
				}
				else
					printf("(END)");
			}
			break;
		case PROMPTVERBOSE:
			printf("Press space to continue, 'q' to abort.");
			break;
		case PROMPTINVALID:
			printf("Invalid keypress, press 'h' for help.");
			break;
		case PROMPTLINE:
			printf("Line %ld",top_of_form);
			break;
		case PROMPTCURR:
			if(!pipe)
				printf("\rCurrent file is %s, at line %d",*currfile,top_of_form);
			else
				printf("\rCurrent file is a pipe, at line %d",top_of_form);
			break;
		case PROMPTNONEXT:
			if(!pipe)
				printf("\rNo next file.");
			else
				printf("\rData is from a pipe.");
			break;
		case PROMPTNOREGEX:
			printf("Pattern not found.");
			break;
		case PROMPTMISSING:
			printf("No regular expression entered.");
			break;
		case PROMPTNOEDIT:
			printf("Data is from a pipe, editing not allowed.");
			break;
		case PROMPTILLREG:
			printf("Illegal regular expression entered.");
			break;
		case PROMPTNONEXTF:
			printf("Attempt to skip to a non-existant next file.");
			break;
		case PROMPTNOPREV:
			if(!pipe)
				printf("\rNo previous file.");
			else
				printf("\rData is from a pipe.");
			break;
		case PROMPTNOPREVF:
			printf("Attemp to skip to a non-existant previous file.");
			break;
	}
	tputs(norm,1,putch);
	tputs(cleol,1,putch);
	fflush(stdout);
	number=0;
	optpl=0;
	while(doing)
	{
		if(space_number)	/*only comes here when <#><sp>*/
			c=' ';	/*set to space*/
		else
			c=fgetc(tty);	/*get keypress*/
		if(c>='0' && c<='9')	/*handle numbers*/
		{
			xxx=1;		/*counts how many characters entered*/
			number=(number*10)+(c-'0');
			printf("\r%c",c);	/*display*/
			tputs(cleol,1,putch);	/*and erase to EOL*/
			fflush(stdout);
			while(xxx>0)	/*always >, unless user <bs> over all chars*/
			{
				c=fgetc(tty);
				if(c=='\b')
				{
					xxx--;
					printf("\b");
					tputs(cleol,1,putch);
					number=(number/10);	/*erase*/
				}
				else if(c>='0' && c<='9')
				{
					xxx++;
					number=(number*10)+(c-'0');
					printf("%c",c);
				}
				else
					goto do_c;
				fflush(stdout);
			}
			
		}
		else
		{
do_c:
/*number is 0 if user doesnt type anything except a character*/
			if((c!='.') && !space_number)
			{
				last_number=number;	/*reset to prev.*/
				last_command=c;
			}
			savec=c;	/*save the keypress*/
			switch(c)
			{
				case 'q':
				case 'Q':
					pcr();
					doing=FALSE;
					*qmore=FALSE;
					break;
				case ' ':
					if(number>1)
						space_number=number;
/*space_number takes care of paging for number times*/
					if(space_number>0)
						space_number--;
					pcr();
					*mlcounter =0;
					doing=FALSE;
					if(optc && cls)
						tputs(cls,1,putch);
					break;
				case '\n':
					if(number>mlines-3)
						number=mlines-3;
					if(number)
						cr_number=number;/*save*/
/*if number == 1 then we want the defualt number to be used*/
					if(cr_number)
						number=cr_number;
/*start off w/ number==0, so we really want it to be 1*/
					if(!number)
						number=1;
					pcr();
					if(*mlcounter+1 == mlines)
						*mlcounter -= number;
					else	/*for -l option*/
	/*must be -2 at least, so change from -2 to -1-number(e.g. 2)*/
						*mlcounter=mlines-1-number;
					retflag=TRUE;
					doing=FALSE;
					break;
				case '\b':
					pcr();
					do_prompt(tty,qmore,mlcounter,poffset,pipe,
					  countlines,totallines,longlines,
					  xlonglines,PROMPTNORMAL,FALSE,llist);
					break;
				case '\004':	/*^D*/
				case 'd':
					if(number)
						d_number=number;/*save*/
					if(d_number && d_number<mlines)
						number=d_number;
					else
						number=11;
					pcr();
					*mlcounter -= /*11*/number;
					doing=FALSE;
					break;
				case 'z':
					if(number>1)	/*not checking for error*/
						mlines = number;
					pcr();
					*mlcounter =0;
					doing=FALSE;
					if(optc && cls)
						tputs(cls,1,putch);
					break;
				case 's':
					if(!number)
						number=1;
					optpl=number;
					pcr();
					doing=FALSE;
					break;
				case 'f':
					if(!number)	/*fix 0 -> 1*/
						number=1;
					optpl=number * mlines;
					pcr();
					doing=FALSE;
					break;
				case '\002':	/*^B*/
				case 'b':
					if(!number)
						number=1;
					if(top_of_form==1)
						goto here1;
					pcr();
		/*also should be 2*(~mlin...)  but made it 1+number(e.g. 2)*/
					*mlcounter= (1+number)*(~mlines+2+dum1);
/*					*mlcounter=-((1+number)*(mlines-1));*/
/*have to be careful if just doing a*/
/*page since we could go negative-'d'*/	doing=FALSE;
					break;
				case '\014':
				case 'l':	/*REDRAW*/
					retflag=FALSE;
					*mlcounter= (~mlines+2+dum1);
					doing=FALSE;
					break;
				case '=':
					pcr();
					do_prompt(tty,qmore,mlcounter,poffset,pipe,
					  countlines,totallines,longlines,
					  xlonglines,PROMPTLINE,FALSE,llist);
					break;
				case 'v':
					if(!pipe)
					{
						handle_v(conv_xl_to_string(top_of_form),pipe);
						retflag=FALSE;
						*mlcounter=(~mlines+2+dum1);
						doing=FALSE;
					}
					else
						do_prompt(tty,qmore,mlcounter,
						poffset,pipe,countlines,
						totallines,longlines,xlonglines,
						PROMPTNOEDIT,FALSE,llist);
					break;
				case '!':
					handle_exclam(tty,pipe);
					do_prompt(tty,qmore,mlcounter,poffset,
					pipe,countlines,totallines,
					longlines,xlonglines,PROMPTNORMAL,FALSE,llist);
					break;
				case 'h':
				case '?':
					handle_help(pipe);
					retflag=FALSE;
					*mlcounter=(~mlines+2+dum1);
					doing=FALSE;
					break;
				case '/':
					save_rgx_pos=top_of_form;
					xxx=handle_r(tty, number);
					switch(xxx)
					{
						case 0:
						do_prompt(tty,qmore,mlcounter,
							  poffset,pipe,
							  countlines,totallines,
							  longlines,xlonglines,
							  PROMPTNORMAL,FALSE,
							  llist);
							break;
						case 1:
doing_n:
						optpl=0;	/*clear*/
						if(!number)
							number=1;
						while(number--)
						{
/*look for the regexp*/					search_regex(poffset,top_of_form,pipe,llist);
							if(number>=1)	/*only do if #>1*/
								top_of_form=optpl;
							if(!optpl)
								number=0;/*break*/
						}
						pcr();
/*if found?*/					if(optpl)
						{
/*if it is on the current page,we will scroll*/		if((optpl>=top_of_form) && (optpl<=countlines))
							{
								*poffset=FALSE;
								dum1=0;
								for(xxx=0;xxx<xlonglines;xxx++)
/*longlines < optpl(vs <= ) fixed the problem w/ the regexp in the longline
scrolling off the top of the screen*/
/*this offsets for longlines*/						if((longlines[xxx]>=countlines-(*mlcounter)+xl-xxx+1) && (longlines[xxx] < optpl))
										dum1++;
/*and set the scroll amount*/					*mlcounter-=(optpl-top_of_form+dum1);
/*reset*/							optpl=0;
							}
/*else we will skip*/					else
								optpl-=countlines;
							doing=FALSE;
						}
						else
						{
							do_prompt(tty,qmore,mlcounter,
							poffset,pipe,countlines,
							totallines,longlines,xlonglines,
							PROMPTNOREGEX,FALSE,llist);
						}
							break;
						case 2:
						do_prompt(tty,qmore,mlcounter,
							poffset,pipe,countlines,
							totallines,longlines,xlonglines,
							PROMPTILLREG,FALSE,llist);
							break;
					}
					break;
				case 'n':
					if(globrgx)	/*if not NULL*/
						goto doing_n;
					else
						do_prompt(tty,qmore,mlcounter,
						poffset,pipe,countlines,
						totallines,longlines,xlonglines,
						PROMPTMISSING,FALSE,llist);
					break;
				case '.':
					number=last_number;
					c=last_command;
					goto do_c;
					break;
				case '\'':
/*-(mlines) will go back EXACTLY one line*/
					if(save_rgx_pos)
						*mlcounter=-(mlines-dum1-1)-(top_of_form-save_rgx_pos);
					save_rgx_pos=0;
					doing=FALSE;
					break;
				case ':':
					localflag=FALSE;
					if(!number)
						pcr();
					printf(":");
					tputs(curson,1,putch);
					fflush(stdout);
					c=fgetc(tty);
					switch(c)
					{
						case 'n':
							if((!pipe) && (*nextfile != NULL))
							{
					char **local_next;

					if(number>1)
						global_skipper=number;
					else
						global_skipper=0;

					local_next=nextfile;
					while(number>1 && *local_next!=NULL)
					{
						number--;
						*local_next++;
					}
					if(*local_next!=NULL)
						nextfile=local_next;
					else
					{
						do_prompt(tty,qmore,mlcounter,poffset,pipe,
						  countlines,totallines,longlines,
						  xlonglines,PROMPTNONEXTF,FALSE,llist);
						global_skipper=1;
						goto bye_n;
					}
								printf("\r\nSkipping to %s...\n",*nextfile);
								fflush(stdout);
								doing=FALSE;
								*qmore=FALSE;
							}
							else
							{
							do_prompt(tty,qmore,
							mlcounter,poffset,pipe,
							countlines,totallines,
							longlines,xlonglines,
							PROMPTNONEXT,FALSE,llist);
							}
bye_n:
							break;
						case 'p':
					prevfile=currfile;
/*actually point to prev file(if it exists*/
					*prevfile--;
/*but remember that argv[0] points to who WE are*/
					if((!pipe) && (*prevfile!=NULL) && (*prevfile!=prog_name))
					{
						char **local_prev;
						if(number>1)
							global_skipper=(-number);
						else
							global_skipper=(-1);
						local_prev=prevfile;

						while(number>1 && *local_prev!=NULL)
						{
							number--;
							*local_prev--;
						}
						if(*local_prev==prog_name)
							*local_prev=NULL;
						if(*local_prev!=NULL)
							prevfile=local_prev;
						else
						{
							do_prompt(tty,qmore,mlcounter,poffset,pipe,
							countlines,totallines,longlines,
							xlonglines,PROMPTNOPREVF,FALSE,llist);
							global_skipper=0;
							goto bye_p;
						}
						printf("\r\nSkipping back to %s...\n",*prevfile);
						fflush(stdout);
						doing=FALSE;
						*qmore=FALSE;
					}
					else
					{
						do_prompt(tty,qmore,
						mlcounter,poffset,pipe,
						countlines,totallines,
						longlines,xlonglines,
						PROMPTNOPREV,FALSE,llist);
					}
bye_p:
					break;
						case '!':
							handle_exclam(tty,pipe);
							do_prompt(tty,qmore,
							mlcounter,poffset,pipe,
							countlines,totallines,
							longlines,xlonglines,
							PROMPTNORMAL,FALSE,llist);
							break;
						case 'f':
							do_prompt(tty,qmore,
							mlcounter,poffset,pipe,
							countlines,totallines,
							longlines,xlonglines,
							PROMPTCURR,FALSE,llist);
							break;
						case 'q':
						case 'Q':
							pcr();
							doing=FALSE;
							*qmore=FALSE;
							global_out_of_here=TRUE;
							break;
						case '\b':
							localflag=TRUE;
							pcr();
							break;
						default:
							goto here1;
							break;
					}
					tputs(cursoff,1,putch);
					if(localflag)
						do_prompt(tty,qmore,mlcounter,
						  poffset,pipe,countlines,
						  totallines,longlines,xlonglines,
						  PROMPTNORMAL,FALSE,llist);
					break;
				default:
here1:
					if(optd)
					{
						printf("\a");
						pcr();
						do_prompt(tty, qmore, mlcounter,poffset,
						pipe,countlines,totallines,
						longlines,xlonglines,
						PROMPTINVALID,FALSE,llist);
					}
					else
					{
						pcr();
						printf(":\a");
					}	
					break;
			}
			fflush(stdout);
			number=0;	/*clear so it doesn't carry over*/
		}
	}
	return(savec);
}

/******************************
    sort- used to sort the longlines array so it works correctly with an
	initial offset.
********************************/
void sort(int longlines[], int xlonglines)
{
	int x,y,temp;

	for(x=0; x<xlonglines; x++)
		for(y=0;y<xlonglines;y++)
			if(longlines[x] < longlines[y])
			{
				temp=longlines[x];
				longlines[x]=longlines[y];
				longlines[y]=temp;
			}
}
