2001-08-21 16:56:08 +04:00
/*
2001-10-03 15:06:31 +04:00
* Copyright ( C ) 2001 Sistina Software ( UK ) Limited .
2001-08-21 16:56:08 +04:00
*
2001-10-31 15:47:01 +03:00
* This file is released under the LGPL .
2001-08-21 16:56:08 +04:00
*/
2002-11-18 17:01:16 +03:00
# include "lib.h"
# include "config.h"
# include "crc.h"
# include "pool.h"
# include "device.h"
2001-08-21 16:56:08 +04:00
# include <sys/stat.h>
# include <sys/mman.h>
# include <unistd.h>
# include <fcntl.h>
# include <ctype.h>
2001-09-13 16:38:31 +04:00
2001-08-21 16:56:08 +04:00
enum {
2002-04-24 22:20:51 +04:00
TOK_INT ,
TOK_FLOAT ,
TOK_STRING ,
TOK_EQ ,
TOK_SECTION_B ,
TOK_SECTION_E ,
TOK_ARRAY_B ,
TOK_ARRAY_E ,
TOK_IDENTIFIER ,
2001-08-21 16:56:08 +04:00
TOK_COMMA ,
TOK_EOF
} ;
struct parser {
2002-11-18 17:01:16 +03:00
char * fb , * fe ; /* file limits */
2001-08-21 16:56:08 +04:00
2002-04-24 22:20:51 +04:00
int t ; /* token limits and type */
2002-11-18 17:01:16 +03:00
char * tb , * te ;
2001-08-21 16:56:08 +04:00
2002-04-24 22:20:51 +04:00
int fd ; /* descriptor for file being parsed */
2001-08-21 16:56:08 +04:00
int line ; /* line number we are on */
2002-04-24 22:20:51 +04:00
struct pool * mem ;
2001-08-21 16:56:08 +04:00
} ;
struct cs {
2002-11-18 17:01:16 +03:00
struct config_tree cf ;
2002-04-24 22:20:51 +04:00
struct pool * mem ;
2002-11-18 17:01:16 +03:00
time_t timestamp ;
char * filename ;
2001-08-21 16:56:08 +04:00
} ;
2003-02-03 23:08:45 +03:00
static void _get_token ( struct parser * p , int tok_prev ) ;
2001-08-21 16:56:08 +04:00
static void _eat_space ( struct parser * p ) ;
static struct config_node * _file ( struct parser * p ) ;
static struct config_node * _section ( struct parser * p ) ;
static struct config_value * _value ( struct parser * p ) ;
static struct config_value * _type ( struct parser * p ) ;
static int _match_aux ( struct parser * p , int t ) ;
static struct config_value * _create_value ( struct parser * p ) ;
static struct config_node * _create_node ( struct parser * p ) ;
static char * _dup_tok ( struct parser * p ) ;
# define MAX_INDENT 32
# define match(t) do {\
if ( ! _match_aux ( p , ( t ) ) ) { \
2001-10-23 15:50:49 +04:00
log_error ( " Parse error at line %d: unexpected token " , p - > line ) ; \
2001-08-21 16:56:08 +04:00
return 0 ; \
} \
} while ( 0 ) ;
2002-01-07 13:23:52 +03:00
static int _tok_match ( const char * str , const char * b , const char * e )
{
while ( * str & & ( b ! = e ) ) {
if ( * str + + ! = * b + + )
return 0 ;
}
return ! ( * str | | ( b ! = e ) ) ;
}
2001-08-21 16:56:08 +04:00
/*
* public interface
*/
2002-11-18 17:01:16 +03:00
struct config_tree * create_config_tree ( void )
2001-08-21 16:56:08 +04:00
{
2002-04-24 22:20:51 +04:00
struct cs * c ;
struct pool * mem = pool_create ( 10 * 1024 ) ;
if ( ! mem ) {
stack ;
return 0 ;
}
if ( ! ( c = pool_alloc ( mem , sizeof ( * c ) ) ) ) {
stack ;
pool_destroy ( mem ) ;
return 0 ;
}
c - > mem = mem ;
c - > cf . root = ( struct config_node * ) NULL ;
2002-11-18 17:01:16 +03:00
c - > timestamp = 0 ;
c - > filename = NULL ;
2002-04-24 22:20:51 +04:00
return & c - > cf ;
2001-08-21 16:56:08 +04:00
}
2002-11-18 17:01:16 +03:00
void destroy_config_tree ( struct config_tree * cf )
2001-08-21 16:56:08 +04:00
{
2002-04-24 22:20:51 +04:00
pool_destroy ( ( ( struct cs * ) cf ) - > mem ) ;
2001-08-21 16:56:08 +04:00
}
2003-07-05 02:34:56 +04:00
int read_config_fd ( struct config_tree * cf , struct device * dev ,
2002-12-20 02:25:55 +03:00
off_t offset , size_t size , off_t offset2 , size_t size2 ,
2002-11-18 17:01:16 +03:00
checksum_fn_t checksum_fn , uint32_t checksum )
2001-08-21 16:56:08 +04:00
{
struct cs * c = ( struct cs * ) cf ;
2002-04-24 22:20:51 +04:00
struct parser * p ;
2002-11-18 17:01:16 +03:00
int r = 0 ;
2003-07-05 02:34:56 +04:00
int use_mmap = 1 ;
off_t mmap_offset = 0 ;
2002-04-24 22:20:51 +04:00
if ( ! ( p = pool_alloc ( c - > mem , sizeof ( * p ) ) ) ) {
stack ;
return 0 ;
}
2001-08-21 16:56:08 +04:00
p - > mem = c - > mem ;
2003-07-05 02:34:56 +04:00
/* Only use mmap with regular files */
if ( ! ( dev - > flags & DEV_REGULAR ) | | size2 )
use_mmap = 0 ;
if ( use_mmap ) {
2003-03-24 21:08:53 +03:00
mmap_offset = offset % getpagesize ( ) ;
2002-11-18 17:01:16 +03:00
/* memory map the file */
p - > fb = mmap ( ( caddr_t ) 0 , size + mmap_offset , PROT_READ ,
2003-07-05 02:34:56 +04:00
MAP_PRIVATE , dev_fd ( dev ) , offset - mmap_offset ) ;
2002-11-18 17:01:16 +03:00
if ( p - > fb = = ( caddr_t ) ( - 1 ) ) {
2003-07-05 02:34:56 +04:00
log_sys_error ( " mmap " , dev_name ( dev ) ) ;
2002-11-18 17:01:16 +03:00
goto out ;
}
p - > fb = p - > fb + mmap_offset ;
2003-07-05 02:34:56 +04:00
} else {
if ( ! ( p - > fb = dbg_malloc ( size + size2 ) ) ) {
stack ;
return 0 ;
}
if ( ! dev_read ( dev , ( uint64_t ) offset , size , p - > fb ) ) {
log_error ( " Read from %s failed " , dev_name ( dev ) ) ;
goto out ;
}
if ( size2 ) {
if ( ! dev_read ( dev , ( uint64_t ) offset2 , size2 ,
p - > fb + size ) ) {
log_error ( " Circular read from %s failed " ,
dev_name ( dev ) ) ;
goto out ;
}
}
2002-11-18 17:01:16 +03:00
}
if ( checksum_fn & & checksum ! =
( checksum_fn ( checksum_fn ( INITIAL_CRC , p - > fb , size ) ,
p - > fb + size , size2 ) ) ) {
2003-07-05 02:34:56 +04:00
log_error ( " %s: Checksum error " , dev_name ( dev ) ) ;
2002-11-18 17:01:16 +03:00
goto out ;
}
p - > fe = p - > fb + size + size2 ;
/* parse */
p - > tb = p - > te = p - > fb ;
p - > line = 1 ;
2003-02-03 23:08:45 +03:00
_get_token ( p , TOK_SECTION_E ) ;
2002-11-18 17:01:16 +03:00
if ( ! ( cf - > root = _file ( p ) ) ) {
stack ;
goto out ;
}
r = 1 ;
out :
2003-07-05 02:34:56 +04:00
if ( ! use_mmap )
2002-11-18 17:01:16 +03:00
dbg_free ( p - > fb ) ;
else {
/* unmap the file */
2003-03-20 17:29:28 +03:00
if ( munmap ( ( char * ) ( p - > fb - mmap_offset ) , size + mmap_offset ) ) {
2003-07-05 02:34:56 +04:00
log_sys_error ( " munmap " , dev_name ( dev ) ) ;
2002-11-18 17:01:16 +03:00
r = 0 ;
}
}
return r ;
}
int read_config_file ( struct config_tree * cf , const char * file )
{
struct cs * c = ( struct cs * ) cf ;
struct stat info ;
2003-07-05 02:34:56 +04:00
struct device * dev ;
int r = 1 ;
2002-11-18 17:01:16 +03:00
if ( stat ( file , & info ) ) {
2002-04-24 22:20:51 +04:00
log_sys_error ( " stat " , file ) ;
return 0 ;
}
2002-11-18 17:01:16 +03:00
if ( ! S_ISREG ( info . st_mode ) ) {
log_error ( " %s is not a regular file " , file ) ;
return 0 ;
}
2002-04-24 22:20:51 +04:00
if ( info . st_size = = 0 ) {
log_verbose ( " %s is empty " , file ) ;
return 1 ;
}
2003-07-05 02:34:56 +04:00
if ( ! ( dev = dev_create_file ( file , NULL , NULL ) ) ) {
stack ;
return 0 ;
}
if ( ! dev_open_flags ( dev , O_RDONLY , 0 , 0 ) ) {
stack ;
2002-04-24 22:20:51 +04:00
return 0 ;
}
2003-07-05 02:34:56 +04:00
r = read_config_fd ( cf , dev , 0 , ( size_t ) info . st_size , 0 , 0 ,
2002-11-18 17:01:16 +03:00
( checksum_fn_t ) NULL , 0 ) ;
2003-07-05 02:34:56 +04:00
dev_close ( dev ) ;
2002-11-18 17:01:16 +03:00
c - > timestamp = info . st_mtime ;
c - > filename = pool_strdup ( c - > mem , file ) ;
return r ;
}
2003-01-07 00:09:04 +03:00
time_t config_file_timestamp ( struct config_tree * cf )
{
struct cs * c = ( struct cs * ) cf ;
return c - > timestamp ;
}
2002-11-18 17:01:16 +03:00
/*
* Returns 1 if config file reloaded
*/
int reload_config_file ( struct config_tree * * cf )
{
struct config_tree * new_cf ;
struct cs * c = ( struct cs * ) * cf ;
struct cs * new_cs ;
struct stat info ;
2003-07-05 02:34:56 +04:00
struct device * dev ;
int r ;
2002-11-18 17:01:16 +03:00
2002-11-26 15:14:37 +03:00
if ( ! c - > filename )
return 0 ;
2002-11-18 17:01:16 +03:00
if ( stat ( c - > filename , & info ) = = - 1 ) {
if ( errno = = ENOENT )
return 1 ;
log_sys_error ( " stat " , c - > filename ) ;
log_error ( " Failed to reload configuration file " ) ;
2002-04-24 22:20:51 +04:00
return 0 ;
}
2002-11-18 17:01:16 +03:00
if ( ! S_ISREG ( info . st_mode ) ) {
log_error ( " Configuration file %s is not a regular file " ,
c - > filename ) ;
return 0 ;
2002-04-24 22:20:51 +04:00
}
2002-11-18 17:01:16 +03:00
/* Unchanged? */
if ( c - > timestamp = = info . st_mtime )
return 0 ;
log_verbose ( " Detected config file change: Reloading %s " , c - > filename ) ;
if ( info . st_size = = 0 ) {
log_verbose ( " Config file reload: %s is empty " , c - > filename ) ;
return 0 ;
}
2003-07-05 02:34:56 +04:00
if ( ! ( new_cf = create_config_tree ( ) ) ) {
log_error ( " Allocation of new config_tree failed " ) ;
2002-11-18 17:01:16 +03:00
return 0 ;
2002-04-24 22:20:51 +04:00
}
2003-07-05 02:34:56 +04:00
if ( ! ( dev = dev_create_file ( c - > filename , NULL , NULL ) ) ) {
stack ;
2002-11-18 17:01:16 +03:00
return 0 ;
}
2003-07-05 02:34:56 +04:00
if ( ! dev_open_flags ( dev , O_RDONLY , 0 , 0 ) ) {
stack ;
return 0 ;
}
r = read_config_fd ( new_cf , dev , 0 , ( size_t ) info . st_size ,
2002-12-20 02:25:55 +03:00
0 , 0 , ( checksum_fn_t ) NULL , 0 ) ;
2003-07-05 02:34:56 +04:00
dev_close ( dev ) ;
2002-11-18 17:01:16 +03:00
if ( r ) {
new_cs = ( struct cs * ) new_cf ;
new_cs - > filename = pool_strdup ( new_cs - > mem , c - > filename ) ;
new_cs - > timestamp = info . st_mtime ;
destroy_config_tree ( * cf ) ;
* cf = new_cf ;
}
2002-04-24 22:20:51 +04:00
return r ;
2001-08-21 16:56:08 +04:00
}
2002-11-18 17:01:16 +03:00
static void _write_value ( FILE * fp , struct config_value * v )
2001-08-21 16:56:08 +04:00
{
switch ( v - > type ) {
case CFG_STRING :
fprintf ( fp , " \" %s \" " , v - > v . str ) ;
break ;
case CFG_FLOAT :
fprintf ( fp , " %f " , v - > v . r ) ;
break ;
case CFG_INT :
fprintf ( fp , " %d " , v - > v . i ) ;
break ;
2002-08-01 16:46:52 +04:00
case CFG_EMPTY_ARRAY :
fprintf ( fp , " [] " ) ;
break ;
default :
2002-11-18 17:01:16 +03:00
log_error ( " _write_value: Unknown value type: %d " , v - > type ) ;
2001-08-21 16:56:08 +04:00
}
}
2002-11-18 17:01:16 +03:00
static int _write_config ( struct config_node * n , FILE * fp , int level )
2001-08-21 16:56:08 +04:00
{
2002-04-24 22:20:51 +04:00
char space [ MAX_INDENT + 1 ] ;
int l = ( level < MAX_INDENT ) ? level : MAX_INDENT ;
int i ;
2001-08-21 16:56:08 +04:00
if ( ! n )
return 1 ;
2002-04-24 22:20:51 +04:00
for ( i = 0 ; i < l ; i + + )
2002-08-01 12:22:09 +04:00
space [ i ] = ' \t ' ;
2002-04-24 22:20:51 +04:00
space [ i ] = ' \0 ' ;
2001-08-21 16:56:08 +04:00
2002-04-24 22:20:51 +04:00
while ( n ) {
fprintf ( fp , " %s%s " , space , n - > key ) ;
2001-08-21 16:56:08 +04:00
if ( ! n - > v ) {
/* it's a sub section */
fprintf ( fp , " { \n " ) ;
_write_config ( n - > child , fp , level + 1 ) ;
fprintf ( fp , " %s} " , space ) ;
} else {
/* it's a value */
struct config_value * v = n - > v ;
fprintf ( fp , " = " ) ;
if ( v - > next ) {
fprintf ( fp , " [ " ) ;
while ( v ) {
_write_value ( fp , v ) ;
v = v - > next ;
if ( v )
fprintf ( fp , " , " ) ;
}
fprintf ( fp , " ] " ) ;
} else
_write_value ( fp , v ) ;
}
fprintf ( fp , " \n " ) ;
2002-04-24 22:20:51 +04:00
n = n - > sib ;
}
2001-08-21 16:56:08 +04:00
/* FIXME: add error checking */
return 1 ;
}
2002-11-18 17:01:16 +03:00
int write_config_file ( struct config_tree * cf , const char * file )
2001-08-21 16:56:08 +04:00
{
int r = 1 ;
2003-10-16 00:17:19 +04:00
FILE * fp ;
if ( ! file ) {
fp = stdout ;
file = " stdout " ;
} else if ( ! ( fp = fopen ( file , " w " ) ) ) {
2002-04-24 22:20:51 +04:00
log_sys_error ( " open " , file ) ;
return 0 ;
}
2001-08-21 16:56:08 +04:00
2003-10-16 00:17:19 +04:00
log_verbose ( " Dumping configuration to %s " , file ) ;
2002-04-24 22:20:51 +04:00
if ( ! _write_config ( cf - > root , fp , 0 ) ) {
2003-10-16 00:17:19 +04:00
log_error ( " Failure while writing configuration " ) ;
2001-08-21 16:56:08 +04:00
r = 0 ;
}
2003-10-16 00:17:19 +04:00
if ( fp ! = stdout )
fclose ( fp ) ;
2001-08-21 16:56:08 +04:00
return r ;
}
/*
* parser
*/
static struct config_node * _file ( struct parser * p )
{
2001-10-25 17:08:29 +04:00
struct config_node * root = NULL , * n , * l = NULL ;
2001-08-21 16:56:08 +04:00
while ( p - > t ! = TOK_EOF ) {
if ( ! ( n = _section ( p ) ) ) {
stack ;
return 0 ;
}
if ( ! root )
root = n ;
else
l - > sib = n ;
l = n ;
}
return root ;
}
static struct config_node * _section ( struct parser * p )
{
2002-04-24 22:20:51 +04:00
/* IDENTIFIER '{' VALUE* '}' */
2001-10-25 17:08:29 +04:00
struct config_node * root , * n , * l = NULL ;
2001-08-21 16:56:08 +04:00
if ( ! ( root = _create_node ( p ) ) ) {
stack ;
return 0 ;
}
if ( ! ( root - > key = _dup_tok ( p ) ) ) {
stack ;
return 0 ;
}
2002-04-24 22:20:51 +04:00
match ( TOK_IDENTIFIER ) ;
2001-08-21 16:56:08 +04:00
if ( p - > t = = TOK_SECTION_B ) {
match ( TOK_SECTION_B ) ;
while ( p - > t ! = TOK_SECTION_E ) {
if ( ! ( n = _section ( p ) ) ) {
stack ;
return 0 ;
}
if ( ! root - > child )
root - > child = n ;
else
l - > sib = n ;
l = n ;
}
match ( TOK_SECTION_E ) ;
} else {
match ( TOK_EQ ) ;
if ( ! ( root - > v = _value ( p ) ) ) {
stack ;
return 0 ;
}
}
2002-04-24 22:20:51 +04:00
return root ;
2001-08-21 16:56:08 +04:00
}
static struct config_value * _value ( struct parser * p )
{
2002-04-24 22:20:51 +04:00
/* '[' TYPE* ']' | TYPE */
2002-08-01 12:22:09 +04:00
struct config_value * h = NULL , * l , * ll = NULL ;
2002-04-24 22:20:51 +04:00
if ( p - > t = = TOK_ARRAY_B ) {
match ( TOK_ARRAY_B ) ;
while ( p - > t ! = TOK_ARRAY_E ) {
if ( ! ( l = _type ( p ) ) ) {
2001-08-21 16:56:08 +04:00
stack ;
return 0 ;
}
if ( ! h )
h = l ;
else
ll - > next = l ;
ll = l ;
if ( p - > t = = TOK_COMMA )
match ( TOK_COMMA ) ;
}
2002-04-24 22:20:51 +04:00
match ( TOK_ARRAY_E ) ;
2002-08-01 16:46:52 +04:00
/*
2002-11-18 17:01:16 +03:00
* Special case for an empty array .
2002-08-01 16:46:52 +04:00
*/
if ( ! h ) {
if ( ! ( h = _create_value ( p ) ) )
return NULL ;
h - > type = CFG_EMPTY_ARRAY ;
}
2002-11-18 17:01:16 +03:00
2002-04-24 22:20:51 +04:00
} else
2001-08-21 16:56:08 +04:00
h = _type ( p ) ;
2002-04-24 22:20:51 +04:00
return h ;
2001-08-21 16:56:08 +04:00
}
2001-10-25 15:34:55 +04:00
static struct config_value * _type ( struct parser * p )
{
2003-07-15 20:32:20 +04:00
/* [+-]{0,1}[0-9]+ | [0-9]*\.[0-9]* | ".*" */
2001-08-21 16:56:08 +04:00
struct config_value * v = _create_value ( p ) ;
2002-11-18 17:01:16 +03:00
2002-08-01 16:46:52 +04:00
if ( ! v )
return NULL ;
2001-08-21 16:56:08 +04:00
2002-04-24 22:20:51 +04:00
switch ( p - > t ) {
case TOK_INT :
2001-08-21 16:56:08 +04:00
v - > type = CFG_INT ;
2002-08-01 12:22:09 +04:00
v - > v . i = strtol ( p - > tb , NULL , 0 ) ; /* FIXME: check error */
2002-04-24 22:20:51 +04:00
match ( TOK_INT ) ;
break ;
2001-08-21 16:56:08 +04:00
2002-04-24 22:20:51 +04:00
case TOK_FLOAT :
2001-08-21 16:56:08 +04:00
v - > type = CFG_FLOAT ;
2002-08-01 12:22:09 +04:00
v - > v . r = strtod ( p - > tb , NULL ) ; /* FIXME: check error */
2002-04-24 22:20:51 +04:00
match ( TOK_FLOAT ) ;
break ;
2001-08-21 16:56:08 +04:00
2002-04-24 22:20:51 +04:00
case TOK_STRING :
2001-08-21 16:56:08 +04:00
v - > type = CFG_STRING ;
2002-04-24 22:20:51 +04:00
p - > tb + + , p - > te - - ; /* strip "'s */
2001-08-21 16:56:08 +04:00
if ( ! ( v - > v . str = _dup_tok ( p ) ) ) {
stack ;
return 0 ;
}
p - > te + + ;
2002-04-24 22:20:51 +04:00
match ( TOK_STRING ) ;
break ;
2001-08-21 16:56:08 +04:00
2002-04-24 22:20:51 +04:00
default :
2001-10-23 15:50:49 +04:00
log_error ( " Parse error at line %d: expected a value " , p - > line ) ;
2002-04-24 22:20:51 +04:00
return 0 ;
}
return v ;
2001-08-21 16:56:08 +04:00
}
static int _match_aux ( struct parser * p , int t )
{
if ( p - > t ! = t )
return 0 ;
2003-02-03 23:08:45 +03:00
_get_token ( p , t ) ;
2001-08-21 16:56:08 +04:00
return 1 ;
}
/*
* tokeniser
*/
2003-02-03 23:08:45 +03:00
static void _get_token ( struct parser * p , int tok_prev )
2001-08-21 16:56:08 +04:00
{
2003-02-03 23:08:45 +03:00
int values_allowed = 0 ;
2002-04-24 22:20:51 +04:00
p - > tb = p - > te ;
_eat_space ( p ) ;
2002-11-18 17:01:16 +03:00
if ( p - > tb = = p - > fe | | ! * p - > tb ) {
2001-08-21 16:56:08 +04:00
p - > t = TOK_EOF ;
return ;
}
2003-02-03 23:08:45 +03:00
/* Should next token be interpreted as value instead of identifier? */
if ( tok_prev = = TOK_EQ | | tok_prev = = TOK_ARRAY_B | |
tok_prev = = TOK_COMMA )
values_allowed = 1 ;
2002-04-24 22:20:51 +04:00
p - > t = TOK_INT ; /* fudge so the fall through for
floats works */
switch ( * p - > te ) {
case ' { ' :
p - > t = TOK_SECTION_B ;
p - > te + + ;
break ;
case ' } ' :
p - > t = TOK_SECTION_E ;
p - > te + + ;
break ;
case ' [ ' :
p - > t = TOK_ARRAY_B ;
p - > te + + ;
break ;
case ' ] ' :
p - > t = TOK_ARRAY_E ;
p - > te + + ;
break ;
case ' , ' :
p - > t = TOK_COMMA ;
p - > te + + ;
break ;
case ' = ' :
p - > t = TOK_EQ ;
p - > te + + ;
break ;
case ' " ' :
p - > t = TOK_STRING ;
p - > te + + ;
2002-11-18 17:01:16 +03:00
while ( ( p - > te ! = p - > fe ) & & ( * p - > te ) & & ( * p - > te ! = ' " ' ) ) {
if ( ( * p - > te = = ' \\ ' ) & & ( p - > te + 1 ! = p - > fe ) & &
* ( p - > te + 1 ) )
2002-04-24 22:20:51 +04:00
p - > te + + ;
p - > te + + ;
}
2002-11-18 17:01:16 +03:00
if ( ( p - > te ! = p - > fe ) & & ( * p - > te ) )
2002-04-24 22:20:51 +04:00
p - > te + + ;
break ;
2003-01-28 20:20:11 +03:00
case ' \' ' :
p - > t = TOK_STRING ;
p - > te + + ;
while ( ( p - > te ! = p - > fe ) & & ( * p - > te ) & & ( * p - > te ! = ' \' ' ) )
p - > te + + ;
if ( ( p - > te ! = p - > fe ) & & ( * p - > te ) )
p - > te + + ;
break ;
2002-04-24 22:20:51 +04:00
case ' . ' :
p - > t = TOK_FLOAT ;
case ' 0 ' :
case ' 1 ' :
case ' 2 ' :
case ' 3 ' :
case ' 4 ' :
case ' 5 ' :
case ' 6 ' :
case ' 7 ' :
case ' 8 ' :
case ' 9 ' :
2003-07-15 20:32:20 +04:00
case ' + ' :
case ' - ' :
2003-02-03 23:08:45 +03:00
if ( values_allowed ) {
2002-04-24 22:20:51 +04:00
p - > te + + ;
2003-02-03 23:08:45 +03:00
while ( ( p - > te ! = p - > fe ) & & ( * p - > te ) ) {
if ( * p - > te = = ' . ' ) {
if ( p - > t = = TOK_FLOAT )
break ;
p - > t = TOK_FLOAT ;
} else if ( ! isdigit ( ( int ) * p - > te ) )
break ;
p - > te + + ;
}
break ;
2002-04-24 22:20:51 +04:00
}
default :
p - > t = TOK_IDENTIFIER ;
2002-11-18 17:01:16 +03:00
while ( ( p - > te ! = p - > fe ) & & ( * p - > te ) & & ! isspace ( * p - > te ) & &
2003-01-28 19:07:04 +03:00
( * p - > te ! = ' # ' ) & & ( * p - > te ! = ' = ' ) & & ( * p - > te ! = ' { ' ) & &
( * p - > te ! = ' } ' ) )
2002-04-24 22:20:51 +04:00
p - > te + + ;
break ;
}
2001-08-21 16:56:08 +04:00
}
static void _eat_space ( struct parser * p )
{
2002-11-18 17:01:16 +03:00
while ( ( p - > tb ! = p - > fe ) & & ( * p - > tb ) ) {
2002-04-24 22:20:51 +04:00
if ( * p - > te = = ' # ' ) {
2002-11-18 17:01:16 +03:00
while ( ( p - > te ! = p - > fe ) & & ( * p - > te ) & & ( * p - > te ! = ' \n ' ) )
2002-04-24 22:20:51 +04:00
p - > te + + ;
2001-08-21 16:56:08 +04:00
p - > line + + ;
}
else if ( isspace ( * p - > te ) ) {
2002-11-18 17:01:16 +03:00
while ( ( p - > te ! = p - > fe ) & & ( * p - > te ) & & isspace ( * p - > te ) ) {
2001-08-21 16:56:08 +04:00
if ( * p - > te = = ' \n ' )
p - > line + + ;
2002-04-24 22:20:51 +04:00
p - > te + + ;
2001-08-21 16:56:08 +04:00
}
}
2002-04-24 22:20:51 +04:00
else
return ;
2001-08-21 16:56:08 +04:00
2002-04-24 22:20:51 +04:00
p - > tb = p - > te ;
}
2001-08-21 16:56:08 +04:00
}
/*
* memory management
*/
static struct config_value * _create_value ( struct parser * p )
{
struct config_value * v = pool_alloc ( p - > mem , sizeof ( * v ) ) ;
memset ( v , 0 , sizeof ( * v ) ) ;
return v ;
}
static struct config_node * _create_node ( struct parser * p )
{
struct config_node * n = pool_alloc ( p - > mem , sizeof ( * n ) ) ;
memset ( n , 0 , sizeof ( * n ) ) ;
return n ;
}
static char * _dup_tok ( struct parser * p )
{
2002-12-20 02:25:55 +03:00
size_t len = p - > te - p - > tb ;
2001-08-21 16:56:08 +04:00
char * str = pool_alloc ( p - > mem , len + 1 ) ;
if ( ! str ) {
stack ;
return 0 ;
}
strncpy ( str , p - > tb , len ) ;
str [ len ] = ' \0 ' ;
return str ;
}
/*
* utility functions
*/
struct config_node * find_config_node ( struct config_node * cn ,
2002-12-20 02:25:55 +03:00
const char * path , const int sep )
2001-08-21 16:56:08 +04:00
{
const char * e ;
while ( cn ) {
/* trim any leading slashes */
while ( * path & & ( * path = = sep ) )
path + + ;
/* find the end of this segment */
2002-04-24 22:20:51 +04:00
for ( e = path ; * e & & ( * e ! = sep ) ; e + + ) ;
2001-08-21 16:56:08 +04:00
/* hunt for the node */
while ( cn ) {
if ( _tok_match ( cn - > key , path , e ) )
break ;
cn = cn - > sib ;
}
if ( cn & & * e )
cn = cn - > child ;
else
break ; /* don't move into the last node */
path = e ;
}
return cn ;
}
2002-04-24 22:20:51 +04:00
const char * find_config_str ( struct config_node * cn ,
2002-12-20 02:25:55 +03:00
const char * path , const int sep , const char * fail )
2001-08-21 16:56:08 +04:00
{
struct config_node * n = find_config_node ( cn , path , sep ) ;
2002-01-16 02:34:13 +03:00
if ( n & & n - > v - > type = = CFG_STRING ) {
2002-04-24 22:20:51 +04:00
if ( * n - > v - > v . str )
log_very_verbose ( " Setting %s to %s " , path , n - > v - > v . str ) ;
2001-08-21 16:56:08 +04:00
return n - > v - > v . str ;
2002-01-16 02:34:13 +03:00
}
2001-08-21 16:56:08 +04:00
2001-10-23 22:20:27 +04:00
if ( fail )
2002-01-28 00:30:47 +03:00
log_very_verbose ( " %s not found in config: defaulting to %s " ,
2002-04-24 22:20:51 +04:00
path , fail ) ;
2001-08-21 16:56:08 +04:00
return fail ;
}
2001-10-25 15:34:55 +04:00
int find_config_int ( struct config_node * cn , const char * path ,
2002-12-20 02:25:55 +03:00
const int sep , int fail )
2001-08-21 16:56:08 +04:00
{
struct config_node * n = find_config_node ( cn , path , sep ) ;
2002-01-16 02:34:13 +03:00
if ( n & & n - > v - > type = = CFG_INT ) {
2002-01-28 00:30:47 +03:00
log_very_verbose ( " Setting %s to %d " , path , n - > v - > v . i ) ;
2001-08-21 16:56:08 +04:00
return n - > v - > v . i ;
2002-01-16 02:34:13 +03:00
}
2001-08-21 16:56:08 +04:00
2002-04-24 22:20:51 +04:00
log_very_verbose ( " %s not found in config: defaulting to %d " ,
2002-01-28 00:30:47 +03:00
path , fail ) ;
2001-08-21 16:56:08 +04:00
return fail ;
}
float find_config_float ( struct config_node * cn , const char * path ,
2002-12-20 02:25:55 +03:00
const int sep , float fail )
2001-08-21 16:56:08 +04:00
{
struct config_node * n = find_config_node ( cn , path , sep ) ;
2002-01-16 02:34:13 +03:00
if ( n & & n - > v - > type = = CFG_FLOAT ) {
2002-01-28 00:30:47 +03:00
log_very_verbose ( " Setting %s to %f " , path , n - > v - > v . r ) ;
2001-08-21 16:56:08 +04:00
return n - > v - > v . r ;
2002-01-16 02:34:13 +03:00
}
2002-01-28 00:30:47 +03:00
log_very_verbose ( " %s not found in config: defaulting to %f " ,
2002-04-24 22:20:51 +04:00
path , fail ) ;
2001-08-21 16:56:08 +04:00
return fail ;
}
2002-01-07 13:23:52 +03:00
static int _str_in_array ( const char * str , const char * values [ ] )
2001-08-21 16:56:08 +04:00
{
2002-01-07 13:23:52 +03:00
int i ;
for ( i = 0 ; values [ i ] ; i + + )
if ( ! strcasecmp ( str , values [ i ] ) )
return 1 ;
return 0 ;
}
static int _str_to_bool ( const char * str , int fail )
{
2002-04-24 22:20:51 +04:00
static const char * _true_values [ ] = { " y " , " yes " , " on " , " true " , NULL } ;
static const char * _false_values [ ] =
{ " n " , " no " , " off " , " false " , NULL } ;
2002-01-07 13:23:52 +03:00
if ( _str_in_array ( str , _true_values ) )
return 1 ;
if ( _str_in_array ( str , _false_values ) )
return 0 ;
return fail ;
}
int find_config_bool ( struct config_node * cn , const char * path ,
2002-12-20 02:25:55 +03:00
const int sep , int fail )
2002-01-07 13:23:52 +03:00
{
struct config_node * n = find_config_node ( cn , path , sep ) ;
struct config_value * v ;
if ( ! n )
return fail ;
v = n - > v ;
switch ( v - > type ) {
case CFG_INT :
return v - > v . i ? 1 : 0 ;
case CFG_STRING :
return _str_to_bool ( v - > v . str , fail ) ;
2001-08-21 16:56:08 +04:00
}
2002-01-07 13:23:52 +03:00
return fail ;
2001-08-21 16:56:08 +04:00
}
2002-01-10 19:47:58 +03:00
int get_config_uint32 ( struct config_node * cn , const char * path ,
2002-12-20 02:25:55 +03:00
const int sep , uint32_t * result )
2002-01-10 19:47:58 +03:00
{
struct config_node * n ;
n = find_config_node ( cn , path , sep ) ;
if ( ! n | | ! n - > v | | n - > v - > type ! = CFG_INT )
return 0 ;
* result = n - > v - > v . i ;
return 1 ;
}
int get_config_uint64 ( struct config_node * cn , const char * path ,
2002-12-20 02:25:55 +03:00
const int sep , uint64_t * result )
2002-01-10 19:47:58 +03:00
{
struct config_node * n ;
n = find_config_node ( cn , path , sep ) ;
if ( ! n | | ! n - > v | | n - > v - > type ! = CFG_INT )
return 0 ;
/* FIXME Support 64-bit value! */
* result = ( uint64_t ) n - > v - > v . i ;
return 1 ;
}
2002-07-11 18:07:43 +04:00
int get_config_str ( struct config_node * cn , const char * path ,
2002-12-20 02:25:55 +03:00
const int sep , char * * result )
2002-07-11 18:07:43 +04:00
{
struct config_node * n ;
n = find_config_node ( cn , path , sep ) ;
if ( ! n | | ! n - > v | | n - > v - > type ! = CFG_STRING )
return 0 ;
* result = n - > v - > v . str ;
return 1 ;
}