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

	CMatch()

	This recursive function trys to match one match construct with the
character pointed to by EBPtr2.  It sets SamChr, which indicates whether the
match was successful or not.  SStPtr is left pointing to the last character
of the match construct.
	If the match construct is ^Em or ^S,  then EBPtr2 will be updated to
point to the last matched character.  In this case,  RhtSid is needed to
indicate the limit past which EBPtr2 should not be incremented.

	Match constructs are:

	^X		match any character
	^S		match a seperator character (not letter or digit)
	^N		match anything but following match construct
	^EA		match any alphabetic
	^EB		match a seperator character (not letter or digit)
	^EC		match symbol constituent
	^ED		match any digit
	^EGq		match any character in q-register q
	^EL		match any line terminator (LF, VT, FF)
	^EM		match non-null string of following match construct
	^ER		match any alphanumeric
	^ES		match non-null string of spaces and/or tabs
	^EV		match lowercase alphabetic
	^EW		match uppercase alphabetic
	^EX		match any character
	^E<nnn>		match character with ASCII code nnn (octal)
	^E[x1,x2,...xn]	match any of the match constructs x1, x2, etc.
	else		match the character itself

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

#include "ZPort.h"		/* define portability identifiers */
#include "DefTeco.h"		/* define general identifiers */
#include "DefChars.h"		/* define identifiers for characters */
#include "ChrMacs.h"		/* define character processing macros */
#include "DefError.h"		/* define identifiers for error messages */

extern	VOID	ErrMsg();	/* type error message */
extern	DEFAULT	FindQR();	/* find q-register index */
extern	char	ZChrIt();	/* type convert long to character */

EXTERN	char	*CBfPtr;	/* pointer into command string */
EXTERN	char	*CStEnd;	/* pointer to last char of command string */
EXTERN	char	*EBPtr2;	/* edit buffer pointer */
EXTERN	char	*(*QBfBeg);	/* beginning of q-register text area */
EXTERN	char	*(*QBfPtr);	/* end of q-register text area, plus 1 */
EXTERN	char	*RhtSid;	/* right-hand side of area to be searched */
EXTERN	char	*SBfPtr;	/* end of search string in search buffer */
EXTERN	WORD	SMFlag;		/* search mode flag */
EXTERN	char	*SStPtr;	/* pointer into search string */


