/*	mark saeger,	msaeger@cse.unl.edu				*/
/*	main.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.			*/
#ifdef MINT
#include <mintbind.h>
#include <ioctl.h>
#endif

#include <termio.h>
#include <signal.h>
#include "more.h"	/*our .h file*/
#include "version.h"

/*prototypes*/
void process_switch(int c);

char **process_options(int *argc, char *argv[],char *prog_name);

/************************/
/*	GLOBALS		*/
/************************/
char Copyright[]={"\nCopyright 1995 Mark Saeger.\n
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.\n
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.\n"};

int	optc=FALSE,
	optd=FALSE,
	optf=FALSE,
	optl=FALSE,
	optm=FALSE,
	optr=FALSE,
	opts=FALSE,
	optu=FALSE,
	optw=FALSE,	/*externals option[cdflmrsuw]*/
	optml=0,	/* -### */
	optpl=0;	/* +### */
char	*optreg;	/* pointer to the regexp entered on commandline*/
char	**nextfile;	/*points to the next file to look at, or NULL*/
char	**currfile;	/*points to the current file*/
char	*prog_name;	/*who we are*/
rgx	*globrgx=NULL;
int	global_skipper;	/*used with <#>:n to get the right file*/
int	global_out_of_here=FALSE;	/*used to signal when :q/:Q pressed*/

	FILE *tty;

#ifdef UNIX
	struct termio ttytty/*, stdintty*/;
#else
	struct termios ttytty/*, stdintty*/;
#endif

/*
	func:	main
	passed:	argc, *argv
	return:	void
	from:	n/a
	calls:	
*/
void main(int argc, char *argv[])
{
	extern char **nextfile;	/*when showing multiple files*/
	extern char **currfile;
	FILE *ip;	/*the file handle for the input*/
	extern FILE *tty;	/*for opening device tty for keyboard input*/
	extern char *prog_name;	/*points to name of this program(eg: more)*/
	char *defaultmore;	/*filled from MORE env. var.*/
	extern int global_skipper;
	extern int global_out_of_here;

#ifdef UNIX
	struct termio otty;
#else
	struct termios otty;
#endif
	int no_pipe;	/*flag for piped data*/
/*	int mark;*/	/*dummy*/
	int c;		/*holds the character value(dummy)*/
	int dum;	/*dummy*/


/*turn off the interupt type signals*/
	signal(SIGINT,SIG_IGN);
	signal(SIGQUIT,SIG_IGN);
	signal(SIGTERM,SIG_IGN);
	signal(SIGTSTP,SIG_IGN);
/*this will require some serious testing, MiNT doesnt send the signal*/
	signal(SIGWINCH,SIGNALTYPE handle_sig_winch);

	prog_name=argv[0];	/*keep who we are for later*/
/************************/
/*  	process MORE	*/
/* 	env. variable	*/
/************************/
	if((defaultmore = getenv("MORE"))!=NULL)
	{
		if((defaultmore)[0] == '-')
		{
			dum=1;
			while (c = defaultmore[dum++])
			{
				if(c!='v')	/*v is not allowed in MORE*/
					process_switch(c);
			}
		}
	}

	tty=fopen("/dev/tty","r");	/*open keyboard for input*/

	setup_tty();

	ip = stdin;
#ifdef UNIX
	no_pipe = ioctl(ip->_file, TCGETA, &otty);
#else
	no_pipe = tcgetattr(ip->_file, &otty);
#endif
	if((argc==1) || (no_pipe))
	{
		if(!no_pipe)	/*not from a pipe*/
		{
			fprintf(stderr,"USAGE: %s [-cdflmrsuvwL] [-lines] [+linenumber] [+/pattern] [filename ...]\n",prog_name);
			cleanup_tty();
			exit(-1);
		}
		if(argc > 1)	/*any options?*/
			argv=process_options(&argc,argv,prog_name);
		output(TRUE, ip, tty);	/*and output the data*/
		cleanup_tty();	/*must exit now*/
		exit(0);	/*else we end up in the lower loops*/
	}
	else	/*not from a pipe, process options*/
		argv = process_options(&argc,argv,prog_name);

	global_skipper=0;	/*reset*/

	if(argc > 0)	/*now get the files, one at a time*/
	{
		while((argc-- > 0) && !global_out_of_here)
		{
			if(argc > 0)
				optw=TRUE;	/*for multiple files, turn on*/
/*global_skipper:   >1 move forward	*/
/*		    <0 move backward	*/
/*this handles :n, we dont check for an invalid because that was checked
in the original calling process.*/
	while(global_skipper>1)
	{
		global_skipper--;
		*argv++;	/*already checked for invalid*/
		argc--;		/*adjust*/
	}
/*handles :p*/
	while(global_skipper<0)	/*0 since we want to handle default of 1*/
	{
		global_skipper++;
		*argv--;
		argc++;
	}
			if((ip = fopen(*argv, "r"))==NULL)
			{		/*was *argc++ */
				char **testnext;

				fprintf(stderr,"%s ERROR:  cannot open '%s'\n",
					prog_name, *argv);
				testnext=argv;
				*testnext++;				
				if(*testnext)
					fprintf(stderr,"Skipping to '%s'...\n",*testnext);
				goto go_on;
			}
			nextfile = argv;
			currfile = argv;
			*nextfile++;	/*increment to point to next filename*/
			if(check_bin(ip))
			{
				int answer;

				printf("'%s' may be a binary file. Continue? ",*currfile);
				fflush(stdout);
				answer=fgetc(tty);
				printf("\n");
				switch(answer)
				{
					case 'y':
					case 'Y':
						output(FALSE,ip,tty);
						break;
					default:
						break;
				}
			}
			else
				output(FALSE, ip, tty);
			fclose(ip);	/*close file*/
go_on:
			*argv++;/*have here else it increments beyond*/
/*normally we go forward, so we code the backward so it works with a -1*/
/*this little bit of code must be here since if we are at the last file
and go backwards, argc has been erased*/
			if(global_skipper<0)
			{
				*argv--;	/*put it back where it was*/
				argc++;		/*and adjust*/
			}
		}
	}					
	cleanup_tty();
	exit(0);	/*bye bye*/
}

void setup_tty(void)
{
#ifdef UNIX
	extern struct termio ttytty;
#else
	extern struct termios ttytty;
#endif
	extern FILE *tty;
	int mark;	/*dummy*/

#ifdef UNIX
	mark=ioctl(tty->_file,TCGETA,&ttytty);
#else
	mark=tcgetattr(tty->_file,&ttytty);
#endif
	/*the following turns off echo, and returns immediately with char*/
	ttytty.c_lflag &= ~(ICANON | ECHO);
	ttytty.c_cc[VMIN]=1;
	ttytty.c_cc[VTIME]=0;
	/*this actually sets the terminal to behave that way*/
#ifdef UNIX
	mark=ioctl(tty->_file,TCSETA,&ttytty);
#else
	mark=tcsetattr(tty->_file,TCSANOW,&ttytty);
#endif
}

void cleanup_tty(void)
{
#ifdef UNIX                                  
	extern struct termio ttytty;
#else
	extern struct termios ttytty;
#endif
	extern FILE *tty;
	int mark;	/*dummy*/

#ifdef UNIX
	mark = ioctl(tty->_file, TCGETA, &ttytty);
#else
	mark = tcgetattr(tty->_file, &ttytty);
#endif
	ttytty.c_lflag |= (ICANON | ECHO);	/*back to normal*/
#ifdef UNIX
	mark = ioctl(tty->_file, TCSETA, &ttytty);
#else
	mark = tcsetattr(tty->_file, TCSANOW, &ttytty);
#endif
}

char **process_options(int *argc, char *argv[],char *prog_name)
{
	extern int optml, optpl;
	extern char *optreg;
	extern rgx *globrgx;
	int c;


	while ((--(*argc)) > 0 && (*++argv)[0] == '-')
	{
		if(((*argv)[1] >= '0') && ((*argv)[1] <= '9'))
		{	/*checks for a number of form -#### */
			*++argv[0];	/*around -*/
			/*printf("number of lines to display %d\n", atoi(*argv));*/
			optml = atoi(*argv);
			/*if enter something like 12ab will get 12 back*/
		}
		else	/*process all others here*/
		{
			while (c = *++argv[0])	/*still need to process -lines*/
			{
			if(c=='v')
			{
				printf("%s: version %i (%s / %s).\n",prog_name,VERSION,__TIME__,__DATE__);
				cleanup_tty();
				exit(0);
			}
			else if(c=='L')
			{
				printf("%s",Copyright);
				cleanup_tty();
				exit(0);
			}
			else
				process_switch(c);
		}
		}
	}

	while((*argc) > 0 && (*argv)[0] == '+')
	{
		*++argv[0];	/*around +.......*/
		--(*argc);	/*decrement argc*/
		if(((*argv)[0] >= '0') && ((*argv)[0] <= '9'))
			optpl = atoi(*argv);
		else if((*argv)[0] == '/')
		{
			*++argv[0];	/*around / */
			optreg = *argv;
			if(validate_regex())
				printf("\nIllegal regular expression entered...\n");
			else
				globrgx=store_regex();
		}
		else
			printf("Invalid option: %s\n",*argv);
		(*++argv)[0];	/*next option*/
	}
	return argv;
}

void process_switch(int c)
{
	extern int optc,optd,optf,optl,optm,optr,opts,optu,optw;

	switch(c)
	{
		case 'c':	/*clear screen*/
			optc = TRUE;
			break;
		case 'd': 	
			optd = TRUE;
			break;
		case 'f':	/*fold lines*/
			optf = TRUE;
			break;
		case 'l':	/*handle form feeds*/
			optl = TRUE;
			break;
		case 'm':	/*ignore ^M at end of lines*/
			optm = TRUE;
			break;
		case 'r':
			optr = TRUE;
			break;
		case 's':
			opts = TRUE;
			break;
		case 'u':	/*underline*/
			optu = TRUE;
			break;
		case 'w':	/*pause at end of file*/
			optw = TRUE;
			break;
		default:	/*invalide options fall here*/
			fprintf(stderr,"Invalid option %c\n",c);
			break;
	}
}
