#ifdef	ournix
#include "ournix.h"
#endif
char sccsID[] = "@(#) grep.c V0.0 Copyright http://www.berklix.com (pjc) 1988\n" ;
/*
 * grep	for MS-DOS by Phil Cockcroft
 * Staceyfied
 */

#include <stdio.h>

#define	CHAR	1
#define	DOT	2
#define	LSTART	3
#define	EOL	4
#define	CCL	5
#define	NCCL	6
#define	SRANGE	7
#define	EOP	0	/* end of pattern */
#define	STAR	040
#define	QSTAR	0100

#define	LSIZE	512

/*
 * flags
 */
int	vflag;	/* reverse the sense of	the grep */
int	nflag;
int	lflag;
int	cflag;

char	line[LSIZE];
char	ex_p[LSIZE];
FILE	*infile;
int	estatus	= 0;
char	*curfile;
char	*eol;

char	*progname;

char	**ARGV ;

main(argc, argv)
	char	**argv;
	{
	ARGV = argv ;
#ifdef	VSL	/* { */
#include	"../../include/vsl.h"
#endif		/* } */
	progname = *argv;
	while(--argc > 0){
		argv++;
		if(**argv == '-'){
			setflags(*argv + 1);
			continue;
		}
		break;
	}
	if(argc	< 1){
		fprintf(stderr,	"Usage:	%s pattern files....\n", progname);
		exit(100);
	}
	compile(*argv++);
	if(--argc <= 0){
		infile = stdin;
		dofile();
	}
	else
		for(;argc > 0; argc--, argv++){
			if(**argv == '-'){
				setflags(*argv + 1);
				continue;
			}
			infile = fopen(*argv, "r");
			if(infile == NULL){
				fprintf(stderr,	"%s: Cannot open %s\n",
							progname, *argv);
				estatus	|= 1;
				continue;
			}
			if(argc	> 1 || curfile)
				curfile	= *argv;
			dofile();
			fclose(infile);
		}
	exit(estatus);
}

setflags(p)
char	*p;
{
	while(*p)
		switch(*p++){
		case 'l':
			lflag++;
			break;
		case 'v':
			vflag++;
			break;
		case 'n':
			nflag++;
			break;
		case 'c':
			cflag++;
			break;
		default:
			fprintf(stderr,	"%s: Unknown flag -%c\n",
						progname, *(p-1));
			exit(2);
		}
}

compile(pat)
char	*pat;
{
	char	*p;
	char	*lastr = 0;
	char	*sp;
	
	for(p =	ex_p; *pat ; pat++){
		if(p >=	&ex_p[LSIZE-2]){
			fprintf(stderr,	"%s: RE	overflow\n", progname);
			exit(2);
		}
		switch(*pat){
		case '\\':
			if(*++pat == '\0')
				botch();
			/* fall	through	*/
		default:
			lastr =	p;
			*p++ = CHAR;
			*p++ = *pat;
			continue;
		case '*':
			if(lastr == 0)
				botch();
			*lastr |= STAR;
			*lastr &= ~QSTAR;
			continue;
		case '?':
			if(lastr == 0)
				botch();
			if((*lastr & STAR) == 0)
				*lastr |= QSTAR;
			continue;
		case '^':
			lastr =	p;
			*p++ = LSTART;
			continue;
		case '.':
			lastr =	p;
			*p++ = DOT;
			continue;
		case '$':
			lastr =	p;
			*p++ = EOL;
			continue;
		case '[':
			lastr =	p;
			if(pat[1] == '^'){
				*p++ = NCCL;
				pat++;
			}
			else
				*p++ = CCL;
			sp = p;
			for(p++,pat++;;pat++){
				switch(*pat){
				case '\\':
					if(*++pat == '\0')
						botch();
					/* fall	through	*/
				default:
					if(pat[1] == '-'){
						/* a range */
						*p++ = SRANGE;
						*p++ = *pat++;
						*p++ = *++pat;
						if(p[-1] < p[-2])
							botch();
						continue;
					}
					*p++ = CHAR;
					*p++ = *pat;
					continue;
				case '^':
					*p++ = LSTART;
					continue;
				case '$':
					*p++ = EOL;
					continue;
				case ']':
					*p++ = EOP;
					*sp = p	- sp;
					break;
				case '\0':
					botch();
				}
				break;
			}
			break;
		}
	}
	*p = EOP;
}

botch()
{
	fprintf(stderr,	"%s: Regular Expression	Botch\n", progname);
	exit(3);
}


/*
 * do the file 
 */

