/****************************************************************************************************/
/* */
/* option.lib.c: */
/* */
/****************************************************************************************************/
/****************************************************************************************************/
/* */
/* Copyright (C) 2004 Joerg Kunze */
/* */
/* This file is part of siliconBrain. */
/* */
/* siliconBrain 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. */
/* */
/* siliconBrain 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 <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <errno.h>
#include <pwd.h>
#include "siliconBrainLib"
#include "siliconBrainSpecification"
#include "siliconBrainOption"
// static const char *siliconBrainRelease = "$siliconBrainRelease: 0.2.3 $";
// static const char *siliconBrainRcsIdentifier = "$Id: option.lib.c,v 1.8 2004/12/14 23:31:26 joerg Exp $";
// static const char *siliconBrainSaveStamp = "$siliconBrainSaveStamp: 2004/10/29 23:40:58, Joerg Kunze$";
/****************************************************************************************************/
/* */
/* typedef: */
/* */
/****************************************************************************************************/
typedef enum {
localContextNo,
localContextInPackage,
localContextInOption,
localContextOptionUnknown,
} LocalXmlContextState;
typedef struct {
OptionProcessed *options;
OptionProcessed *currentOption;
LocalXmlContextState state;
Obstack *obstack;
GHashTable *optionNames;
} Local;
/****************************************************************************************************/
/* */
/* parser: */
/* */
/****************************************************************************************************/
static void xmlStartElement(
GMarkupParseContext *context,
const gchar *name,
const gchar **attribute,
const gchar **value,
gpointer userData,
GError **error
) {
Local *user = userData;
switch( user->state ) {
case localContextNo:
user->state = localContextInPackage;
break;
case localContextInPackage:
user->currentOption = g_hash_table_lookup( user->optionNames, name );
user->state = user->currentOption ? localContextInOption : localContextOptionUnknown;
break;
case localContextInOption:
case localContextOptionUnknown:
break;
}
}
static void xmlText(
GMarkupParseContext *context,
const gchar *text,
gsize textLength,
gpointer user_data,
GError **error
) {
Local *user = user_data;
/*---------------------------------*/
/* ignore text in ceratin contexts */
/*---------------------------------*/
switch( user->state ) {
case localContextNo:
case localContextInPackage:
case localContextOptionUnknown:
return;
default: break;
}
if( user->currentOption->alreadyConfigured ) return;
Obstack *obstack = user->obstack;
const char *textEnd = text + textLength - 1;
char *textSavedAsString;
/*--------------------------------------------*/
/* trim text: skip left and right white space */
/*--------------------------------------------*/
while( textLength ) {
switch( *text ) {
case ' ': case '\n': case '\t':
--textLength;
++text;
break;
default:
goto endOfPrefix;
}
}
endOfPrefix:
while( textLength ) {
switch( *textEnd ) {
case ' ': case '\n': case '\t': case 0:
--textLength;
--textEnd;
break;
default:
goto endOfSuffix;
}
}
endOfSuffix:
textSavedAsString = obstack_copy0( obstack, text, textLength );
switch( user->currentOption->optionType ) {
case optionValue:
*((char **)user->currentOption->value) = textSavedAsString;
break;
case optionFlag:
*((bool *)user->currentOption->value) = stringToBool( textSavedAsString );
break;
}
user->currentOption->alreadyConfigured = true;
}
static void xmlEndElement(
GMarkupParseContext *context,
const gchar *element_name,
gpointer user_data,
GError **error
) {
Local *user = user_data;
switch( user->state ) {
case localContextNo:
user->state = localContextNo;
break;
case localContextInPackage:
user->state = localContextNo;
break;
case localContextInOption:
if( !user->currentOption->alreadyConfigured ) xmlText( context, "", 0, user_data, error );
case localContextOptionUnknown:
user->state = localContextInPackage;
break;
}
}
static GMarkupParser parser = { &xmlStartElement, &xmlEndElement, &xmlText, 0, 0 };
/****************************************************************************************************/
/* */
/* */
/* */
/****************************************************************************************************/
void optionReadOptions( OptionProcessed options[], Obstack *obstack, const char * const packageName ) {
char xmlStreamChunk[ 1234 ];
size_t xmlStreamChunkLength;
GError *error;
Local local = {
.options = options,
.currentOption = 0,
.state = localContextNo,
.obstack = obstack,
.optionNames = 0
};
local.optionNames = g_hash_table_new( g_str_hash, g_str_equal );
OptionProcessed *option;
for( option = local.options; option->name; ++option )
g_hash_table_insert( local.optionNames, (char *)option->name, option );
bool *complete = ((OptionProcessed *)g_hash_table_lookup( local.optionNames, "complete" ))->value;
GMarkupParseContext *context = g_markup_parse_context_new( &parser, 0, &local, 0 );
FILE *xmlSource = 0;
#define defaultNumberOfConfigurationDirectories 42
char *configurationDirectoriesImplementation[ defaultNumberOfConfigurationDirectories ] = {
"./" ,
"~/" ,
"/etc/",
"" ,
0
};
char **configurationDirectories = configurationDirectoriesImplementation;
char **configurationDirectory;
char *configurationPath = getenv( "siliconBrainConfigurationPath" );
char *configurationPathIterator;
if( configurationPath ) {
int numberOfDirectoryEntries = 1;
for( configurationPathIterator = configurationPath; *configurationPathIterator; ++configurationPathIterator ) {
if( *configurationPathIterator == ':' ) ++numberOfDirectoryEntries;
}
if( numberOfDirectoryEntries <= defaultNumberOfConfigurationDirectories ) {
configurationDirectories = obstack_alloc( obstack, numberOfDirectoryEntries * sizeof( *configurationDirectory ) + 1 );
}
configurationPathIterator = configurationPath;
configurationDirectory = configurationDirectories;
char *begin;
int length;
while( true ) {
while( *configurationPathIterator == ' ' || *configurationPathIterator == '\t' ) ++configurationPathIterator;
begin = configurationPathIterator;
length = 0;
while( *configurationPathIterator != ':' && *configurationPathIterator != 0 ) ++length, ++configurationPathIterator;
while( *(begin+length-1) == ' ' || *(begin+length-1) == '\t' ) --length;
if( *(begin+length-1) != '/' ) ++length;
*configurationDirectory = obstack_copy0( obstack, begin, length );
if( *(*configurationDirectory+length-1) != '/' ) *(*configurationDirectory+length-1) = '/';
++configurationDirectory; *configurationDirectory = 0;
if( *configurationPathIterator == 0 ) break;
else ++configurationPathIterator;
}
*configurationDirectory = 0;
}
char *fileName;
int saveStderr = dup( STDERR_FILENO );
freopen( "/dev/null", "w", stderr );
for( configurationDirectory = configurationDirectories; !*complete && *configurationDirectory; ++configurationDirectory ) {
osprintf( obstack, &fileName, "%s%s.configuration", *configurationDirectory, packageName );
if( !(xmlSource = popen( fileName, "r" ) ) )
continue;
while( xmlStreamChunkLength = fread( xmlStreamChunk, 1, sizeof( xmlStreamChunk ) - 1, xmlSource ) )
g_markup_parse_context_parse( context, xmlStreamChunk, xmlStreamChunkLength, &error);
}
fclose( stderr );
stderr = fdopen( saveStderr, "w+" );
g_markup_parse_context_end_parse( context, &error );
g_markup_parse_context_free ( context );
g_hash_table_destroy( local.optionNames );
}