// --------------------------------------------------------------------------
// Citadel: Script.CPP
//
// The script interpretter, but not the functions (ScrF*.CPP).

#include "ctdl.h"
#pragma hdrstop

#define SCRIPTMAIN
#include "script.h"
#include "scrfarry.h"

#include "msg.h"
#include "log.h"

// --------------------------------------------------------------------------
// Contents


// Debugging stuff - SCRIPTDB.CPP
Bool dwHandler(EVENT evt, long param, int more, CITWINDOW *wnd);



static void (*findInternalFunction(const strList *callWith))(strList *);
static scriptFunctionList *findFunc(const char *name);
static scriptVariables *getVar(const char *name);
static Bool specialEvaluateBool(const scriptVariables *var);


ScriptInfoS *CurScript;

discardable *ScriptDData;				// all script discardable data

const char *resultStr = "_RESULT";

static Bool AssignVariable(scriptVariables *Var, const char *Expr)
	{
	if (!Var)
		{
		return (FALSE);
		}

	switch (Var->type)
		{
		case TYPE_INT:
			{
			Var->v.i = evaluateInt(Expr);
			break;
			}

		case TYPE_UINT:
			{
			Var->v.ui = evaluateUint(Expr);
			break;
			}

		case TYPE_LONG:
			{
			Var->v.l = evaluateLong(Expr);
			break;
			}

		case TYPE_ULONG:
			{
			Var->v.ul = evaluateUlong(Expr);
			break;
			}

		case TYPE_BOOL:
			{
			Var->v.b = evaluateBool(Expr);
			break;
			}

		default:
			{
			if (Var->type >= TYPE_STRING_MIN && Var->type <= TYPE_STRING_MAX)
				{
				CopyStringToBuffer(Var->v.string, evaluateString(Expr),
						Var->type - TYPE_STRING_MIN + 1);
				}
			else
				{
				return (FALSE);
				}

			break;
			}
		}

	return (TRUE);
	}