DEFAULT CMatch(SamChr)		/* match a character */
BOOLEAN *SamChr;		/* returned match indicator */
{
	LOCAL	char	Charac;		/* holds a character */
	LOCAL	BOOLEAN	ChrMat;		/* character match indicator */
	LOCAL	char	OtCase;		/* "other" case character */
	LOCAL	char	*QRPtr;		/* pointer into q-register text */
	LOCAL	char	*SavEP2;	/* temporary holder of EBPtr2 */
	LOCAL	char	*SavSSP;	/* temporary holder of SStPtr */
	LOCAL	DEFAULT	Status;
	LOCAL	char	*TCBfPt;	/* temporary holder of CBfPtr */
	LOCAL	char	*TCStEn;	/* temporary holder of CStEnd */
	LOCAL	LONG	TmpLng;

#if DEBUGGING
DbgInd+=2;if(DbgLvl>=3){DbgMsg();DbgDBf("CMatch: called. *SStPtr = \"");
DspChr(*SStPtr);DbgDBf("\", *EBPtr2 = \"");DspChr(*EBPtr2);
DbgDBf("\"\015\012");DbgROf();}
#endif

	switch (*SStPtr) {
		case CTRL_X:
			*SamChr = YES;
			break;
		case CTRL_S:
			*SamChr = !Is_Alnum(*EBPtr2);
			break;
		case CTRL_N:
			if (++SStPtr == SBfPtr)
				{
				ErrMsg(ERR_ISS);	/* ill. search str. */
#if DEBUGGING
if(DbgLvl>=3)
{DbgMsg();DbgDBf("CMatch: returning FAILURE.\015\012");DbgROf();}DbgInd-=2;
#endif
				return(FAILURE);
				}
			if (CMatch(&ChrMat) == FAILURE)
#if DEBUGGING
{if(DbgLvl>=3)
{DbgMsg();DbgDBf("CMatch: returning FAILURE.\015\012");DbgROf();}DbgInd-=2;
#endif
				return(FAILURE);
#if DEBUGGING
}
#endif
			*SamChr = !ChrMat;
#if DEBUGGING
if(DbgLvl>=3){DbgMsg();DbgDBf("CMatch: returning SUCCESS. *SamChr = ");
DbgDBf(*SamChr ? "YES\015\012" : "NO\015\012");DbgROf();}DbgInd-=2;
#endif
			return(SUCCESS);
		case CTRL_E:
			if (++SStPtr == SBfPtr)
				{
				ErrMsg(ERR_ICE);	/* ICE = illegal ^E */
#if DEBUGGING
if(DbgLvl>=3)
{DbgMsg();DbgDBf("CMatch: returning FAILURE.\015\012");DbgROf();}DbgInd-=2;
#endif
				return(FAILURE);
				}
			switch (To_Upper(*SStPtr)) {
			case 'A':
				*SamChr = Is_Alpha(*EBPtr2);
				break;
			case 'B':
				*SamChr = !Is_Alnum(*EBPtr2);
				break;
			case 'C':
				*SamChr = Is_SyCon(*EBPtr2);
				break;
			case 'D':
				*SamChr = Is_Digit(*EBPtr2);
				break;
			case 'G':
				if (++SStPtr == SBfPtr)
					{
					ErrMsg(ERR_ICE); /* ill. ^E command */
#if DEBUGGING
if(DbgLvl>=3)
{DbgMsg();DbgDBf("CMatch: returning FAILURE.\015\012");DbgROf();}DbgInd-=2;
#endif
					return(FAILURE);
					}
				TCBfPt = CBfPtr;	/* save CBfPtr */
				TCStEn = CStEnd;	/* save CStEnd */
				CBfPtr = SStPtr;
				CStEnd = SBfPtr;
				Status = FindQR();
				SStPtr = CBfPtr;
				SBfPtr = CStEnd;
				CBfPtr = TCBfPt;	/* restore CBfPtr */
				CStEnd = TCStEn;	/* restore CStEnd */
				if (Status == FAILURE)
#if DEBUGGING
{if(DbgLvl>=3)
{DbgMsg();DbgDBf("CMatch: returning FAILURE.\015\012");DbgROf();}DbgInd-=2;
#endif
					return(FAILURE);
#if DEBUGGING
}
#endif
				QRPtr = *QBfBeg;
				while (QRPtr < *QBfPtr)
					{
					if (*QRPtr++ == *EBPtr2)
						{
						*SamChr = YES;
#if DEBUGGING
if(DbgLvl>=3){DbgMsg();DbgDBf("CMatch: returning SUCCESS. *SamChr = ");
DbgDBf(*SamChr ? "YES\015\012" : "NO\015\012");DbgROf();}DbgInd-=2;
#endif
						return(SUCCESS);
						}
					}
				*SamChr = NO;
				break;
			case 'L':
				*SamChr = IsEOL(*EBPtr2);
				break;
			case 'M':
				if (++SStPtr == SBfPtr)
					{
					ErrMsg(ERR_ICE);
#if DEBUGGING
if(DbgLvl>=3)
{DbgMsg();DbgDBf("CMatch: returning FAILURE.\015\012");DbgROf();}DbgInd-=2;
#endif
					return(FAILURE);
					}
				SavSSP = SStPtr;
				if (CMatch(&ChrMat) == FAILURE)
#if DEBUGGING
{if(DbgLvl>=3)
{DbgMsg();DbgDBf("CMatch: returning FAILURE.\015\012");DbgROf();}DbgInd-=2;
#endif
					return(FAILURE);
#if DEBUGGING
}
#endif
				*SamChr = ChrMat;
				if (ChrMat)
					while (EBPtr2 <= RhtSid)
					    {
					    SavEP2 = EBPtr2;
					    ++EBPtr2;
					    SStPtr = SavSSP;
					    if (CMatch(&ChrMat) == FAILURE)
#if DEBUGGING
{if(DbgLvl>=3)
{DbgMsg();DbgDBf("CMatch: returning FAILURE.\015\012");DbgROf();}DbgInd-=2;
#endif
						    return(FAILURE);
#if DEBUGGING
}
#endif
					    if (!ChrMat)
						    {
						    EBPtr2 = SavEP2;
						    break;
						    }
					    }
#if DEBUGGING
if(DbgLvl>=3){DbgMsg();DbgDBf("CMatch: returning SUCCESS. *SamChr = ");
DbgDBf(*SamChr ? "YES\015\012" : "NO\015\012");DbgROf();}DbgInd-=2;
#endif
				return(SUCCESS);
			case 'R':
				*SamChr = Is_Alnum(*EBPtr2);
				break;
			case 'S':
				if ((*EBPtr2 != SPACE) &&
				    (*EBPtr2 != TABCHR))
					*SamChr = NO;
				else
					{
					*SamChr = YES;
					while (EBPtr2 <= RhtSid)
						{
						++EBPtr2;
						if ((*EBPtr2 != SPACE) &&
						    (*EBPtr2 != TABCHR))
							{
							EBPtr2--;
							break;
							}
						}
					}
				break;
			case 'V':
				*SamChr = Is_Lower(*EBPtr2);
				break;
			case 'W':
				*SamChr = Is_Upper(*EBPtr2);
				break;
			case 'X':
				*SamChr = YES;
				break;
			case '<':
				if (++SStPtr == SBfPtr)
					{
					ErrMsg(ERR_ICE);
#if DEBUGGING
if(DbgLvl>=3)
{DbgMsg();DbgDBf("CMatch: returning FAILURE.\015\012");DbgROf();}DbgInd-=2;
#endif
					return(FAILURE);
					}
				TmpLng = 0L;
				while (Is_Digit(*SStPtr))
					{
					TmpLng *= 8;
					TmpLng += *SStPtr - '0';
					if (TmpLng > 127)
						{
						ErrMsg(ERR_ICE);
#if DEBUGGING
if(DbgLvl>=3)
{DbgMsg();DbgDBf("CMatch: returning FAILURE.\015\012");DbgROf();}DbgInd-=2;
#endif
						return(FAILURE);
						}
					if (++SStPtr == SBfPtr)
						{
						ErrMsg(ERR_ICE);
#if DEBUGGING
if(DbgLvl>=3)
{DbgMsg();DbgDBf("CMatch: returning FAILURE.\015\012");DbgROf();}DbgInd-=2;
#endif
						return(FAILURE);
						}
					}
				if (*SStPtr != '>')
					{
					ErrMsg(ERR_ICE);
#if DEBUGGING
if(DbgLvl>=3)
{DbgMsg();DbgDBf("CMatch: returning FAILURE.\015\012");DbgROf();}DbgInd-=2;
#endif
					return(FAILURE);
					}
				Charac = ZChrIt(TmpLng);
				*SamChr = (*EBPtr2 == Charac);
				break;
			case '[':
				if (++SStPtr == SBfPtr)
					{
					ErrMsg(ERR_ICE);
#if DEBUGGING
if(DbgLvl>=3)
{DbgMsg();DbgDBf("CMatch: returning FAILURE.\015\012");DbgROf();}DbgInd-=2;
#endif
					return(FAILURE);
					}
				while (*SStPtr != ']')
					if (*SStPtr == ',')
						{
						if (++SStPtr == SBfPtr)
							{
							ErrMsg(ERR_ICE);
#if DEBUGGING
if(DbgLvl>=3)
{DbgMsg();DbgDBf("CMatch: returning FAILURE.\015\012");DbgROf();}DbgInd-=2;
#endif
							return(FAILURE);
							}
						}
					else
						{
					if (CMatch(&ChrMat) == FAILURE)
#if DEBUGGING
{if(DbgLvl>=3)
{DbgMsg();DbgDBf("CMatch: returning FAILURE.\015\012");DbgROf();}DbgInd-=2;
#endif
						return(FAILURE);
#if DEBUGGING
}
#endif
					if (ChrMat)
						{
						while (*SStPtr != ']')
						if (++SStPtr == SBfPtr)
							{
							ErrMsg(ERR_ICE);
#if DEBUGGING
if(DbgLvl>=3)
{DbgMsg();DbgDBf("CMatch: returning FAILURE.\015\012");DbgROf();}DbgInd-=2;
#endif
							return(FAILURE);
							}
						*SamChr = YES;
#if DEBUGGING
if(DbgLvl>=3){DbgMsg();DbgDBf("CMatch: returning SUCCESS. *SamChr = ");
DbgDBf(*SamChr ? "YES\015\012" : "NO\015\012");DbgROf();}DbgInd-=2;
#endif
						return(SUCCESS);
						}
					if (++SStPtr == SBfPtr)
						{
						ErrMsg(ERR_ICE);
#if DEBUGGING
if(DbgLvl>=3)
{DbgMsg();DbgDBf("CMatch: returning FAILURE.\015\012");DbgROf();}DbgInd-=2;
#endif
						return(FAILURE);
						}
					}
				break;
			default:
				ErrMsg(ERR_ICE);
#if DEBUGGING
if(DbgLvl>=3)
{DbgMsg();DbgDBf("CMatch: returning FAILURE.\015\012");DbgROf();}DbgInd-=2;
#endif
				return(FAILURE);
			}
			break;
		default:
			if (SMFlag == 0)	/* if case independence */
				{
				if (Is_Upper(*SStPtr))
					OtCase = To_Lower(*SStPtr);
				else
					OtCase = To_Upper(*SStPtr);
				*SamChr = ((*EBPtr2 == *SStPtr) ||
					   (*EBPtr2 == OtCase));
				}
			else
				*SamChr = (*EBPtr2 == *SStPtr);
	}	/* end of switch */
#if DEBUGGING
if(DbgLvl>=3){DbgMsg();DbgDBf("CMatch: returning SUCCESS. *SamChr = ");
DbgDBf(*SamChr ? "YES\015\012" : "NO\015\012");DbgROf();}DbgInd-=2;
#endif
	return(SUCCESS);
}
