]> git.evergreen-ils.org Git - OpenSRF.git/blob - src/libopensrf/osrfConfig.c
LP#1243841: quiet a misleading indentation warning
[OpenSRF.git] / src / libopensrf / osrfConfig.c
1 /* defines the currently used bootstrap config file */
2 #include <opensrf/osrfConfig.h>
3
4 /**
5         @file osrfConfig.c
6         @brief Routines for managing osrfConfigs to represent configuration information.
7 */
8
9 /**
10         @brief Points to the default configuration.
11 */
12 static osrfConfig* osrfConfigDefault = NULL;
13
14 /**
15         @brief Install a specified osrfConfig as the default configuration.
16         @param cfg Pointer to the configuration to be stored.
17
18         Store the passed pointer for future reference.  The calling code yields ownership of the
19         associated osrfConfig.
20 */
21 void osrfConfigSetDefaultConfig(osrfConfig* cfg) {
22         if(cfg) {
23                 if( osrfConfigDefault )
24                         osrfConfigFree( osrfConfigDefault );
25                 osrfConfigDefault = cfg;
26         }
27 }
28
29 osrfConfig* osrfConfigGetDefaultConfig() {
30     return osrfConfigDefault;
31 }
32
33 /**
34         @brief Free an osrfConfig.
35         @param cfg Pointer to the osrfConfig to be freed.
36 */
37 void osrfConfigFree(osrfConfig* cfg) {
38         if(cfg) {
39                 jsonObjectFree(cfg->config);
40                 free(cfg->configContext);
41                 free(cfg->configFileName);
42                 free(cfg);
43         }
44 }
45
46 /**
47         @brief Report whether a default configuration has been installed.
48         @return Boolean: true if a default configuration is available, or false if not.
49 */
50 int osrfConfigHasDefaultConfig( void ) {
51         return ( osrfConfigDefault != NULL );
52 }
53
54 /**
55         @brief Free the default configuration, if it exists.
56 */
57 void osrfConfigCleanup( void ) {
58         osrfConfigFree(osrfConfigDefault);
59         osrfConfigDefault = NULL;
60 }
61
62 /**
63         @brief Replace the jsonObject of an osrfConfig.
64         @param cfg The osrfConfig to alter.
65         @param obj The jsonObject to install in the osrfConfig.
66
67         This is useful if you have a json object already, rather than an XML configuration file
68         to parse.
69 */
70 void osrfConfigReplaceConfig(osrfConfig* cfg, const jsonObject* obj) {
71         if(!cfg || !obj) return;
72         jsonObjectFree(cfg->config);
73         cfg->config = jsonObjectClone(obj);
74 }
75
76 /**
77         @brief Load an XML configuration file into a jsonObject within an osrfConfig.
78         @param configFile Name of the XML configuration file.
79         @param configContext (Optional) Root of a subtree in the configuration file,
80         @return If successful, a pointer to the resulting osrfConfig; otherwise NULL.
81
82         If @a configContext is not NULL, save a copy of the string to which it points.  It is a
83         tag identifying one or more subtrees within the XML; subsequent searches will examine
84         only matching subtrees.  Otherwise they will search the tree from the root.
85
86         (In practice a configContext is always supplied, so that different programs can share
87         the same configuration file, partitioned by context tags.)
88
89         The calling code is responsible for freeing the returned config object by calling
90         osrfConfigFree().
91 */
92 osrfConfig* osrfConfigInit(const char* configFile, const char* configContext) {
93         if(!configFile) return NULL;
94
95         // Load XML from the configuration file
96
97         xmlDocPtr doc = xmlParseFile(configFile);
98         if(!doc) {
99                 osrfLogWarning( OSRF_LOG_MARK, "Unable to parse XML config file %s", configFile);
100                 return NULL;
101         }
102
103         // Translate it into a jsonObject
104         jsonObject* json_config = xmlDocToJSON(doc);
105         xmlFreeDoc(doc);
106
107         if(!json_config ) {
108                 osrfLogWarning( OSRF_LOG_MARK, "xmlDocToJSON failed for config %s", configFile);
109                 return NULL;
110         }
111
112         // Build an osrfConfig and return it by pointer
113         osrfConfig* cfg = safe_malloc(sizeof(osrfConfig));
114
115         if( configContext )
116                 cfg->configContext = strdup(configContext);
117         else
118                 cfg->configContext = NULL;
119
120     cfg->configFileName = strdup(configFile);
121         cfg->config = json_config;
122
123         return cfg;
124 }
125
126 /**
127         @brief Search a configuration for a specified value.
128         @param cfg (Optional) The configuration to search, or NULL for the default configuration.
129         @param path A printf-style format string representing the search path.  Subsequent
130         parameters, if any, are inserted into the format string to form the search path.
131         @return A pointer to a newly allocated string containing the value, if found; otherwise
132         NULL.
133
134         Search for a value in the configuration, as specified by the search path.
135
136         If cfg is NULL, search the default configuration; otherwise search the configuration
137         specified.
138
139         If the configuration includes a configContext, then prepend it to the path, like so:
140         "//<configContext><path>".  Hence the path should begin with a slash to separate it from
141         the context.  Search for the resulting effective path at any level within the
142         configuration.
143
144         If the configuration does @em not include a configContext, then start the search at the
145         root of the configuration.  In this case the path should @em not begin with a slash.
146
147         If the configuration contains more than one entry at locations matching the effective
148         search path, return NULL.
149
150         Return numeric values as numeric strings.
151
152         The calling code is responsible for freeing the returned string by calling free().
153 */
154 char* osrfConfigGetValue(const osrfConfig* cfg, const char* path, ...) {
155         if(!path) return NULL;
156         if(!cfg)
157                 cfg = osrfConfigDefault;
158         if(!cfg) {
159                 osrfLogWarning( OSRF_LOG_MARK, "No Config object in osrfConfigGetValue()");
160                 return NULL;
161         }
162
163         VA_LIST_TO_STRING(path);
164         jsonObject* obj;
165
166         if(cfg->configContext) {
167                 jsonObject* outer_obj =
168                         jsonObjectFindPath(cfg->config, "//%s%s", cfg->configContext, VA_BUF);
169                 obj = jsonObjectExtractIndex( outer_obj, 0 );
170                 jsonObjectFree( outer_obj );
171         } else
172                 obj = jsonObjectFindPath( cfg->config, VA_BUF );
173
174         char* val = jsonObjectToSimpleString(obj);
175         jsonObjectFree(obj);
176         return val;
177 }
178
179 /**
180         @brief Search for one or more subtrees of a configuration.
181         @param cfg (Optional) The configuration to search, or NULL for the default configuration.
182         @param path A printf-style format string representing the search path.  Subsequent
183         parameters, if any, are inserted into the format string to form the search path.
184         @return A pointer to a jsonObject representing a subset of the specified configuration,
185         if found; otherwise NULL.
186
187         Search for subtrees of the configuration, as specified by the search path.
188
189         If the configuration includes a configContext, then prepend it to the path, like so:
190         "//<configContext><path>".  Hence the path should begin with a slash to separate it from
191         the context.  Search for the resulting effective path at any level within the
192         configuration.
193
194         If the configuration does @em not include a configContext, then start the search at the
195         root of the configuration.  In this case the path should @em not begin with a slash.
196
197         If any entries match the effective path, return copies of them all as elements of a
198         jsonObject of type JSON_ARRAY.
199
200         If no entries match the effective path, return a jsonObject of type JSON_NULL.
201
202         The calling code is responsible for freeing the returned jsonObject by calling
203         jsonObjectFree().
204 */
205 jsonObject* osrfConfigGetValueObject(osrfConfig* cfg, const char* path, ...) {
206         if(!path) return NULL;
207         if(!cfg)
208                 cfg = osrfConfigDefault;
209         if(!cfg) {
210                 osrfLogWarning( OSRF_LOG_MARK, "No Config object in osrfConfigGetValueObject()");
211                 return NULL;
212         }
213
214         VA_LIST_TO_STRING(path);
215         if(cfg->configContext)
216                 return jsonObjectFindPath(cfg->config, "//%s%s", cfg->configContext, VA_BUF);
217         else
218                 return jsonObjectFindPath(cfg->config, VA_BUF);
219 }
220
221 /**
222         @brief Search for one or more values in a configuration, specified by a path.
223         @param cfg (Optional) The configuration to search, or NULL for the default configuration.
224         @param arr Pointer to an osrfStringArray to be populated with values.
225         @param path A printf-style format string representing the search path.  Subsequent
226         parameters, if any, are inserted into the format string to form the search path.
227         @return The number of values loaded into the osrfStringArray.
228
229         Search the configuration for values specified by the search path.  Load any values
230         found (either strings or numbers) into an existing osrfStringArray supplied by the
231         calling code.
232
233         Make no effort to delete any strings that may already be in the osrfStringArray.
234         Ordinarily the calling code should ensure that the osrfStringArray is empty when passed.
235
236         If the configuration includes a configContext, then prepend it to the path, like so:
237         "//<configContext><path>".  Hence the path should begin with a slash to separate it from
238         the context.  Search for the resulting effective path at any level within the
239         configuration.
240
241         If the configuration does @em not include a configContext, then start the search at the
242         root of the configuration.  In this case the path should @em not begin with a slash.
243 */
244 int osrfConfigGetValueList(const osrfConfig* cfg, osrfStringArray* arr,
245                 const char* path, ...) {
246
247         if(!arr || !path) return 0;
248         if(!cfg)
249                 cfg = osrfConfigDefault;
250         if(!cfg) {
251                 osrfLogWarning( OSRF_LOG_MARK, "No Config object!");
252                 return -1;
253         }
254
255         VA_LIST_TO_STRING(path);
256
257         jsonObject* obj;
258         if(cfg->configContext) {
259                 obj = jsonObjectFindPath( cfg->config, "//%s%s", cfg->configContext, VA_BUF);
260         } else {
261                 obj = jsonObjectFindPath( cfg->config, VA_BUF);
262         }
263
264         int count = 0;
265
266         if(obj && obj->type == JSON_ARRAY ) {
267
268                 int i;
269                 for( i = 0; i < obj->size; i++ ) {
270
271                         const char* val = jsonObjectGetString( jsonObjectGetIndex(obj, i) );
272                         if(val) {
273                                 count++;
274                                 osrfStringArrayAdd(arr, val);
275                         }
276                 }
277         }
278
279         jsonObjectFree(obj);
280         return count;
281 }