This section of the archives stores flipcode's complete Developer Toolbox collection, featuring a variety of mini-articles and source code contributions from our readers.

| Simple Configuration Manager Submitted by

This is what I have been writing during the past 2 evenings. It consists of one class, CConfig. It also includes one little program I used to test it with. With it, you can do the following:

> - Parse statements of type:
>   variable value
> - Obtain values in 3 formats: float, int and string.
> - Read Quake style .CFG files.
> - Read Windows .INI files (ignores sections, case-sensitive).
> - Parse CGI data (not tested).
> - Hidden feature: When only supplied a name, Parse() will return NO_VALUE and fill the Config.Latest struct with values i.e. to get the int associated with "r_mipmapping" you can do this:

int MipMaps = Config.GetInt( "r_mipmapping" ); or this: Config.Parse( "r_mipmapping" );
int MipMaps = Config.Latest.Int;
Feel free to use this source in any way. Don't blame me if anything goes wrong. Please post every comment and suggestion that comes to mind.

Currently browsing [config.zip] (2,360 bytes) - [main.cpp] - (755 bytes)

    #include "config.h"
    #include <iostream>
    #include <cstring>

    #define SZ_FEATURE_NAME "CConfig"

    CConfig Config;

    int main() {
    	char Str[64];
    	int r;

    	cout << "Welcome to the lab..." << endl;
    	cout << "Testing feature: " << SZ_FEATURE_NAME << endl;
    	cout << "Type Quit to exit." << endl << endl;

    	while ( true ) {
    		cout << "? ";
    		for (int i = 0; i < 64; i++) { Str[i] = 0; }
    		cin.getline( Str, 64 );
    		if (strcmp( Str, "Quit" ) == 0) return 0;
    		if ((r = Config.Parse( Str )) == CConfig::NO_VALUE) {
    			cout << "String: " << Config.Latest.String << endl;
    			cout << "Int:    " << Config.Latest.Int << endl;
    			cout << "Float:  " << Config.Latest.Float << endl;
    		}
    		cout << "Returned: " << r << endl;
    	}
    	return -1;
    }

Currently browsing [config.zip] (2,360 bytes) - [config.h] - (983 bytes)

    #pragma once

    #pragma warning(disable: 4786)
    #define SILENT_PARSER		// Comment this line in console app to see the inner workings of Parse()

    #include <string>
    #include <map>
    using namespace std;

    struct CConfig {
    	CConfig() {};
    	~CConfig() {};

    	enum ENUM_REPLIES {
    		OK = 0,
    		NO_NAME,
    		NO_VALUE,
    		NUM_REPLIES
    	};

    	// Parses a string
    	ENUM_REPLIES Parse( char *psz );
    	// Parses Quake style .CFG files
    	void ParseCfg( char *File );
    	// Parses Windows .INI files, ignores sections
    	void ParseIni( char *File );
    	// Parses CGI data from both GET and POST (not tested)
    	void ParseCgi();

    	inline string GetString( string &Name );
    	inline int GetInt( string &Name );
    	inline float GetFloat( string &Name );

    	struct CVar {
    		int Int;
    		float Float;
    		string String;
    	} Latest;

    protected:
    	typedef map<string, CVar> MYMAP;
    	MYMAP Variables;
    	map<string, CVar>::iterator Iterator;
    	CVar Variable;
    	bool GetVarByName( string &Name );
    };

