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

	BldStr()

	This function "builds" a string.  This means converting string
build constructs in the input string into their intended equivalents
in the output string.  The string build constructs are as follows:

	^Q	use next character literally,  not as a string build char
	^R	use next character literally,  not as a string build char
	^V	lowercase the next character
	^V^V	lowercase all following characters
	^W	uppercase the next character
	^W^W	uppercase all following characters
	^EQq	use string in q-register q here
	^EUq	use ASCII char for number in q-register q here

	When this function is called,  CBfPtr points to the first character
of the input string.  It is assumed that the string is terminated by an ESCAPE
character (or something else if the calling command was @-modified).  If the
string is not properly terminate this function will die with "unterminated
command" when it encounters CStEnd while looking for the terminator character.

	When this function returns,  CBfPtr points to the ESCAPE which
terminates the string, the built string is in the buffer pointed to by
XBfBeg,  and XBfPtr points to the character after the last character in
the built string.

	The commands which contain a file specification (EB, EI, EN, ER and
EW) use this function.  The EG command, which exits with an operating system
command line, uses this function.  The O command, which jumps to a tag, uses
this function.  The search commands (E_, FK, FN, FS, F_, N, S and _) use this
function.

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

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

extern	VOID	ErrMsg();	/* display an error message */
extern	DEFAULT	FindES();	/* find end of string */
extern	DEFAULT	FindQR();	/* find a q-register index */
extern	char	ZChrIt();	/* type-convert a long into a char */
extern	VOID	ZCpyBl();	/* copy a block of memory */

EXTERN	char	*ArgPtr;	/* beginning of text argument */
EXTERN	char	*CBfPtr;	/* pointer into command string */
EXTERN	char	*CStEnd;	/* pointer to last char of command string */
EXTERN	WORD	EdFlag;		/* ED mode control flag */
EXTERN	BYTE	IniSrM;		/* initial search mode */
EXTERN	char	*(*QBfBeg);	/* beginning of q-register text area */
EXTERN	char	*(*QBfPtr);	/* end of q-register text area, plus 1 */
EXTERN	LONG	*QNumbr;	/* q-register number */


