diff options
| author | Jørgen P. Tjernø <[email protected]> | 2013-12-02 19:31:46 -0800 |
|---|---|---|
| committer | Jørgen P. Tjernø <[email protected]> | 2013-12-02 19:46:31 -0800 |
| commit | f56bb35301836e56582a575a75864392a0177875 (patch) | |
| tree | de61ddd39de3e7df52759711950b4c288592f0dc /mp/src/utils/common/scriplib.cpp | |
| parent | Mark some more files as text. (diff) | |
| download | source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.tar.xz source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.zip | |
Fix line endings. WHAMMY.
Diffstat (limited to 'mp/src/utils/common/scriplib.cpp')
| -rw-r--r-- | mp/src/utils/common/scriplib.cpp | 2698 |
1 files changed, 1349 insertions, 1349 deletions
diff --git a/mp/src/utils/common/scriplib.cpp b/mp/src/utils/common/scriplib.cpp index 469c7885..1c8b47f8 100644 --- a/mp/src/utils/common/scriplib.cpp +++ b/mp/src/utils/common/scriplib.cpp @@ -1,1349 +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, ¯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 <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();
-}
+//========= 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, ¯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 <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(); +} |