#include "Script.hpp"
//===========================================================================//
// File:	 Script	.cpp													 //
// Project:  GOSScript				                                         //
// Contents: Script control													 //
//---------------------------------------------------------------------------//
// Date      Who    Modification                                             //
// 02/27/98  AG		Created													 //
//---------------------------------------------------------------------------//
// Copyright (C) 2000, Microsoft, Inc.										//
// All Rights reserved worldwide                                             //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL               //
//===========================================================================//

extern void AddVariable( VAR_SCOPE NewScope, VARIABLE* newVariable );
extern HGOSHEAP gScriptHeap[];
DWORD FindKeyWord();

BYTE ThisLine[SCRIPT_MAX_LINE_LENGTH];	// Decoded line during processing

//
// Ascii versions of the messages possible in functions
//
char* Messages[]={
"gui_init",
"gui_mailbox",
"gui_focus",
"gui_unfocus",
"gui_activate",
"gui_deactivate",
"region_entered",
"region_exited",
"lbutton_update",
"mbutton_update",
"rbutton_update",
"aux1button_update",
"aux2button_update",
"wheel_moved",
"gui_create",
"gui_execute",
"gui_destroy",
"gui_draw",
"gui_char",
"gui_pause",
"gui_continue",
"gui_reschange"
};




DEFINE* DefineArray[256];
DWORD NumberDefines=0;
//
// Init the fast define lookup table.
//
void InitDefines()
{
//
// Check that our keywords and routines match their enums
//
	gosASSERT( LAST_MESSAGE==(sizeof(Messages)/4) );
	memset( DefineArray, 0, sizeof(DefineArray) );
	NumberDefines=0;
}

//
// Clean up the fast define loopup table
//
void DestroyDefines()
{
	for( int t0=0; t0<256; t0++ )
	{
		DEFINE* pThis=DefineArray[t0];
		while( pThis )
		{
			DEFINE* pTemp=pThis->pNext;
			gos_Free( pThis );
			pThis=pTemp;
		}
		DefineArray[t0]=0;
	}
	NumberDefines=0;
}


DWORD DefineHash;
DWORD DefineIndex;
//
// Return pointer to define structure if one exists (or NULL)
//
// Source is moved past the define when it's not found
// Source remains unchanged when it is found
//
DEFINE* DefineExist( BYTE* &Source )
{
	DefineHash=*Source;
	DWORD Length=1;
	while( DefineChar[*(Source+Length)]==1 )
	{
		DefineHash=(DefineHash<<3)+*(Source+Length);					// Generate hash of keyword
		Length++;
	}
	DefineIndex=((DefineHash&31)<<3)+(Length&7);						// Make into index in #define table

	DEFINE* pThis=DefineArray[DefineIndex];

	while( pThis && (pThis->Hash!=DefineHash || !Equals(Source, pThis->Strings)) )
	{
		pThis=pThis->pNext;
	}

	if( pThis )
	{
		return pThis;
	}

	Source+=Length;

	return 0;
}