Currently browsing [config.zip] (2,360 bytes) - [config.cpp] - (3,442 bytes)

    #include "config.h"
    #include <cctype>
    #include <cstdlib>
    #include <iostream>
    #include <fstream>
    #include <strstream>

    CConfig::ENUM_REPLIES CConfig::Parse( char *psz ) {
    	char *p = psz;
    	string Name("");
    	Variable.String = "";

    #ifndef SILENT_PARSER
    	cout << "Parsing: " << psz << endl;
    #endif

    	// Eat leading spaces
    	while (*p && isspace(*p)) p++;

    	// Read name
    	while (*p && !isspace(*p)) {
    		Name += *p;
    		p++;
    	}

    	// Eat whitespace
    	while (*p && isspace(*p)) p++;

    	// Read value
    	while (*p) {
    		Variable.String += *p;
    		p++;
    	}

    #ifndef SILENT_PARSER
    	cout << "Name.size(): " << Name.size() << endl;
    	cout << "Variable.String.size(): " << Variable.String.size() << endl;
    #endif

    	if (Name.size() == 0) return NO_NAME;

    	// TODO: Optimize
    	if (Variable.String.size() == 0) {
    		Latest.Int = GetInt( Name );
    		Latest.Float = GetFloat( Name );
    		Latest.String = GetString( Name );
    		return NO_VALUE;
    	}

    	Variable.Int = atoi( Variable.String.c_str() );
    	Variable.Float = atof( Variable.String.c_str() );

    	// Delete previous variable with same name
    	if ((Iterator = Variables.find( Name )) != Variables.end()) Variables.erase(Iterator);
    	// Insert new variable
    	Variables.insert( MYMAP::value_type( Name, Variable ) );

    	return OK;
    }

    string CConfig::GetString( string &Name ) {
    	if (GetVarByName( Name )) return Variable.String;
    	return string("undefined");
    }

    int CConfig::GetInt( string &Name ) {
    	if (GetVarByName( Name )) return Variable.Int;
    	return 0;
    }

    float CConfig::GetFloat( string &Name ) {
    	if (GetVarByName( Name )) return Variable.Float;
    	return 0.0f;
    }

    bool CConfig::GetVarByName( string &Name ) {
    	Iterator = Variables.find( Name );
    	if (Iterator == Variables.end()) return false;
    	Variable = (*Iterator).second;
    	return true;
    }

    void CConfig::ParseCfg( char *File ) {
    	ifstream istr(File);
    	char Buffer[256];

    	if (!istr.is_open()) {
    		return;
    	}
    	while (!istr.eof()) {
    		istr.getline( Buffer, 256 );
    		if (Buffer[0] == '#') continue;
    		if (Buffer[0] == 0x27) continue;
    		Parse( Buffer );
    	}
    }

    // This function silently ignores sections!
    void CConfig::ParseIni( char *File ) {
    	ifstream istr(File);
    	char Buffer[256];
    	int i = 0;

    	if (!istr.is_open()) {
    		return;
    	}
    	while (!istr.eof()) {
    		istr.getline( Buffer, 256 );
    		if (Buffer[0] == ';') continue;
    		if (Buffer[0] == '[') continue;
    		while (Buffer[i]) {
    			if (Buffer[i] == '=') Buffer[i] = ' ';
    			i++;
    		}
    		Parse( Buffer );
    	}
    }

    void CConfig::ParseCgi() {
    	char Buffer[4096], b[3]={0,0,0};
    	int i = 0;
    	string Method, Query;
    	const string POST("POST"), GET("GET");
    	istream *istr = NULL;

    	// Environment variables involved:
    	// REQUEST_METHOD, CONTENT_LENGTH, QUERY_STRING

    	Method = getenv( "REQUEST_METHOD" );
    	if ( Method == POST ) {
    		istr = &cin;
    	}
    	if ( Method == GET ) {
    		istrstream istrQuery( getenv( "QUERY_STRING" ) );
    		istr = &istrQuery;
    	}

    	if (!istr) return;

    	while ( !istr->eof() ) {
    		istr->getline( Buffer, 4096, '&' );
    		while ( Buffer[i] ) {
    			if (Buffer[i] == '=') Buffer[i] = ' ';
    			if (Buffer[i] == '+') Buffer[i] = ' ';
    			if (Buffer[i] == '%') {
    				// Hexadecimal encoding
    				b[0] = Buffer[i+1];
    				b[1] = Buffer[i+2];
    				Buffer[i+1] = ' ';
    				Buffer[i+2] = 0x08; // Should be backspace
    				Buffer[i] = atoi( b );
    			}
    			i++;
    		}
    		Parse( Buffer );
    	}
    }

The zip file viewer built into the Developer Toolbox made use of the zlib library, as well as the zlibdll source additions.

Copyright 1999-2008 (C) FLIPCODE.COM and/or the original content author(s). All rights reserved.
Please read our Terms, Conditions, and Privacy information.