@ -16,6 +16,7 @@
# include <stdlib.h>
# include <string.h>
# include <errno.h>
# include <time.h>
# include <asterisk/config.h>
# include <asterisk/options.h>
# include <asterisk/logger.h>
@ -28,12 +29,22 @@ struct ast_category {
char name [ 80 ] ;
struct ast_variable * root ;
struct ast_category * next ;
struct ast_comment * precomments ;
struct ast_comment * sameline ;
} ;
struct ast_config {
/* Maybe this structure isn't necessary but we'll keep it
for now */
struct ast_category * root ;
struct ast_category * prev ;
struct ast_comment * trailingcomments ;
} ;
struct ast_comment_struct
{
struct ast_comment * root ;
struct ast_comment * prev ;
} ;
static char * strip ( char * buf )
@ -49,6 +60,16 @@ static char *strip(char *buf)
return start ;
}
static void free_comments ( struct ast_comment * com )
{
struct ast_comment * l ;
while ( com ) {
l = com ;
com = com - > next ;
free ( l ) ;
}
}
void ast_destroy ( struct ast_config * ast )
{
struct ast_category * cat , * catn ;
@ -64,13 +85,18 @@ void ast_destroy(struct ast_config *ast)
vn = v ;
free ( v - > name ) ;
free ( v - > value ) ;
free_comments ( v - > precomments ) ;
free_comments ( v - > sameline ) ;
v = v - > next ;
free ( vn ) ;
}
catn = cat ;
free_comments ( cat - > precomments ) ;
free_comments ( cat - > sameline ) ;
cat = cat - > next ;
free ( catn ) ;
}
free_comments ( ast - > trailingcomments ) ;
free ( ast ) ;
}
@ -138,6 +164,220 @@ char *ast_variable_retrieve(struct ast_config *config, char *category, char *val
return NULL ;
}
int ast_variable_delete ( struct ast_config * cfg , char * category , char * variable , char * value )
{
struct ast_variable * v , * pv , * bv , * bpv ;
struct ast_category * cat ;
cat = cfg - > root ;
while ( cat ) {
if ( cat - > name = = category ) {
break ;
}
cat = cat - > next ;
}
if ( ! cat ) {
cat = cfg - > root ;
while ( cat ) {
if ( ! strcasecmp ( cat - > name , category ) ) {
break ;
}
cat = cat - > next ;
}
}
if ( ! cat )
return - 1 ;
v = cat - > root ;
pv = NULL ;
while ( v ) {
if ( ( variable = = v - > name ) & & ( ! value | | ! strcmp ( v - > value , value ) ) )
break ;
pv = v ;
v = v - > next ;
}
if ( ! v ) {
/* Get the last one that looks like it */
bv = NULL ;
bpv = NULL ;
v = cat - > root ;
pv = NULL ;
while ( v ) {
if ( ! strcasecmp ( variable , v - > name ) & & ( ! value | | ! strcmp ( v - > value , value ) ) ) {
bv = v ;
bpv = pv ;
}
pv = v ;
v = v - > next ;
}
v = bv ;
}
if ( v ) {
/* Unlink from original position */
if ( pv )
pv - > next = v - > next ;
else
cat - > root = v - > next ;
v - > next = NULL ;
free ( v - > name ) ;
if ( v - > value )
free ( v - > value ) ;
free_comments ( v - > sameline ) ;
free_comments ( v - > precomments ) ;
return 0 ;
}
return - 1 ;
}
int ast_category_delete ( struct ast_config * cfg , char * category )
{
struct ast_variable * v , * pv ;
struct ast_category * cat , * cprev ;
cat = cfg - > root ;
cprev = NULL ;
while ( cat ) {
if ( cat - > name = = category ) {
break ;
}
cprev = cat ;
cat = cat - > next ;
}
if ( ! cat ) {
cat = cfg - > root ;
cprev = NULL ;
while ( cat ) {
if ( ! strcasecmp ( cat - > name , category ) ) {
break ;
}
cprev = cat ;
cat = cat - > next ;
}
}
if ( ! cat )
return - 1 ;
/* Unlink it */
if ( cprev )
cprev - > next = cat - > next ;
else
cfg - > root = cat - > next ;
v = cat - > root ;
while ( v ) {
pv = v ;
v = v - > next ;
if ( pv - > value )
free ( pv - > value ) ;
if ( pv - > name )
free ( pv - > name ) ;
free_comments ( pv - > sameline ) ;
free_comments ( pv - > precomments ) ;
free ( pv ) ;
}
free_comments ( cat - > sameline ) ;
free_comments ( cat - > precomments ) ;
free ( cat ) ;
return 0 ;
}
struct ast_variable * ast_variable_append_modify ( struct ast_config * config , char * category , char * variable , char * value , int newcat , int newvar , int move )
{
struct ast_variable * v , * pv , * bv , * bpv ;
struct ast_category * cat , * pcat ;
cat = config - > root ;
if ( ! newcat ) {
while ( cat ) {
if ( cat - > name = = category ) {
break ;
}
cat = cat - > next ;
}
if ( ! cat ) {
cat = config - > root ;
while ( cat ) {
if ( ! strcasecmp ( cat - > name , category ) ) {
break ;
}
cat = cat - > next ;
}
}
}
if ( ! cat ) {
cat = malloc ( sizeof ( struct ast_category ) ) ;
if ( ! cat )
return NULL ;
memset ( cat , 0 , sizeof ( struct ast_category ) ) ;
strncpy ( cat - > name , category , sizeof ( cat - > name ) ) ;
if ( config - > root ) {
/* Put us at the end */
pcat = config - > root ;
while ( pcat - > next )
pcat = pcat - > next ;
pcat - > next = cat ;
} else {
/* We're the first one */
config - > root = cat ;
}
}
if ( ! newvar ) {
v = cat - > root ;
pv = NULL ;
while ( v ) {
if ( variable = = v - > name )
break ;
pv = v ;
v = v - > next ;
}
if ( ! v ) {
/* Get the last one that looks like it */
bv = NULL ;
bpv = NULL ;
v = cat - > root ;
pv = NULL ;
while ( v ) {
if ( ! strcasecmp ( variable , v - > name ) ) {
bv = v ;
bpv = pv ;
}
pv = v ;
v = v - > next ;
}
v = bv ;
}
} else v = NULL ;
if ( v & & move ) {
/* Unlink from original position */
if ( pv )
pv - > next = v - > next ;
else
cat - > root = v - > next ;
v - > next = NULL ;
}
if ( ! v ) {
v = malloc ( sizeof ( struct ast_variable ) ) ;
if ( ! v )
return NULL ;
memset ( v , 0 , sizeof ( struct ast_variable ) ) ;
v - > name = strdup ( variable ) ;
move = 1 ;
}
if ( v - > value )
free ( v - > value ) ;
if ( value )
v - > value = strdup ( value ) ;
else
v - > value = strdup ( " " ) ;
if ( move ) {
if ( cat - > root ) {
pv = cat - > root ;
while ( pv - > next )
pv = pv - > next ;
pv - > next = v ;
} else {
cat - > root = v ;
}
}
return v ;
}
int ast_category_exist ( struct ast_config * config , char * category_name )
{
struct ast_category * category = NULL ;
@ -153,16 +393,33 @@ int ast_category_exist(struct ast_config *config, char *category_name)
return 0 ;
}
static struct ast_config * __ast_load ( char * configfile , struct ast_config * tmp , struct ast_category * * _tmpc , struct ast_variable * * _last , int includelevel ) ;
static int cfg_process ( struct ast_config * tmp , struct ast_category * * _tmpc , struct ast_variable * * _last , char * buf , int lineno , char * configfile , int includelevel )
static struct ast_comment * build_comment ( char * cmt )
{
struct ast_comment * c ;
c = malloc ( sizeof ( struct ast_comment ) ) ;
if ( c ) {
memset ( c , 0 , sizeof ( struct ast_comment ) ) ;
c - > comment = strdup ( cmt ) ;
}
return c ;
}
static struct ast_config * __ast_load ( char * configfile , struct ast_config * tmp , struct ast_category * * _tmpc , struct ast_variable * * _last , int includelevel , struct ast_comment_struct * acs ) ;
static int cfg_process ( struct ast_config * tmp , struct ast_category * * _tmpc , struct ast_variable * * _last , char * buf , int lineno , char * configfile , int includelevel , struct ast_comment_struct * acs )
{
char * c ;
char * cur ;
struct ast_variable * v ;
struct ast_comment * com = NULL ;
int object ;
/* Strip off lines using ; as comment */
c = strchr ( buf , ' ; ' ) ;
if ( c )
if ( c ) {
* c = ' \0 ' ;
c + + ;
if ( * c ! = ' ! ' )
com = build_comment ( c ) ;
}
cur = strip ( buf ) ;
if ( strlen ( cur ) ) {
/* Actually parse the entry */
@ -181,8 +438,16 @@ static int cfg_process(struct ast_config *tmp, struct ast_category **_tmpc, stru
memset ( * _tmpc , 0 , sizeof ( struct ast_category ) ) ;
strncpy ( ( * _tmpc ) - > name , cur + 1 , sizeof ( ( * _tmpc ) - > name ) - 1 ) ;
( * _tmpc ) - > root = NULL ;
( * _tmpc ) - > next = tmp - > root ;
tmp - > root = * _tmpc ;
( * _tmpc ) - > precomments = acs - > root ;
( * _tmpc ) - > sameline = com ;
if ( ! tmp - > prev )
tmp - > root = * _tmpc ;
else
tmp - > prev - > next = * _tmpc ;
tmp - > prev = * _tmpc ;
acs - > root = NULL ;
acs - > prev = NULL ;
* _last = NULL ;
} else {
ast_log ( LOG_WARNING ,
@ -216,7 +481,7 @@ static int cfg_process(struct ast_config *tmp, struct ast_category **_tmpc, stru
break ;
}
if ( includelevel < MAX_INCLUDE_LEVEL ) {
__ast_load ( cur , tmp , _tmpc , _last , includelevel + 1 );
__ast_load ( cur , tmp , _tmpc , _last , includelevel + 1 , acs );
} else
ast_log ( LOG_WARNING , " Maximum Include level (%d) exceeded \n " , includelevel ) ;
} else
@ -237,8 +502,11 @@ static int cfg_process(struct ast_config *tmp, struct ast_category **_tmpc, stru
* c = 0 ;
c + + ;
/* Ignore > in => */
if ( * c = = ' > ' )
if ( * c = = ' > ' ) {
object = 1 ;
c + + ;
} else
object = 0 ;
v = malloc ( sizeof ( struct ast_variable ) ) ;
if ( v ) {
memset ( v , 0 , sizeof ( struct ast_variable ) ) ;
@ -246,7 +514,14 @@ static int cfg_process(struct ast_config *tmp, struct ast_category **_tmpc, stru
v - > name = strdup ( strip ( cur ) ) ;
v - > value = strdup ( strip ( c ) ) ;
v - > lineno = lineno ;
if ( * _last )
v - > object = object ;
/* Put and reset comments */
v - > precomments = acs - > root ;
v - > blanklines = 0 ;
acs - > prev = NULL ;
acs - > root = NULL ;
v - > sameline = com ;
if ( * _last )
( * _last ) - > next = v ;
else
( * _tmpc ) - > root = v ;
@ -260,17 +535,108 @@ static int cfg_process(struct ast_config *tmp, struct ast_category **_tmpc, stru
ast_log ( LOG_WARNING , " No '=' (equal sign) in line %d of %s \n " , lineno , configfile ) ;
}
}
} else {
/* store any comments if there are any */
if ( com ) {
if ( acs - > prev )
acs - > prev - > next = com ;
else
acs - > root = com ;
acs - > prev = com ;
} else {
if ( * _last )
( * _last ) - > blanklines + + ;
}
}
return 0 ;
}
static struct ast_config * __ast_load ( char * configfile , struct ast_config * tmp , struct ast_category * * _tmpc , struct ast_variable * * _last , int includelevel )
static void dump_comments ( FILE * f , struct ast_comment * comment )
{
while ( comment ) {
fprintf ( f , " ;%s " , comment - > comment ) ;
comment = comment - > next ;
}
}
int ast_save ( char * configfile , struct ast_config * cfg , char * generator )
{
FILE * f ;
char fn [ 256 ] ;
char date [ 256 ] ;
time_t t ;
struct ast_variable * var ;
struct ast_category * cat ;
int blanklines = 0 ;
if ( configfile [ 0 ] = = ' / ' ) {
strncpy ( fn , configfile , sizeof ( fn ) - 1 ) ;
} else {
snprintf ( fn , sizeof ( fn ) , " %s/%s " , AST_CONFIG_DIR , configfile ) ;
}
time ( & t ) ;
strncpy ( date , ctime ( & t ) , sizeof ( date ) ) ;
if ( ( f = fopen ( fn , " w " ) ) ) {
if ( ( option_verbose > 1 ) & & ! option_debug )
ast_verbose ( VERBOSE_PREFIX_2 " Saving '%s': " , fn ) ;
fprintf ( f , " ;! \n " ) ;
fprintf ( f , " ;! Automatically generated configuration file \n " ) ;
fprintf ( f , " ;! Filename: %s (%s) \n " , configfile , fn ) ;
fprintf ( f , " ;! Generator: %s \n " , generator ) ;
fprintf ( f , " ;! Creation Date: %s " , date ) ;
fprintf ( f , " ;! \n " ) ;
cat = cfg - > root ;
while ( cat ) {
/* Dump any precomments */
dump_comments ( f , cat - > precomments ) ;
/* Dump section with any appropriate comment */
if ( cat - > sameline )
fprintf ( f , " [%s] ; %s \n " , cat - > name , cat - > sameline - > comment ) ;
else
fprintf ( f , " [%s] \n " , cat - > name ) ;
var = cat - > root ;
while ( var ) {
dump_comments ( f , var - > precomments ) ;
if ( var - > sameline )
fprintf ( f , " %s %s %s ; %s \n " , var - > name , ( var - > object ? " => " : " = " ) , var - > value , var - > sameline - > comment ) ;
else
fprintf ( f , " %s %s %s \n " , var - > name , ( var - > object ? " => " : " = " ) , var - > value ) ;
if ( var - > blanklines ) {
blanklines = var - > blanklines ;
while ( blanklines ) {
fprintf ( f , " \n " ) ;
blanklines - - ;
}
}
var = var - > next ;
}
#if 0
/* Put an empty line */
fprintf ( f , " \n " ) ;
# endif
cat = cat - > next ;
}
dump_comments ( f , cfg - > trailingcomments ) ;
} else {
if ( option_debug )
printf ( " Unable to open for writing: %s \n " , fn ) ;
else if ( option_verbose > 1 )
printf ( " Unable to write (%s) " , strerror ( errno ) ) ;
return - 1 ;
}
fclose ( f ) ;
return 0 ;
}
static struct ast_config * __ast_load ( char * configfile , struct ast_config * tmp , struct ast_category * * _tmpc , struct ast_variable * * _last , int includelevel , struct ast_comment_struct * acs )
{
char fn [ 256 ] ;
char buf [ 256 ] ;
FILE * f ;
int lineno = 0 ;
int master = 0 ;
if ( configfile [ 0 ] = = ' / ' ) {
strncpy ( fn , configfile , sizeof ( fn ) - 1 ) ;
@ -290,6 +656,8 @@ static struct ast_config *__ast_load(char *configfile, struct ast_config *tmp, s
tmp = malloc ( sizeof ( struct ast_config ) ) ;
if ( tmp )
memset ( tmp , 0 , sizeof ( struct ast_config ) ) ;
master = 1 ;
}
if ( ! tmp ) {
ast_log ( LOG_WARNING , " Out of memory \n " ) ;
@ -300,7 +668,7 @@ static struct ast_config *__ast_load(char *configfile, struct ast_config *tmp, s
fgets ( buf , sizeof ( buf ) , f ) ;
lineno + + ;
if ( ! feof ( f ) ) {
if ( cfg_process ( tmp , _tmpc , _last , buf , lineno , configfile , includelevel )) {
if ( cfg_process ( tmp , _tmpc , _last , buf , lineno , configfile , includelevel , acs )) {
fclose ( f ) ;
return NULL ;
}
@ -313,6 +681,12 @@ static struct ast_config *__ast_load(char *configfile, struct ast_config *tmp, s
else if ( option_verbose > 1 )
ast_verbose ( " Not found (%s) " , strerror ( errno ) ) ;
}
if ( master ) {
/* Keep trailing comments */
tmp - > trailingcomments = acs - > root ;
acs - > root = NULL ;
acs - > prev = NULL ;
}
return tmp ;
}
@ -320,7 +694,8 @@ struct ast_config *ast_load(char *configfile)
{
struct ast_category * tmpc = NULL ;
struct ast_variable * last = NULL ;
return __ast_load ( configfile , NULL , & tmpc , & last , 0 ) ;
struct ast_comment_struct acs = { NULL , NULL } ;
return __ast_load ( configfile , NULL , & tmpc , & last , 0 , & acs ) ;
}
char * ast_category_browse ( struct ast_config * config , char * prev )