/*
 *************************************************************************
 * Match.c 
 * by Mike Pinson of MicroBotics, Inc. (based on YesNo by Joanne B. Dow)
 *
 * Version 2.0
 *
 *	Match allows user interactive script files by prompting for
 *	operator input and comparing the response to a string.  It
 *	returns a warn level error if the match fails.   For example:
 *
 *	Match yes|y no|n prompt "Are you sure? (yes/no) :" noblanks
 *	If not warn
 *	  Echo "You typed 'yes' or 'y'"
 *	Else
 *	  Echo "You typed 'no' or 'n'"
 *	EndIf
 *
 *************************************************************************
 * Copyright 14-Feb-86  by Joanne Dow   - original released for free
 * distribution as long as this copyright notice is retained in the file.
 *
 * Modified 25-Jan-88 by Mike Pinson (copyright 1988, MicroBotics, Inc.) for
 * Manx compile and added prompting and 'NOBLANKS' keywords to allow more
 * complex operations (freely usable so long as both J. B. Dow's and
 * MicroBotics' copyrights are presented intact.
 *************************************************************************
 *
 * Usage:
 *	Match "match string"/A [,"fail string"] [,NOCAPS/S]
 *				 [,PROMPT/K "prompt string"] [,NOBLANKS/S]
 *
 *
 *	"match string"		string that allows a no-error exit
 *	"fail string"		string that allows an error exit
 *	PROMPT "string"		string to prompt with
 *	NOBLANKS		switch to disallow blank lines (user MUST type
 *					the match string (or the fail string,
 *					if supplied))
 *	NOCAPS			switch to make user input and match strings
 *					case-sensitive
 *
 *
 * Example:	prompt "Are you sure? (yes/no)"
 *		then accept only the answers "yes" or "y", "no" or "n"
 *			(no empty returns)
 *
 *	Match yes|y no|n prompt "Are you sure? (yes/no) :" noblanks
 *
 * The "match string" MUST come before the "fail string", but this is
 * the only ordering requirement.  Single word switches will be parsed before
 * two word keywords.  So, the following line is equivalent in function to the
 * line above: (though why you'ld want to write it this way is beyond me...)
 *
 *	Match yes prompt noblanks "Are you sure? (yes/no) :" no
 *
 * If the user types "\n" or "go away" and you had specified noblanks, he'll
 * get the message: "Please type only "match string" or "fail string"
 *
 * If NOBLANKS is NOT used and user just hits return, the match will fail.
 *
 */

#include "stdio.h"

#define NO      6       /* warn level exit code */
#define YES     0       /* No warning exit code */

#define  MaxString 255	/* Size of read buffer    */

#ifndef  TRUE
#define  TRUE  (1==1)
#define  FALSE (1==0)
#endif

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


		General string handling routines


*/

/************************************************************************/
/*	upcase - upcase a string					*/
/************************************************************************/
char *upcase(a)
register char *a;
{
	register char *cp;

	cp = a;
	while (*cp = toupper(*cp)) cp++;

	return (a);
}

/************************************************************************/
/*	mprint - print a string, decoding all escape sequences in bcpl	*/
/*		or c format without the overhead of linking in printf	*/
/************************************************************************/
void mprint(a)
register char *a;
{
	register char outc;

	while (*a!='\0') {
		if ((outc=*a) == '\\' || outc == '*') {
			if (*(a+(char *)1) != '\0') a++;
			switch (toupper(outc=*a)) {

				case '0' : outc='\000'; break;
				case 'B' : outc='\010'; break;
				case 'E' : outc='\033'; break;
				case 'F' : outc='\014'; break;
				case 'N' : outc='\012'; break;
				case 'R' : outc='\012'; break;
				case 'T' : outc='\011'; break;
			}
		}
		putchar(outc); a++;
	}

}

/************************************************************************/
/*	Strip - Strip spaces from beginning and end of a string		*/
/************************************************************************/
char *strip(s)
register char *s;
{
	register int i;

	while (s[0] == ' ') for (i=0; i<strlen(s); i++) s[i] = s[i+1];

	while (((i=strlen(s))>1) && s[i-1]==' ') s[i-1] = '\0';

	return (s);
}

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


		Pattern matching routines


*/

int	noblanks, nocaps;
char	*strcat(), *strcpy(), *fgets();
char	answer[MaxString];

#define MAXPATTERNS 10

typedef	char PARRAY[MAXPATTERNS][81];

PARRAY	matchpatterns, failpatterns;


/************************************************************************/
/*	listp - list patterns in an array of strings			*/
/************************************************************************/
void listp(s,plist)
char s[];
PARRAY plist;
{
	register int i=0,comma=FALSE;

	mprint(s);
	if (plist[1][0]=='\0') mprint(" ");
	else mprint(" one of ");

	while (plist[i][0] != '\0' && i<MAXPATTERNS) {
		if (comma) mprint(", ");
		comma = TRUE;
		mprint("'");
		mprint(plist[i++]);
		mprint("'");
	}
}

