/* $Id: conf.c 13 2011-04-20 15:41:43Z mmamonski $ */
/*
* PSNC DRMAA 2.0 utilities library
* Copyright (C) 2012 Poznan Supercomputing and Networking Center
*
* 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 3 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, see .
*/
#ifdef HAVE_CONFIG_H
# include
#endif
#include
#include
#include
#include
#include
#include
#include
#include
#ifndef lint
static char rcsid[]
# ifdef __GNUC__
__attribute__ ((unused))
# endif
= "$Id: conf.c 13 2011-04-20 15:41:43Z mmamonski $";
#endif
fsd_conf_dict_t *
fsd_conf_read(
fsd_conf_dict_t * volatile configuration,
const char *filename, bool must_exist,
const char *content, size_t content_len
)
{
fsd_conf_dict_t *volatile result = NULL;
fsd_conf_parser_t *parser = NULL;
fsd_conf_lexer_t *lexer = NULL;
char *file_content = NULL;
size_t file_content_len = 0;
fsd_log_enter((
"(filename=%s, must_exist=%s, content=%s)",
filename, must_exist ? "true" : "false", content
));
TRY
{
fsd_malloc( parser, fsd_conf_parser_t );
fsd_malloc( lexer, fsd_conf_lexer_t );
parser->lexer = lexer;
parser->result = NULL;
parser->n_errors = 0;
parser->errors = NULL;
lexer->parser = parser;
lexer->filename = filename;
lexer->buffer = NULL;
lexer->buflen = 0;
lexer->pos = NULL;
lexer->lineno = 0;
lexer->cline = NULL;
if( filename )
TRY
{
fsd_read_file(
filename, must_exist,
&file_content, &file_content_len
);
}
EXCEPT_DEFAULT
{
const fsd_exc_t *e = fsd_exc_get();
if( must_exist )
fsd_exc_raise_fmt( e->code(e), "%s: %s", filename, e->message(e) );
else
{
fsd_log_warning(( "%s: %s", filename, e->message(e) ));
}
}
END_TRY
if( file_content )
{
lexer->buffer = (const uchar*)file_content;
lexer->buflen = file_content_len;
fsd_log_trace(( "content from file" ));
}
else if( content )
{
lexer->buffer = (const uchar*)content;
lexer->buflen = content_len;
fsd_log_trace(( "content from memory" ));
}
if( lexer->buffer )
{
lexer->pos = lexer->cline = lexer->buffer;
lexer->lineno = 1;
fsd_conf_parse( parser, lexer );
result = parser->result;
}
if( parser->n_errors > 0 )
{
fsd_exc_raise(
fsd_exc_new(
FSD_ERRNO_INTERNAL_ERROR,
fsd_explode( (const char*const*)parser->errors, '\n',
parser->n_errors ),
true
)
);
}
}
ELSE
{
configuration = fsd_conf_dict_merge( configuration, result );
result = NULL;
}
FINALLY
{
if( parser )
{
if( parser->errors )
{
int i;
for( i=0; i < parser->n_errors; i++ )
fsd_free( parser->errors[i] );
fsd_free( parser->errors );
}
fsd_free( parser );
}
fsd_free( lexer );
fsd_free( file_content );
fsd_conf_dict_destroy( result );
}
END_TRY
fsd_log_return(( "" ));
return configuration;
}
int
fsd_conf_lex(
union YYSTYPE *lvalp, struct YYLTYPE *locp,
fsd_conf_lexer_t *lexer
)
{
const uchar *c = lexer->pos;
const uchar *end = lexer->buffer + lexer->buflen;
const char *error = NULL;
int result;
while( clineno++;
lexer->cline = c+1;
case ' ': case '\t': case '\r': /* no break */
c++;
break;
default:
goto token_begin;
}
token_begin:
locp->first_line = lexer->lineno;
locp->first_column = c - lexer->cline + 1;
if( c == end )
result = 0;
else
switch( *c )
{
case ':': case ',': case '{': case '}':
result = *c++;
break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
{
int v = 0;
while( c < end && '0' <= *c && *c <= '9' )
{
v *= 10;
v += *c - '0';
c++;
}
lvalp->integer = v;
result = INTEGER;
break;
}
case '"': case '\'':
{
uchar delimiter;
const uchar *begin;
delimiter = *c++;
begin = c;
while( c < end && *c != delimiter )
c++;
if( c == end )
{
error = "expected string delimiter but EOF found";
result = LEXER_ERROR;
}
else
{
lvalp->string = fsd_strndup( (const char*)begin, c-begin );
result = STRING;
c++;
}
break;
}
default:
{
const uchar *begin = c;
while( cstring = fsd_strndup( (const char*)begin, c-begin );
result = STRING;
break;
}
}
locp->last_line = lexer->lineno;
locp->last_column = c - lexer->cline;
if( locp->last_column < locp->first_column )
locp->last_column = locp->first_column;
lexer->pos = c;
if( error )
fsd_conf_error( locp, lexer->parser, lexer, error );
return result;
}
void
fsd_conf_error(
struct YYLTYPE *locp,
fsd_conf_parser_t *parser, fsd_conf_lexer_t *lexer,
const char *fmt, ...
)
{
char *volatile message = NULL;
va_list args;
TRY
{
va_start( args, fmt );
message = fsd_vasprintf( fmt, args );
va_end( args );
fsd_realloc( parser->errors, parser->n_errors+1, char* );
parser->errors[ parser->n_errors ] = fsd_asprintf(
"%s:%d:%d: %s",
parser->lexer->filename, locp->first_line, locp->first_column,
message );
fsd_log_error(("Parser error: %s:%d:%d: %s", parser->lexer->filename, locp->first_line, locp->first_column, message ));
parser->n_errors ++;
}
FINALLY
{ fsd_free( message ); }
END_TRY
}
fsd_conf_option_t *
fsd_conf_option_create( fsd_conf_type_t type, void *value )
{
fsd_conf_option_t *o = NULL;
fsd_malloc( o, fsd_conf_option_t );
o->type = type;
switch( type )
{
case FSD_CONF_INTEGER:
o->val.integer = *(int*)value;
break;
case FSD_CONF_STRING:
o->val.string = (char*)value;
break;
case FSD_CONF_DICT:
o->val.dict = (fsd_conf_dict_t*)value;
break;
default:
fsd_assert(false);
break;
}
return o;
}
void
fsd_conf_option_destroy( fsd_conf_option_t *option )
{
if( option == NULL )
return;
switch( option->type )
{
case FSD_CONF_INTEGER:
break;
case FSD_CONF_STRING:
fsd_free( option->val.string );
break;
case FSD_CONF_DICT:
fsd_conf_dict_destroy( option->val.dict );
break;
default:
fsd_assert( false );
}
fsd_free( option );
}
fsd_conf_option_t *
fsd_conf_option_merge( fsd_conf_option_t *lhs, fsd_conf_option_t *rhs )
{
if( lhs->type == rhs->type && rhs->type == FSD_CONF_DICT )
{
lhs->val.dict = fsd_conf_dict_merge( lhs->val.dict, rhs->val.dict );
fsd_free( rhs );
return lhs;
}
else
{
fsd_conf_option_destroy( lhs );
return rhs;
}
}
void
fsd_conf_option_dump( fsd_conf_option_t *option )
{
if( option == NULL )
{
printf( "(null)" );
return;
}
switch( option->type )
{
case FSD_CONF_STRING:
printf( "\"%s\"", option->val.string );
break;
case FSD_CONF_INTEGER:
printf( "%d", option->val.integer );
break;
case FSD_CONF_DICT:
fsd_conf_dict_dump( option->val.dict );
break;
}
}
struct fsd_conf_dict_s {
fsd_conf_dict_t *next;
char *key;
fsd_conf_option_t *value;
};
fsd_conf_dict_t *
fsd_conf_dict_create(void)
{
fsd_conf_dict_t *dict = NULL;
fsd_malloc( dict, fsd_conf_dict_t );
dict->next = NULL;
dict->key = NULL;
dict->value = NULL;
return dict;
}
void
fsd_conf_dict_destroy( fsd_conf_dict_t *dict )
{
fsd_conf_dict_t *i;
for( i = dict; i != NULL; )
{
fsd_conf_dict_t *c = i;
i = i->next;
fsd_free( c->key );
fsd_conf_option_destroy( c->value );
fsd_free( c );
}
}
fsd_conf_option_t *
fsd_conf_dict_get(
fsd_conf_dict_t *dict, const char *key )
{
fsd_conf_dict_t *i;
if( dict == NULL || key == NULL )
return NULL;
for( i = dict->next; i != NULL; i = i->next )
{
if( !strcmp( i->key, key ) )
return i->value;
}
return NULL;
}
void
fsd_conf_dict_set(
fsd_conf_dict_t *dict, const char *key, fsd_conf_option_t *value
)
{
fsd_conf_dict_t *i;
for( i = dict->next; i != NULL; i = i->next )
{
if( !strcmp( i->key, key ) )
break;
}
if( i != NULL )
{
fsd_conf_option_destroy( i->value );
i->value = value;
}
else
{
fsd_conf_dict_t* volatile n = NULL;
TRY
{
fsd_malloc( n, fsd_conf_dict_t );
n->key = fsd_strdup( key );
n->value = value;
}
EXCEPT_DEFAULT
{
fsd_free( n );
fsd_exc_reraise();
}
ELSE
{
n->next = dict->next;
dict->next = n;
}
END_TRY
}
}
fsd_conf_dict_t *
fsd_conf_dict_merge( fsd_conf_dict_t *lhs, fsd_conf_dict_t *rhs )
{
fsd_conf_dict_t *i, *j;
if( lhs == NULL )
return rhs;
if( rhs == NULL )
return lhs;
for( j = rhs->next; j != NULL; )
{
fsd_conf_dict_t *r = j;
j = j->next;
for( i = lhs->next; i != NULL; i = i->next )
if( !strcmp( i->key, r->key ) )
break;
if( i != NULL )
{
i->value = fsd_conf_option_merge( i->value, r->value );
fsd_free( r->key );
fsd_free( r );
}
else
{
r->next = lhs->next;
lhs->next = r;
}
}
fsd_free( rhs );
return lhs;
}
void
fsd_conf_dict_dump( fsd_conf_dict_t *dict )
{
fsd_conf_dict_t *i;
if( dict == NULL )
{
printf( "(null)" );
return;
}
printf( "{" );
for( i=dict->next; i; i = i->next )
{
if( i != dict->next )
printf( "," );
printf( " %s=", i->key );
fsd_conf_option_dump( i->value );
}
printf( " }" );
}
fsd_conf_option_t *
fsd_conf_option_create_noraise( fsd_conf_type_t type, void *value )
{
fsd_conf_option_t *volatile result = NULL;
TRY{ result = fsd_conf_option_create( type, value ); }
EXCEPT_DEFAULT{}
END_TRY
return result;
}
fsd_conf_dict_t *
fsd_conf_dict_create_noraise(void)
{
fsd_conf_dict_t *volatile result = NULL;
TRY{ result = fsd_conf_dict_create(); }
EXCEPT_DEFAULT{}
END_TRY
return result;
}
int
fsd_conf_dict_set_noraise(
fsd_conf_dict_t *dict, const char *key, fsd_conf_option_t *value )
{
volatile int rc = FSD_ERRNO_SUCCESS;
TRY{ fsd_conf_dict_set( dict, key, value ); }
EXCEPT_DEFAULT
{
const fsd_exc_t *e = fsd_exc_get();
rc = e->code(e);
}
END_TRY
return rc;
}