void executeCurrentCommand(void)
	{
	if (CurScript->LastCmd)
		{
		CurScript->LastCmd->runCounter++;

		ulong TheTime = CurScript->CmdTimer.Read();
		CurScript->LastCmd->time += TheTime;

		if (CurScript->DebuggingWindow)
			{
			char wow[80];

			sprintf(wow, getscrmsg(51), CurScript->LastCmd->line,
					TheTime / (TIMER_HERTZ / 1000),
					CurScript->LastCmd->time / (TIMER_HERTZ / 1000),
					CurScript->LastCmd->runCounter,
					CurScript->LastCmd->time / (TIMER_HERTZ / 1000) /
					CurScript->LastCmd->runCounter);

			DebuggingMsg(wow);
			}
		}

	CurScript->LastCmd = CurScript->curCmd;

	KBReady();

	if (debug && !CurScript->oldSystemDebug)
		{
		CurScript->Debug = TRUE;
		}

	CurScript->oldSystemDebug = debug;

	if (!CurScript->Debug)
		{
		Breakpoints *bp;
		for (bp = CurScript->BPoints; bp; bp = (Breakpoints *)
				getNextLL(bp))
			{
			if (bp->LineNum == CurScript->curCmd->line)
				{
				CurScript->Debug = TRUE;
				break;
				}
			}
		}

	if (CurScript->Debug)
		{
		if (!CurScript->DebuggingWindow && CurScript->curCmd->line)
			{
			char *ld = new char[(conRows / 2 - 1) * (conCols - 2)];

			if (ld)
				{
				memset(ld, 0, (conRows / 2 - 1) * (conCols - 2));
				WINDOWFLAGS flags;
				SRECT rect;

				memset(&flags, 0, sizeof(flags));

				flags.visible = TRUE;
				flags.showTitle = TRUE;
				flags.moveable = TRUE;
				flags.minimize = TRUE;
				flags.resize = TRUE;

				rect.top = 0;
				rect.left = 0;
				rect.bottom = conRows / 2;
				rect.right = conCols / 3;

				CurScript->DebuggingWindow = makeCitWindow(dwHandler, NULL,
						getscrmsg(28), flags, rect, ld, FALSE);

				setFocus(CurScript->DebuggingWindow);
				}
			}
		}
	else
		{
		if (CurScript->DebuggingWindow)
			{
			destroyCitWindow(CurScript->DebuggingWindow, FALSE);
			CurScript->DebuggingWindow = NULL;
			}

		CurScript->Pause = FALSE;
		}

	if (CurScript->DebuggingWindow)
		{
		char wow[80];

		sprintf(wow, getscrmsg(31), CurScript->curCmd->line);
		DebuggingMsg(wow);

		Breakpoints *bp;
		for (bp = CurScript->BPoints; bp; bp = (Breakpoints *)
				getNextLL(bp))
			{
			if (bp->LineNum == CurScript->curCmd->line)
				{
				DebuggingMsg(getscrmsg(32));
				CurScript->Pause = TRUE;
				break;
				}
			}

		if (CurScript->WWindow)
			{
			(CurScript->WWindow->func)(EVT_DRAWINT, 0, 0, CurScript->WWindow);
			}

		if (CurScript->SourceWindow)
			{
			(CurScript->SourceWindow->func)(EVT_DRAWINT, 0, 1,
					CurScript->SourceWindow);
			}

		if (CurScript->Pause)
			{
			if (!getFocus())
				{
				setFocus(CurScript->DebuggingWindow);
				}
			}
		}

	while (CurScript->Pause && CurScript->curCmd->line &&
			!CurScript->SingleStep && !CurScript->Error && CurScript->Debug)
		{
		KBReady();
		}

	CurScript->SingleStep = FALSE;

	CurScript->CmdTimer.Reset();

	switch (CurScript->curCmd->type)
		{
		case CMD_ADD:
			{
			long theResult = 0;

			for (strList *theSL = CurScript->curCmd->c.sl; theSL;
					theSL = (strList *) getNextLL(theSL))
				{
				theResult += evaluateLong(theSL->string);
				}

			CurScript->lastResult.type = TYPE_LONG;
			CurScript->lastResult.v.l = theResult;

			CurScript->curCmd = (scriptCommandRecord *)
					getNextLL(CurScript->curCmd);
			break;
			}

		case CMD_SUB:
			{
			strList *theSL = CurScript->curCmd->c.sl;

			if (theSL)
				{
				long theResult = evaluateLong(theSL->string);

				for (theSL = (strList *) getNextLL(theSL); theSL;
						theSL = (strList *) getNextLL(theSL))
					{
					theResult -= evaluateLong(theSL->string);
					}

				CurScript->lastResult.type = TYPE_LONG;
				CurScript->lastResult.v.l = theResult;
				}

			CurScript->curCmd = (scriptCommandRecord *)
					getNextLL(CurScript->curCmd);
			break;
			}

		case CMD_MUL:
			{
			strList *theSL = CurScript->curCmd->c.sl;

			if (theSL)
				{
				long theResult = evaluateLong(theSL->string);

				for (theSL = (strList *) getNextLL(theSL); theSL;
						theSL = (strList *) getNextLL(theSL))
					{
					theResult *= evaluateLong(theSL->string);
					}

				CurScript->lastResult.type = TYPE_LONG;
				CurScript->lastResult.v.l = theResult;
				}

			CurScript->curCmd = (scriptCommandRecord *)
					getNextLL(CurScript->curCmd);
			break;
			}

		case CMD_DIV:
			{
			strList *theSL = CurScript->curCmd->c.sl;

			if (theSL)
				{
				long theResult = evaluateLong(theSL->string);

				for (theSL = (strList *) getNextLL(theSL); theSL;
						theSL = (strList *) getNextLL(theSL))
					{
					theResult /= evaluateLong(theSL->string);
					}

				CurScript->lastResult.type = TYPE_LONG;
				CurScript->lastResult.v.l = theResult;
				}

			CurScript->curCmd = (scriptCommandRecord *)
					getNextLL(CurScript->curCmd);
			break;
			}

		case CMD_MOD:
			{
			strList *theSL = CurScript->curCmd->c.sl;

			if (theSL)
				{
				long theResult = evaluateLong(theSL->string);

				for (theSL = (strList *) getNextLL(theSL); theSL;
						theSL = (strList *) getNextLL(theSL))
					{
					theResult %= evaluateLong(theSL->string);
					}

				CurScript->lastResult.type = TYPE_LONG;
				CurScript->lastResult.v.l = theResult;
				}

			CurScript->curCmd = (scriptCommandRecord *)
					getNextLL(CurScript->curCmd);
			break;
			}

		case CMD_AND:
			{
			Bool theResult = TRUE;

			for (strList *theSL = CurScript->curCmd->c.sl; theSL;
					theSL = (strList *) getNextLL(theSL))
				{
				if (!evaluateBool(theSL->string))
					{
					theResult = FALSE;
					break;
					}
				}

			CurScript->lastResult.type = TYPE_BOOL;
			CurScript->lastResult.v.b = theResult;

			CurScript->curCmd = (scriptCommandRecord *)
					getNextLL(CurScript->curCmd);
			break;
			}

		case CMD_OR:
			{
			Bool theResult = FALSE;

			for (strList *theSL = CurScript->curCmd->c.sl; theSL;
					theSL = (strList *) getNextLL(theSL))
				{
				if (evaluateBool(theSL->string))
					{
					theResult = TRUE;
					break;
					}
				}

			CurScript->lastResult.type = TYPE_BOOL;
			CurScript->lastResult.v.b = theResult;

			CurScript->curCmd = (scriptCommandRecord *)
					getNextLL(CurScript->curCmd);
			break;
			}

		case CMD_XOR:
			{
			int TrueCount = 0;

			for (strList *theSL = CurScript->curCmd->c.sl; theSL;
					theSL = (strList *) getNextLL(theSL))
				{
				if (evaluateBool(theSL->string))
					{
					TrueCount++;
					}
				}

			CurScript->lastResult.type = TYPE_BOOL;
			CurScript->lastResult.v.b = TrueCount == 1;

			CurScript->curCmd = (scriptCommandRecord *)
					getNextLL(CurScript->curCmd);
			break;
			}

		case CMD_ASGN:
			{
			if (!CurScript->curCmd->ptr)
				{
				CurScript->curCmd->ptr =
						getVar(CurScript->curCmd->c.sl->string);
				}

			scriptVariables *theVar = (scriptVariables *)
					CurScript->curCmd->ptr;

			strList *theSL = (strList *)
					getNextLL(CurScript->curCmd->c.sl);

			if (theVar)
				{
				if (!AssignVariable(theVar, theSL->string))
					{
					CRmPrintfCR(getscrmsg(4), CurScript->Name,
							CurScript->curCmd->line, theVar->type);

					CurScript->curCmd = NULL;
					CurScript->ToRet = FALSE;
					}
				}
			else
				{
				CRmPrintfCR(getscrmsg(5), CurScript->Name, CurScript->curCmd->line,
						CurScript->curCmd->c.sl->string);
				CurScript->curCmd = NULL;
				CurScript->ToRet = FALSE;
				}

			CurScript->curCmd = (scriptCommandRecord *)
					getNextLL(CurScript->curCmd);
			break;
			}

		case CMD_STRB:
			{
			const int Offset = 
					evaluateInt(CurScript->curCmd->c.sl->next->string);
			const int StrLen =
					evaluateInt(CurScript->curCmd->c.sl->next->next->string);
			const char *Str =
					evaluateString(CurScript->curCmd->c.sl->string);

			CurScript->lastResult.type = TYPE_STRING_MAX;
			CurScript->lastResult.v.string = CurScript->wowza;

			if (strlen(Str) > Offset)
				{
				CopyStringToBuffer(CurScript->lastResult.v.string,
						Str + Offset, min(StrLen, 255));
				}
			else
				{
				CurScript->lastResult.v.string[0] = 0;
				}

			CurScript->curCmd = (scriptCommandRecord *)
					getNextLL(CurScript->curCmd);
			break;
			}

		case CMD_STRU:
			{
			CurScript->lastResult.type = TYPE_STRING_MAX;
			CurScript->lastResult.v.string = CurScript->wowza;
			strcpy(CurScript->lastResult.v.string,
					evaluateString(CurScript->curCmd->c.sl->string));
			strupr(CurScript->lastResult.v.string);
			CurScript->curCmd = (scriptCommandRecord *)
					getNextLL(CurScript->curCmd);
			break;
			}

		case CMD_STRL:
			{
			CurScript->lastResult.type = TYPE_STRING_MAX;
			CurScript->lastResult.v.string = CurScript->wowza;
			strcpy(CurScript->lastResult.v.string,
					evaluateString(CurScript->curCmd->c.sl->string));
			strlwr(CurScript->lastResult.v.string);
			CurScript->curCmd = (scriptCommandRecord *)
					getNextLL(CurScript->curCmd);
			break;
			}

		case CMD_STRC:
			{
			char Temp[512]; 	// Twice max size
			*Temp = 0;

			for (const strList *theSL = CurScript->curCmd->c.sl; theSL;
					theSL = (strList *) getNextLL(theSL))
				{
				strcat(Temp, evaluateString(theSL->string));
				Temp[255] = 0;	// Truncate in case of overflow
				}

			CurScript->lastResult.type = TYPE_STRING_MAX;
			CurScript->lastResult.v.string = CurScript->wowza;
			CopyStringToBuffer(CurScript->lastResult.v.string, Temp,
					sizeof(CurScript->wowza) - 1);

			CurScript->curCmd = (scriptCommandRecord *)
					getNextLL(CurScript->curCmd);
			break;
			}

		case CMD_STRS:
			{
			CurScript->lastResult.type = TYPE_LONG;
			scriptVariables *theVar =
					getVar(CurScript->curCmd->c.sl->string);

			if (theVar)
				{
				CurScript->lastResult.v.l = theVar->type - TYPE_STRING_MIN + 1;
				}
			else
				{
				CurScript->lastResult.v.l = 0;
				}

			CurScript->curCmd = (scriptCommandRecord *)
					getNextLL(CurScript->curCmd);
			break;
			}

		case CMD_STRE:
			{
			const long Length = 
					strlen(evaluateString(CurScript->curCmd->c.sl->string));

			CurScript->lastResult.type = TYPE_LONG;
			CurScript->lastResult.v.l = Length;

			CurScript->curCmd = (scriptCommandRecord *)
					getNextLL(CurScript->curCmd);
			break;
			}

		case CMD_STRPR:
		case CMD_STRPL:
			{
			if (CurScript->curCmd->c.sl->next)
				{
				int j = strlen(evaluateString(CurScript->curCmd->c.sl->string));

				if (j < evaluateInt(CurScript->curCmd->c.sl->next->string))
					{
					j = evaluateInt(CurScript->curCmd->c.sl->next->string) - j;

					if (CurScript->curCmd->type == CMD_STRPR)
						{
						strcpy(CurScript->wowza,
								evaluateString(CurScript->curCmd->c.sl->string));

						for (; j; j--)
							{
							strcat(CurScript->wowza, spc);
							}
						}
					else
						{
						CurScript->wowza[0] = 0;
						for (; j; j--)
							{
							strcat(CurScript->wowza, spc);
							}

						strcat(CurScript->wowza,
								evaluateString(CurScript->curCmd->c.sl->string));
						}
					}
				else
					{
					strcpy(CurScript->wowza,
							evaluateString(CurScript->curCmd->c.sl->string));
					}

				CurScript->lastResult.v.string = CurScript->wowza;
				CurScript->lastResult.type = TYPE_STRING_MAX;
				}
			else
				{
				CRmPrintfCR(getscrmsg(6), CurScript->Name, CurScript->curCmd->line);
				CurScript->curCmd = NULL;
				CurScript->ToRet = FALSE;
				}

			CurScript->curCmd = (scriptCommandRecord *)
					getNextLL(CurScript->curCmd);
			break;
			}

		case CMD_GOTO:
			{
			for (scriptCommandRecord *theCmd = CurScript->curFunc->cmds;
					theCmd; theCmd = (scriptCommandRecord *) getNextLL(theCmd))
				{
				if (theCmd->type == CMD_LABEL &&
						SameString(theCmd->c.str,
						evaluateString(CurScript->curCmd->c.str)))
					{
					CurScript->curCmd = (scriptCommandRecord *)
							getNextLL(theCmd);
					break;
					}
				}

			if (!theCmd)
				{
				// no matching label - bad stuff
				CRmPrintfCR(getscrmsg(7), CurScript->Name, CurScript->curCmd->line,
						evaluateString(CurScript->curCmd->c.str));
				CurScript->curCmd = NULL;
				CurScript->ToRet = FALSE;
				}

			break;
			}

		case CMD_RUN:
			{
			char toRun[128];
			CopyStringToBuffer(toRun,
					evaluateString(CurScript->curCmd->c.str),
					sizeof(toRun) - 1);

			// Use temp var Ran just to be safe - runScript messes
			// with CurScript. It shouldn't do anything bad, but
			// this incures such little overhead that i'm doing it.

			Bool Ran = runScript(toRun);

			CurScript->lastResult.v.b = Ran;
			CurScript->lastResult.type = TYPE_BOOL;

			CurScript->curCmd = (scriptCommandRecord *)
					getNextLL(CurScript->curCmd);
			break;
			}

		case CMD_CHAIN:
			{
			char toRun[128];
			CopyStringToBuffer(toRun,
					evaluateString(CurScript->curCmd->c.str),
					sizeof(toRun) - 1);

			CurScript->ToRet = runScript(toRun);

			// Don't continue with this script when chained is done
			CurScript->curCmd = NULL;
			break;
			}

		case CMD_IF:
		case CMD_IFNOT:
			{
			if (!CurScript->curCmd->ptr &&
					CurScript->curCmd->c.str[0] == '_')
				{
				CurScript->curCmd->ptr =
						getVar(CurScript->curCmd->c.str);
				}

			Bool EvalsTo = CurScript->curCmd->ptr ?
					specialEvaluateBool((scriptVariables *) CurScript->curCmd->ptr) :
					evaluateBool(CurScript->curCmd->c.str);

			if (CurScript->curCmd->type == CMD_IFNOT)
				{
				EvalsTo = !EvalsTo;
				}

			if (!EvalsTo)
				{
				// skip to #ELSE or #ENDIF
				int IfCounter;
				scriptCommandRecord *theCmd;

				for (IfCounter = 0, theCmd = (scriptCommandRecord *)
						getNextLL(CurScript->curCmd); theCmd;
						theCmd = (scriptCommandRecord *) getNextLL(theCmd))
					{
					if (theCmd->type == CMD_IF ||
							theCmd->type == CMD_IFNOT)
						{
						IfCounter++;
						}

					if ((theCmd->type == CMD_ELSE ||
							theCmd->type == CMD_ENDIF) && !IfCounter)
						{
						CurScript->curCmd = theCmd;
						break;
						}

					if (theCmd->type == CMD_ENDIF)
						{
						IfCounter--;
						}
					}

				if (!theCmd)
					{
					CRmPrintfCR(getscrmsg(8), CurScript->Name, CurScript->curCmd->line);
					CurScript->curCmd = NULL;
					CurScript->ToRet = FALSE;
					break;
					}
				}

			CurScript->curCmd = (scriptCommandRecord *)
					getNextLL(CurScript->curCmd);
			break;
			}

		case CMD_ELSE:
			{
			// skip to endif
			int IfCounter;
			scriptCommandRecord *theCmd;

			for (IfCounter = 0, theCmd = CurScript->curCmd; theCmd;
					theCmd = (scriptCommandRecord *) getNextLL(theCmd))
				{
				if (theCmd->type == CMD_IF || theCmd->type == CMD_IFNOT)
					{
					IfCounter++;
					}

				if (theCmd->type == CMD_ENDIF)
					{
					if (!IfCounter)
						{
						CurScript->curCmd = (scriptCommandRecord *)
								getNextLL(theCmd);
						break;
						}
					else
						{
						IfCounter--;
						}
					}
				}

			if (!theCmd)
				{
				CRmPrintfCR(getscrmsg(8), CurScript->Name, CurScript->curCmd->line);
				CurScript->curCmd = NULL;
				CurScript->ToRet = FALSE;
				}

			break;
			}

		case CMD_EQ:
		case CMD_GE:
		case CMD_LE:
		case CMD_NE:
		case CMD_GT:
		case CMD_LT:
			{
			scriptVariables *theVar;

			if (CurScript->curCmd->ptr)
				{
				theVar = (scriptVariables *) CurScript->curCmd->ptr;
				}
			else
				{
				if (CurScript->curCmd->c.sl->string[0] == '_')
					{
					// first is a variable
					if ((theVar = getVar(CurScript->curCmd->c.sl->string)) ==
							NULL)
						{
						CRmPrintfCR(getscrmsg(5), CurScript->Name,
								CurScript->curCmd->line,
								CurScript->curCmd->c.sl->string);

						CurScript->curCmd = NULL;
						CurScript->ToRet = FALSE;
						break;
						}
					}
				else if (CurScript->curCmd->c.sl->next->string[0] == '_')
					{
					// second is a variable
					if ((theVar =
							getVar(CurScript->curCmd->c.sl->next->string)) ==
							NULL)
						{
						CRmPrintfCR(getscrmsg(5), CurScript->Name, CurScript->curCmd->line,
								CurScript->curCmd->c.sl->next->string);
						CurScript->curCmd = NULL;
						CurScript->ToRet = FALSE;
						break;
						}
					}
				else
					{
					// const with const - icky bad
					CRmPrintfCR(getscrmsg(9), CurScript->Name, CurScript->curCmd->line);
					CurScript->curCmd = NULL;
					CurScript->ToRet = FALSE;
					break;
					}

				CurScript->curCmd->ptr = theVar;
				}

			long l;
			switch (theVar->type)
				{
				case TYPE_INT:
					{
					l = evaluateInt(CurScript->curCmd->c.sl->string) -
							evaluateInt(CurScript->curCmd->c.sl->next->string);
					break;
					}

				case TYPE_UINT:
					{
					l = evaluateUint(CurScript->curCmd->c.sl->string) -
							evaluateUint(CurScript->curCmd->c.sl->next->string);
					break;
					}

				case TYPE_LONG:
					{
					l = evaluateLong(CurScript->curCmd->c.sl->string) -
							evaluateLong(CurScript->curCmd->c.sl->next->string);
					break;
					}

				case TYPE_ULONG:
					{
					l = evaluateUlong(CurScript->curCmd->c.sl->string) -
							evaluateUlong(CurScript->curCmd->c.sl->next->string);
					break;
					}

				case TYPE_BOOL:
					{
					l = evaluateBool(CurScript->curCmd->c.sl->string) -
							evaluateBool(CurScript->curCmd->c.sl->next->string);
					break;
					}

				default:
					{
					if (theVar->type >= TYPE_STRING_MIN &&
							theVar->type <= TYPE_STRING_MAX)
						{
						l = strcmpi(evaluateString(CurScript->curCmd->c.sl->string),
								evaluateString(CurScript->curCmd->c.sl->next->string));
						}
					else
						{
						CRmPrintfCR(getscrmsg(10), CurScript->Name,
								CurScript->curCmd->line, theVar->type);
						CurScript->curCmd = NULL;
						CurScript->ToRet = FALSE;
						}

					break;
					}
				}

			CurScript->lastResult.type = TYPE_BOOL;
			switch (CurScript->curCmd->type)
				{
				case CMD_EQ:
					{
					CurScript->lastResult.v.b = l == 0;
					break;
					}

				case CMD_GE:
					{
					CurScript->lastResult.v.b = l >= 0;
					break;
					}

				case CMD_LE:
					{
					CurScript->lastResult.v.b = l <= 0;
					break;
					}

				case CMD_NE:
					{
					CurScript->lastResult.v.b = l != 0;
					break;
					}

				case CMD_GT:
					{
					CurScript->lastResult.v.b = l > 0;
					break;
					}

				case CMD_LT:
					{
					CurScript->lastResult.v.b = l < 0;
					break;
					}
				}

			CurScript->curCmd = (scriptCommandRecord *)
					getNextLL(CurScript->curCmd);
			break;
			}

		case CMD_CALL:
			{
			if (CurScript->curCmd->c.sl->string[0] != '_')
				{
				// internal function
				if (CurScript->curCmd->ptr)
					{
					(*(void (*)(strList *)) (CurScript->curCmd->ptr))
							(CurScript->curCmd->c.sl->next);
					}
				else
					{
					void (*func)(strList *params) =
							findInternalFunction(CurScript->curCmd->c.sl);

					if (func)
						{
						CurScript->curCmd->ptr = func;
						(*func)(CurScript->curCmd->c.sl->next);
						}
					}

				CurScript->curCmd = (scriptCommandRecord *)
						getNextLL(CurScript->curCmd);
				// add code here to deal with null-functions???
				}
			else
				{
				scriptFunctionList *theFunc;

				// script function
				if (!CurScript->curCmd->ptr)
					{
					CurScript->curCmd->ptr = theFunc =
							findFunc(CurScript->curCmd->c.sl->string);
					}
				else
					{
					theFunc = (scriptFunctionList *) CurScript->curCmd->ptr;
					}

				if (theFunc)
					{
					disposeLL((void **) &(theFunc->loopInfo));

					scriptCallList *theCallList = (scriptCallList *)
							addLL((void **) &CurScript->callList,
							sizeof(*theCallList));

					if (theCallList)
						{
						theCallList->oldFunc = CurScript->curFunc;
						theCallList->oldCmd = (scriptCommandRecord *)
								getNextLL(CurScript->curCmd);

						strList *theSL;
						int j;

						for (j = 0, theSL = CurScript->curCmd->c.sl->next;
								j < MAXARGS && theSL && CurScript->curCmd;
								j++, theSL = (strList *) getNextLL(theSL))
							{
							if (theFunc->argt[j] != TYPE_NONE)
								{
								assert(theFunc->argv[j]);

								if (theFunc->argt[j] & BY_REF)
									{
									theFunc->byref[j] = getVar(theSL->string);
									}

								if (!AssignVariable(theFunc->argv[j],
										theSL->string))
									{
									CRmPrintfCR(getscrmsg(4), CurScript->Name,
											CurScript->curCmd->line,
											theFunc->argv[j]->type);

									CurScript->curCmd = NULL;
									CurScript->ToRet = FALSE;
									}
								}
							else
								{
								CRmPrintfCR(getscrmsg(12), CurScript->Name,
										CurScript->curCmd->line,
										CurScript->curCmd->c.sl->string);
								CurScript->curCmd = NULL;
								CurScript->ToRet = FALSE;
								}
							}

						if (CurScript->curCmd)
							{
							CurScript->curCmd = theFunc->cmds;
							// add code here to deal with null-functions???
							CurScript->curFunc = theFunc;
							}
						}
					else
						{
						mPrintfCR(getscrmsg(13), CurScript->Name, CurScript->curCmd->line);
						CurScript->curCmd = NULL;
						CurScript->ToRet = FALSE;
						}
					}
				else
					{
					mPrintfCR(getscrmsg(14), CurScript->Name, CurScript->curCmd->line,
							CurScript->curCmd->c.sl->string);
					CurScript->curCmd = NULL;
					CurScript->ToRet = FALSE;
					}
				}

			break;
			}

		case CMD_RET:
			{
			int j = (int) getLLCount((void *) CurScript->callList);
			scriptCallList *theCallList = (scriptCallList *)
					getLLNum((void *) CurScript->callList, j);

			if (theCallList)
				{
				switch (CurScript->curFunc->rett)
					{
					case TYPE_BOOL:
						{
						CurScript->lastResult.v.b =
								evaluateBool(CurScript->curCmd->c.str);
						CurScript->lastResult.type = TYPE_BOOL;
						break;
						}

					case TYPE_INT:
						{
						CurScript->lastResult.v.i =
								evaluateInt(CurScript->curCmd->c.str);
						CurScript->lastResult.type = TYPE_INT;
						break;
						}

					case TYPE_UINT:
						{
						CurScript->lastResult.v.ui =
								evaluateUint(CurScript->curCmd->c.str);
						CurScript->lastResult.type = TYPE_UINT;
						break;
						}

					case TYPE_ULONG:
						{
						CurScript->lastResult.v.ul =
								evaluateUlong(CurScript->curCmd->c.str);
						CurScript->lastResult.type = TYPE_ULONG;
						break;
						}

					case TYPE_LONG:
						{
						CurScript->lastResult.v.l =
								evaluateLong(CurScript->curCmd->c.str);
						CurScript->lastResult.type = TYPE_LONG;
						break;
						}

					default:
						{
						if (CurScript->curFunc->rett >= TYPE_STRING_MIN &&
								CurScript->curFunc->rett <= TYPE_STRING_MAX)
							{
							CurScript->lastResult.v.string = CurScript->wowza;
							strcpy(CurScript->wowza,
									evaluateString(CurScript->curCmd->c.str));
							CurScript->lastResult.type = TYPE_STRING_MAX;
							}
						}
					}

				for (int i = 0; i < MAXARGS; i++)
					{
					if ((CurScript->curFunc->argt[i] & BY_REF))
						{
						AssignVariable(CurScript->curFunc->byref[i],
								CurScript->curFunc->argn[i]);
						}
					}

				CurScript->curFunc = theCallList->oldFunc;
				CurScript->curCmd = theCallList->oldCmd;

				deleteLLNode((void **) &CurScript->callList, j);
				}
			else
				{
				mPrintfCR(getscrmsg(27), CurScript->Name, CurScript->curCmd->line);
				CurScript->curCmd = NULL;
				CurScript->ToRet = FALSE;
				}

			break;
			}

		case CMD_DO:
			{
			scriptLoops *theLoop = (scriptLoops *) addLL((void **)
					&(CurScript->curFunc->loopInfo), sizeof(*theLoop));

			if (theLoop)
				{
				theLoop->LoopType = LOOP_DO;
				theLoop->where = CurScript->curCmd;
				}
			else
				{
				mPrintfCR(getscrmsg(13), CurScript->Name, CurScript->curCmd->line);
				CurScript->curCmd = NULL;
				CurScript->ToRet = FALSE;
				}

			CurScript->curCmd = (scriptCommandRecord *)
					getNextLL(CurScript->curCmd);
			break;
			}

		case CMD_LOOP:
		case CMD_LOOPNOT:
			{
			for (scriptLoops *theLoop = CurScript->curFunc->loopInfo;
					theLoop && theLoop->next;
					theLoop = (scriptLoops *) getNextLL(theLoop));

			if (theLoop && theLoop->LoopType == LOOP_DO)
				{
				if (!CurScript->curCmd->ptr &&
						CurScript->curCmd->c.str[0] == '_')
					{
					CurScript->curCmd->ptr =
							getVar(CurScript->curCmd->c.str);
					}

				Bool EvalsTo = CurScript->curCmd->ptr ?
						specialEvaluateBool((scriptVariables *)
						CurScript->curCmd->ptr) :
						evaluateBool(CurScript->curCmd->c.str);

				if (CurScript->curCmd->type == CMD_LOOPNOT)
					{
					EvalsTo = !EvalsTo;
					}

				if (EvalsTo)
					{
					CurScript->curCmd = theLoop->where;
					}
				else
					{
					deleteLLNode((void **) &(CurScript->curFunc->loopInfo),
							getLLCount(CurScript->curFunc->loopInfo));
					}
				}
			else
				{
				mPrintfCR(getscrmsg(15), CurScript->Name, CurScript->curCmd->line);
				CurScript->curCmd = NULL;
				CurScript->ToRet = FALSE;
				}

			CurScript->curCmd = (scriptCommandRecord *)
					getNextLL(CurScript->curCmd);
			break;
			}

		case CMD_WHILE:
		case CMD_WHILENOT:
			{
			if (!CurScript->curCmd->ptr &&CurScript->curCmd->c.str[0] == '_')
				{
				CurScript->curCmd->ptr = getVar(CurScript->curCmd->c.str);
				}


			Bool EvalsTo = CurScript->curCmd->ptr ?
					specialEvaluateBool((scriptVariables *)
					CurScript->curCmd->ptr) :
					evaluateBool(CurScript->curCmd->c.str);

			if (CurScript->curCmd->type == CMD_WHILENOT)
					{
					EvalsTo = !EvalsTo;
					}

			if (EvalsTo)
				{
				scriptLoops *theLoop = (scriptLoops *) addLL((void **)
						&(CurScript->curFunc->loopInfo),
						sizeof(*theLoop));

				if (theLoop)
					{
					theLoop->LoopType =
							(CurScript->curCmd->type == CMD_WHILENOT) ?
							LOOP_WHILENOT : LOOP_WHILE;

					theLoop->where = CurScript->curCmd;
					CurScript->curCmd = (scriptCommandRecord *)
							getNextLL(CurScript->curCmd);
					}
				else
					{
					mPrintfCR(getscrmsg(13), CurScript->Name, CurScript->curCmd->line);
					CurScript->curCmd = NULL;
					CurScript->ToRet = FALSE;
					}
				}
			else
				{
				int WhileCounter;
				scriptCommandRecord *theCmd;

				for (WhileCounter = 0, theCmd = (scriptCommandRecord *)
						getNextLL(CurScript->curCmd);
						theCmd; theCmd = (scriptCommandRecord *)
						getNextLL(theCmd))
					{
					if (theCmd->type == CMD_WHILE || theCmd->type == CMD_WHILENOT)
						{
						WhileCounter++;
						}
					else if (theCmd->type == CMD_WEND)
						{
						if (!WhileCounter)
							{
							CurScript->curCmd = (scriptCommandRecord *)
									getNextLL(theCmd);
							break;
							}
						else
							{
							WhileCounter--;
							}
						}
					}

				if (!theCmd)
					{
					CRmPrintfCR(getscrmsg(53), CurScript->Name, CurScript->curCmd->line);
					CurScript->curCmd = NULL;
					CurScript->ToRet = FALSE;
					}
				}

			break;
			}

		case CMD_WEND:
			{
			for (scriptLoops *theLoop = CurScript->curFunc->loopInfo;
					theLoop && theLoop->next;
					theLoop = (scriptLoops *) getNextLL(theLoop));

			if (theLoop &&
					(theLoop->LoopType == LOOP_WHILE ||
					theLoop->LoopType == LOOP_WHILENOT))
				{
				CurScript->curCmd = theLoop->where;

				deleteLLNode((void **) &(CurScript->curFunc->loopInfo),
						(int) getLLCount(CurScript->curFunc->loopInfo));
				}
			else
				{
				mPrintfCR(getscrmsg(52), CurScript->Name, CurScript->curCmd->line);
				CurScript->curCmd = NULL;
				CurScript->ToRet = FALSE;
				}

			break;
			}

		case CMD_EXIT:
			{
			CurScript->ToRet = evaluateBool(CurScript->curCmd->c.str);
			CurScript->curCmd = NULL;
			break;
			}

		case CMD_LABEL:
		case CMD_ENDIF:
			{
			CurScript->curCmd = (scriptCommandRecord *)
					getNextLL(CurScript->curCmd);
			break;
			}

		default:
			{
			mPrintfCR(getscrmsg(16), CurScript->Name, CurScript->curCmd->line,
					CurScript->curCmd->type);
			CurScript->curCmd = NULL;
			CurScript->ToRet = FALSE;
			break;
			}
		}
	}

