summaryrefslogtreecommitdiffstats
path: root/src/core/settings.c
diff options
context:
space:
mode:
authorMichael Brown2009-03-06 15:40:44 +0100
committerMichael Brown2009-03-06 15:40:44 +0100
commitec24672db720a97305823012033c65f685b41368 (patch)
treeb6ca3a8b2a5e4668ef49db1ad0484fbbe9addada /src/core/settings.c
parent[release] Update version to 0.9.7+ post release (diff)
downloadipxe-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.c164
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 );
}