Add string configuration type
[people/mcb30/gpxe.git] / src / core / settings.c
1 /*
2  * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18
19 #include <stdint.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <errno.h>
23 #include <assert.h>
24 #include <gpxe/settings.h>
25
26 /** @file
27  *
28  * Configuration settings
29  *
30  */
31
32 /** Registered configuration setting types */
33 static struct config_setting_type
34 config_setting_types[0] __table_start ( config_setting_types );
35 static struct config_setting_type
36 config_setting_types_end[0] __table_end ( config_setting_types );
37
38 /** Registered configuration settings */
39 static struct config_setting
40 config_settings[0] __table_start ( config_settings );
41 static struct config_setting
42 config_settings_end[0] __table_end ( config_settings );
43
44 /**
45  * Find configuration setting type
46  *
47  * @v name              Name
48  * @ret type            Configuration setting type, or NULL
49  */
50 static struct config_setting_type *
51 find_config_setting_type ( const char *name ) {
52         struct config_setting_type *type;
53
54         for ( type = config_setting_types ; type < config_setting_types_end ;
55               type++ ) {
56                 if ( strcmp ( name, type->name ) == 0 )
57                         return type;
58         }
59         return NULL;
60 }
61
62 /**
63  * Find configuration setting
64  *
65  * @v name              Name
66  * @ret setting         Configuration setting, or NULL
67  */
68 static struct config_setting * find_config_setting ( const char *name ) {
69         struct config_setting *setting;
70
71         for ( setting = config_settings ; setting < config_settings_end ;
72               setting++ ) {
73                 if ( strcmp ( name, setting->name ) == 0 )
74                         return setting;
75         }
76         return NULL;
77 }
78
79 /**
80  * Find or build configuration setting
81  *
82  * @v name              Name
83  * @v tmp_setting       Temporary buffer for constructing a setting
84  * @ret setting         Configuration setting, or NULL
85  *
86  * Find setting if it exists.  If it doesn't exist, but the name is of
87  * the form "<num>.<type>" (e.g. "12.string"), then construct a
88  * setting for that tag and data type, and return it.  The constructed
89  * setting will be placed in the temporary buffer.
90  */
91 static struct config_setting *
92 find_or_build_config_setting ( const char *name,
93                                struct config_setting *tmp_setting ) {
94         struct config_setting *setting;
95         char *separator;
96
97         /* Look in the list of registered settings first */
98         setting = find_config_setting ( name );
99         if ( setting )
100                 return setting;
101
102         /* If name is of the form "<num>.<type>", try to construct a setting */
103         setting = tmp_setting;
104         memset ( setting, 0, sizeof ( *setting ) );
105         setting->name = name;
106         setting->tag = strtoul ( name, &separator, 10 );
107         if ( *separator != '.' )
108                 return NULL;
109         setting->type = find_config_setting_type ( separator + 1 );
110         if ( ! setting->type )
111                 return NULL;
112         return setting;
113 }
114
115 /** Show value of setting
116  *
117  * @v context           Configuration context
118  * @v name              Configuration setting name
119  * @v buf               Buffer to contain value
120  * @v len               Length of buffer
121  * @ret rc              Return status code
122  */
123 int ( show_setting ) ( struct config_context *context, const char *name,
124                        char *buf, size_t len ) {
125         struct config_setting *setting;
126         struct config_setting tmp_setting;
127
128         setting = find_or_build_config_setting ( name, &tmp_setting );
129         if ( ! setting )
130                 return -ENOENT;
131         return setting->type->show ( context, setting, buf, len );
132 }
133
134 /** Set value of setting
135  *
136  * @v context           Configuration context
137  * @v name              Configuration setting name
138  * @v value             Setting value (as a string)
139  * @ret rc              Return status code
140  */
141 int ( set_setting ) ( struct config_context *context, const char *name,
142                       const char *value ) {
143         struct config_setting *setting;
144         struct config_setting tmp_setting;
145
146         setting = find_or_build_config_setting ( name, &tmp_setting );
147         if ( ! setting )
148                 return -ENOENT;
149         return setting->type->set ( context, setting, value );
150 }
151
152 /**
153  * Show value of string setting
154  *
155  * @v context           Configuration context
156  * @v setting           Configuration setting
157  * @v buf               Buffer to contain value
158  * @v len               Length of buffer
159  * @ret rc              Return status code
160  */
161 static int show_string ( struct config_context *context,
162                          struct config_setting *setting,
163                          char *buf, size_t len ) {
164         struct dhcp_option *option;
165
166         option = find_dhcp_option ( context->options, setting->tag );
167         if ( ! option )
168                 return -ENOENT;
169         dhcp_snprintf ( buf, len, option );
170         return 0;
171 }
172
173 /** Set value of string setting
174  *
175  * @v context           Configuration context
176  * @v setting           Configuration setting
177  * @v value             Setting value (as a string)
178  * @ret rc              Return status code
179  */ 
180 static int set_string ( struct config_context *context,
181                         struct config_setting *setting,
182                         const char *value ) {
183         struct dhcp_option *option;
184
185         option = set_dhcp_option ( context->options, setting->tag,
186                                    value, strlen ( value ) );
187         if ( ! option )
188                 return -ENOMEM;
189         return 0;
190 }
191
192 /** A string configuration setting */
193 struct config_setting_type config_setting_type_string __config_setting_type = {
194         .name = "string",
195         .show = show_string,
196         .set = set_string,
197 };