www.pudn.com > rDUNclientBeta1.zip > cfg.cpp


////
// File: cfg.c
// Desc: Configuration file parser
//
// Changelog: 04/08/2002 - Magicdude - Created basic parser, not very robust, no memory leaks
//			  05/08/2002 - Magicdude - Renamed cfgPrivateFindEntry to _cfgFindEntry 
//			  06/08/2002 - Magicdude - Added default parameters to cfgGet* 
//			  06/08/2002 - Magicdude - Fixed it so it doesnt append the EOF character to the final value.
////
//Copyright (C) Chris Barnaby 2002  
 
//This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License  
//as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 
//This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied  
//warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 
//You should have received a copy of the GNU General Public License along with this program; if not, write to the  
//Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

#include 
#include 
#include 

#include "cfg.h"

void cfgRelease( cfg_ptr cfg )
{
	if( !cfg ){
		return;
	}

	cfgcategory_ptr curr_category;
	cfgentry_ptr curr_entry;

	curr_category = cfg->categories;

	while ( curr_category != NULL )
	{
		curr_entry = curr_category->entries;

		while ( curr_entry != NULL )
		{
			if ( curr_entry->next != NULL )
			{
				curr_entry = curr_entry->next;
				free( curr_entry->prev );
			}
			else
			{
				free( curr_entry );
				curr_entry = NULL;
			}
		}

		if ( curr_category->next != NULL )
		{
			curr_category = curr_category->next;
			free( curr_category->prev );
		}
		else
		{
			free( curr_category );
			curr_category = NULL;
		}
	}

	free( cfg );
}

cfg_ptr cfgParse( const char *filename )
{
	FILE *fp;
	char c;
	cfg_ptr cfg;
	cfgcategory_ptr curr_category;
	cfgentry_ptr curr_entry;
	int state;

	fp = fopen( filename, "rt" );

	if ( fp == NULL )
	{
		return NULL;
	}

	cfg = (cfg_ptr)malloc( sizeof( cfg_t ) );
	memset( cfg, 0, sizeof( cfg_t ) );
	strncpy( cfg->filename, filename, 29 );
	curr_category = NULL;
	curr_entry = NULL;

	while ( feof( fp ) == 0 )
	{
		c = fgetc( fp );
		 
		if ( c == EOF ) 
			break; 

		switch ( c )
		{
		case '[':
			{
				if ( cfg->categories == NULL )
				{
					cfg->categories = (cfgcategory_ptr)malloc( sizeof( cfgcategory_t ) );
					memset( cfg->categories, 0, sizeof( cfgcategory_t ) );
					curr_category = cfg->categories;
				}
				else
				{
					if ( curr_category->next == NULL )
					{
						curr_category->next = (cfgcategory_ptr)malloc( sizeof( cfgcategory_t ) );
						memset( curr_category->next, 0, sizeof( cfgcategory_t ) );
						curr_category->next->prev = curr_category;
						curr_category = curr_category->next;
					}
				}

				state = STATE_CATEGORY;
			}break;
		case ']':
			{
				state = STATE_GLOBAL;
			}break;
		case '=':
			{
				state = STATE_VALUE;
			}break;
		case '\n':
			{
				if ( curr_category->entries == NULL )
				{
					curr_category->entries = (cfgentry_ptr)malloc( sizeof( cfgentry_t ) );
					memset( curr_category->entries, 0, sizeof( cfgentry_t ) );
					curr_entry = curr_category->entries;
				}
				else
				{
					if ( curr_entry->next == NULL )
					{
						curr_entry->next = (cfgentry_ptr)malloc( sizeof( cfgentry_t ) );
						memset( curr_entry->next, 0, sizeof( cfgentry_t ) );
						curr_entry->next->prev = curr_entry;
						curr_entry = curr_entry->next;
					}
				}
			
				state = STATE_ENTRY;
			}break;
		default:
			{
				if ( state == STATE_CATEGORY )
					curr_category->name[ strlen( curr_category->name ) ] = c;
				if ( state == STATE_ENTRY )
					curr_entry->name[ strlen( curr_entry->name ) ] = c;
				if ( state == STATE_VALUE )
					curr_entry->val[ strlen( curr_entry->val ) ] = c;
			}
		}
	}

	fclose( fp );

	return cfg;
}

cfgentry_ptr _cfgFindEntry( cfg_ptr cfg, const char *category, const char *variable )
{
	if( !cfg ){
		return NULL;
	}

	cfgcategory_ptr curr_category;
	cfgentry_ptr curr_entry;

	// First locate the category
	curr_category = cfg->categories;
	
	while ( curr_category != NULL )
	{
		if ( stricmp( curr_category->name, category ) == 0 )
			break;
		else
			curr_category = curr_category->next;
	}

	if ( curr_category == NULL )
		return NULL;

	// Next locate the entry and return the integer result
	curr_entry = curr_category->entries;

	while ( curr_entry != NULL )
	{
		if ( stricmp( curr_entry->name, variable ) == 0 )
			break;
		else
			curr_entry = curr_entry->next;
	}

	return curr_entry;
}