static void (*findInternalFunction(const strList *callWith))(strList *)
	{
	int i, high, low, found = FALSE;
	const char *str = callWith->string; // speed
	const char **arry = (const char **) ScriptDData->next->aux; // more speed

	low = 0;
	high = sizeof(internalFunctions) / sizeof(internalFunctionRecord) - 1;

	for (i = high / 2; !found; i = ((high - low) / 2) + low)
		{
		int test = strcmpi(arry[i], str);

		if (test == 0)
			{
			found = TRUE;
			}
		else if (test > 0)
			{
			high = i - 1;
			}
		else
			{
			low = i + 1;
			}

		if (high < low)
			{
			break;
			}
		}

	if (found)
		{
		return (internalFunctions[i].func);
		}
	else
		{
		mPrintfCR(getscrmsg(14), CurScript->Name,
				CurScript->curCmd->line, callWith->string);
		return (NULL);
		}
	}

scriptFunctionList *findFunc(const char *name)
	{
	scriptFunctionList *cur;

	for (cur = CurScript->sfBase; cur;
			cur = (scriptFunctionList *) getNextLL(cur))
		{
		if (SameString(name, cur->name))
			{
			break;
			}
		}

	return (cur);
	}

// returns a script variable based on the name
scriptVariables *getVar(const char *name)
	{
	scriptVariables *cur;
	int i;

	// is it _RESULT?
	if (SameString(name, resultStr))
		{
		return (&CurScript->lastResult);
		}

	if (CurScript->curFunc)
		{
		// no; search local vars
		for (cur = CurScript->curFunc->vars; cur;
				cur = (scriptVariables *) getNextLL(cur))
			{
			if (SameString(cur->name, name))
				{
				return (cur);
				}
			}

		// then, try function's parameters
		for (i = 0; i < MAXARGS; i++)
			{
			if (SameString(CurScript->curFunc->argn[i], name))
				{
				return (CurScript->curFunc->argv[i]);
				}
			}
		}

	// perhaps global?
	for (cur = CurScript->gvBase; cur; cur = (scriptVariables *)
			getNextLL(cur))
		{
		if (SameString(cur->name, name))
			{
			return (cur);
			}
		}

	return (NULL);
	}

