|
|
//===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======//
//
// Purpose:
//
// $NoKeywords: $
//
//===========================================================================//
// CScriptObject and CDescription class definitions
//
#include "ScriptObject.h"
#include <stdio.h>
#include <stdlib.h>
#include "EngineInterface.h"
#include <vgui_controls/Label.h>
#include "FileSystem.h"
#include "tier1/convar.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
using namespace vgui; static char token[ 1024 ];
void StripFloatTrailingZeros(char *str) { // scan for a '.'
char *period = strchr(str, '.'); if (!period) return;
// start at the end and scan back to the period
char *end = 0; for ( end = str + strlen(str) - 1; end > period; --end ) { if (*end == '0') { *end = '\0'; } else { // we've hit a real value, stop truncating
break; } }
// if we've made it up to the period, kill that to
if ( *end == '.' ) { *end = '\0'; } }
/////////////////////
objtypedesc_t objtypes[] = { { O_BOOL , "BOOL" }, { O_NUMBER, "NUMBER" }, { O_LIST , "LIST" }, { O_STRING, "STRING" }, { O_OBSOLETE , "OBSOLETE" }, };
mpcontrol_t::mpcontrol_t( Panel *parent, char const *panelName ) : Panel( parent, panelName ) { type = O_BADTYPE; pControl = NULL; pPrompt = NULL; pScrObj = NULL;
next = NULL;
SetPaintBackgroundEnabled( false ); }
void mpcontrol_t::OnSizeChanged( int wide, int tall ) { int inset = 4;
if ( pPrompt ) { int w = wide / 2;
if ( pControl ) { pControl->SetBounds( w + 20, inset, w - 20, tall - 2 * inset ); } pPrompt->SetBounds( 0, inset, w + 20, tall - 2 * inset ); } else { if ( pControl ) { pControl->SetBounds( 0, inset, wide, tall - 2 * inset ); } } }
CScriptListItem::CScriptListItem() { pNext = NULL; memset( szItemText, 0, 128 ); memset( szValue, 0, 256 ); }
CScriptListItem::CScriptListItem( char const *strItem, char const *strValue ) { pNext = NULL; Q_strncpy( szItemText, strItem, sizeof( szItemText ) ); Q_strncpy( szValue , strValue, sizeof( szValue ) ); }
CScriptObject::CScriptObject( void ) { type = O_BOOL; bSetInfo = false; // Prepend "Setinfo" to keyvalue pair in config?
pNext = NULL; pListItems = NULL; }
CScriptObject::~CScriptObject() { CScriptListItem *p, *n;
p = pListItems; while ( p ) { n = p->pNext; delete p; p = n; } pListItems = NULL; }
void CScriptObject::SetCurValue( char const *strValue ) { Q_strncpy( curValue, strValue, sizeof( curValue ) );
fcurValue = (float)atof( curValue );
if ( type == O_NUMBER || type == O_BOOL ) { StripFloatTrailingZeros( curValue ); } }
void CScriptObject::AddItem( CScriptListItem *pItem ) { // Link it into the end of the list;
CScriptListItem *p; p = pListItems; if ( !p ) { pListItems = pItem; pItem->pNext = NULL; return; }
while ( p ) { if ( !p->pNext ) { p->pNext = pItem; pItem->pNext = NULL; return; } p = p->pNext; } }
/*
=================== UTIL_StripInvalidCharacters
Removes any possible formatting codes and double quote characters from the input string =================== */ void UTIL_StripInvalidCharacters( char *pszInput, int maxlen ) { char szOutput[4096]; char *pIn, *pOut; pIn = pszInput; pOut = szOutput;
*pOut = '\0';
while ( *pIn ) { if ( ( *pIn != '"' ) && ( *pIn != '%' ) ) { *pOut++ = *pIn; } pIn++; }
*pOut = '\0';
// Copy back over, in place
Q_strncpy( pszInput, szOutput, maxlen ); }
void FixupString( char *inString, int maxlen ) { char szBuffer[ 4096 ]; Q_strncpy( szBuffer, inString, sizeof( szBuffer ) ); UTIL_StripInvalidCharacters( szBuffer, sizeof( szBuffer ) ); Q_strncpy( inString, szBuffer, maxlen ); }
/*
=================== CleanFloat
Removes any ".000" from the end of floats =================== */ char * CleanFloat( float val ) { static int curstring = 0; static char string[2][32]; curstring = ( curstring + 1 ) % 2;
Q_snprintf( string[curstring], sizeof( string[curstring] ), "%f", val );
char * str = string[curstring];
char * tmp = str; if ( !str || !*str || !strchr( str, '.' ) ) return str;
while ( *tmp ) ++tmp; --tmp;
while ( *tmp == '0' && tmp > str ) { *tmp = 0; --tmp; }
if ( *tmp == '.' ) { *tmp = 0; }
return str; }
void CScriptObject::WriteToScriptFile( FileHandle_t fp ) { if ( type == O_OBSOLETE ) return;
FixupString( cvarname, sizeof( cvarname ) ); g_pFullFileSystem->FPrintf( fp, "\t\"%s\"\r\n", cvarname );
g_pFullFileSystem->FPrintf( fp, "\t{\r\n" );
CScriptListItem *pItem;
FixupString( prompt, sizeof( prompt ) );
switch ( type ) { case O_BOOL: g_pFullFileSystem->FPrintf( fp, "\t\t\"%s\"\r\n", prompt ); g_pFullFileSystem->FPrintf( fp, "\t\t{ BOOL }\r\n" ); g_pFullFileSystem->FPrintf( fp, "\t\t{ \"%i\" }\r\n", (int)fcurValue ? 1 : 0 ); break; case O_NUMBER: g_pFullFileSystem->FPrintf( fp, "\t\t\"%s\"\r\n", prompt ); g_pFullFileSystem->FPrintf( fp, "\t\t{ NUMBER %s %s }\r\n", CleanFloat(fMin), CleanFloat(fMax) ); g_pFullFileSystem->FPrintf( fp, "\t\t{ \"%s\" }\r\n", CleanFloat(fcurValue) ); break; case O_STRING: g_pFullFileSystem->FPrintf( fp, "\t\t\"%s\"\r\n", prompt ); g_pFullFileSystem->FPrintf( fp, "\t\t{ STRING }\r\n" ); FixupString( curValue, sizeof( curValue ) ); g_pFullFileSystem->FPrintf( fp, "\t\t{ \"%s\" }\r\n", curValue ); break; case O_LIST: g_pFullFileSystem->FPrintf( fp, "\t\t\"%s\"\r\n", prompt ); g_pFullFileSystem->FPrintf( fp, "\t\t{\r\n\t\t\tLIST\r\n" ); pItem = pListItems; while ( pItem ) { UTIL_StripInvalidCharacters( pItem->szItemText, sizeof( pItem->szItemText ) ); UTIL_StripInvalidCharacters( pItem->szValue, sizeof( pItem->szValue ) ); g_pFullFileSystem->FPrintf( fp, "\t\t\t\"%s\" \"%s\"\r\n", pItem->szItemText, pItem->szValue );
pItem = pItem->pNext; }
g_pFullFileSystem->FPrintf( fp, "\t\t}\r\n"); g_pFullFileSystem->FPrintf( fp, "\t\t{ \"%s\" }\r\n", CleanFloat(fcurValue) ); break; }
if ( bSetInfo ) g_pFullFileSystem->FPrintf( fp, "\t\tSetInfo\r\n" );
g_pFullFileSystem->FPrintf( fp, "\t}\r\n\r\n" ); }
void CScriptObject::WriteToFile( FileHandle_t fp ) { if ( type == O_OBSOLETE ) return;
FixupString( cvarname, sizeof( cvarname ) ); g_pFullFileSystem->FPrintf( fp, "\"%s\"\t\t", cvarname );
CScriptListItem *pItem; int n, i; float fVal;
switch ( type ) { case O_BOOL: g_pFullFileSystem->FPrintf( fp, "\"%s\"\r\n", fcurValue != 0.0 ? "1" : "0" ); break; case O_NUMBER: fVal = fcurValue; if ( fMin != -1.0 ) fVal = MAX( fVal, fMin ); if ( fMax != -1.0 ) fVal = MIN( fVal, fMax ); g_pFullFileSystem->FPrintf( fp, "\"%f\"\r\n", fVal ); break; case O_STRING: FixupString( curValue, sizeof( curValue ) ); g_pFullFileSystem->FPrintf( fp, "\"%s\"\r\n", curValue ); break; case O_LIST: pItem = pListItems; n = (int)fcurValue; i = 0; while ( (i < n) && pItem ) { i++; pItem = pItem->pNext; }
if ( pItem ) { UTIL_StripInvalidCharacters( pItem->szValue, sizeof( pItem->szValue ) ); g_pFullFileSystem->FPrintf( fp, "\"%s\"\r\n", pItem->szValue ); } else //Couln't find index
{ g_pFullFileSystem->FPrintf( fp, "\"0.0\"\r\n" ); } break; } }
void CScriptObject::WriteToConfig( void ) { if ( type == O_OBSOLETE ) return;
char *pszKey; char szValue[2048];
pszKey = ( char * )cvarname;
CScriptListItem *pItem; int n, i; float fVal;
switch ( type ) { case O_BOOL: Q_snprintf( szValue, sizeof( szValue ), "%s", fcurValue != 0.0 ? "1" : "0" ); break; case O_NUMBER: fVal = fcurValue; if ( fMin != -1.0 ) fVal = MAX( fVal, fMin ); if ( fMax != -1.0 ) fVal = MIN( fVal, fMax ); Q_snprintf( szValue, sizeof( szValue ), "%f", fVal ); break; case O_STRING: Q_snprintf( szValue, sizeof( szValue ), "\"%s\"", (char *)curValue ); UTIL_StripInvalidCharacters( szValue, sizeof( szValue ) ); break; case O_LIST: pItem = pListItems; n = (int)fcurValue; i = 0; while ( (i < n) && pItem ) { i++; pItem = pItem->pNext; }
if ( pItem ) { Q_snprintf( szValue, sizeof( szValue ), "%s", pItem->szValue ); UTIL_StripInvalidCharacters( szValue, sizeof( szValue ) ); } else //Couln't find index
{ Q_strncpy( szValue, "0.0", sizeof( szValue ) ); } break; }
char command[ 256 ]; if ( bSetInfo ) { Q_snprintf( command, sizeof(command), "setinfo %s \"%s\"\n", pszKey, szValue ); } else { Q_snprintf( command, sizeof(command), "%s \"%s\"\n", pszKey, szValue ); }
engine->ClientCmd_Unrestricted( command );
// CFG_SetKey( g_szCurrentConfigFile, pszKey, szValue, bSetInfo );
}
objtype_t CScriptObject::GetType( char *pszType ) { int i; int nTypes;
nTypes = sizeof( objtypes ) / sizeof( objtypedesc_t);
for ( i = 0; i < nTypes; i++ ) { if ( !stricmp( objtypes[i].szDescription, pszType ) ) return objtypes[i].type; }
return O_BADTYPE; }
bool CScriptObject::ReadFromBuffer( const char **pBuffer, bool isNewObject ) { // Get the first token.
// The cvar we are setting
*pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) ); if ( strlen( token ) <= 0 ) return false;
if ( isNewObject ) { Q_strncpy( cvarname, token, sizeof( cvarname ) ); }
// Parse the {
*pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) ); if ( strlen( token ) <= 0 ) return false;
if ( strcmp( token, "{" ) ) { Msg( "Expecting '{', got '%s'", token ); return false; }
// Parse the Prompt
*pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) ); if ( strlen( token ) <= 0 ) return false;
if ( isNewObject ) { Q_strncpy( prompt, token, sizeof( prompt ) ); }
// Parse the next {
*pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) ); if ( strlen( token ) <= 0 ) return false;
if ( strcmp( token, "{" ) ) { Msg( "Expecting '{', got '%s'", token ); return false; }
// Now parse the type:
*pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) ); if ( strlen( token ) <= 0 ) return false;
objtype_t newType = GetType( token ); if ( isNewObject ) { type = newType; } if ( newType == O_BADTYPE ) { Msg( "Type '%s' unknown", token ); return false; }
switch ( newType ) { case O_OBSOLETE: case O_BOOL: // Parse the next {
*pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) ); if ( strlen( token ) <= 0 ) return false;
if ( strcmp( token, "}" ) ) { Msg( "Expecting '{', got '%s'", token ); return false; } break; case O_NUMBER: // Parse the Min
*pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) ); if ( strlen( token ) <= 0 ) return false; if ( isNewObject ) { fMin = (float)atof( token ); }
// Parse the Min
*pBuffer = engine->ParseFile( *pBuffer, token , sizeof( token )); if ( strlen( token ) <= 0 ) return false; if ( isNewObject ) { fMax = (float)atof( token ); }
// Parse the next {
*pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) ); if ( strlen( token ) <= 0 ) return false;
if ( strcmp( token, "}" ) ) { Msg( "Expecting '{', got '%s'", token ); return false; } break; case O_STRING: // Parse the next {
*pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) ); if ( strlen( token ) <= 0 ) return false;
if ( strcmp( token, "}" ) ) { Msg( "Expecting '{', got '%s'", token ); return false; } break; case O_LIST: // Parse items until we get the }
while ( 1 ) { // Parse the next {
*pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) ); if ( strlen( token ) <= 0 ) return false;
// Done?
if ( !strcmp( token, "}" ) ) break;
//
// Add the item to a list somewhere
// AddItem( token )
char strItem[ 128 ]; char strValue[128];
Q_strncpy( strItem, token, sizeof( strItem ) );
// Parse the value
*pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) ); if ( strlen( token ) <= 0 ) return false;
Q_strncpy( strValue, token, sizeof( strValue ) );
if ( isNewObject ) { CScriptListItem *pItem; pItem = new CScriptListItem( strItem, strValue );
AddItem( pItem ); } } break; }
//
// Now read in the default value
// Parse the {
*pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) ); if ( strlen( token ) <= 0 ) return false;
if ( strcmp( token, "{" ) ) { Msg( "Expecting '{', got '%s'", token ); return false; }
// Parse the default
*pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) ); //if ( strlen( token ) <= 0 )
// return false;
// Set the values
Q_strncpy( defValue, token, sizeof( defValue ) ); fdefValue = (float)atof( token );
if (type == O_NUMBER) { StripFloatTrailingZeros( defValue ); }
SetCurValue( defValue );
// Parse the }
*pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) ); if ( strlen( token ) <= 0 ) return false;
if ( strcmp( token, "}" ) ) { Msg( "Expecting '{', got '%s'", token ); return false; }
// Parse the final }
*pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) ); if ( strlen( token ) <= 0 ) return false;
if ( !stricmp( token, "SetInfo" ) ) { bSetInfo = true; // Parse the final }
*pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) ); if ( strlen( token ) <= 0 ) return false; }
if ( strcmp( token, "}" ) ) { Msg( "Expecting '{', got '%s'", token ); return false; } return true; }
/////////////////////////
CDescription::CDescription( CPanelListPanel *panel ) { pObjList = NULL;
m_pListPanel = panel; }
CDescription::~CDescription() { CScriptObject *p, *n;
p = pObjList; while ( p ) { n = p->pNext; p->pNext = NULL; p->MarkForDeletion(); //delete p;
p = n; }
pObjList = NULL; if ( m_pszHintText ) free( m_pszHintText ); if ( m_pszDescriptionType ) free( m_pszDescriptionType ); }
CScriptObject * CDescription::FindObject( const char *pszObjectName ) { if ( !pszObjectName ) return NULL;
CScriptObject *p; p = pObjList; while ( p ) { if ( !stricmp( pszObjectName, p->cvarname ) ) return p; p = p->pNext; } return NULL; }
void CDescription::AddObject( CScriptObject *pObj ) { CScriptObject *p; p = pObjList; if ( !p ) { pObjList = pObj; pObj->pNext = NULL; return; }
while ( p ) { if ( !p->pNext ) { p->pNext = pObj; pObj->pNext = NULL; return; } p = p->pNext; } }
bool CDescription::ReadFromBuffer( const char **pBuffer ) { // Get the first token.
*pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) ); if ( strlen( token ) <= 0 ) return false;
// Read VERSION #
if ( stricmp ( token, "VERSION" ) ) { Msg( "Expecting 'VERSION', got '%s'", token ); return false; }
// Parse in the version #
// Get the first token.
*pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) ); if ( strlen( token ) <= 0 ) { Msg( "Expecting version #" ); return false; }
float fVer; fVer = (float)atof( token );
if ( fVer != SCRIPT_VERSION ) { Msg( "Version mismatch, expecting %f, got %f", SCRIPT_VERSION, fVer ); return false; }
// Get the "DESCRIPTION"
*pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) ); if ( strlen( token ) <= 0 ) return false;
// Read DESCRIPTION
if ( stricmp ( token, "DESCRIPTION" ) ) { Msg( "Expecting 'DESCRIPTION', got '%s'", token ); return false; }
// Parse in the description type
*pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) ); if ( strlen( token ) <= 0 ) { Msg( "Expecting '%s'", m_pszDescriptionType ); return false; }
if ( stricmp ( token, m_pszDescriptionType ) ) { Msg( "Expecting %s, got %s", m_pszDescriptionType, token ); return false; }
// Parse the {
*pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) ); if ( strlen( token ) <= 0 ) return false;
if ( strcmp( token, "{" ) ) { Msg( "Expecting '{', got '%s'", token ); return false; }
const char *pStart; CScriptObject *pObj; // Now read in the objects and link them in
while ( 1 ) { pStart = *pBuffer;
// Get the first token.
*pBuffer = engine->ParseFile( *pBuffer, token, sizeof( token ) ); if ( strlen( token ) <= 0 ) return false;
// Read "cvar name" or } when done
if ( !stricmp ( token, "}" ) ) break;
// Unget the token
*pBuffer = pStart;
// Create a new object
bool mustAdd = true; pObj = FindObject( token ); if ( pObj ) { pObj->ReadFromBuffer( &pStart, false ); mustAdd = false; // already in list
} else { pObj = new CScriptObject(); if ( !pObj ) { Msg( "Couldn't create script object" ); return false; }
if ( !pObj->ReadFromBuffer( &pStart, true ) ) { delete pObj; return false; } }
*pBuffer = pStart;
// Add to list
// Fixme, move to end of list first
if ( mustAdd ) { AddObject( pObj ); } }
return true; }
bool CDescription::InitFromFile( char *pszFileName ) {
// Load file into memory
FileHandle_t file = g_pFullFileSystem->Open( pszFileName, "rb" ); if ( !file ) return false;
int len =g_pFullFileSystem->Size( file );
// read the file
byte *buffer = new unsigned char[ len ]; Assert( buffer ); g_pFullFileSystem->Read( buffer, len, file ); g_pFullFileSystem->Close( file );
const char *pBuffer = (const char*)buffer; ReadFromBuffer( &pBuffer );
delete[] buffer;
return true; }
void CDescription::WriteToFile( FileHandle_t fp ) { CScriptObject *pObj;
WriteFileHeader( fp );
pObj = pObjList; while ( pObj ) { pObj->WriteToFile( fp ); pObj = pObj->pNext; } }
void CDescription::WriteToConfig( void ) { CScriptObject *pObj;
pObj = pObjList; while ( pObj ) { pObj->WriteToConfig(); pObj = pObj->pNext; } }
void CDescription::WriteToScriptFile( FileHandle_t fp ) { CScriptObject *pObj;
WriteScriptHeader( fp );
pObj = pObjList; while ( pObj ) { pObj->WriteToScriptFile( fp ); pObj = pObj->pNext; }
g_pFullFileSystem->FPrintf( fp, "}\r\n" ); }
void CDescription::TransferCurrentValues( const char *pszConfigFile ) { char szValue[ 1024 ];
CScriptObject *pObj;
pObj = pObjList; while ( pObj ) {
/*
TODO: if/when prefixed keys are implemented const char *value; if ( pObj->bSetInfo ) { value = engine->LocalPlayerInfo_ValueForKey( pObj->cvarname ); // use LocalPlayerInfo because PlayerInfo strips keys prefixed with "_"
} else { value = engine->pfnGetCvarString( pObj->cvarname ); } */
ConVarRef var( pObj->cvarname ); if ( !var.IsValid() ) { DevMsg( "Could not find '%s'\n", pObj->cvarname ); pObj = pObj->pNext; continue; } const char *value = var.GetString();
if ( value && value[ 0 ] ) //if ( CFG_GetValue( pszConfigFile, pObj->cvarname, szValue ) )
{ Q_strncpy( szValue, value, sizeof( szValue ) );
// Fill in better default value
//
Q_strncpy( pObj->curValue, szValue, sizeof( pObj->curValue ) ); pObj->fcurValue = (float)atof( szValue );
Q_strncpy( pObj->defValue, szValue, sizeof( pObj->defValue ) ); pObj->fdefValue = (float)atof( szValue ); }
pObj = pObj->pNext; } }
void CDescription::setDescription( const char *pszDesc ) { m_pszDescriptionType = strdup( pszDesc ); }
void CDescription::setHint( const char *pszHint ) { m_pszHintText = strdup( pszHint ); }
|