2
0
mirror of https://github.com/xcat2/xNBA.git synced 2025-02-02 20:11:48 +00:00

[settings] Allow for autovivification of settings blocks

Allow for settings blocks to be created on demand.  This allows for
constructions such as

  set defaults/filename http://bootserver/bootfile
  set defaults/priority 0xff
  dhcp net0
  chain ${filename}

which will boot from the DHCP-provided filename, or from
"http://bootserver/bootfile" if the DHCP server does not provide a
filename.

(Note that "priority" gets interpreted as a signed integer, so setting
"defaults/priority" to 0xff will cause the "defaults" settings block
to have an effective priority of -1.)
This commit is contained in:
Michael Brown 2009-03-06 14:40:44 +00:00
parent f95c919741
commit ec24672db7
2 changed files with 113 additions and 53 deletions

View File

@ -117,6 +117,108 @@ struct simple_settings simple_settings_root = {
/** Root settings block */
#define settings_root simple_settings_root.settings
/**
* Find child named settings block
*
* @v parent Parent settings block
* @v name Name within this parent
* @ret settings Settings block, or NULL
*/
static struct settings * find_child_settings ( struct settings *parent,
const char *name ) {
struct settings *settings;
/* Treat empty name as meaning "this block" */
if ( ! *name )
return parent;
/* Look for child with matching name */
list_for_each_entry ( settings, &parent->children, siblings ) {
if ( strcmp ( settings->name, name ) == 0 )
return settings;
}
return NULL;
}
/**
* Find or create child named settings block
*
* @v parent Parent settings block
* @v name Name within this parent
* @ret settings Settings block, or NULL
*/
static struct settings * autovivify_child_settings ( struct settings *parent,
const char *name ) {
struct {
struct simple_settings simple;
char name[ strlen ( name ) + 1 /* NUL */ ];
} *new_child;
struct settings *settings;
/* Return existing settings, if existent */
if ( ( settings = find_child_settings ( parent, name ) ) != NULL )
return settings;
/* Create new simple settings block */
new_child = zalloc ( sizeof ( *new_child ) );
if ( ! new_child ) {
DBGC ( parent, "Settings %p could not create child %s\n",
parent, name );
return NULL;
}
memcpy ( new_child->name, name, sizeof ( new_child->name ) );
simple_settings_init ( &new_child->simple, NULL, new_child->name );
settings = &new_child->simple.settings;
register_settings ( settings, parent );
return settings;
}
/**
* Parse settings block name
*
* @v name Name
* @v get_child Function to find or create child settings block
* @ret settings Settings block, or NULL
*/
static struct settings *
parse_settings_name ( const char *name,
struct settings * ( * get_child ) ( struct settings *,
const char * ) ) {
struct settings *settings = &settings_root;
char name_copy[ strlen ( name ) + 1 ];
char *subname;
char *remainder;
/* Create modifiable copy of name */
memcpy ( name_copy, name, sizeof ( name_copy ) );
remainder = name_copy;
/* Parse each name component in turn */
while ( remainder ) {
subname = remainder;
remainder = strchr ( subname, '.' );
if ( remainder )
*(remainder++) = '\0';
settings = get_child ( settings, subname );
if ( ! settings )
break;
}
return settings;
}
/**
* Find named settings block
*
* @v name Name
* @ret settings Settings block, or NULL
*/
struct settings * find_settings ( const char *name ) {
return parse_settings_name ( name, find_child_settings );
}
/**
* Apply all settings
*
@ -228,52 +330,6 @@ void unregister_settings ( struct settings *settings ) {
apply_settings();
}
/**
* Find child named settings block
*
* @v parent Parent settings block
* @v name Name within this parent
* @ret settings Settings block, or NULL
*/
struct settings * find_child_settings ( struct settings *parent,
const char *name ) {
struct settings *settings;
size_t len;
/* NULL parent => add to settings root */
if ( parent == NULL )
parent = &settings_root;
/* Look for a child whose name matches the initial component */
list_for_each_entry ( settings, &parent->children, siblings ) {
len = strlen ( settings->name );
if ( strncmp ( name, settings->name, len ) != 0 )
continue;
if ( name[len] == 0 )
return settings;
if ( name[len] == '.' )
return find_child_settings ( settings,
( name + len + 1 ) );
}
return NULL;
}
/**
* Find named settings block
*
* @v name Name
* @ret settings Settings block, or NULL
*/
struct settings * find_settings ( const char *name ) {
/* If name is empty, use the root */
if ( ! *name )
return &settings_root;
return find_child_settings ( &settings_root, name );
}
/******************************************************************************
*
* Core settings routines
@ -641,6 +697,7 @@ static struct setting_type * find_setting_type ( const char *name ) {
* Parse setting name
*
* @v name Name of setting
* @v get_child Function to find or create child settings block
* @v settings Settings block to fill in
* @v setting Setting to fill in
* @ret rc Return status code
@ -649,8 +706,11 @@ static struct setting_type * find_setting_type ( const char *name ) {
* "[settings_name/]tag_name[:type_name]" and fills in the appropriate
* fields.
*/
static int parse_setting_name ( const char *name, struct settings **settings,
struct setting *setting ) {
static int
parse_setting_name ( const char *name,
struct settings * ( * get_child ) ( struct settings *,
const char * ),
struct settings **settings, struct setting *setting ) {
char tmp_name[ strlen ( name ) + 1 ];
char *settings_name;
char *setting_name;
@ -677,7 +737,7 @@ static int parse_setting_name ( const char *name, struct settings **settings,
/* Identify settings block, if specified */
if ( settings_name ) {
*settings = find_settings ( settings_name );
*settings = parse_settings_name ( settings_name, get_child );
if ( *settings == NULL ) {
DBG ( "Unrecognised settings block \"%s\" in \"%s\"\n",
settings_name, name );
@ -731,7 +791,8 @@ int storef_named_setting ( const char *name, const char *value ) {
struct setting setting;
int rc;
if ( ( rc = parse_setting_name ( name, &settings, &setting ) ) != 0 )
if ( ( rc = parse_setting_name ( name, autovivify_child_settings,
&settings, &setting ) ) != 0 )
return rc;
return storef_setting ( settings, &setting, value );
}
@ -749,7 +810,8 @@ int fetchf_named_setting ( const char *name, char *buf, size_t len ) {
struct setting setting;
int rc;
if ( ( rc = parse_setting_name ( name, &settings, &setting ) ) != 0 )
if ( ( rc = parse_setting_name ( name, find_child_settings,
&settings, &setting ) ) != 0 )
return rc;
return fetchf_setting ( settings, &setting, buf, len );
}

View File

@ -193,8 +193,6 @@ extern int fetch_uuid_setting ( struct settings *settings,
struct setting *setting, union uuid *uuid );
extern int setting_cmp ( struct setting *a, struct setting *b );
extern struct settings * find_child_settings ( struct settings *parent,
const char *name );
extern struct settings * find_settings ( const char *name );
extern int storef_setting ( struct settings *settings,