aboutsummaryrefslogtreecommitdiff
path: root/mp/src/utils/common/scriplib.cpp
diff options
context:
space:
mode:
authorJoe Ludwig <[email protected]>2013-06-26 15:22:04 -0700
committerJoe Ludwig <[email protected]>2013-06-26 15:22:04 -0700
commit39ed87570bdb2f86969d4be821c94b722dc71179 (patch)
treeabc53757f75f40c80278e87650ea92808274aa59 /mp/src/utils/common/scriplib.cpp
downloadsource-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.tar.xz
source-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.zip
First version of the SOurce SDK 2013
Diffstat (limited to 'mp/src/utils/common/scriplib.cpp')
-rw-r--r--mp/src/utils/common/scriplib.cpp1349
1 files changed, 1349 insertions, 0 deletions
diff --git a/mp/src/utils/common/scriplib.cpp b/mp/src/utils/common/scriplib.cpp
new file mode 100644
index 00000000..469c7885
--- /dev/null
+++ b/mp/src/utils/common/scriplib.cpp
@@ -0,0 +1,1349 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//===========================================================================//
+
+// scriplib.c
+
+#include "tier1/strtools.h"
+#include "tier2/tier2.h"
+#include "cmdlib.h"
+#include "scriplib.h"
+#if defined( _X360 )
+#include "xbox\xbox_win32stubs.h"
+#endif
+#if defined(POSIX)
+#include "../../filesystem/linux_support.h"
+#include <sys/stat.h>
+#endif
+/*
+=============================================================================
+
+ PARSING STUFF
+
+=============================================================================
+*/
+
+typedef struct
+{
+ char filename[1024];
+ char *buffer,*script_p,*end_p;
+ int line;
+
+ char macrobuffer[4096];
+ char *macroparam[64];
+ char *macrovalue[64];
+ int nummacroparams;
+
+} script_t;
+
+#define MAX_INCLUDES 64
+script_t scriptstack[MAX_INCLUDES];
+script_t *script = NULL;
+int scriptline;
+
+char token[MAXTOKEN];
+qboolean endofscript;
+qboolean tokenready; // only true if UnGetToken was just called
+
+typedef struct
+{
+ char *param;
+ char *value;
+} variable_t;
+
+CUtlVector<variable_t> g_definevariable;
+
+/*
+Callback stuff
+*/
+
+void DefaultScriptLoadedCallback( char const *pFilenameLoaded, char const *pIncludedFromFileName, int nIncludeLineNumber )
+{
+ NULL;
+}
+
+SCRIPT_LOADED_CALLBACK g_pfnCallback = DefaultScriptLoadedCallback;
+
+SCRIPT_LOADED_CALLBACK SetScriptLoadedCallback( SCRIPT_LOADED_CALLBACK pfnNewScriptLoadedCallback )
+{
+ SCRIPT_LOADED_CALLBACK pfnCallback = g_pfnCallback;
+ g_pfnCallback = pfnNewScriptLoadedCallback;
+ return pfnCallback;
+}
+
+/*
+==============
+AddScriptToStack
+==============
+*/
+void AddScriptToStack (char *filename, ScriptPathMode_t pathMode = SCRIPT_USE_ABSOLUTE_PATH)
+{
+ int size;
+
+ script++;
+ if (script == &scriptstack[MAX_INCLUDES])
+ Error ("script file exceeded MAX_INCLUDES");
+
+ if ( pathMode == SCRIPT_USE_RELATIVE_PATH )
+ Q_strncpy( script->filename, filename, sizeof( script->filename ) );
+ else
+ Q_strncpy (script->filename, ExpandPath (filename), sizeof( script->filename ) );
+
+ size = LoadFile (script->filename, (void **)&script->buffer);
+
+ // printf ("entering %s\n", script->filename);
+ if ( g_pfnCallback )
+ {
+ if ( script == scriptstack + 1 )
+ g_pfnCallback( script->filename, NULL, 0 );
+ else
+ g_pfnCallback( script->filename, script[-1].filename, script[-1].line );
+ }
+
+ script->line = 1;
+
+ script->script_p = script->buffer;
+ script->end_p = script->buffer + size;
+}
+
+
+/*
+==============
+LoadScriptFile
+==============
+*/
+void LoadScriptFile (char *filename, ScriptPathMode_t pathMode)
+{
+ script = scriptstack;
+ AddScriptToStack (filename, pathMode);
+
+ endofscript = false;
+ tokenready = false;
+}
+
+
+/*
+==============
+==============
+*/
+
+script_t *macrolist[256];
+int nummacros;
+
+void DefineMacro( char *macroname )
+{
+ script_t *pmacro = (script_t *)malloc( sizeof( script_t ) );
+
+ strcpy( pmacro->filename, macroname );
+ pmacro->line = script->line;
+ pmacro->nummacroparams = 0;
+
+ char *mp = pmacro->macrobuffer;
+ char *cp = script->script_p;
+
+ while (TokenAvailable( ))
+ {
+ GetToken( false );
+
+ if (token[0] == '\\' && token[1] == '\\')
+ {
+ break;
+ }
+ cp = script->script_p;
+
+ pmacro->macroparam[pmacro->nummacroparams++] = mp;
+
+ strcpy( mp, token );
+ mp += strlen( token ) + 1;
+
+ if (mp >= pmacro->macrobuffer + sizeof( pmacro->macrobuffer ))
+ Error("Macro buffer overflow\n");
+ }
+ // roll back script_p to previous valid location
+ script->script_p = cp;
+
+ // find end of macro def
+ while (*cp && *cp != '\n')
+ {
+ //Msg("%d ", *cp );
+ if (*cp == '\\' && *(cp+1) == '\\')
+ {
+ // skip till end of line
+ while (*cp && *cp != '\n')
+ {
+ *cp = ' '; // replace with spaces
+ cp++;
+ }
+
+ if (*cp)
+ {
+ cp++;
+ }
+ }
+ else
+ {
+ cp++;
+ }
+ }
+
+ int size = (cp - script->script_p);
+
+ pmacro->buffer = (char *)malloc( size + 1);
+ memcpy( pmacro->buffer, script->script_p, size );
+ pmacro->buffer[size] = '\0';
+ pmacro->end_p = &pmacro->buffer[size];
+
+ macrolist[nummacros++] = pmacro;
+
+ script->script_p = cp;
+}
+
+
+void DefineVariable( char *variablename )
+{
+ variable_t v;
+
+ v.param = strdup( variablename );
+
+ GetToken( false );
+
+ v.value = strdup( token );
+
+ g_definevariable.AddToTail( v );
+}
+
+
+
+/*
+==============
+==============
+*/
+bool AddMacroToStack( char *macroname )
+{
+ // lookup macro
+ if (macroname[0] != '$')
+ return false;
+
+ int i;
+ for (i = 0; i < nummacros; i++)
+ {
+ if (strcmpi( macrolist[i]->filename, &macroname[1] ) == 0)
+ {
+ break;
+ }
+ }
+ if (i == nummacros)
+ return false;
+
+ script_t *pmacro = macrolist[i];
+
+ // get tokens
+ script_t *pnext = script + 1;
+
+ pnext++;
+ if (pnext == &scriptstack[MAX_INCLUDES])
+ Error ("script file exceeded MAX_INCLUDES");
+
+ // get tokens
+ char *cp = pnext->macrobuffer;
+
+ pnext->nummacroparams = pmacro->nummacroparams;
+
+ for (i = 0; i < pnext->nummacroparams; i++)
+ {
+ GetToken(false);
+
+ strcpy( cp, token );
+ pnext->macroparam[i] = pmacro->macroparam[i];
+ pnext->macrovalue[i] = cp;
+
+ cp += strlen( token ) + 1;
+
+ if (cp >= pnext->macrobuffer + sizeof( pnext->macrobuffer ))
+ Error("Macro buffer overflow\n");
+ }
+
+ script = pnext;
+ strcpy( script->filename, pmacro->filename );
+
+ int size = pmacro->end_p - pmacro->buffer;
+ script->buffer = (char *)malloc( size + 1 );
+ memcpy( script->buffer, pmacro->buffer, size );
+ pmacro->buffer[size] = '\0';
+ script->script_p = script->buffer;
+ script->end_p = script->buffer + size;
+ script->line = pmacro->line;
+
+ return true;
+}
+
+
+
+bool ExpandMacroToken( char *&token_p )
+{
+ if ( script->nummacroparams && *script->script_p == '$' )
+ {
+ char *cp = script->script_p + 1;
+
+ while ( *cp > 32 && *cp != '$' )
+ {
+ cp++;
+ }
+
+ // found a word with $'s on either end?
+ if (*cp != '$')
+ return false;
+
+ // get token pointer
+ char *tp = script->script_p + 1;
+ int len = (cp - tp);
+ *(tp + len) = '\0';
+
+ // lookup macro parameter
+ int index = 0;
+ for (index = 0; index < script->nummacroparams; index++)
+ {
+ if (stricmp( script->macroparam[index], tp ) == 0)
+ break;
+ }
+ if (index >= script->nummacroparams)
+ {
+ Error("unknown macro token \"%s\" in %s\n", tp, script->filename );
+ }
+
+ // paste token into
+ len = strlen( script->macrovalue[index] );
+ strcpy( token_p, script->macrovalue[index] );
+ token_p += len;
+
+ script->script_p = cp + 1;
+
+ if (script->script_p >= script->end_p)
+ Error ("Macro expand overflow\n");
+
+ if (token_p >= &token[MAXTOKEN])
+ Error ("Token too large on line %i\n",scriptline);
+
+ return true;
+ }
+ return false;
+}
+
+
+
+/*
+==============
+==============
+*/
+// FIXME: this should create a new script context so the individual tokens in the variable can be parsed
+bool ExpandVariableToken( char *&token_p )
+{
+ if ( *script->script_p == '$' )
+ {
+ char *cp = script->script_p + 1;
+
+ while ( *cp > 32 && *cp != '$' )
+ {
+ cp++;
+ }
+
+ // found a word with $'s on either end?
+ if (*cp != '$')
+ return false;
+
+ // get token pointer
+ char *tp = script->script_p + 1;
+ int len = (cp - tp);
+ *(tp + len) = '\0';
+
+ // lookup macro parameter
+
+ int index;
+ for (index = 0; index < g_definevariable.Count(); index++)
+ {
+ if (Q_strnicmp( g_definevariable[index].param, tp, len ) == 0)
+ break;
+ }
+
+ if (index >= g_definevariable.Count() )
+ {
+ Error("unknown variable token \"%s\" in %s\n", tp, script->filename );
+ }
+
+ // paste token into
+ len = strlen( g_definevariable[index].value );
+ strcpy( token_p, g_definevariable[index].value );
+ token_p += len;
+
+ script->script_p = cp + 1;
+
+ if (script->script_p >= script->end_p)
+ Error ("Macro expand overflow\n");
+
+ if (token_p >= &token[MAXTOKEN])
+ Error ("Token too large on line %i\n",scriptline);
+
+ return true;
+ }
+ return false;
+}
+
+
+
+/*
+==============
+ParseFromMemory
+==============
+*/
+void ParseFromMemory (char *buffer, int size)
+{
+ script = scriptstack;
+ script++;
+ if (script == &scriptstack[MAX_INCLUDES])
+ Error ("script file exceeded MAX_INCLUDES");
+ strcpy (script->filename, "memory buffer" );
+
+ script->buffer = buffer;
+ script->line = 1;
+ script->script_p = script->buffer;
+ script->end_p = script->buffer + size;
+
+ endofscript = false;
+ tokenready = false;
+}
+
+
+//-----------------------------------------------------------------------------
+// Used instead of ParseFromMemory to temporarily add a memory buffer
+// to the script stack. ParseFromMemory just blows away the stack.
+//-----------------------------------------------------------------------------
+void PushMemoryScript( char *pszBuffer, const int nSize )
+{
+ if ( script == NULL )
+ {
+ script = scriptstack;
+ }
+ script++;
+ if ( script == &scriptstack[MAX_INCLUDES] )
+ {
+ Error ( "script file exceeded MAX_INCLUDES" );
+ }
+ strcpy (script->filename, "memory buffer" );
+
+ script->buffer = pszBuffer;
+ script->line = 1;
+ script->script_p = script->buffer;
+ script->end_p = script->buffer + nSize;
+
+ endofscript = false;
+ tokenready = false;
+}
+
+
+//-----------------------------------------------------------------------------
+// Used after calling PushMemoryScript to clean up the memory buffer
+// added to the script stack. The normal end of script terminates
+// all parsing at the end of a memory buffer even if there are more scripts
+// remaining on the script stack
+//-----------------------------------------------------------------------------
+bool PopMemoryScript()
+{
+ if ( V_stricmp( script->filename, "memory buffer" ) )
+ return false;
+
+ if ( script == scriptstack )
+ {
+ endofscript = true;
+ return false;
+ }
+ script--;
+ scriptline = script->line;
+
+ endofscript = false;
+
+ return true;
+}
+
+
+/*
+==============
+UnGetToken
+
+Signals that the current token was not used, and should be reported
+for the next GetToken. Note that
+
+GetToken (true);
+UnGetToken ();
+GetToken (false);
+
+could cross a line boundary.
+==============
+*/
+void UnGetToken (void)
+{
+ tokenready = true;
+}
+
+
+qboolean EndOfScript (qboolean crossline)
+{
+ if (!crossline)
+ Error ("Line %i is incomplete\n",scriptline);
+
+ if (!strcmp (script->filename, "memory buffer"))
+ {
+ endofscript = true;
+ return false;
+ }
+
+ free (script->buffer);
+ script->buffer = NULL;
+ if (script == scriptstack+1)
+ {
+ endofscript = true;
+ return false;
+ }
+ script--;
+ scriptline = script->line;
+ // printf ("returning to %s\n", script->filename);
+ return GetToken (crossline);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Given an absolute path, do a find first find next on it and build
+// a list of files. Physical file system only
+//-----------------------------------------------------------------------------
+static void FindFileAbsoluteList( CUtlVector< CUtlString > &outAbsolutePathNames, const char *pszFindName )
+{
+ char szPath[MAX_PATH];
+ V_strncpy( szPath, pszFindName, sizeof( szPath ) );
+ V_StripFilename( szPath );
+
+ char szResult[MAX_PATH];
+ FileFindHandle_t hFile = FILESYSTEM_INVALID_FIND_HANDLE;
+
+ for ( const char *pszFoundFile = g_pFullFileSystem->FindFirst( pszFindName, &hFile ); pszFoundFile && hFile != FILESYSTEM_INVALID_FIND_HANDLE; pszFoundFile = g_pFullFileSystem->FindNext( hFile ) )
+ {
+ V_ComposeFileName( szPath, pszFoundFile, szResult, sizeof( szResult ) );
+ outAbsolutePathNames.AddToTail( szResult );
+ }
+
+ g_pFullFileSystem->FindClose( hFile );
+}
+
+
+//-----------------------------------------------------------------------------
+// Data for checking for single character tokens while parsing
+//-----------------------------------------------------------------------------
+bool g_bCheckSingleCharTokens = false;
+CUtlString g_sSingleCharTokens;
+
+
+//-----------------------------------------------------------------------------
+// Sets whether the scriplib parser will do a special check for single
+// character tokens. Returns previous state of whether single character
+// tokens will be checked.
+//-----------------------------------------------------------------------------
+bool SetCheckSingleCharTokens( bool bCheck )
+{
+ const bool bRetVal = g_bCheckSingleCharTokens;
+
+ g_bCheckSingleCharTokens = bCheck;
+
+ return bRetVal;
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets the list of single character tokens to check if SetCheckSingleCharTokens
+// is turned on.
+//-----------------------------------------------------------------------------
+CUtlString SetSingleCharTokenList( const char *pszSingleCharTokenList )
+{
+ const CUtlString sRetVal = g_sSingleCharTokens;
+
+ if ( pszSingleCharTokenList )
+ {
+ g_sSingleCharTokens = pszSingleCharTokenList;
+ }
+
+ return sRetVal;
+}
+
+
+/*
+==============
+GetToken
+==============
+*/
+qboolean GetToken (qboolean crossline)
+{
+ char *token_p;
+
+ if (tokenready) // is a token allready waiting?
+ {
+ tokenready = false;
+ return true;
+ }
+
+ // printf("script_p %x (%x)\n", script->script_p, script->end_p ); fflush( stdout );
+
+ if (script->script_p >= script->end_p)
+ {
+ return EndOfScript (crossline);
+ }
+
+ tokenready = false;
+
+ // skip space, ctrl chars
+skipspace:
+ while (*script->script_p <= 32)
+ {
+ if (script->script_p >= script->end_p)
+ {
+ return EndOfScript (crossline);
+ }
+ if (*(script->script_p++) == '\n')
+ {
+ if (!crossline)
+ {
+ Error ("Line %i is incomplete\n",scriptline);
+ }
+ scriptline = ++script->line;
+ }
+ }
+
+ if (script->script_p >= script->end_p)
+ {
+ return EndOfScript (crossline);
+ }
+
+ // strip single line comments
+ if (*script->script_p == ';' || *script->script_p == '#' || // semicolon and # is comment field
+ (*script->script_p == '/' && *((script->script_p)+1) == '/')) // also make // a comment field
+ {
+ if (!crossline)
+ Error ("Line %i is incomplete\n",scriptline);
+ while (*script->script_p++ != '\n')
+ {
+ if (script->script_p >= script->end_p)
+ {
+ return EndOfScript (crossline);
+ }
+ }
+ scriptline = ++script->line;
+ goto skipspace;
+ }
+
+ // strip out matching /* */ comments
+ if (*script->script_p == '/' && *((script->script_p)+1) == '*')
+ {
+ script->script_p += 2;
+ while (*script->script_p != '*' || *((script->script_p)+1) != '/')
+ {
+ if (*script->script_p++ != '\n')
+ {
+ if (script->script_p >= script->end_p)
+ {
+ return EndOfScript (crossline);
+ }
+
+ scriptline = ++script->line;
+ }
+ }
+ script->script_p += 2;
+ goto skipspace;
+ }
+
+ // copy token to buffer
+ token_p = token;
+
+ if (*script->script_p == '"')
+ {
+ // quoted token
+ script->script_p++;
+ while (*script->script_p != '"')
+ {
+ *token_p++ = *script->script_p++;
+ if (script->script_p == script->end_p)
+ break;
+ if (token_p == &token[MAXTOKEN])
+ Error ("Token too large on line %i\n",scriptline);
+ }
+ script->script_p++;
+ }
+ else if ( g_bCheckSingleCharTokens && !g_sSingleCharTokens.IsEmpty() && strchr( g_sSingleCharTokens.String(), *script->script_p ) != NULL )
+ {
+ *token_p++ = *script->script_p++;
+ }
+ else // regular token
+ while ( *script->script_p > 32 && *script->script_p != ';')
+ {
+ if ( !ExpandMacroToken( token_p ) )
+ {
+ if ( !ExpandVariableToken( token_p ) )
+ {
+ *token_p++ = *script->script_p++;
+ if (script->script_p == script->end_p)
+ break;
+ if (token_p == &token[MAXTOKEN])
+ Error ("Token too large on line %i\n",scriptline);
+
+ }
+ }
+ }
+
+ // add null to end of token
+ *token_p = 0;
+
+ // check for other commands
+ if ( !stricmp( token, "$include" ) )
+ {
+ GetToken( false );
+
+ bool bFallbackToToken = true;
+
+ CUtlVector< CUtlString > expandedPathList;
+
+ if ( CmdLib_ExpandWithBasePaths( expandedPathList, token ) > 0 )
+ {
+ for ( int i = 0; i < expandedPathList.Count(); ++i )
+ {
+ CUtlVector< CUtlString > findFileList;
+ FindFileAbsoluteList( findFileList, expandedPathList[i].String() );
+
+ if ( findFileList.Count() > 0 )
+ {
+ bFallbackToToken = false;
+
+ // Only add the first set of glob matches from the first base path
+ for ( int j = 0; j < findFileList.Count(); ++j )
+ {
+ AddScriptToStack( const_cast< char * >( findFileList[j].String() ) );
+ }
+
+ break;
+ }
+ }
+ }
+
+ if ( bFallbackToToken )
+ {
+ AddScriptToStack( token );
+ }
+
+ return GetToken( crossline );
+ }
+ else if (!stricmp (token, "$definemacro"))
+ {
+ GetToken (false);
+ DefineMacro(token);
+ return GetToken (crossline);
+ }
+ else if (!stricmp (token, "$definevariable"))
+ {
+ GetToken (false);
+ DefineVariable(token);
+ return GetToken (crossline);
+ }
+ else if (AddMacroToStack( token ))
+ {
+ return GetToken (crossline);
+ }
+
+ return true;
+}
+
+
+/*
+==============
+GetExprToken - use C mathematical operator parsing rules to split tokens instead of whitespace
+==============
+*/
+qboolean GetExprToken (qboolean crossline)
+{
+ char *token_p;
+
+ if (tokenready) // is a token allready waiting?
+ {
+ tokenready = false;
+ return true;
+ }
+
+ if (script->script_p >= script->end_p)
+ return EndOfScript (crossline);
+
+ tokenready = false;
+
+//
+// skip space
+//
+skipspace:
+ while (*script->script_p <= 32)
+ {
+ if (script->script_p >= script->end_p)
+ return EndOfScript (crossline);
+ if (*script->script_p++ == '\n')
+ {
+ if (!crossline)
+ Error ("Line %i is incomplete\n",scriptline);
+ scriptline = ++script->line;
+ }
+ }
+
+ if (script->script_p >= script->end_p)
+ return EndOfScript (crossline);
+
+ if (*script->script_p == ';' || *script->script_p == '#' || // semicolon and # is comment field
+ (*script->script_p == '/' && *((script->script_p)+1) == '/')) // also make // a comment field
+ {
+ if (!crossline)
+ Error ("Line %i is incomplete\n",scriptline);
+ while (*script->script_p++ != '\n')
+ if (script->script_p >= script->end_p)
+ return EndOfScript (crossline);
+ goto skipspace;
+ }
+
+//
+// copy token
+//
+ token_p = token;
+
+ if (*script->script_p == '"')
+ {
+ // quoted token
+ script->script_p++;
+ while (*script->script_p != '"')
+ {
+ *token_p++ = *script->script_p++;
+ if (script->script_p == script->end_p)
+ break;
+ if (token_p == &token[MAXTOKEN])
+ Error ("Token too large on line %i\n",scriptline);
+ }
+ script->script_p++;
+ }
+ else
+ {
+ if ( V_isalpha( *script->script_p ) || *script->script_p == '_' )
+ {
+ // regular token
+ while ( V_isalnum( *script->script_p ) || *script->script_p == '_' )
+ {
+ *token_p++ = *script->script_p++;
+ if (script->script_p == script->end_p)
+ break;
+ if (token_p == &token[MAXTOKEN])
+ Error ("Token too large on line %i\n",scriptline);
+ }
+ }
+ else if ( V_isdigit( *script->script_p ) || *script->script_p == '.' )
+ {
+ // regular token
+ while ( V_isdigit( *script->script_p ) || *script->script_p == '.' )
+ {
+ *token_p++ = *script->script_p++;
+ if (script->script_p == script->end_p)
+ break;
+ if (token_p == &token[MAXTOKEN])
+ Error ("Token too large on line %i\n",scriptline);
+ }
+ }
+ else
+ {
+ // single char
+ *token_p++ = *script->script_p++;
+ }
+ }
+
+ *token_p = 0;
+
+ if (!stricmp (token, "$include"))
+ {
+ GetToken (false);
+ AddScriptToStack (token);
+ return GetToken (crossline);
+ }
+
+ return true;
+}
+
+
+/*
+==============
+TokenAvailable
+
+Returns true if there is another token on the line
+==============
+*/
+qboolean TokenAvailable (void)
+{
+ char *search_p;
+
+ if (tokenready) // is a token allready waiting?
+ {
+ return true;
+ }
+
+ search_p = script->script_p;
+
+ if (search_p >= script->end_p)
+ return false;
+
+ while ( *search_p <= 32)
+ {
+ if (*search_p == '\n')
+ return false;
+ search_p++;
+ if (search_p == script->end_p)
+ return false;
+
+ }
+
+ if (*search_p == ';' || *search_p == '#' || // semicolon and # is comment field
+ (*search_p == '/' && *((search_p)+1) == '/')) // also make // a comment field
+ return false;
+
+ return true;
+}
+
+qboolean GetTokenizerStatus( char **pFilename, int *pLine )
+{
+ // is this the default state?
+ if (!script)
+ return false;
+
+ if (script->script_p >= script->end_p)
+ return false;
+
+ if (pFilename)
+ {
+ *pFilename = script->filename;
+ }
+ if (pLine)
+ {
+ *pLine = script->line;
+ }
+ return true;
+}
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef WIN32
+#include <direct.h>
+#include <io.h>
+#include <sys/utime.h>
+#endif
+#include <time.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include "tier1/utlbuffer.h"
+
+class CScriptLib : public IScriptLib
+{
+public:
+ virtual bool ReadFileToBuffer( const char *pSourceName, CUtlBuffer &buffer, bool bText = false, bool bNoOpenFailureWarning = false );
+ virtual bool WriteBufferToFile( const char *pTargetName, CUtlBuffer &buffer, DiskWriteMode_t writeMode );
+ virtual int FindFiles( char* pFileMask, bool bRecurse, CUtlVector<fileList_t> &fileList );
+ virtual char *MakeTemporaryFilename( char const *pchModPath, char *pPath, int pathSize );
+ virtual void DeleteTemporaryFiles( const char *pFileMask );
+ virtual int CompareFileTime( const char *pFilenameA, const char *pFilenameB );
+ virtual bool DoesFileExist( const char *pFilename );
+
+private:
+
+ int GetFileList( const char* pDirPath, const char* pPattern, CUtlVector< fileList_t > &fileList );
+ void RecurseFileTree_r( const char* pDirPath, int depth, CUtlVector< CUtlString > &dirList );
+};
+
+static CScriptLib g_ScriptLib;
+IScriptLib *scriptlib = &g_ScriptLib;
+IScriptLib *g_pScriptLib = &g_ScriptLib;
+
+//-----------------------------------------------------------------------------
+// Existence check
+//-----------------------------------------------------------------------------
+bool CScriptLib::DoesFileExist( const char *pFilename )
+{
+ return g_pFullFileSystem->FileExists( pFilename );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Helper utility, read file into buffer
+//-----------------------------------------------------------------------------
+bool CScriptLib::ReadFileToBuffer( const char *pSourceName, CUtlBuffer &buffer, bool bText, bool bNoOpenFailureWarning )
+{
+ bool bSuccess = true;
+
+ if ( !g_pFullFileSystem->ReadFile( pSourceName, NULL, buffer ) )
+ {
+ if ( !bNoOpenFailureWarning )
+ {
+ Msg( "ReadFileToBuffer(): Error opening %s: %s\n", pSourceName, strerror( errno ) );
+ }
+ return false;
+ }
+
+ if ( bText )
+ {
+ // force it into text mode
+ buffer.SetBufferType( true, true );
+ }
+ else
+ {
+ buffer.SetBufferType( false, false );
+ }
+
+ return bSuccess;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Helper utility, Write buffer to file
+//-----------------------------------------------------------------------------
+bool CScriptLib::WriteBufferToFile( const char *pTargetName, CUtlBuffer &buffer, DiskWriteMode_t writeMode )
+{
+ char* ptr;
+ char dirPath[MAX_PATH];
+
+ bool bSuccess = true;
+
+ // create path
+ // prime and skip to first seperator
+ strcpy( dirPath, pTargetName );
+ ptr = strchr( dirPath, '\\' );
+ while ( ptr )
+ {
+ ptr = strchr( ptr+1, '\\' );
+ if ( ptr )
+ {
+ *ptr = '\0';
+ _mkdir( dirPath );
+ *ptr = '\\';
+ }
+ }
+
+ bool bDoWrite = false;
+ if ( writeMode == WRITE_TO_DISK_ALWAYS )
+ {
+ bDoWrite = true;
+ }
+ else if ( writeMode == WRITE_TO_DISK_UPDATE )
+ {
+ if ( DoesFileExist( pTargetName ) )
+ {
+ bDoWrite = true;
+ }
+ }
+
+ if ( bDoWrite )
+ {
+ bSuccess = g_pFullFileSystem->WriteFile( pTargetName, NULL, buffer );
+ }
+
+ return bSuccess;
+}
+
+//-----------------------------------------------------------------------------
+// Returns -1, 0, or 1.
+//-----------------------------------------------------------------------------
+int CScriptLib::CompareFileTime( const char *pFilenameA, const char *pFilenameB )
+{
+ int timeA = g_pFullFileSystem->GetFileTime( (char *)pFilenameA );
+ int timeB = g_pFullFileSystem->GetFileTime( (char *)pFilenameB );
+
+ if ( timeA == -1)
+ {
+ // file a not exist
+ timeA = 0;
+ }
+ if ( timeB == -1 )
+ {
+ // file b not exist
+ timeB = 0;
+ }
+
+ if ( (unsigned int)timeA < (unsigned int)timeB )
+ {
+ return -1;
+ }
+ else if ( (unsigned int)timeA > (unsigned int)timeB )
+ {
+ return 1;
+ }
+
+ return 0;
+}
+
+//-----------------------------------------------------------------------------
+// Make a temporary filename
+//-----------------------------------------------------------------------------
+char *CScriptLib::MakeTemporaryFilename( char const *pchModPath, char *pPath, int pathSize )
+{
+ char *pBuffer = _tempnam( pchModPath, "mgd_" );
+ if ( pBuffer[0] == '\\' )
+ {
+ pBuffer++;
+ }
+ if ( pBuffer[strlen( pBuffer )-1] == '.' )
+ {
+ pBuffer[strlen( pBuffer )-1] = '\0';
+ }
+ V_snprintf( pPath, pathSize, "%s.tmp", pBuffer );
+
+ free( pBuffer );
+
+ return pPath;
+}
+
+//-----------------------------------------------------------------------------
+// Delete temporary files
+//-----------------------------------------------------------------------------
+void CScriptLib::DeleteTemporaryFiles( const char *pFileMask )
+{
+#if !defined( _X360 )
+ const char *pEnv = getenv( "temp" );
+ if ( !pEnv )
+ {
+ pEnv = getenv( "tmp" );
+ }
+
+ if ( pEnv )
+ {
+ char tempPath[MAX_PATH];
+ strcpy( tempPath, pEnv );
+ V_AppendSlash( tempPath, sizeof( tempPath ) );
+ strcat( tempPath, pFileMask );
+
+ CUtlVector<fileList_t> fileList;
+ FindFiles( tempPath, false, fileList );
+ for ( int i=0; i<fileList.Count(); i++ )
+ {
+ _unlink( fileList[i].fileName.String() );
+ }
+ }
+#else
+ AssertOnce( !"CScriptLib::DeleteTemporaryFiles: Not avail on 360\n" );
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Get list of files from current path that match pattern
+//-----------------------------------------------------------------------------
+int CScriptLib::GetFileList( const char* pDirPath, const char* pPattern, CUtlVector< fileList_t > &fileList )
+{
+ char sourcePath[MAX_PATH];
+ char fullPath[MAX_PATH];
+ bool bFindDirs;
+
+ fileList.Purge();
+
+ strcpy( sourcePath, pDirPath );
+ int len = (int)strlen( sourcePath );
+ if ( !len )
+ {
+ strcpy( sourcePath, ".\\" );
+ }
+ else if ( sourcePath[len-1] != '\\' )
+ {
+ sourcePath[len] = '\\';
+ sourcePath[len+1] = '\0';
+ }
+
+ strcpy( fullPath, sourcePath );
+ if ( pPattern[0] == '\\' && pPattern[1] == '\0' )
+ {
+ // find directories only
+ bFindDirs = true;
+ strcat( fullPath, "*" );
+ }
+ else
+ {
+ // find files, use provided pattern
+ bFindDirs = false;
+ strcat( fullPath, pPattern );
+ }
+
+#ifdef WIN32
+ struct _finddata_t findData;
+ intptr_t h = _findfirst( fullPath, &findData );
+ if ( h == -1 )
+ {
+ return 0;
+ }
+
+ do
+ {
+ // dos attribute complexities i.e. _A_NORMAL is 0
+ if ( bFindDirs )
+ {
+ // skip non dirs
+ if ( !( findData.attrib & _A_SUBDIR ) )
+ continue;
+ }
+ else
+ {
+ // skip dirs
+ if ( findData.attrib & _A_SUBDIR )
+ continue;
+ }
+
+ if ( !stricmp( findData.name, "." ) )
+ continue;
+
+ if ( !stricmp( findData.name, ".." ) )
+ continue;
+
+ char fileName[MAX_PATH];
+ strcpy( fileName, sourcePath );
+ strcat( fileName, findData.name );
+
+ int j = fileList.AddToTail();
+ fileList[j].fileName.Set( fileName );
+ fileList[j].timeWrite = findData.time_write;
+ }
+ while ( !_findnext( h, &findData ) );
+
+ _findclose( h );
+#elif defined(POSIX)
+ FIND_DATA findData;
+ Q_FixSlashes( fullPath );
+ void *h = FindFirstFile( fullPath, &findData );
+ if ( (int)h == -1 )
+ {
+ return 0;
+ }
+
+ do
+ {
+ // dos attribute complexities i.e. _A_NORMAL is 0
+ if ( bFindDirs )
+ {
+ // skip non dirs
+ if ( !( findData.dwFileAttributes & S_IFDIR ) )
+ continue;
+ }
+ else
+ {
+ // skip dirs
+ if ( findData.dwFileAttributes & S_IFDIR )
+ continue;
+ }
+
+ if ( !stricmp( findData.cFileName, "." ) )
+ continue;
+
+ if ( !stricmp( findData.cFileName, ".." ) )
+ continue;
+
+ char fileName[MAX_PATH];
+ strcpy( fileName, sourcePath );
+ strcat( fileName, findData.cFileName );
+
+ int j = fileList.AddToTail();
+ fileList[j].fileName.Set( fileName );
+ struct stat statbuf;
+ if ( stat( fileName, &statbuf ) )
+#ifdef OSX
+ fileList[j].timeWrite = statbuf.st_mtimespec.tv_sec;
+#else
+ fileList[j].timeWrite = statbuf.st_mtime;
+#endif
+ else
+ fileList[j].timeWrite = 0;
+ }
+ while ( !FindNextFile( h, &findData ) );
+
+ FindClose( h );
+
+#else
+#error
+#endif
+
+
+ return fileList.Count();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Recursively determine directory tree
+//-----------------------------------------------------------------------------
+void CScriptLib::RecurseFileTree_r( const char* pDirPath, int depth, CUtlVector< CUtlString > &dirList )
+{
+ // recurse from source directory, get directories only
+ CUtlVector< fileList_t > fileList;
+ int dirCount = GetFileList( pDirPath, "\\", fileList );
+ if ( !dirCount )
+ {
+ // add directory name to search tree
+ int j = dirList.AddToTail();
+ dirList[j].Set( pDirPath );
+ return;
+ }
+
+ for ( int i=0; i<dirCount; i++ )
+ {
+ // form new path name, recurse into
+ RecurseFileTree_r( fileList[i].fileName.String(), depth+1, dirList );
+ }
+
+ int j = dirList.AddToTail();
+ dirList[j].Set( pDirPath );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Generate a list of file matching mask
+//-----------------------------------------------------------------------------
+int CScriptLib::FindFiles( char* pFileMask, bool bRecurse, CUtlVector<fileList_t> &fileList )
+{
+ char dirPath[MAX_PATH];
+ char pattern[MAX_PATH];
+ char extension[MAX_PATH];
+
+ // get path only
+ strcpy( dirPath, pFileMask );
+ V_StripFilename( dirPath );
+
+ // get pattern only
+ V_FileBase( pFileMask, pattern, sizeof( pattern ) );
+ V_ExtractFileExtension( pFileMask, extension, sizeof( extension ) );
+ if ( extension[0] )
+ {
+ strcat( pattern, "." );
+ strcat( pattern, extension );
+ }
+
+ if ( !bRecurse )
+ {
+ GetFileList( dirPath, pattern, fileList );
+ }
+ else
+ {
+ // recurse and get the tree
+ CUtlVector< fileList_t > tempList;
+ CUtlVector< CUtlString > dirList;
+ RecurseFileTree_r( dirPath, 0, dirList );
+ for ( int i=0; i<dirList.Count(); i++ )
+ {
+ // iterate each directory found
+ tempList.Purge();
+ tempList.EnsureCapacity( dirList.Count() );
+
+ GetFileList( dirList[i].String(), pattern, tempList );
+
+ int start = fileList.AddMultipleToTail( tempList.Count() );
+ for ( int j=0; j<tempList.Count(); j++ )
+ {
+ fileList[start+j] = tempList[j];
+ }
+ }
+ }
+
+ return fileList.Count();
+}