From 39ed87570bdb2f86969d4be821c94b722dc71179 Mon Sep 17 00:00:00 2001 From: Joe Ludwig Date: Wed, 26 Jun 2013 15:22:04 -0700 Subject: First version of the SOurce SDK 2013 --- mp/src/utils/common/scriplib.cpp | 1349 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 1349 insertions(+) create mode 100644 mp/src/utils/common/scriplib.cpp (limited to 'mp/src/utils/common/scriplib.cpp') 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 +#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 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, ¯oname[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 +#include +#ifdef WIN32 +#include +#include +#include +#endif +#include +#include +#include +#include +#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 ); + 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; + FindFiles( tempPath, false, fileList ); + for ( int i=0; i &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 &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