//
// Open a script for processing (either a new script, or an #include file)
//
void OpenScript( char* FileName )
{
	// Am I already reading a script? (ie: #include)
	if( pProcessScripts )
	{
		pProcessScripts->pFileName=pFileName;
		pProcessScripts->pLongFileName=pLongFileName;
		pProcessScripts->Line=CurrentLineNumber;
		pProcessScripts->Offset=pStartofLine;
	}

	// i just want the filename, not the whole path!
	// Add this file name to list of scripts valid files

	char * placeholder = FileName+strlen(FileName);
	while (placeholder != FileName)
	{
		if (*placeholder == '\\') 
		{
			placeholder++;
			break;
		}
		placeholder--;
	}

	// Is this a recursive include?
	PROCESS_SCRIPT* pTemp=pProcessScripts;	
	while( pTemp )
	{
		if( 0==strcmp( placeholder, pTemp->pFileName ) )
			ScriptError("Recursive #include of \"%s\"", placeholder);
		pTemp=pTemp->pParent;
	}

	FILENAME* pFile = (FILENAME*)gos_Malloc(sizeof(FILENAME)+strlen(placeholder)+strlen(FileName)+2, gScriptHeap[0] );
	memcpy( pFile->FileName, placeholder, strlen(placeholder)+1 );
	memcpy( &pFile->FileName[strlen(placeholder)+2], FileName, strlen(FileName)+1 );
	pFile->LongFileName=&pFile->FileName[strlen(placeholder)+2];
	pFile->pNext=pScript->pFileNames;						// Add to chain
	pScript->pFileNames=pFile;
//
// Create a new PROCESS_SCRIPT structure
//
	PROCESS_SCRIPT*	pNewScript = (PROCESS_SCRIPT*)gos_Malloc(sizeof(PROCESS_SCRIPT),gScriptHeap[0]);
	memset( pNewScript, 0 , sizeof(PROCESS_SCRIPT) );
//
// Read in the file
//
	gos_PushCurrentHeap(gScriptHeap[3]);
	DWORD Length;
	gos_GetFile( FileName, (BYTE**)&pNewScript->pStart, &Length );
	gos_PopCurrentHeap();
	pNewScript->pEnd=pNewScript->pStart+Length;
//
// Setup to parse script
//
	CurrentLineNumber=0;
	pFileName=pFile->FileName;
	pLongFileName=pFile->LongFileName;
	pStartofLine=pNewScript->pStart;
	pNewScript->pParent=pProcessScripts;
	pProcessScripts=pNewScript;					// Add this process script to the chain
//
// Clear any cache addresses
//
	memset( KeywordCache, 0, sizeof(KeywordCache) );
}



//
// Closes a script and frees all the memory allocated
//
void CloseScript()
{
//
// Release script buffer
//
	gos_Free( pProcessScripts->pStart );
//
// Remove the process scrip structure
//
	gos_Free( pProcessScripts );
	pProcessScripts=0;
}









//
//
// Get the next line, Expand the next line into Line, move StartofLine pointer to next
//
//
char* ReadLine()
{
	char chr;
	BYTE* Dest = ThisLine;
	BYTE* Source = (BYTE*)pStartofLine;
	BYTE* EndFile = (BYTE*)pProcessScripts->pEnd;

	do
	{
		if( Source >= EndFile )
			return 0;

		CurrentLineNumber++;
		
		while( *Source==32 || *Source==9 )											// Skip all leading spaces
			Source++;
		
		while( (Source < EndFile) && *Source!=0xd )
		{
			chr = *Source;

			if( chr==34 )															// Quotes?
			{
				*Dest++ = *Source++;
				while( *Source!=34 )
				{
					if( Source<EndFile && *Source==0xd )							// End line while quotes still open?
		 				ScriptError("Missing quote.\n" );
					*Dest++=*Source++;
				}
				*Dest++ = *Source++;
			}
			else
			{
				if( chr=='/' && (*(Source+1)=='/') )
				{
					while( Source+1<EndFile && *(Source+1)!=0xd )					// Skip line until end of comment
						Source++;
				}
				else
				{
					if( chr==9 || chr==32 )
					{
						*Dest++=' ';							// tabs and spaces both 'whitespace'
						while( *(Source+1)==32 || *(Source+1)==9 )
							Source++;
					}
					else
					{
						if( chr>='A' && chr<=('Z') )
							chr+=32;							// Make all non-quoted text lower case
						*Dest++ = chr;
					}
				}
				Source++;
			}
		}

		if( Dest!=ThisLine && *(Dest-1)==32 )
			*--Dest=0xd;										// Remove any extra spaces at the end of line
			
		if( Source<EndFile && *Source==0xd )
		{
			Source++;
			if( Source<EndFile && *Source==0xa )				// Skip any linefeeds
				Source++;
		}
	}
	while ( Dest == ThisLine );									// Ignore blank lines

	*Dest = 0;
	pStartofLine = (char*)Source;

	return (char*)ThisLine;
}



