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

	BakSrc()

	This recursive function does a backward search in the edit buffer,
looking for a string which will match the first match construct in the search
buffer.  Basically,  it is the high-speed part of the search algorithm: it
scans the edit buffer looking for the first character in the search string.
	On entry, SStPtr points to the first match construct in the search
buffer.  On exit,  SStPtr points to the last character of the first match
construct in the search buffer.
	SBfPtr points to the character following the last character in
the search string.  This function does not modify SBfPtr.
	On entry,  EBPtr1 points to the place in the edit buffer where
the search starts.  On exit,  if the search was successful,  EBPtr1 will
point to the found character.  If the search was unsuccessful,  EBPtr1 will
be less than EndSAr.
	On entry,  EBPtr2 is undefined.  On exit,  if the search was
successful,  EBPtr2 points to the last character of the found string.  If
the search was unsuccessful,  EBPtr2 is undefined.
	EndSAr points to the end of the search area (where the search ends).
Note that for backwards searches,  EndSAr is less than EBPtr1.  This function
does not modify EndSAr.

	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	DEFAULT	CMatch();	/* match a character */
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	*EBPtr1;	/* pointer to start of found string */
EXTERN	char	*EBPtr2;	/* pointer to end of found string */
EXTERN	char	*EndSAr;	/* end of search area */
EXTERN	char	*(*QBfBeg);	/* beginning of q-register text area */
EXTERN	char	*(*QBfPtr);	/* end of q-register text area, plus 1 */
EXTERN	char	*SBfPtr;	/* end of search string, plus one */
EXTERN	WORD	SMFlag;		/* search mode flag */
EXTERN	char	*SStPtr;	/* pointer into search string */