/************************************************************************/
/*	ScanPattern - process match strings into a pattern array	*/
/************************************************************************/
void ScanPattern(s,plist)
char	s[];
PARRAY	plist;
{
	register int i=0,j=0,k=0;

	while (s[i] && j<MAXPATTERNS) {
		while (s[i] && s[i]!='|') {
			plist[j][k++]=s[i++];
		}
		strip(&plist[j][0]);
		j++; k=0; if (s[i]) i++;
	}

	while (j<MAXPATTERNS) plist[j++][0] = '\0';

}

/************************************************************************/
/*	matches - scan for a string anywhere in a pattern array		*/
/************************************************************************/
matches(string,plist)
char string[];
PARRAY plist;
{
	register int i=0;

	while (plist[i][0] != '\0' && i<MAXPATTERNS) {
		if (strcmp(plist[i++],string)==0) return TRUE;
	}
	return FALSE;
}

/************************************************************************/
/*	badanswer - if noblanks used, determines when the prompt should */
/*		be repeated						*/
/************************************************************************/
badanswer(nargs,argc)
int nargs;
char *argc[];
{
	if (answer[0]=='\n') return TRUE;	/* it's bad */

	if (matches(answer,matchpatterns)) return FALSE;

	if (nargs==3)
		if (matches(answer,failpatterns)) return FALSE;

	return TRUE;
}

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


		Main program


*/

main(argc, argv)
int argc;
char *argv[];

{
	register int	i,j,nargs;
	int	repeat;
	char	S[MaxString];
	char	*prompt;

	nargs = argc;

/* set one word flags */

	repeat = noblanks = nocaps = FALSE;

	if (nargs>1) for (i=1; i<nargs;) {
		strcpy (S,argv[i]);
		upcase (S);

		if (strcmp(S,"NOBLANKS") == 0) {
			noblanks = TRUE;
			if (i<nargs-1) for (j=i;j<nargs-1; j++)
				argv[j] = argv[j+1];
			argv[--nargs] = '\0';
		} else
		if (strcmp(S,"NOCAPS") == 0) {
			nocaps = TRUE;
			if (i<nargs-1) for (j=i;j<nargs-1; j++)
				argv[j] = argv[j+1];
			argv[--nargs] = '\0';
		} else i++;
	}

/* set prompt */

	prompt = "";

	if (nargs>2) for (i=1; i<nargs-1;) {
		strcpy (S,argv[i]);
		upcase (S);
		if (strcmp(S,"PROMPT") == 0) {
			prompt = argv[i+1];
			if (i<nargs-2) for (j=i;j<nargs-2; j++)
				argv[j] = argv[j+2];
			argv[nargs-2] = argv[nargs-1] = '\0';
			nargs -= 2;
		} else i++;
	}

/* does user need help? */

	if ( nargs<=1 || (nargs==2 && argv[1][0] == '?')) {
	    if (argc>0) {
		mprint("Usage:\n");
		mprint("  Match \"match option\"/A,\"fail option\",PROMPT/K,NOCAPS/S,NOBLANKS/S\n");
		mprint("   for match on multiple options, separate options with \"|\" as in \"Yes|y|ok\"\n");

		mprint("\nCopyright (c)1988 MicroBotics, Inc. Enhancements by Mike Pinson.\n");
		mprint(  "Copyright (c)1986 Joanne Dow.\n\n");
	    }
	    exit(20);
	}

/* do I need help? */

#ifdef DEBUG
	printf("Prompt is: '%s'\n",prompt);
	printf("Fname  is: '%s'\n",fname);

	printf("NoBlanks is %s.\n", noblanks?"on":"off");
	printf("NoCaps   is %s.\n", nocaps  ?"on":"off");

	for (i=0; i<argc-1; i++) printf("arg[%d] : '%s'\n",i,argv[i]);
	printf("\n");
#endif

	if (!nocaps) {
		upcase(argv[1]);		/* upcase match string */
		if (nargs==3) upcase(argv[2]);	/* upcase fail string */
	}

	ScanPattern(argv[1],matchpatterns);
	if (nargs==3) ScanPattern(argv[2],failpatterns);
		 else ScanPattern("",failpatterns);

	do {
		if (repeat) {
			listp("Please type",matchpatterns);
			if (nargs==3) listp(" or",failpatterns);
			mprint(".\n");
		}
		repeat = TRUE;
		mprint (prompt);
		fgets(answer, MaxString, stdin);

		answer[strlen(answer)-1] = '\0';	/* erase newline */

		strip(answer);
		i=0;				/* isolate first word */
		while(answer[i]!='\0' && answer[i]!=' ') i++;
		answer[i] = '\0';

		if (!nocaps) {
			upcase(answer);		/* upcase user input */
		}

	} while (noblanks && (badanswer(nargs,argv)));

	if (matches(answer,matchpatterns)) exit(YES);
	else exit(NO);
}