//
//
// Get the next line, Expand any defines
//
//
char* ExpandDefinesOnLine()
{
	static BYTE ExpandedLine[SCRIPT_MAX_LINE_LENGTH];

	if( !ReadLine())
		return 0;

	if( 0==NumberDefines )									// If there are no defines yet, return
		return (char*)ThisLine;
	
	BYTE* Source = ThisLine;
	BYTE* LastSource = ThisLine;
	BYTE* LastDest = ExpandedLine;
	bool Found = FALSE;										// Some defines were replaced (otherwise don't copy line)

	if( *Source=='#' )
	{
		if( Equals( Source+1, "ifdef " ) ||					// Do not replace 'ifdef' values
			Equals( Source+1, "ifndef " ) )
		{
			return (char*)ThisLine;							// Otherwise no coping occurs
		}
		if( Equals( Source+1, "define " ) ) 				// Do not replace 'define name'
		{
			Source += 8;
			while( *Source!=' ' && *Source!=0 )
				Source++;
		}
	}

	while( *Source!=0 )
	{
		while( FirstKeywordChar[*Source]==0 && *Source!=0 )			// Search for a 'start of keyword' character
		{
			Source++;
			if( *Source=='"' )
			{
				Source++;											// Do not allow defines to effect strings in quotes
				while( *Source!='"' && *Source!=0 )
					Source++;
			}
		}

		if( *Source )
		{
			DEFINE* pThis=DefineExist( Source );

			if( pThis )
			{
				Found=TRUE;
				memcpy( LastDest, LastSource, Source-LastSource );
				memcpy( LastDest+(Source-LastSource), &pThis->Strings[pThis->DefineLength+1], pThis->TextLength );
				LastDest+=(Source-LastSource)+pThis->TextLength;		// Replace 'keyword' with define
				Source+=pThis->DefineLength;
				LastSource+=(Source-LastSource);
			}
		}
	}

	if( Found )
	{
		memcpy( LastDest, LastSource, (Source-LastSource)+1 );		// If keywords have been replaced, return expanded line
		return (char*)ExpandedLine;
	}
	else
		return (char*)ThisLine;										// Otherwise no copying occurs
}




