#include #include #include #include #include "appl.h" #include "config.h" #include "error.h" #include "misc.h" /* config.c Configuration file management functions Note: Configuration keys 1000-1999 are reserved for colours. C-Desktop Copyright (C)1998, Brett Porter. */ /* # TYPE DEFINITIONS # */ typedef enum { CFGLINE_VALID, CFGLINE_INVALID, CFGLINE_COMMENT } E_ConfigLineType; /* # CONSTANTS # */ extern const char *kConfig_Filename; /* # VARIABLE DEFINITIONS # */ static T_ConfigVar *sConfig_VarList; /* # FUNCTION PROTOTYPES # */ static void Config_KillVar( T_ConfigVar *aVar ); static void Config_SaveConfigFile( void ); static void Config_PrintVarConfigString( FILE *aFile, T_ConfigVar *aVar ); static E_ConfigLineType Config_ParseConfigString( char *aString, char **aNamePtr, char **aValuePtr ); /* # FUNCTION DEFINTIONS # */ /***************************************************************************** Function: Config_Initialise Description: Reset all configuration information Parameters: None Return: None *****************************************************************************/ void Config_Initialise( void ) { sConfig_VarList = NULL; Application_RegisterConfigVars(); } /***************************************************************************** Function: Config_ParseCommandLine Description: Parse the command line for options that can be added to the configuration information Parameters: Number of arguments and the actual arguments Return: None *****************************************************************************/ void Config_ParseCommandLine( int argc, char *argv[] ) { char lStr[81]; int i; T_ConfigVar *aCurVar; for ( i = 0; i < argc; i++ ) { aCurVar = sConfig_VarList; while ( aCurVar != NULL ) { if ( argv[i][0] == '-' || argv[i][0] == '/' ) { if ( strcasecmp( aCurVar->fCmdLineSwitch, argv[i]+1 ) == 0 ) { break; } } aCurVar = aCurVar->fNext; } if ( aCurVar != NULL ) { i++; if ( i >= argc || argv[i][0] == '-' || argv[i][0] == '/' ) { i--; sprintf( lStr, "Switch `%s' is missing a parameter", argv[i] ); Error( lStr ); } else { Config_SetVarValue( aCurVar, argv[i] ); } } else { sprintf( lStr, "Unknown command line switch: `%s'", argv[1] ); Error( lStr ); } } } /***************************************************************************** Function: Config_RegisterVar Description: Registers a configuration variable to be used in the config. file and to store game parameters. Parameters: A name, a key for the variable, the name of the switch on the command line, the type of value to be stored, a pointer to that value, and whether to save it in PAGOS.CFG at the end. Return: None *****************************************************************************/ T_ConfigVar *Config_RegisterVar( const char *aName, int aKey, const char *aCmdLineSwitch, E_CfgVarType aValType, const char *aValueStr, bool aSave ) { /* start by checking if any parameters conflict */ T_ConfigVar *aCurVar = sConfig_VarList; while ( aCurVar != NULL ) { if ( strcasecmp( aName, aCurVar->fName ) == 0 ) { FatalError( "Name already exists" ); } if ( aKey == aCurVar->fKey ) { FatalError( "Key already exists" ); } /* for now, the vars. can share a command line switch */ aCurVar = aCurVar->fNext; } /* everything's fine, so allocate a new var., set it up with the arguments, then add it to the front of the linked list */ P_InitVar( aCurVar, T_ConfigVar ); P_CreateStr( aCurVar->fName, aName ); P_CreateStr( aCurVar->fCmdLineSwitch, aCmdLineSwitch ); aCurVar->fKey = aKey; aCurVar->fValueType = aValType; aCurVar->fSave = aSave; aCurVar->fArchive = false; if ( !Config_SetVarValue( aCurVar, aValueStr )) { Config_KillVar( aCurVar ); return NULL; } else { /* put it at the front of the list */ aCurVar->fNext = sConfig_VarList; sConfig_VarList = aCurVar; return aCurVar; } } /***************************************************************************** Function: Config_Shutdown Description: Kills off the configuration variables Parameters: None Return: None *****************************************************************************/ void Config_Shutdown( void ) { T_ConfigVar *aCurVar = sConfig_VarList, *aNextVar; Config_SaveConfigFile(); sConfig_VarList = NULL; while ( aCurVar != NULL ) { aNextVar = aCurVar->fNext; Config_KillVar( aCurVar ); aCurVar = aNextVar; } } /***************************************************************************** Function: Config_KillVar Description: Brutally murders a variable that has outlived its use :) Parameters: The variable to be annihalated Return: None *****************************************************************************/ void Config_KillVar( T_ConfigVar *aVar ) { free( aVar->fName ); free( aVar->fCmdLineSwitch ); if ( aVar->fValueType == CFGVAR_STRING ) { if ( aVar->fValue.fString != NULL ) { free( aVar->fValue.fString ); } } free( aVar ); } /***************************************************************************** Function: Config_SetVarValue Description: Sets the value of a configuration variable, if it is valid Parameters: The variable to change and the value to change it to Return: None *****************************************************************************/ bool Config_SetVarValue( T_ConfigVar *aVar, const char *aValue ) { T_ConfigVar lTempVar = *aVar; switch ( aVar->fValueType ) { case CFGVAR_STRING: P_CreateStr( aVar->fValue.fString, aValue ); break; case CFGVAR_INT: aVar->fValue.fInteger = atoi( aValue ); break; case CFGVAR_FLOAT: aVar->fValue.fFloat = atof( aValue ); break; default: FatalError( "Invalid value type" ); break; } /* check its validity */ if ( !Application_CheckConfigVar( aVar )) { char lStr[81]; sprintf( lStr, "Configuration variable `%s' was assigned an invalid value `%s'", aVar->fName, aValue ); Error( lStr ); if ( aVar->fValueType == CFGVAR_STRING ) { free( aVar->fValue.fString ); } *aVar = lTempVar; return false; } else { aVar->fArchive = true; if ( aVar->fValueType == CFGVAR_STRING ) { if ( lTempVar.fValue.fString != NULL ) { free( lTempVar.fValue.fString ); } } return true; } } /***************************************************************************** Function: Config_LoadConfigFile Description: Load a configuration file and set the options contained within. If the file doesn't exist, just return. Parameters: None Return: None *****************************************************************************/ void Config_LoadConfigFile( void ) { FILE *lCFGFile; char lStr[256]; int lLine = 0; T_ConfigVar *lVar; lCFGFile = fopen( kConfig_Filename, "r" ); if ( lCFGFile == NULL ) { sprintf( lStr, "Couldn't open configuration file %s", kConfig_Filename ); Error( lStr ); return; } while ( fgets( lStr, 256, lCFGFile ) != NULL ) { char *lName, *lValue; E_ConfigLineType lRetVal; lLine++; lRetVal = Config_ParseConfigString( lStr, &lName, &lValue ); if ( lRetVal == CFGLINE_INVALID ) { sprintf( lStr, "Line %d is invalid in configuration file", lLine ); Error( lStr ); } else { if ( lRetVal == CFGLINE_VALID ) { lVar = Config_FindVar( lName ); if ( lVar != NULL ) { Config_SetVarValue( lVar, lValue ); /* we don't care if it is unsuccessful, just keep the old value */ } else { char lTempStr[32]; strcpy( lTempStr, lName ); sprintf( lStr, "Unknown configuration variable: `%s'", lTempStr ); Error( lStr ); } } } } fclose( lCFGFile ); } /***************************************************************************** Function: Config_SaveConfigFile Description: Save a configuration file. Parameters: None Return: None *****************************************************************************/ void Config_SaveConfigFile( void ) { char lBuffer[256], *lName, *lValue; FILE *lOld, *lNew; T_ConfigVar *lVar; rename( kConfig_Filename, "cfgtmp.$$$" ); lOld = fopen( "cfgtmp.$$$", "r" ); lNew = fopen( kConfig_Filename, "w" ); if ( lOld != NULL ) { while ( fgets( lBuffer, 256, lOld ) != NULL ) { E_ConfigLineType lRetVal = Config_ParseConfigString( lBuffer, &lName, &lValue ); if ( lRetVal == CFGLINE_VALID ) { lVar = Config_FindVar( lName ); if ( lVar == NULL ) { lName[strlen( lName )] = '='; /* replace the equals that has been removed from lBuffer */ fprintf( lNew, "; ***** NEXT LINE REMOVED BECAUSE IT IS AN UNKNOWN VARIABLE *****\n;%s\n", lBuffer ); } else { lVar->fArchive = false; Config_PrintVarConfigString( lNew, lVar ); } } if ( lRetVal == CFGLINE_INVALID ) { fprintf( lNew, "; ***** NEXT LINE REMOVED BECAUSE IT IS INVALID *****\n;%s\n", lBuffer ); } if ( lRetVal == CFGLINE_COMMENT ) { fprintf( lNew, "%s\n", lBuffer ); } } fclose( lOld ); } lVar = sConfig_VarList; while ( lVar != NULL ) { if ( lVar->fSave && lVar->fArchive ) { Config_PrintVarConfigString( lNew, lVar ); } lVar = lVar->fNext; } fclose( lNew ); remove( "cfgtmp.$$$" ); } /***************************************************************************** Function: Config_ParseConfigString Description: Finds the name and value in a configuration string Parameters: string to parse and a pointer to a place to store the name and value Return: Whether the line was valid or not *****************************************************************************/ E_ConfigLineType Config_ParseConfigString( char *aString, char **aNamePtr, char **aValuePtr ) { char *lPtr = aString, *lName; if ( *lPtr != EOS ) { lPtr[strlen( lPtr )-1] = EOS; /* get rid of the pesky newline character */ } while ( *lPtr == ' ' || *lPtr == 9 ) { lPtr++; } lName = lPtr; if ( *lName == ';' || *lName == EOS ) { /* comment or blank line, so skip the line */ return CFGLINE_COMMENT; } while ( *lPtr != '=' ) { if ( *lPtr == EOS ) { break; } lPtr++; } if ( *lPtr == EOS || *lName == '=' ) { return CFGLINE_INVALID; } else { *lPtr = EOS; *aNamePtr = lName; *aValuePtr = lPtr+1; return CFGLINE_VALID; } } /***************************************************************************** Function: Config_FindVar Description: Find a variable by its name Parameters: The name of the variable to find Return: The variable with that name, or NULL if it does not exist *****************************************************************************/ T_ConfigVar *Config_FindVar( const char *aName ) { T_ConfigVar *lVar = sConfig_VarList; while ( lVar != NULL ) { if ( strcasecmp( lVar->fName, aName ) == 0 ) { break; } lVar = lVar->fNext; } return lVar; } /***************************************************************************** Function: Config_PrintVarConfigString Description: Prints = to the file Parameters: file to print to, and variable to print Return: None *****************************************************************************/ void Config_PrintVarConfigString( FILE *aFile, T_ConfigVar *aVar ) { fprintf( aFile, "%s=", aVar->fName ); switch ( aVar->fValueType ) { case CFGVAR_STRING: fprintf( aFile, "%s\n", aVar->fValue.fString ); break; case CFGVAR_INT: fprintf( aFile, "%d\n", aVar->fValue.fInteger ); break; case CFGVAR_FLOAT: fprintf( aFile, "%f\n", aVar->fValue.fFloat ); break; default: FatalError( "Invalid value type" ); break; } }