diff options
author | Michael Brown | 2009-03-06 15:40:44 +0100 |
---|---|---|
committer | Michael Brown | 2009-03-06 15:40:44 +0100 |
commit | ec24672db720a97305823012033c65f685b41368 (patch) | |
tree | b6ca3a8b2a5e4668ef49db1ad0484fbbe9addada /src/core/settings.c | |
parent | [release] Update version to 0.9.7+ post release (diff) | |
download | ipxe-ec24672db720a97305823012033c65f685b41368.tar.gz ipxe-ec24672db720a97305823012033c65f685b41368.tar.xz ipxe-ec24672db720a97305823012033c65f685b41368.zip |
[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.)
Diffstat (limited to 'src/core/settings.c')
-rw-r--r-- | src/core/settings.c | 164 |
1 files changed, 113 insertions, 51 deletions
diff --git a/src/core/settings.c b/src/core/settings.c index f34eb664..bb5a382b 100644 --- a/src/core/settings.c +++ b/src/core/settings.c @@ -118,6 +118,108 @@ struct simple_settings simple_settings_root = { #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 * * @ret rc Return status code @@ -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 ); } |