/*	mark saeger,	msaeger@cse.unl.edu				*/
/*	handle.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"
#include <wait.h>	/*for wait()*/

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

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

#define TABSIZE	8
#define PATH	"/usr/lib/more.help"

void pcr(void)
{
	extern char *cleol;

	printf("\r");
	tputs(cleol,1,putch);
}

int handle_bs(int *x, int *mccounter, unsigned char bigbuf[], int max_to_read)
{
	extern char *under,*nounder,*bright,*nobright;
	int c;
	int is_under_on=FALSE;
	static int savelast;
	int returnvalue;
	int savex;	/*so we know if x is incremented in walk-thru*/
	static int lost_underline;

	if(*x != 1)
	{
		savelast=0;
		*x-=2;			/*back to the character before the \b*/
		*mccounter-=2;		/*adjust this as well*/
		printf("\b");		/*and move the actual curson back*/
		c=bigbuf[*x];		/*get the character*/
		if(c=='_')		/*turn on underline*/
		{
gohere:
			lost_underline=FALSE;
			is_under_on=TRUE;
			tputs(under,1,putch);
			*x+=2;
			if(*x>=max_to_read)
			{
				tputs(nounder,1,putch);
				lost_underline=TRUE;
/*mccounter is at right place*/
				return 0;
			}
			c=bigbuf[*x];
		}			/*or turn on bold*/
		else
			tputs(bright,1,putch);

		if(lost_underline)
		{
			tputs(nobright,1,putch);
			tputs(under,1,putch);
			is_under_on=TRUE;
		}
		lost_underline=FALSE;

		savex=*x;	/*save it*/
		while((bigbuf[*x] == bigbuf[*x+2]) && (bigbuf[*x+1]=='\b') && (*x<max_to_read-2))
			*x+=2;	/*look for next one*/

		printf("%c",bigbuf[*x]);	/*print it*/
/*the following fix with savex was implemented because of a problem in:
man gcc; 43f; and it would infinitely print +'s.  It seems that in order to
print a bullet, troff did '+','\b','o' and our routine above, would say that
the two werent equal so x never was incremented, then below we did ++*x
which would land on the '\b', the routine would then infinitely loop.  NOTE:
underlines also fit this criteria, so it was necessary to make sure underline
was NOT on.  we then reprint the 'o'(which is in bold), increment x to that
character('o'), then below x is moved one further and everything continues like
normal....*/
		if(savex==*x && !is_under_on)	/*no change,so '+' '\b' 'o'*/
		{
			printf("\b%c",bigbuf[*x+2]);
			*x+=2;
		}
		returnvalue=0;
		++*x;			/*around character just printed*/

/*the following lines of code are for when the buffer is exceeded and we
are still in the middle of an operation.  returnvalue is used in output.c
to discard the first characters in the new buffer if they MATCH what we just
printed.  The savelast is used when the first character in the buffer is a
\b and then we need to know what character preceeded it in the previos
buffer*/
		if((*x>max_to_read-2) && (*x<max_to_read) && (bigbuf[*x]=='\b'))
		{
			++*x;
			returnvalue=bigbuf[*x-2];
		}
		else if(*x==max_to_read)
		{
			returnvalue=bigbuf[*x-1];
		}
		else if (*x==max_to_read-1)
		{
			savelast=bigbuf[*x];
		}
		++*mccounter;		/*and now we add one to mccounter*/
		if(is_under_on)		/*turn off options*/
			tputs(nounder,1,putch);
		else
			tputs(nobright,1,putch);
		return (returnvalue);
	}
	else
	{
		int dum;

		dum=savelast;
		savelast=0;
		switch(dum)
		{
			case 0:
/* to fix FAIL#1(only one that uses s]\bs\bs)*/
/*FAIL #3 will make the 1st char bold vs. underline*/
				while((bigbuf[*x]==bigbuf[*x+2]) && (bigbuf[*x+1]=='\b'))
					*x+=2;
				tputs(bright,1,putch);
				printf("\b%c",bigbuf[*x]);
				tputs(nobright,1,putch);
/*reprint prior char. to ensure it was boldfaced*/
				++*x;
				--*mccounter;
				break;
			case '_':
				*x-=2;	/*adjust for above when +2(want current char)*/
				*mccounter-=2;
				printf("\b");
				goto gohere;
				break;
			default:
				while((bigbuf[*x]==bigbuf[*x+2]) && (bigbuf[*x+1]=='\b'))
					*x+=2;
				tputs(bright,1,putch);
				printf("\b%c",bigbuf[*x]);
				++*x;
				--*mccounter;
				break;
		}
		return (0);
	}
}

/* DONT USE X*/

void handle_tab(int x,int *mccounter)
{
	int lmc,ttab,dum,t;

	--x;		/*set both of these back to original value*/
	lmc=*mccounter;
	--*mccounter;
	t=1;
	while((lmc/(t*TABSIZE))>0)
		t++;		/*get smallest multiple*/
	if(lmc<TABSIZE)		/*if below 8 is simple subtract*/
		ttab=TABSIZE-lmc;
	else
	{
		if(lmc%TABSIZE==0)	/*fix for tab in pos. right before a multiple*/
			t--;	/*e.g. tab in pos 15, text at 16*/
		ttab=((t*TABSIZE)-lmc);	/*get the count*/
	}
	for(dum=0;dum<=ttab;dum++)
	{
		printf(" ");	/*psuedo-TAB*/
		++*mccounter;
	}
}