dofile()
{
	char	*p;
	int	c;
	int	nline =	0;
	int	nmatch = 0;

	for(;;nline++){
		for(p =	line ; (c = getc(infile)) != EOF ;){
			if(c ==	'\n'){
				*p = '\0';
				break;
			}
			if(p < &line[LSIZE-2])
				*p++ = c;
		}
		if(c ==	EOF){
			if(cflag){
				if(curfile)
					printf("%s: %d\n", curfile, nmatch);
				else
					printf("%d\n", nmatch);
			}
			return;
		}
		eol = p;
		if(match()){
			if(vflag)
				continue;
		}
		else {
			if(!vflag)
				continue;
		}
		if(cflag){
			nmatch++;
			continue;
		}
		if(lflag && curfile){
			if(nflag)
				printf("%s: %d\n", curfile, nline);
			else
				printf("%s\n", curfile);
			fflush(stdout);
			return;
		}
		if(curfile){
			if(nflag)
				printf("%s: %d %s\n", curfile, nline, line);
			else
				printf("%s: %s\n", curfile, line);
		}
		else {
			if(nflag)
				printf("%d: %s\n", nline, line);
			else
				printf("%s\n", line);
		}
		fflush(stdout);
	}
}


match()
{
	char	*curp;
	char	c;

	curp = line;
	switch(*ex_p){
	case CHAR:
		for(c =	ex_p[1]	; *curp	!= c ; curp++)
			if(*curp == '\0')
				return(0);
		break;
	case LSTART:
		return(matchit(ex_p, line));
	}
	do {
		if(matchit(ex_p, curp))
			return(1);
	} while(*curp++);
	return(0);
}

matchit(matp, curp)
char	*matp, *curp;
{
	char	*savep,	c;

	for(;;){
		switch(*matp++){
		case CHAR:
			if(*matp++ != *curp++)
				return(0);
			break;
		case CHAR|STAR:
			for(c =	*matp++	; *curp	&& c !=	*curp ;	curp++)
				if(!matchit(matp-2, curp+1))
					break;
			break;
		case CHAR|QSTAR:
			if(*matp++ == *curp)
				if(matchit(matp, curp+1))
					return(1);
			break;
		case DOT:
			if(*curp++ == '\0')
				return(0);
			break;
		case DOT|STAR:
			for(savep = eol	; savep	> curp ; savep--)
				if(matchit(matp, savep))
					break;
			curp = savep;
			break;
		case DOT|QSTAR:
			if(matchit(matp, curp+1))
				return(1);
			break;
		case LSTART:
		case LSTART|STAR:
			if(curp	!= line)
				return(0);
			break;
		case LSTART|QSTAR:
			break;
		case EOL:
		case EOL|STAR:
			if(*curp != '\0')
				return(0);
			break;
		case EOL|QSTAR:
			break;
		case CCL:
			if(!inset(matp+1, curp))
				return(0);
			curp++;
			matp +=	*matp;
			break;
		case CCL|QSTAR:
			if(inset(matp+1, curp))
				if(matchit(matp	+ *matp, curp+1))
					return(1);
			matp +=	*matp;
			break;
		case NCCL:
			if(inset(matp+1, curp))
				return(0);
			curp++;
			matp +=	*matp;
			break;
		case NCCL|QSTAR:
			if(!inset(matp+1, curp))
				if(matchit(matp	+ *matp, curp+1))
					return(1);
			matp +=	*matp;
			break;
		case CCL|STAR:
			for(; inset(matp+1, curp) ;curp++){
				if(!matchit(matp-1, curp+1))
					break;
				if(*curp == '\0')
					break;
			}
			matp +=	*matp;
			break;
		case NCCL|STAR:
			for(;;curp++){
				if(inset(matp+1, curp))
					break;
				if(!matchit(matp-1, curp+1))
					break;
				if(*curp == '\0')
					break;
			}
			matp +=	*matp;
			break;
		case EOP:
			/* end of pattern - success */
			return(1);
		default:
			fprintf(stderr,	"%s: Unknown type 0x%x in ex_p !\n",
							progname, *matp);
			exit(23);
		}
	}
}

inset(pat, curp)
char	*pat, *curp;
{
	char	c = *curp;
	char	cc;

	for(;*pat != EOP;pat++)
		switch(*pat){
		case CHAR:
			if(*++pat == c)
				return(1);
			break;
		case LSTART:
			if(curp	== line)
				return(1);
			break;
		case EOL:
			if(c ==	'\0')
				return(1);
			break;
		case SRANGE:
			cc = *++pat;
			if(c <=	*++pat && c >= cc)
				return(1);
			break;
		}
	return(0);
}