DEFAULT BldStr(XBfBeg, XBfEnd, XBfPtr)		/* build a string */
char *XBfBeg;			/* beginning of build-string buffer */
char *XBfEnd;			/* end of build-string buffer */
char *(*XBfPtr);		/* pointer into build-string buffer */
{
	LOCAL	char	*ErrTxt;	/* error text string */
	LOCAL	char	*BBfPtr;	/* pointer into XBf */
	LOCAL	BYTE	CaseCv;		/* case conversion */
	LOCAL	char	*EndArg;	/* end of input string, plus 1 */
	LOCAL	DEFAULT	Status;		/* returned from FindQR */
	LOCAL	char	*TCStEn;	/* temporary holder of CStEnd */
	LOCAL	char	TmpChr;		/* temporary character */
	LOCAL	char	WVFlag;		/* ^W or ^V flag */

 
#if DEBUGGING
DbgInd+=2;if(DbgLvl>=2){DbgMsg();DbgDBf("BldStr: called.\015\012");DbgROf();}
#endif

	if (FindES(ESCAPE) == FAILURE)	/* move CBfPtr to end of argument */
#if DEBUGGING
{if(DbgLvl>=2)
{DbgMsg();DbgDBf("BldStr: returning FAILURE.\015\012");DbgROf();}DbgInd-=2;
#endif
		return(FAILURE);
#if DEBUGGING
}
#endif

	WVFlag = '\0';
	CaseCv = IniSrM;	/* initialize internal search mode */
	BBfPtr = XBfBeg;	/* init ptr into build-string buffer */
	EndArg = CBfPtr;	/* save pointer to end of argument */
	CBfPtr = ArgPtr;	/* reset to beginning of argument */

	while (CBfPtr < EndArg)
		{
		if ((*CBfPtr == '^') && ((EdFlag & ED_CARET_OK) == 0))
			{
			if (++CBfPtr == EndArg)
				{
				ErrMsg(ERR_ISS);
#if DEBUGGING
if(DbgLvl>=2)
{DbgMsg();DbgDBf("BldStr: returning FAILURE.\015\012");DbgROf();}DbgInd-=2;
#endif
				return(FAILURE);
				}
			TmpChr = To_Upper(*CBfPtr);
			if ((TmpChr < 'A') || (TmpChr > '_'))
				{
				*ErrTxt = *CBfPtr;
				ErrMsg(ERR_IUC, ErrTxt);
#if DEBUGGING
if(DbgLvl>=2)
{DbgMsg();DbgDBf("BldStr: returning FAILURE.\015\012");DbgROf();}DbgInd-=2;
#endif
				return(FAILURE);
				}
			TmpChr = TmpChr & '\077';
			}
		else
			TmpChr = *CBfPtr;
		switch (TmpChr) {
		case CTRL_R:
		case CTRL_Q:
			if (++CBfPtr == EndArg)
				{
				ErrMsg(ERR_ISS);
#if DEBUGGING
if(DbgLvl>=2)
{DbgMsg();DbgDBf("BldStr: returning FAILURE.\015\012");DbgROf();}DbgInd-=2;
#endif
				return(FAILURE);
				}
			*BBfPtr++ = *CBfPtr;
			break;
		case CTRL_V:
		case CTRL_W:
			WVFlag = TmpChr;
			if (++CBfPtr == EndArg)
				{
				ErrMsg(ERR_ISS);
#if DEBUGGING
if(DbgLvl>=2)
{DbgMsg();DbgDBf("BldStr: returning FAILURE.\015\012");DbgROf();}DbgInd-=2;
#endif
				return(FAILURE);
				}
			if ((*CBfPtr == '^') && ((EdFlag & ED_CARET_OK) == 0))
				{
				if (++CBfPtr == EndArg)
					{
					ErrMsg(ERR_ISS);
#if DEBUGGING
if(DbgLvl>=2)
{DbgMsg();DbgDBf("BldStr: returning FAILURE.\015\012");DbgROf();}DbgInd-=2;
#endif
					return(FAILURE);
					}
				TmpChr = To_Upper(*CBfPtr);
				if ((TmpChr < 'A') || (TmpChr > '_'))
					{
					*ErrTxt = *CBfPtr;
					ErrMsg(ERR_IUC, ErrTxt);
#if DEBUGGING
if(DbgLvl>=2)
{DbgMsg();DbgDBf("BldStr: returning FAILURE.\015\012");DbgROf();}DbgInd-=2;
#endif
					return(FAILURE);
					}
				TmpChr = TmpChr & '\077';
				}
			else
				TmpChr = *CBfPtr;
			if (WVFlag == CTRL_V)
				if (TmpChr == CTRL_V)
					CaseCv = LOWER;
				else
					*BBfPtr++ = To_Lower(TmpChr);
			else
				if (TmpChr == CTRL_W)
					CaseCv = UPPER;
				else
					*BBfPtr++ = To_Upper(TmpChr);
			WVFlag = '\0';
			break;
		case CTRL_E:
			if (++CBfPtr == EndArg)
				{
				ErrMsg(ERR_ICE);
#if DEBUGGING
if(DbgLvl>=2)
{DbgMsg();DbgDBf("BldStr: returning FAILURE.\015\012");DbgROf();}DbgInd-=2;
#endif
				return(FAILURE);
				}
			if ((*CBfPtr == 'Q') || (*CBfPtr == 'q'))
				{
				if (++CBfPtr == EndArg)
					{
					ErrMsg(ERR_ISS);
#if DEBUGGING
if(DbgLvl>=2)
{DbgMsg();DbgDBf("BldStr: returning FAILURE.\015\012");DbgROf();}DbgInd-=2;
#endif
					return(FAILURE);
					}
				TCStEn = CStEnd;	/* save CStEnd */
				CStEnd = EndArg;
				Status = FindQR();
				CStEnd = TCStEn;	/* restore CStEnd */
				if (Status == FAILURE)
#if DEBUGGING
{if(DbgLvl>=2)
{DbgMsg();DbgDBf("BldStr: returning FAILURE.\015\012");DbgROf();}DbgInd-=2;
#endif
					return(FAILURE);
#if DEBUGGING
}
#endif
				if ((*QBfBeg-*QBfPtr) > (XBfEnd-BBfPtr))
					{
					ErrMsg(ERR_STL);
#if DEBUGGING
if(DbgLvl>=2)
{DbgMsg();DbgDBf("BldStr: returning FAILURE.\015\012");DbgROf();}DbgInd-=2;
#endif
					return(FAILURE);
					}
				ZCpyBl(*QBfPtr-*QBfBeg, *QBfBeg, BBfPtr);
				BBfPtr += *QBfPtr-*QBfBeg;
				}
			else if ((*CBfPtr == 'U') || (*CBfPtr == 'u'))
				{
				if (++CBfPtr == EndArg)
					{
					ErrMsg(ERR_ISS);
#if DEBUGGING
if(DbgLvl>=2)
{DbgMsg();DbgDBf("BldStr: returning FAILURE.\015\012");DbgROf();}DbgInd-=2;
#endif
					return(FAILURE);
					}
				TCStEn = CStEnd;	/* save CStEnd */
				CStEnd = EndArg;
				Status = FindQR();
				CStEnd = TCStEn;	/* restore CStEnd */
				if (Status == FAILURE)
#if DEBUGGING
{if(DbgLvl>=2)
{DbgMsg();DbgDBf("BldStr: returning FAILURE.\015\012");DbgROf();}DbgInd-=2;
#endif
					return(FAILURE);
#if DEBUGGING
}
#endif
				*BBfPtr++ = ZChrIt(*QNumbr);
				}
			else
				{
				*BBfPtr++ = CTRL_E;
				*BBfPtr++ = *CBfPtr;
				}
			break;
		default:
			if (CaseCv == LOWER)
				TmpChr = To_Lower(TmpChr);
			else if (CaseCv == UPPER)
				TmpChr = To_Upper(TmpChr);
			*BBfPtr++ = TmpChr;
		}
		if (BBfPtr > XBfEnd)
			{
			ErrMsg(ERR_STL);	/* string too long */
#if DEBUGGING
if(DbgLvl>=2)
{DbgMsg();DbgDBf("BldStr: returning FAILURE.\015\012");DbgROf();}DbgInd-=2;
#endif
			return(FAILURE);
			}
		++CBfPtr;
		}
	*XBfPtr = BBfPtr;

#if DEBUGGING
if(DbgLvl>=2)
{DbgMsg();DbgDBf("BldStr: returning, string = \"");
TypBuf(XBfBeg, *XBfPtr);DbgDBf("\"\015\012");DbgROf();}DbgInd-=2;
#endif
	return(SUCCESS);
}