void sim_handle_tab(int *lmcounter)
{
	int ttab,t;
	int lmc;

	lmc=*lmcounter;
	--*lmcounter;
	t=1;
	while((lmc/(t*TABSIZE))>0)
		t++;
	if(lmc<TABSIZE)
		ttab=TABSIZE-lmc;
	else
	{
		if(lmc%TABSIZE==0)
			t--;
		ttab=((t*TABSIZE)-lmc);
	}
	for(t=0;t<=ttab;t++)
		++*lmcounter;
}


void handle_v(char *number, int pipe)
{
	extern char *curson,*cursoff;
	extern char **currfile;
	char *editor,*shell, *commandline;
	int id;

	if((shell=getenv("SHELL"))==NULL)
		shell="/bin/sh";
	if((editor=getenv("EDITOR"))==NULL)
		editor="/bin/vi";
	commandline=(char *)malloc(128*sizeof(char));
	commandline[0]='\0';
	strcpy(commandline,editor);
	strcat(commandline," ");
	strcat(commandline, number);
	strcat(commandline," ");
	strcat(commandline, *currfile);
	pcr();
	printf("!%s %s %s\n",shell,"-c",commandline);
	cleanup_tty();
	tputs(curson,1,putch);
	if((id=fork())==0)
	{
		if(pipe)
			fclose(stdin);
		execl(shell,shell,"-c",commandline,NULL);
	}
	if(id<0)
/*	{*/
		printf("fork failed\n");
	/*	goto done;
	}*/
	while(wait(0)>0);
/*done:*/
	free(commandline);
	setup_tty();
	tputs(cursoff,1,putch);
}

int handle_r(FILE *tty, int number)
{
/*	returns:
	0:	no regexp entered(e.g. backed up over it)
	1:	regexp found
	2:	invalid regexp entered
*/
#define RETURN2 2

	extern char *curson, *cursoff, *cleol;
	extern rgx *globrgx;
	extern char *optreg;
	char *rgline;
	int x=0,localflag=TRUE,c;
	int retvalue=FALSE;
	int flag=TRUE;
	static int alloced_rgline;

	if(alloced_rgline)
		free(optreg);	/*free the old one, since we know we allocd it*/
	rgline=(char *)malloc(128*sizeof(char));
	alloced_rgline=TRUE;
	if(!number)
		pcr();
	printf("/");
	tputs(curson,1,putch);
	fflush(stdout);

	while((x>=0) && localflag)
	{
		c=fgetc(tty);
		switch(c)
		{
			case '\b':
				x--;
				printf("\b");
				tputs(cleol,1,putch);
				break;
			case '\n':
				flag=TRUE;
				localflag=FALSE;
				break;
			default:
				if(x>=0)
				{
					printf("%c",c);
					rgline[x++]=c;
				}
				break;
		}
		fflush(stdout);
	}
	if(x>0)
	{
		rgline[x]='\0';
		optreg=rgline;
		if(validate_regex())
			retvalue=RETURN2;
		else
		{
			globrgx=store_regex();
			retvalue=TRUE;
		}
	}
	else
	{
		free(rgline);	/*erase since not used*/
		alloced_rgline=FALSE;
	}
	if(!x && flag && globrgx/*added this*/)	/*the following handles if just do a '/' */
		retvalue=TRUE;
	tputs(cursoff,1,putch);
/*	free(rgline); cant do this, since global is pointing to it*/
	return(retvalue);
}

void handle_exclam(FILE *tty, int pipe)
{
	extern char *curson, *cursoff, *cleol;
	char *shell, *commandline;
	int x=0,localflag=TRUE,c,id;

	if((shell=getenv("SHELL"))==NULL)
		shell="/bin/sh";
	commandline=(char *)malloc(128*sizeof(char));
	commandline[0]='\0';
	pcr();
	printf("!");
	tputs(curson,1,putch);
	fflush(stdout);
	while((x>=0) && localflag)
	{
		c=fgetc(tty);
		switch(c)
		{
			case '\b':
				x--;
				printf("\b");
				tputs(cleol,1,putch);
				break;
			case '\n':
				localflag=FALSE;
				break;
			default:
				if(x>=0)
				{
					printf("%c",c);
					commandline[x++]=c;
				}
				break;
		}
		fflush(stdout);
	}
	cleanup_tty();
	if(x<0)
		goto donex;
	commandline[x]='\0';
	printf("\n");
	if((id=fork())==0)
	{
		if(pipe)
			fclose(stdin);
		execl(shell,shell,"-c",commandline,NULL);
	}
	if(id<0)
/*	{*/
		printf("fork failed\n");
	/*	goto donex;
	}*/
	while(wait(0)>0);
	printf("\n");
donex:
	free(commandline);
	tputs(cursoff,1,putch);
	setup_tty();
}

void handle_help(int pipe)
{
	extern char *cursoff;
	extern char *prog_name;
	char *shell;
	int id;
	char *commandline;
/*	FILE *idd;
	int save_stdin;*/

	commandline=(char *)malloc(128*sizeof(char));
	strcpy(commandline,prog_name);
	strcat(commandline," -w ");
	strcat(commandline, PATH);
	if((shell=getenv("SHELL"))==NULL)
		shell="/bin/sh";
	pcr();
	cleanup_tty();
	tputs(cursoff,1,putch);

	if((id=fork())==0)
	{
		if(pipe)
			fclose(stdin);
		execl(shell,shell,"-c",commandline,NULL);
	}
	if(id<0)
		printf("fork failed, unable to load help file...");

	while(wait(0)>0);

	tputs(cursoff,1,putch);
	free(commandline);
	setup_tty();
}