//
//
// Read the next line, deal with preprocessor keywords
//
//
char* ProcessNextLine()
{
	while(1)
	{
//
// Have we reach the end of the file?
//
		pLine=ExpandDefinesOnLine();
		if( !pLine )
		{
			if( pProcessScripts->pParent )
			{
				PROCESS_SCRIPT* Parent=pProcessScripts->pParent;	// Within an include, go back to parent
				gos_Free( pProcessScripts->pStart );
				gos_Free( pProcessScripts );						// Remove PROCESS_SCRIPT structure

				pProcessScripts=Parent;								// Return to parent script
				CurrentLineNumber=pProcessScripts->Line;
				pFileName=pProcessScripts->pFileName;
				pLongFileName=pProcessScripts->pLongFileName;
				pStartofLine=pProcessScripts->Offset;
				continue;
			}
			if( IFState!=IFNormal )					// Check if in a conditional
			{
				CurrentLineNumber=FirstIFLine;
			 	ScriptError("No matching '#endif'" );
			}
			return 0;
		}
//
//		SPEW(( 0, "Line #%d File '%s' : %s",CurrentLineNumber,pFileName,pLine));
//
// All pre-processor defines start with #
//
		if( *pLine!='#' )
		{
			if( IFState > IFDo2Endif )
				continue;									// Ignore lines if skipping inside an '#IF'
			return pLine;
		}
//
// #if x		<- Stop decoding lines if x is 0
//
		if( Equals( pLine, "#if " ) )
		{
			if( IFState > IFDo2Endif )
			{
				IFStack[IFNesting++]=IFState;
				IFState=IFIgnore2Endif;
				continue;
			}
			IFStack[IFNesting++]=IFState;
			pLine += 4;
			FirstIFLine=CurrentLineNumber;			// Save line number, in case we don't have an endif
			if( GetExpression()!=0 )
				IFState=IFDo2Else;
			else
				IFState=IFSkip2Else;
			continue;
		}
//
// #ifdef x
//
		else if( Equals( pLine, "#ifdef " ) )
		{
			if( IFState > IFDo2Endif )
			{
				IFStack[IFNesting++]=IFState;
				IFState=IFIgnore2Endif;
				continue;
			}
			IFStack[IFNesting++]=IFState;
			pLine += 7;
			FirstIFLine=CurrentLineNumber;			// Save line number, in case we don't have an endif

			if( FirstKeywordChar[ *pLine ]==0 )
				ScriptError( "Expected a define name" );

			BYTE* Source=(BYTE*)pLine;
			DEFINE* pThis=DefineExist( Source );

			IFState=pThis ? IFDo2Else : IFSkip2Else;
						
			continue;
		}
//
// #ifndef x
//
		else if( Equals( pLine, "#ifndef " ) )
		{
			if( IFState > IFDo2Endif )
			{
				IFStack[IFNesting++]=IFState;
				IFState=IFIgnore2Endif;
				continue;
			}
			IFStack[IFNesting++]=IFState;
			pLine += 8;
			FirstIFLine=CurrentLineNumber;			// Save line number, in case we don't have an endif

			if( FirstKeywordChar[ *pLine ]==0 )
				ScriptError( "Expected a define name" );

			BYTE* Source=(BYTE*)pLine;
			DEFINE* pThis=DefineExist( Source );

			IFState=pThis ? IFSkip2Else : IFDo2Else;

			continue;
		}
//
// #else
//
		else if( Equals( pLine, "#else" ) )
		{
			if( IFState==IFIgnore2Endif )
				continue;
			if( IFState==IFNormal )
			 	ScriptError("Not in an '#if'" );
			if( IFState==IFDo2Else )
			{
				IFState=IFSkip2Endif;
				continue;
			}
			if( IFState==IFDo2Endif || IFState==IFSkip2Endif )
			 	ScriptError("Already done '#else'" );
			if( IFState==IFSkip2Else )
			{
				IFState=IFDo2Endif;
				continue;
			}
		}
//
// #endif
//
		else if( Equals( pLine, "#endif" ) )
		{
			if( IFNesting )
			{
				IFNesting--;							// One less level of nesting
				IFState=IFStack[IFNesting];
				continue;
			}
			if( IFState==IFNormal )
			 	ScriptError("Not in an '#if'" );
			IFState=IFNormal;
			continue;
		}
//
// Check if inside an IF statement
//
		if( IFState > IFDo2Endif )
			continue;									// Ignore lines if skipping inside an '#IF'
//
// #include file
//
		else if( Equals( pLine, "#include " ) )
		{
			pLine += 9;
			char* FileName=GetSimpleString();			// Add to list of 'pProcessScripts'
			if (!FileName)
				ScriptError("Couldn't resolve #include statement");
			OpenScript(	FileName );
			continue;
		}
//
// #define x y
//
		else if( Equals( pLine, "#define " ) )
		{
			pLine += 8;

			if( FirstKeywordChar[ *pLine ]==0 )
				ScriptError( "Expected a define name" );

			BYTE* Source=(BYTE*)pLine;
			DEFINE* pThis=DefineExist( Source );
//
// Define already exists, make sure the redefinition is the same
//
			if( pThis )
			{
				Source+=pThis->DefineLength+1;
				if( !Equals( Source, &pThis->Strings[pThis->DefineLength+1] ) )
				{
					ScriptError( "#define \"%s\" redefined from \"%s\" to \"%s\"",pThis->Strings, &pThis->Strings[pThis->DefineLength+1], Source );
				}
				continue;
			}
//
// Define did not exist - add it to the lookup table
//
			if( *Source!=' ' )
				ScriptError( "Bad define" );

			NumberDefines++;

			DWORD NameLength=Source-(BYTE*)pLine;

			Source++;

			DWORD TextLength=strlen((char*)Source);

			DEFINE* NewDefine=(DEFINE*)gos_Malloc(sizeof(DEFINE)+NameLength+TextLength+2, gScriptHeap[0] );
			
			memcpy( &NewDefine->Strings[0], pLine, NameLength );
			memcpy( &NewDefine->Strings[NameLength+1], Source, TextLength );
			
			NewDefine->Strings[NameLength]=0;
			NewDefine->Strings[NameLength+TextLength+1]=0;			// Build a 'NewDefine' variable0

			NewDefine->DefineLength = (BYTE)NameLength;
			NewDefine->TextLength = (BYTE)TextLength;

			NewDefine->Hash=DefineHash;

			NewDefine->pNext=DefineArray[DefineIndex];

			DefineArray[DefineIndex]=NewDefine;
			continue;
		}
		else
			return pLine;
	}
}