int cfgGetInt( cfg_ptr cfg, const char *category, const char *variable, int def )
{
	cfgentry_ptr entry;

	entry = _cfgFindEntry( cfg, category, variable );

	if ( entry == NULL )
		return def;

	return atoi( entry->val );
} 
 
void cfgSetInt( cfg_ptr cfg, const char *category, const char *variable, int def ) 
{ 
	char str[255]; 
 
	itoa( def, str, 10 ); 
 
	cfgSetString( cfg, category, variable, str ); 
}

const char *cfgGetString( cfg_ptr cfg, const char *category, const char *variable, const char *def )
{
	cfgentry_ptr entry;

	entry = _cfgFindEntry( cfg, category, variable );

	if ( entry == NULL )
		return def;

	return entry->val;
}
 
void cfgSetString( cfg_ptr cfg, const char *category, const char *variable, const char *val ) 
{ 
	cfgentry_ptr entry; 
	cfgcategory_ptr curr_category; 
 
	curr_category = cfg->categories; 
 
	while ( curr_category->next != NULL ) 
	{ 
		if ( stricmp( curr_category->name, category ) == 0 ) 
			break; 
 
		curr_category = curr_category->next; 
	} 
 
	if ( curr_category->next != NULL ) 
	{ 
		entry = curr_category->entries; 
 
		while ( entry->next != NULL ) 
		{ 
			if ( stricmp( entry->name, variable ) == 0 ) 
				break; 
 
			entry = entry->next; 
		} 
	} 
	else 
	{ 
		curr_category->next = (cfgcategory_ptr)malloc( sizeof( cfgcategory_t ) ); 
		memset( curr_category->next, 0, sizeof( cfgcategory_t ) ); 
		curr_category->next->prev = curr_category; 
		memset( curr_category->next->name, 0, strlen( category ) + 1 ); 
		strcpy( curr_category->next->name, category ); 
 
		entry = (cfgentry_ptr)malloc( sizeof( cfgentry_t ) ); 
		memset( entry, 0, sizeof( cfgentry_t ) ); 
		memset( entry->name, 0, strlen( variable ) + 1 ); 
		strcpy( entry->name, variable ); 
		memset( entry->val, 0, strlen( val ) + 1 ); 
		strcpy( entry->val, val ); 
 
		curr_category->next->entries = entry; 
	} 
 
	if ( entry->next != NULL ) 
	{ 
		memset( entry->val, 0, strlen( val ) + 1 ); 
		strcpy( entry->val, val ); 
	} 
	else 
	{ 
		entry->next = (cfgentry_ptr)malloc( sizeof( cfgentry_t ) ); 
		memset( entry->next, 0, sizeof( cfgentry_t ) ); 
		entry->next->prev = entry; 
		memset( entry->next->name, 0, strlen( variable ) + 1 ); 
		strcpy( entry->next->name, variable ); 
		memset( entry->next->val, 0, strlen( val ) + 1 ); 
		strcpy( entry->next->val, val ); 
	} 
} 

int cfgGetBoolean( cfg_ptr cfg, const char *category, const char *variable, int def )
{
	cfgentry_ptr entry;

	entry = _cfgFindEntry( cfg, category, variable );

	if ( entry == NULL )
		return def;

	if ( stricmp( entry->val, "true" ) == 0 )
		return 1;
	else
		return 0;
} 
 
void cfgSetBoolean( cfg_ptr cfg, const char *category, const char *variable, int def ) 
{ 
	if ( def == 1 ) 
	{ 
		cfgSetString( cfg, category, variable, "true" ); 
	} 
	else 
	{ 
		cfgSetString( cfg, category, variable, "false" ); 
	} 
}
 
void cfgWrite( cfg_ptr cfg ) 
{ 
	cfgentry_ptr entry; 
	cfgcategory_ptr category; 
	FILE *fp; 
 
	category = cfg->categories; 
 
	fp = fopen( cfg->filename, "wt" ); 
 
	while ( category != NULL ) 
	{ 
		fprintf( fp, "[%s]\n", category->name ); 
 
		entry = category->entries; 
 
		while ( entry != NULL ) 
		{ 
			if ( strcmp( entry->name, "" ) != 0 ) 
				fprintf( fp, "%s=%s\n", entry->name, entry->val ); 
			entry = entry->next; 
		} 
 
		fprintf( fp, "\n" ); 
 
		category = category->next; 
	} 
 
	fclose( fp ); 
}