Browse Source

[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.)
tags/v0.9.8
Michael Brown 15 years ago
parent
commit
ec24672db7
2 changed files with 113 additions and 53 deletions
  1. 113
    51
      src/core/settings.c
  2. 0
    2
      src/include/gpxe/settings.h

+ 113
- 51
src/core/settings.c View File

@@ -117,6 +117,108 @@ struct simple_settings simple_settings_root = {
117 117
 /** Root settings block */
118 118
 #define settings_root simple_settings_root.settings
119 119
 
120
+/**
121
+ * Find child named settings block
122
+ *
123
+ * @v parent		Parent settings block
124
+ * @v name		Name within this parent
125
+ * @ret settings	Settings block, or NULL
126
+ */
127
+static struct settings * find_child_settings ( struct settings *parent,
128
+					       const char *name ) {
129
+	struct settings *settings;
130
+
131
+	/* Treat empty name as meaning "this block" */
132
+	if ( ! *name )
133
+		return parent;
134
+
135
+	/* Look for child with matching name */
136
+	list_for_each_entry ( settings, &parent->children, siblings ) {
137
+		if ( strcmp ( settings->name, name ) == 0 )
138
+			return settings;
139
+	}
140
+
141
+	return NULL;
142
+}
143
+
144
+/**
145
+ * Find or create child named settings block
146
+ *
147
+ * @v parent		Parent settings block
148
+ * @v name		Name within this parent
149
+ * @ret settings	Settings block, or NULL
150
+ */
151
+static struct settings * autovivify_child_settings ( struct settings *parent,
152
+						     const char *name ) {
153
+	struct {
154
+		struct simple_settings simple;
155
+		char name[ strlen ( name ) + 1 /* NUL */ ];
156
+	} *new_child;
157
+	struct settings *settings;
158
+
159
+	/* Return existing settings, if existent */
160
+	if ( ( settings = find_child_settings ( parent, name ) ) != NULL )
161
+		return settings;
162
+
163
+	/* Create new simple settings block */
164
+	new_child = zalloc ( sizeof ( *new_child ) );
165
+	if ( ! new_child ) {
166
+		DBGC ( parent, "Settings %p could not create child %s\n",
167
+		       parent, name );
168
+		return NULL;
169
+	}
170
+	memcpy ( new_child->name, name, sizeof ( new_child->name ) );
171
+	simple_settings_init ( &new_child->simple, NULL, new_child->name );
172
+	settings = &new_child->simple.settings;
173
+	register_settings ( settings, parent );
174
+	return settings;
175
+}
176
+
177
+/**
178
+ * Parse settings block name
179
+ *
180
+ * @v name		Name
181
+ * @v get_child		Function to find or create child settings block
182
+ * @ret settings	Settings block, or NULL
183
+ */
184
+static struct settings *
185
+parse_settings_name ( const char *name,
186
+		      struct settings * ( * get_child ) ( struct settings *,
187
+							  const char * ) ) {
188
+	struct settings *settings = &settings_root;
189
+	char name_copy[ strlen ( name ) + 1 ];
190
+	char *subname;
191
+	char *remainder;
192
+
193
+	/* Create modifiable copy of name */
194
+	memcpy ( name_copy, name, sizeof ( name_copy ) );
195
+	remainder = name_copy;
196
+
197
+	/* Parse each name component in turn */
198
+	while ( remainder ) {
199
+		subname = remainder;
200
+		remainder = strchr ( subname, '.' );
201
+		if ( remainder )
202
+			*(remainder++) = '\0';
203
+		settings = get_child ( settings, subname );
204
+		if ( ! settings )
205
+			break;
206
+	}
207
+
208
+	return settings;
209
+}
210
+
211
+/**
212
+ * Find named settings block
213
+ *
214
+ * @v name		Name
215
+ * @ret settings	Settings block, or NULL
216
+ */
217
+struct settings * find_settings ( const char *name ) {
218
+
219
+	return parse_settings_name ( name, find_child_settings );
220
+}
221
+
120 222
 /**
121 223
  * Apply all settings
122 224
  *
@@ -228,52 +330,6 @@ void unregister_settings ( struct settings *settings ) {
228 330
 	apply_settings();
229 331
 }
230 332
 
231
-/**
232
- * Find child named settings block
233
- *
234
- * @v parent		Parent settings block
235
- * @v name		Name within this parent
236
- * @ret settings	Settings block, or NULL
237
- */
238
-struct settings * find_child_settings ( struct settings *parent,
239
-					const char *name ) {
240
-	struct settings *settings;
241
-	size_t len;
242
-
243
-	/* NULL parent => add to settings root */
244
-	if ( parent == NULL )
245
-		parent = &settings_root;
246
-
247
-	/* Look for a child whose name matches the initial component */
248
-	list_for_each_entry ( settings, &parent->children, siblings ) {
249
-		len = strlen ( settings->name );
250
-		if ( strncmp ( name, settings->name, len ) != 0 )
251
-			continue;
252
-		if ( name[len] == 0 )
253
-			return settings;
254
-		if ( name[len] == '.' )
255
-			return find_child_settings ( settings,
256
-						     ( name + len + 1 ) );
257
-	}
258
-
259
-	return NULL;
260
-}
261
-
262
-/**
263
- * Find named settings block
264
- *
265
- * @v name		Name
266
- * @ret settings	Settings block, or NULL
267
- */
268
-struct settings * find_settings ( const char *name ) {
269
-
270
-	/* If name is empty, use the root */
271
-	if ( ! *name )
272
-		return &settings_root;
273
-
274
-	return find_child_settings ( &settings_root, name );
275
-}
276
-
277 333
 /******************************************************************************
278 334
  *
279 335
  * Core settings routines
@@ -641,6 +697,7 @@ static struct setting_type * find_setting_type ( const char *name ) {
641 697
  * Parse setting name
642 698
  *
643 699
  * @v name		Name of setting
700
+ * @v get_child		Function to find or create child settings block
644 701
  * @v settings		Settings block to fill in
645 702
  * @v setting		Setting to fill in
646 703
  * @ret rc		Return status code
@@ -649,8 +706,11 @@ static struct setting_type * find_setting_type ( const char *name ) {
649 706
  * "[settings_name/]tag_name[:type_name]" and fills in the appropriate
650 707
  * fields.
651 708
  */
652
-static int parse_setting_name ( const char *name, struct settings **settings,
653
-				struct setting *setting ) {
709
+static int
710
+parse_setting_name ( const char *name,
711
+		     struct settings * ( * get_child ) ( struct settings *,
712
+							 const char * ),
713
+		     struct settings **settings, struct setting *setting ) {
654 714
 	char tmp_name[ strlen ( name ) + 1 ];
655 715
 	char *settings_name;
656 716
 	char *setting_name;
@@ -677,7 +737,7 @@ static int parse_setting_name ( const char *name, struct settings **settings,
677 737
 
678 738
 	/* Identify settings block, if specified */
679 739
 	if ( settings_name ) {
680
-		*settings = find_settings ( settings_name );
740
+		*settings = parse_settings_name ( settings_name, get_child );
681 741
 		if ( *settings == NULL ) {
682 742
 			DBG ( "Unrecognised settings block \"%s\" in \"%s\"\n",
683 743
 			      settings_name, name );
@@ -731,7 +791,8 @@ int storef_named_setting ( const char *name, const char *value ) {
731 791
 	struct setting setting;
732 792
 	int rc;
733 793
 
734
-	if ( ( rc = parse_setting_name ( name, &settings, &setting ) ) != 0 )
794
+	if ( ( rc = parse_setting_name ( name, autovivify_child_settings,
795
+					 &settings, &setting ) ) != 0 )
735 796
 		return rc;
736 797
 	return storef_setting ( settings, &setting, value );
737 798
 }
@@ -749,7 +810,8 @@ int fetchf_named_setting ( const char *name, char *buf, size_t len ) {
749 810
 	struct setting setting;
750 811
 	int rc;
751 812
 
752
-	if ( ( rc = parse_setting_name ( name, &settings, &setting ) ) != 0 )
813
+	if ( ( rc = parse_setting_name ( name, find_child_settings,
814
+					 &settings, &setting ) ) != 0 )
753 815
 		return rc;
754 816
 	return fetchf_setting ( settings, &setting, buf, len );
755 817
 }

+ 0
- 2
src/include/gpxe/settings.h View File

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

Loading…
Cancel
Save