//
// Gets the next line of the currently executing script (or 0 if reached end)
//
char* GetNextLine()
{
	LINEINFO* pLineInfo=(LINEINFO*)pStartofLine;
	CurrentLineNumber=pLineInfo->LineNumber;

	if( CurrentLineNumber<0xfffe )
	{
		pLongFileName=pFileName=pLineInfo->FileName;
		pLine=(char*)pLineInfo->Line;
		WORD LineLength=pLineInfo->LineLength;
		CurrentKeyword=(DWORD)pLineInfo->Keyword;
		pCurrentKeyword=&pLineInfo->Keyword;
		pCurrentLineFlags=&pLineInfo->LineFlags;
		pStartofLine=pLine+LineLength;						// Move start of line onto next line
		return pLine;
	}
	else if( CurrentLineNumber==0xfffe )					// Found next block?
	{
		pStartofLine=pLineInfo->FileName;
		return GetNextLine();
	}
	return 0;
}

SCRIPTSTACK	ScriptStack[MAX_MAILSTACK];
int ScriptSP=0;

//
// Save the current script execution position
//
void SavePosition()
{
	if( ScriptSP==MAX_MAILSTACK-1 )
		ScriptError( "Stack nesting too deep " );

	ScriptStack[ScriptSP].CurrentLineNumber=CurrentLineNumber;
	ScriptStack[ScriptSP].pStartofLine=pStartofLine;
	ScriptStack[ScriptSP].pFileName=pFileName;
	ScriptStack[ScriptSP].pLongFileName=pLongFileName;
	ScriptStack[ScriptSP].pLine=pLine;
	ScriptStack[ScriptSP].pScript=pScript;
	ScriptStack[ScriptSP].pObject=pObject;
	ScriptStack[ScriptSP].pLastVariable=(int*)pLastVariable;
	ScriptStack[ScriptSP].pTempVariables=pTempVariables;
	ScriptStack[ScriptSP].CurrentMessage=CurrentMessage;
	ScriptStack[ScriptSP].LastVariableScope=LastVariableScope;

	ScriptSP++;
}


//
// Restore a previous script execution position
//
void RestorePosition()
{
	ScriptSP--;

	CurrentLineNumber=ScriptStack[ScriptSP].CurrentLineNumber;
	pStartofLine=ScriptStack[ScriptSP].pStartofLine;
	pFileName=ScriptStack[ScriptSP].pFileName;
	pLongFileName=ScriptStack[ScriptSP].pLongFileName;
	pLine=ScriptStack[ScriptSP].pLine;
	pScript=ScriptStack[ScriptSP].pScript;
	pObject=ScriptStack[ScriptSP].pObject;
	pLastVariable=(long *) ScriptStack[ScriptSP].pLastVariable;
	pTempVariables=ScriptStack[ScriptSP].pTempVariables;
	CurrentMessage=ScriptStack[ScriptSP].CurrentMessage;
	LastVariableScope=ScriptStack[ScriptSP].LastVariableScope;
}




//
// Returns the keyword on the next line (used to check if an 'else' is next, or an 'if' is finished
//
int PeekNextLine()
{
	DWORD temp=CurrentKeyword;
	
	SavePosition();

	int Keyword=0;

	if( GetNextLine() )
		Keyword=CurrentKeyword;				// Find keyword and reset pointer

	RestorePosition();

	CurrentKeyword=temp;

	return Keyword;
}






