|  | @@ -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 |  }
 |