int evaluateInt(const char *what)
	{
	scriptVariables *cur;

	if (what[0] == '_')
		{
		cur = getVar(what);
		if (cur->type >= TYPE_STRING_MIN && cur->type <= TYPE_STRING_MAX)
			{
			return (atoi(cur->v.string));
			}
		return (cur->v.i);
		}
	else
		{
		return (atoi(what));
		}
	}

uint evaluateUint(const char *what)
	{
	scriptVariables *cur;

	if (what[0] == '_')
		{
		cur = getVar(what);
		if (cur->type >= TYPE_STRING_MIN && cur->type <= TYPE_STRING_MAX)
			{
			return ((uint) atoi(cur->v.string));
			}
		return (cur->v.ui);
		}
	else
		{
		return ((uint) atoi(what));
		}
	}

long evaluateLong(const char *what)
	{
	scriptVariables *cur;

	if (what[0] == '_')
		{
		cur = getVar(what);
		if (cur->type >= TYPE_STRING_MIN && cur->type <= TYPE_STRING_MAX)
			{
			return (atol(cur->v.string));
			}

		if (cur->type == TYPE_LONG || cur->type == TYPE_ULONG)
			{
			return (cur->v.l);
			}
		else
			{
			return ((long) cur->v.i);
			}
		}
	else
		{
		return (atol(what));
		}
	}