//
//
// Process a script
//
//
SCRIPT* ProcessScript( char* FileName, int Priority, void * instance )
{
//
// Reserve memory for new script
//
	SCRIPT*	pTemp = (SCRIPT*)gos_Malloc(sizeof(SCRIPT), gScriptHeap[0] );

	memset( pTemp, 0 , sizeof(SCRIPT) );			// Clear all variables
	pTemp->Instance = (int) instance;

	pTemp->pNext=pListofScripts;
	pListofScripts=pTemp;							// Add script to others loaded

	FUNCTION* pMainFunc=0;							// Points at the main function
	SCRIPT * pTemp2 = pScript;
	pScript=pTemp;									// Make this the current script
	pFileName = FileName;
	pLongFileName = FileName;
	char tmpName[260];
	strcpy(tmpName, FileName);
//
// Init #define array
//
	InitDefines();
//
// Open the script file
//
	OpenScript( tmpName );
//
// Create buffer to read file into
//
	pScript->pBuffer=(char*)gos_Malloc(SizeOfProcessBlock+4, gScriptHeap[0] );
	char* pDest=pScript->pBuffer;
	char* pBase=pDest;
	*((DWORD*)(pDest+SizeOfProcessBlock))=0;							// Pointer to any 'next block'
//
// Parse each line, store in compressed form in new buffer
//
	CurrentLineNumber=0;

	while(1)
	{
		pLine=ProcessNextLine();						// Get next line

		LINEINFO* pLineInfo=(LINEINFO*)pDest;

		if( pLine )
		{
			DWORD KeyWord=FindKeyWord();
			
			DWORD Length=strlen(pLine)+1;				// 8 byte header, line length + zero
			
			Length+=(4-((Length+sizeof(LINEINFO))&3))&3;

			if( pDest+Length+sizeof(LINEINFO)-pBase > SizeOfProcessBlock-sizeof(LINEINFO) )
			{
				pDest=(char*)gos_Malloc(SizeOfProcessBlock+4, gScriptHeap[0] );
				pLineInfo->LineNumber=0xfffe;										// Line Number -2 = End of Block marker
				pLineInfo->FileName=pDest;
				*((DWORD*)(pBase+SizeOfProcessBlock))=(DWORD)pDest;					// Pointer to the 'next block'
				*((DWORD*)(pDest+SizeOfProcessBlock))=0;							// Pointer to any 'next block'
				pBase=pDest;
				pLineInfo=(LINEINFO*)pDest;
			}
		
			memcpy( pLineInfo->Line, pLine, Length );
			pDest+=Length+sizeof(LINEINFO);

			pLineInfo->LineNumber=(WORD)CurrentLineNumber;
			pLineInfo->FileName=pLongFileName;				// Save original line number and file name
			pLineInfo->LineLength=(WORD)Length;
			pLineInfo->LineFlags=0;
			pLineInfo->Keyword=(BYTE)KeyWord;
		}
		else
		{
			pLineInfo->LineNumber=0xffff;				// Line Number -1 = End of File marker
			break;
		}
	}
//
// Close the script file
//
	CloseScript();
//
// Clean up #defines
//
	DestroyDefines();
//
// Setup to start reading from the begining of the file
//
	pStartofLine=pScript->pBuffer;
//
// Now find all FUNCTION and MESSAGE entry points in script
//
	while( GetNextLine() )			// Find first function
	{
		int Length=0;
		char* FunctionName=pLine;
		FUNCTION* pFunc;

		if( 0==KeywordChar[*(BYTE*)pLine] )
			ScriptError( "Invalid object name" );
		
		// Must be a Object Name - find it's length
		while( KeywordChar[*(BYTE*)pLine] )
		{
			pLine++;
			Length++;
		}

		// Check for duplicate objects
		pFunc=pScript->pFunctions;
		while( pFunc )
		{
			if( 0==strcmp( pFunc->Name, FunctionName ) )
				ScriptError("Duplicated Function '%s'",FunctionName );
			pFunc=pFunc->pNext;
		}

		// Create a OBJECT structure
		pFunc=(FUNCTION*)gos_Malloc(sizeof(FUNCTION)+Length, gScriptHeap[0] );

		// Add the object name
		memcpy( pFunc->Name, FunctionName, Length );
	
		// Init all the objects fields
		pFunc->NameLength=Length;
		pFunc->Name[Length]=0;
		pFunc->pMessages=0;

		// Chain it to the other objects in the script
		pFunc->pNext=pScript->pFunctions;
		pScript->pFunctions=pFunc;

		// Look for 'main' function
		if( 0==pMainFunc && 4==Length && *(DWORD*)FunctionName=='niam' )
			pMainFunc=pFunc;
		//
		// Look for message entry points
		//
		int NestingLevel=0;

		while( GetNextLine() )
		{
			if( *pLine=='{' )
			{
				pLine++;
				NestingLevel++;
				continue;									// Deal with multiple commands within {}
			}
			if( *pLine=='}' )
			{
				pLine++;
				NestingLevel--;
				if( NestingLevel<0 )
					ScriptError("Unexpected }" );
				if(	NestingLevel==0 )	
					break;									// Found end of function	
				continue;
			}

			if( NestingLevel>1 )							// Ignore commands in message
				continue;

			if( NestingLevel==0 )							// Don't allow commands after function name
				ScriptError("Expecting function body" );

			// Must be a message name - find it's length
			unsigned int Length=0;
			char* MessageName=pLine;
			while( KeywordChar[*(BYTE*)pLine] )
			{
				pLine++;
				Length++;
			}

			// Check if a valid message
			int Found=0,MessageNum;
			for( MessageNum=0;MessageNum<sizeof(Messages)/sizeof(char*);MessageNum++)
			{
				if( Length==strlen(Messages[MessageNum]) && Equals(MessageName, Messages[MessageNum]) )
				{
					Found=1;
					break;
				}
			}
			if( !Found )
				ScriptError("Expected a message, found '%s'",MessageName );

			// Check for duplicate Messages
			MESSAGE* pMessage=pFunc->pMessages;
			while( pMessage )
			{
				if( pMessage->Message==MessageNum )
					ScriptError("Duplicated Message '%s'",Messages[MessageNum] );
				pMessage=pMessage->pNext;
			}

			// Create a Message
			pMessage =(MESSAGE*)gos_Malloc(sizeof(MESSAGE), gScriptHeap[0] );

			// Message Details
			pMessage->Message=(MESSAGES)MessageNum;
			pMessage->pOffset=(LINEINFO*)pStartofLine;

			// Chain it to list of message within function
			pMessage->pNext=pFunc->pMessages;
			pFunc->pMessages=pMessage;			
		}
		if( NestingLevel )
			ScriptError("Unexpected end of file found" );
	}

	//
	// Check for a "main" object within a script file. This is not
	// necessary for all scripts, just scripts that are gosScript_Exec'd
	// or "script_run"'d directly.
	//
	if( 0==pMainFunc )
		ScriptError( "No main function found in script %s",FileName );

	//
	// This loop takes the original filename for the script and strips
	// off the path and the dot-extension. The end result is then
	// sandwhiched between two '@' symbols and isused as the object name 
	// of the "main" object
	//
	char FileNameOrig[256];
	strcpy(FileNameOrig, tmpName);
	int i = 0;
	while (FileNameOrig[i] != '\0' && FileNameOrig[i] != '.') i++;
	char tmp[128];
	memcpy(tmp,FileNameOrig,i);
	tmp[i] = 0;
	char * FileNoPath = tmp + i-1;
	while (*FileNoPath && tmp != FileNoPath)
	{
		FileNoPath--;
		if (*FileNoPath == '\\')
		{
			FileNoPath++;
			break;
		}
	}

//
// Create an object for 'main'
//
	pScript->pMainObject=(OBJECT*)gos_Malloc(sizeof(OBJECT)+strlen(tmp)+1, gScriptHeap[3] );
	pObject = pScript->pMainObject;
	strcpy(pScript->pMainObject->Name,"@");
	strcat(pScript->pMainObject->Name,FileNoPath);
	strcat(pScript->pMainObject->Name,"@");

	char* pName=pScript->pMainObject->Name;
	while( *pName )
	{
		if( *pName>='A' && *pName<=(char)'Z' )
			*pName+=32;
		pName++;
	}

	pScript->pMainObject->NameLength=strlen(FileNoPath)+2;

	pScript->pMainObject->pNext=0;
	pScript->pMainObject->pScript=pScript;
	pScript->pMainObject->bActive = true;

	pScript->pMainObject->bInFocus = false;
	pScript->pMainObject->LastRan = (float) gos_GetElapsedTime(1);
	pScript->pMainObject->AlwaysInRegion = false;
	pScript->pMainObject->bMouseInRegion = false;
	pScript->pMainObject->bAddToDeathRow = false;
	pScript->pMainObject->pFunction=pMainFunc;
	pScript->pMainObject->pVariables=0;
	pScript->pMainObject->pParentVariable=0;
	pScript->pMainObject->pParentObject=0;
	pScript->pMainObject->bPosRelative=false;
	pScript->pMainObject->dwBlockingFlags=0;
	pScript->pMainObject->dwAvailIME = 0;
	pScript->pMainObject->dwIMEState = 0;

	pScript->pListofObjects=pScript->pMainObject;					// Treat main object like any other

	CreateDefaultMemberVariables(pScript->pMainObject, Priority);
//
// Now send a GUI_CREATE to the scripts MAIN function
//
	SendScriptMessage( pScript->pMainObject, MSG_GUI_CREATE );		// Start script executing at main

	if (pTemp2 != NULL)
		pScript = pTemp2;
	return pTemp;
}