DEFAULT BakSrc()		/* forward search for 1st search char */
{
	LOCAL	char	Charac;		/* holds a character */
	LOCAL	char	*LstBeg;	/* beginning of ^E[x,x,x] list */
	LOCAL	char	OtCase;		/* "other" case character */
	LOCAL	char	*QRPtr;		/* pointer into q-register text */
	LOCAL	BOOLEAN	SamChr;		/* same character indicator */
	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("BakSrc: called. *SStPtr = \"");DspChr(*SStPtr);
DbgDBf("\", *EBPtr1 = \"");DspChr(*EBPtr1);DbgDBf("\"\015\012");DbgROf();}
#endif

	switch (*SStPtr) {
		case CTRL_X:
			break;
		case CTRL_S:
			for (;EBPtr1>=EndSAr;--EBPtr1)
				if (!Is_Alnum(*EBPtr1))
					break;
			break;
		case CTRL_N:
			if (++SStPtr == SBfPtr)
				{
				ErrMsg(ERR_ISS);	/* ill. search str. */
#if DEBUGGING
if(DbgLvl>=3)
{DbgMsg();DbgDBf("BakSrc: returning FAILURE.\015\012");DbgROf();}DbgInd-=2;
#endif
				return(FAILURE);
				}
			SavSSP = SStPtr;
			for (;EBPtr1>=EndSAr;--EBPtr1)
				{
				EBPtr2 = EBPtr1;
				SStPtr = SavSSP;
				if (CMatch(&SamChr) == FAILURE)
#if DEBUGGING
{if(DbgLvl>=3)
{DbgMsg();DbgDBf("BakSrc: returning FAILURE.\015\012");DbgROf();}DbgInd-=2;
#endif
					return(FAILURE);
#if DEBUGGING
}
#endif
				if (!SamChr)
					break;
				}
			break;
		case CTRL_E:
			if (++SStPtr == SBfPtr)
				{
				ErrMsg(ERR_ICE);	/* ICE = illegal ^E */
#if DEBUGGING
if(DbgLvl>=3)
{DbgMsg();DbgDBf("BakSrc: returning FAILURE.\015\012");DbgROf();}DbgInd-=2;
#endif
				return(FAILURE);
				}
			switch (To_Upper(*SStPtr)) {
			case 'A':
				for (;EBPtr1>=EndSAr;--EBPtr1)
					if (Is_Alpha(*EBPtr1))
						break;
				break;
			case 'B':
				for (;EBPtr1>=EndSAr;--EBPtr1)
					if (!Is_Alnum(*EBPtr1))
						break;
				break;
			case 'C':
				for (;EBPtr1>=EndSAr;--EBPtr1)
					if (Is_SyCon(*EBPtr1))
						break;
				break;
			case 'D':
				for (;EBPtr1>=EndSAr;--EBPtr1)
					if (Is_Digit(*EBPtr1))
						break;
				break;
			case 'G':
				if (++SStPtr == SBfPtr)
					{
					ErrMsg(ERR_ICE);
#if DEBUGGING
if(DbgLvl>=3)
{DbgMsg();DbgDBf("BakSrc: 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("BakSrc: returning FAILURE.\015\012");DbgROf();}DbgInd-=2;
#endif
					return(FAILURE);
#if DEBUGGING
}
#endif
				for (;EBPtr1>=EndSAr;--EBPtr1)
					{
					QRPtr = *QBfBeg;
					while (QRPtr < *QBfPtr)
						if (*QRPtr++ == *EBPtr1)
							goto kludge;
					}
kludge:				break;
			case 'L':
				for (;EBPtr1>=EndSAr;--EBPtr1)
					if (IsEOL(*EBPtr1))
						break;
				break;
			case 'M':
				if (++SStPtr == SBfPtr)
					{
					ErrMsg(ERR_ICE);
#if DEBUGGING
if(DbgLvl>=3)
{DbgMsg();DbgDBf("BakSrc: returning FAILURE.\015\012");DbgROf();}DbgInd-=2;
#endif
					return(FAILURE);
					}
				SavSSP = SStPtr;
				if (BakSrc() == FAILURE)
#if DEBUGGING
{if(DbgLvl>=3)
{DbgMsg();DbgDBf("BakSrc: returning FAILURE.\015\012");DbgROf();}DbgInd-=2;
#endif
					return(FAILURE);
#if DEBUGGING
}
#endif
				if (EBPtr1 < EndSAr)	/* if not found */
					break;
				SavEP2 = EBPtr2;
				while (EBPtr1 > EndSAr)
					{
					EBPtr1--;
					EBPtr2 = EBPtr1;
					SStPtr = SavSSP;
					if (CMatch(&SamChr) == FAILURE)
#if DEBUGGING
{if(DbgLvl>=3)
{DbgMsg();DbgDBf("BakSrc: returning FAILURE.\015\012");DbgROf();}DbgInd-=2;
#endif
						return(FAILURE);
#if DEBUGGING
}
#endif
					if (!SamChr)
						{
						EBPtr1++;
						EBPtr2 = SavEP2;
						break;
						}
					}
#if DEBUGGING
if(DbgLvl>=3)
{DbgMsg();DbgDBf("BakSrc: returning SUCCESS.\015\012");DbgROf();}DbgInd-=2;
#endif
				return(SUCCESS);
			case 'R':
				for (;EBPtr1>=EndSAr;--EBPtr1)
					if (Is_Alnum(*EBPtr1))
						break;
				break;
			case 'S':
				for (;EBPtr1>=EndSAr;--EBPtr1)
					if ((*EBPtr1 == SPACE) ||
					    (*EBPtr1 == TABCHR))
						{
						EBPtr2 = EBPtr1;
						while (EBPtr1 > EndSAr)
						    {
						    EBPtr1--;
						    if ((*EBPtr1 != SPACE) &&
							(*EBPtr1 != TABCHR))
							    {
							    EBPtr1++;
							    break;
							    }
						    }
#if DEBUGGING
if(DbgLvl>=3)
{DbgMsg();DbgDBf("BakSrc: returning SUCCESS.\015\012");DbgROf();}DbgInd-=2;
#endif
						return(SUCCESS);
						}
				break;
			case 'V':
				for (;EBPtr1>=EndSAr;--EBPtr1)
					if (Is_Lower(*EBPtr1))
						break;
				break;
			case 'W':
				for (;EBPtr1>=EndSAr;--EBPtr1)
					if (Is_Upper(*EBPtr1))
						break;
				break;
			case 'X':
				break;
			case '<':
				if (++SStPtr == SBfPtr)
					{
					ErrMsg(ERR_ICE);
#if DEBUGGING
if(DbgLvl>=3)
{DbgMsg();DbgDBf("BakSrc: 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("BakSrc: returning FAILURE.\015\012");DbgROf();}DbgInd-=2;
#endif
						return(FAILURE);
						}
					if (++SStPtr == SBfPtr)
						{
						ErrMsg(ERR_ICE);
#if DEBUGGING
if(DbgLvl>=3)
{DbgMsg();DbgDBf("BakSrc: returning FAILURE.\015\012");DbgROf();}DbgInd-=2;
#endif
						return(FAILURE);
						}
					}
				if (*SStPtr != '>')
					{
					ErrMsg(ERR_ICE);
#if DEBUGGING
if(DbgLvl>=3)
{DbgMsg();DbgDBf("BakSrc: returning FAILURE.\015\012");DbgROf();}DbgInd-=2;
#endif
					return(FAILURE);
					}
				Charac = ZChrIt(TmpLng);
				for (;EBPtr1>=EndSAr;--EBPtr1)
					if (*EBPtr1 == Charac)
						break;
				break;
			case '[':
				if (++SStPtr == SBfPtr)
					{
					ErrMsg(ERR_ICE);
#if DEBUGGING
if(DbgLvl>=3)
{DbgMsg();DbgDBf("BakSrc: returning FAILURE.\015\012");DbgROf();}DbgInd-=2;
#endif
					return(FAILURE);
					}
				LstBeg = SStPtr;
				for (;EBPtr1>=EndSAr;--EBPtr1)
					{
					while (*SStPtr != ']')
						if (*SStPtr == ',')
							{
							if (++SStPtr == SBfPtr)
								{
								ErrMsg(ERR_ICE);
#if DEBUGGING
if(DbgLvl>=3)
{DbgMsg();DbgDBf("BakSrc: returning FAILURE.\015\012");DbgROf();}DbgInd-=2;
#endif
								return(FAILURE);
								}
							}
						else
							{
						EBPtr2 = EBPtr1;
						if (CMatch(&SamChr) == FAILURE)
#if DEBUGGING
{if(DbgLvl>=3)
{DbgMsg();DbgDBf("BakSrc: returning FAILURE.\015\012");DbgROf();}DbgInd-=2;
#endif
							return(FAILURE);
#if DEBUGGING
}
#endif
						if (SamChr)
							{
							while (*SStPtr != ']')
							if (++SStPtr == SBfPtr)
								{
								ErrMsg(ERR_ICE);
#if DEBUGGING
if(DbgLvl>=3)
{DbgMsg();DbgDBf("BakSrc: returning FAILURE.\015\012");DbgROf();}DbgInd-=2;
#endif
								return(FAILURE);
								}
							EBPtr2 = EBPtr1;
#if DEBUGGING
if(DbgLvl>=3)
{DbgMsg();DbgDBf("BakSrc: returning SUCCESS.\015\012");DbgROf();}DbgInd-=2;
#endif
							return(SUCCESS);
							}
						if (++SStPtr == SBfPtr)
							{
							ErrMsg(ERR_ICE);
#if DEBUGGING
if(DbgLvl>=3)
{DbgMsg();DbgDBf("BakSrc: returning FAILURE.\015\012");DbgROf();}DbgInd-=2;
#endif
							return(FAILURE);
							}
						}
					SStPtr = LstBeg;
					}
				break;
			default:
				ErrMsg(ERR_ICE);
#if DEBUGGING
if(DbgLvl>=3)
{DbgMsg();DbgDBf("BakSrc: returning FAILURE.\015\012");DbgROf();}DbgInd-=2;
#endif
				return(FAILURE);
			}
			break;
		default:
			if (SMFlag)		/* if case dependence */
				{
				for (;EBPtr1>=EndSAr;--EBPtr1)
					if (*EBPtr1 == *SStPtr)
						break;
				}
			else			/* else case independence */
				{
				OtCase = (Is_Upper(*SStPtr)) ?
						To_Lower(*SStPtr) :
						To_Upper(*SStPtr);
				for (;EBPtr1>=EndSAr;--EBPtr1)
					if ((*EBPtr1 == *SStPtr) ||
					    (*EBPtr1 == OtCase))
						break;
				}
	}	/* end of switch */
	EBPtr2 = EBPtr1;
#if DEBUGGING
if(DbgLvl>=3)
{DbgMsg();DbgDBf("BakSrc: returning SUCCESS.\015\012");DbgROf();}DbgInd-=2;
#endif
	return(SUCCESS);
}