ulong evaluateUlong(const char *what)
	{
	scriptVariables *cur;

	if (what[0] == '_')
		{
		cur = getVar(what);
		if (cur->type >= TYPE_STRING_MIN && cur->type <= TYPE_STRING_MAX)
			{
			return ((ulong) atol(cur->v.string));
			}

		if (cur->type == TYPE_LONG || cur->type == TYPE_ULONG)
			{
			return (cur->v.ul);
			}
		else
			{
			return ((ulong) cur->v.ui);
			}
		}
	else
		{
		return ((ulong) atol(what));
		}
	}

static Bool specialEvaluateBool(const scriptVariables *var)
	{
	if (var->type >= TYPE_STRING_MIN && var->type <= TYPE_STRING_MAX)
		{
		return (evaluateBool(var->v.string));
		}

	return (var->v.b != 0);
	}

Bool evaluateBool(const char *what)
	{
	if (what[0] == '_')
		{
		const scriptVariables *cur = getVar(what);
		return (specialEvaluateBool(cur));
		}
	else
		{
		if (SameString(what, getscrmsg(25)))
			{
			return (FALSE);
			}

		if (SameString(what, getscrmsg(26)))
			{
			return (TRUE);
			}

		return ((Bool) (atoi(what) != 0));
		}
	}

const char *evaluateString(const char *what)
	{
	scriptVariables *cur;

	if (what[0] == '_')
		{
		cur = getVar(what);

		if (cur)
			{
			if (cur->type >= TYPE_STRING_MIN && cur->type <= TYPE_STRING_MAX)
				{
				return (cur->v.string);
				}

			switch (cur->type)
				{
				case TYPE_INT:
					{
					return (itoa(cur->v.i, CurScript->tmpstr, 10));
					}

				case TYPE_UINT:
					{
					return (itoa(cur->v.ui, CurScript->tmpstr, 10));
					}

				case TYPE_LONG:
					{
					return (ltoa(cur->v.l, CurScript->tmpstr, 10));
					}

				case TYPE_ULONG:
					{
					return (ultoa(cur->v.ul, CurScript->tmpstr, 10));
					}

				case TYPE_BOOL:
					{
					return (cur->v.b ? getscrmsg(26) : getscrmsg(25));
					}
				}
			}

		return (ns);
		}
	else
		{
		return (what);
		}
	}

