From 0cf19359c8f1ec01b6dd99194381c999f3256b43 Mon Sep 17 00:00:00 2001 From: scottmk Date: Mon, 22 Feb 2010 17:53:35 +0000 Subject: [PATCH 1/1] 1. Added doxygen-style comments to document all functions. 2. For osrfConfigHasDefault() and osrfConfigCleanup(): added a formal void parameter so that the header will contain prototypes rather than mere declarations. 3. In osrfConfigValueObject: added a sanity check for a non-loaded configuration. 4. In osrfConfigGetValueList(): replaced a call to jsonObjectToSimpleString() with a call to jsonObjectGetString(), in order to eliminate a malloc() and free(). 5. Tidied up the white space here and there. M include/opensrf/osrfConfig.h M src/libopensrf/osrfConfig.c git-svn-id: svn://svn.open-ils.org/OpenSRF/trunk@1929 9efc2488-bf62-4759-914b-345cdb29e865 --- include/opensrf/osrfConfig.h | 93 +++++------------- src/libopensrf/osrfConfig.c | 185 ++++++++++++++++++++++++++++++----- 2 files changed, 183 insertions(+), 95 deletions(-) diff --git a/include/opensrf/osrfConfig.h b/include/opensrf/osrfConfig.h index e732497..75490f7 100644 --- a/include/opensrf/osrfConfig.h +++ b/include/opensrf/osrfConfig.h @@ -16,6 +16,23 @@ GNU General Public License for more details. #ifndef OSRF_CONFIG_H #define OSRF_CONFIG_H +/** + @file osrfConfig.h + @brief Routines for loading, storing, and searching configurations. + + A configuration file, encoded as XML, is loaded and translated into a jsonObject. This + object is stored in an osrfConfig, along with an optional context string which, if + present, restricts subsequent searches to a subset of the jsonObject. + + In theory the context string could identify multiple subtrees of the total configuration. + In practice it is used to partition a configuration file into different pieces, each piece + to be used by a different application. + + Normally an application loads a default configuration, accessible from every linked + module. It is also possible, although seldom useful, to create and search a configuration + distinct from the default configuration. +*/ + #include #include #include @@ -25,89 +42,29 @@ GNU General Public License for more details. extern "C" { #endif +/** + @brief Represents a configuration; normally loaded from an XML configuration file. +*/ typedef struct { - jsonObject* config; - char* configContext; + jsonObject* config; /**< Represents the contents of the XML configuration file. */ + char* configContext; /**< Context string (optional). */ } osrfConfig; - -/** - Parses a new config file. Caller is responsible for freeing the returned - config object when finished. - @param configFile The XML config file to parse. - @param configContext Optional root of the subtree in the config file where - we will look for values. If it's not provided, searches will be - performed from the root of the config file - @return The config object if the file parses successfully. Otherwise - it returns NULL; -*/ osrfConfig* osrfConfigInit(const char* configFile, const char* configContext); -/** - @return True if we have a default config defined -*/ -int osrfConfigHasDefaultConfig(); +int osrfConfigHasDefaultConfig( void ); -/** - Replaces the config object's json object. This is useful - if you have a json object already and not an XML config - file to parse. - @param cfg The config object to alter - @param obj The json object to use when searching values -*/ void osrfConfigReplaceConfig(osrfConfig* cfg, const jsonObject* obj); -/** Deallocates a config object - @param cfg The config object to free -*/ void osrfConfigFree(osrfConfig* cfg); - -/* Assigns the default config file. This file will be used whenever - NULL is passed to config retrieval functions - @param cfg The config object to use as the default config -*/ void osrfConfigSetDefaultConfig(osrfConfig* cfg); -/* frees the default config if one exists */ -void osrfConfigCleanup(); +void osrfConfigCleanup( void ); - -/** - Returns the value in the config found at 'path'. - If the value found at 'path' is a long or a double, - the value is stringified and then returned. - The caller must free the returned char* - - if there is a configContext, then it will be appended to - the front of the path like so: /// - if no configContext was provided to osfConfigSetFile, then - the path is interpreted literally. - @param cfg The config file to search or NULL if the default - config should be used - @param path The search path -*/ char* osrfConfigGetValue(const osrfConfig* cfg, const char* path, ...); - -/** - * @see osrfConfigGetValue - * @return jsonObject found at path - */ -jsonObject* osrfConfigGetValueObject(osrfConfig* cfg, char* path, ...); - - -/** - Puts the list of values found at 'path' into the pre-allocated - string array. - Note that the config node found at 'path' must be an array. - @param cfg The config file to search or NULL if the default - config should be used - @param arr An allocated string_array where the values will - be stored - @param path The search path - @return the number of values added to the string array; -*/ +jsonObject* osrfConfigGetValueObject(osrfConfig* cfg, const char* path, ...); int osrfConfigGetValueList(const osrfConfig* cfg, osrfStringArray* arr, const char* path, ...); diff --git a/src/libopensrf/osrfConfig.c b/src/libopensrf/osrfConfig.c index d90e272..29ff43c 100644 --- a/src/libopensrf/osrfConfig.c +++ b/src/libopensrf/osrfConfig.c @@ -1,9 +1,23 @@ /* defines the currently used bootstrap config file */ #include +/** + @file osrfConfig.c + @brief Routines for managing osrfConfigs to represent configuration information. +*/ + +/** + @brief Points to the default configuration. +*/ static osrfConfig* osrfConfigDefault = NULL; +/** + @brief Install a specified osrfConfig as the default configuration. + @param cfg Pointer to the configuration to be stored. + Store the passed pointer for future reference. The calling code yields ownership of the + associated osrfConfig. +*/ void osrfConfigSetDefaultConfig(osrfConfig* cfg) { if(cfg) { if( osrfConfigDefault ) @@ -12,37 +26,69 @@ void osrfConfigSetDefaultConfig(osrfConfig* cfg) { } } +/** + @brief Free an osrfConfig. + @param cfg Pointer to the osrfConfig to be freed. +*/ void osrfConfigFree(osrfConfig* cfg) { if(cfg) { jsonObjectFree(cfg->config); free(cfg->configContext); free(cfg); - } + } } - -int osrfConfigHasDefaultConfig() { +/** + @brief Report whether a default configuration has been installed. + @return Boolean: true if a default configuration is available, or false if not. +*/ +int osrfConfigHasDefaultConfig( void ) { return ( osrfConfigDefault != NULL ); } - -void osrfConfigCleanup() { +/** + @brief Free the default configuration, if it exists. +*/ +void osrfConfigCleanup( void ) { osrfConfigFree(osrfConfigDefault); osrfConfigDefault = NULL; } +/** + @brief Replace the jsonObject of an osrfConfig. + @param cfg The osrfConfig to alter. + @param obj The jsonObject to install in the osrfConfig. + This is useful if you have a json object already, rather than an XML configuration file + to parse. +*/ void osrfConfigReplaceConfig(osrfConfig* cfg, const jsonObject* obj) { if(!cfg || !obj) return; jsonObjectFree(cfg->config); - cfg->config = jsonObjectClone(obj); + cfg->config = jsonObjectClone(obj); } +/** + @brief Load an XML configuration file into a jsonObject within an osrfConfig. + @param configFile Name of the XML configuration file. + @param configContext (Optional) Root of a subtree in the configuration file, + @return If successful, a pointer to the resulting osrfConfig; otherwise NULL. + + If @a configContext is not NULL, save a copy of the string to which it points. It is a + tag identifying one or more subtrees within the XML; subsequent searches will examine + only matching subtrees. Otherwise they will search the tree from the root. + + (In practice a configContext is always supplied, so that different programs can share + the same configuration file, partitioned by context tags.) + + The calling code is responsible for freeing the returned config object by calling + osrfConfigFree(). +*/ osrfConfig* osrfConfigInit(const char* configFile, const char* configContext) { if(!configFile) return NULL; // Load XML from the configuration file - + xmlDocPtr doc = xmlParseFile(configFile); if(!doc) { osrfLogWarning( OSRF_LOG_MARK, "Unable to parse XML config file %s", configFile); @@ -50,34 +96,62 @@ osrfConfig* osrfConfigInit(const char* configFile, const char* configContext) { } // Translate it into a jsonObject - jsonObject* json_config = xmlDocToJSON(doc); xmlFreeDoc(doc); if(!json_config ) { osrfLogWarning( OSRF_LOG_MARK, "xmlDocToJSON failed for config %s", configFile); return NULL; - } + } // Build an osrfConfig and return it by pointer - osrfConfig* cfg = safe_malloc(sizeof(osrfConfig)); - if(configContext) cfg->configContext = strdup(configContext); - else cfg->configContext = NULL; + if( configContext ) + cfg->configContext = strdup(configContext); + else + cfg->configContext = NULL; cfg->config = json_config; - + return cfg; } +/** + @brief Search a configuration for a specified value. + @param cfg (Optional) The configuration to search, or NULL for the default configuration. + @param path A printf-style format string representing the search path. Subsequent + parameters, if any, are inserted into the format string to form the search path. + @return A pointer to a newly allocated string containing the value, if found; otherwise + NULL. + + Search for a value in the configuration, as specified by the search path. + + If cfg is NULL, search the default configuration; otherwise search the configuration + specified. + + If the configuration includes a configContext, then prepend it to the path, like so: + "//". Hence the path should begin with a slash to separate it from + the context. Search for the resulting effective path at any level within the + configuration. + + If the configuration does @em not include a configContext, then start the search at the + root of the configuration. In this case the path should @em not begin with a slash. + + If the configuration contains more than one entry at locations matching the effective + search path, return NULL. + Return numeric values as numeric strings. + + The calling code is responsible for freeing the returned string by calling free(). +*/ char* osrfConfigGetValue(const osrfConfig* cfg, const char* path, ...) { if(!path) return NULL; - if(!cfg) cfg = osrfConfigDefault; - if(!cfg) { - osrfLogWarning( OSRF_LOG_MARK, "No Config object in osrfConfigGetValue()"); - return NULL; + if(!cfg) + cfg = osrfConfigDefault; + if(!cfg) { + osrfLogWarning( OSRF_LOG_MARK, "No Config object in osrfConfigGetValue()"); + return NULL; } VA_LIST_TO_STRING(path); @@ -89,29 +163,88 @@ char* osrfConfigGetValue(const osrfConfig* cfg, const char* path, ...) { obj = jsonObjectExtractIndex( outer_obj, 0 ); jsonObjectFree( outer_obj ); } else - obj = jsonObjectFindPath( cfg->config, VA_BUF); + obj = jsonObjectFindPath( cfg->config, VA_BUF ); char* val = jsonObjectToSimpleString(obj); jsonObjectFree(obj); return val; } -jsonObject* osrfConfigGetValueObject(osrfConfig* cfg, char* path, ...) { +/** + @brief Search for one or more subtrees of a configuration. + @param cfg (Optional) The configuration to search, or NULL for the default configuration. + @param path A printf-style format string representing the search path. Subsequent + parameters, if any, are inserted into the format string to form the search path. + @return A pointer to a jsonObject representing a subset of the specified configuration, + if found; otherwise NULL. + + Search for subtrees of the configuration, as specified by the search path. + + If the configuration includes a configContext, then prepend it to the path, like so: + "//". Hence the path should begin with a slash to separate it from + the context. Search for the resulting effective path at any level within the + configuration. + + If the configuration does @em not include a configContext, then start the search at the + root of the configuration. In this case the path should @em not begin with a slash. + + If any entries match the effective path, return copies of them all as elements of a + jsonObject of type JSON_ARRAY. + + If no entries match the effective path, return a jsonObject of type JSON_NULL. + + The calling code is responsible for freeing the returned jsonObject by calling + jsonObjectFree(). +*/ +jsonObject* osrfConfigGetValueObject(osrfConfig* cfg, const char* path, ...) { if(!path) return NULL; - if(!cfg) cfg = osrfConfigDefault; + if(!cfg) + cfg = osrfConfigDefault; + if(!cfg) { + osrfLogWarning( OSRF_LOG_MARK, "No Config object in osrfConfigGetValueObject()"); + return NULL; + } + VA_LIST_TO_STRING(path); - if(cfg->configContext) - return jsonObjectFindPath(cfg->config, "//%s%s", cfg->configContext, VA_BUF); + if(cfg->configContext) + return jsonObjectFindPath(cfg->config, "//%s%s", cfg->configContext, VA_BUF); else return jsonObjectFindPath(cfg->config, VA_BUF); } +/** + @brief Search for one or more values in a configuration, specified by a path. + @param cfg (Optional) The configuration to search, or NULL for the default configuration. + @param arr Pointer to an osrfStringArray to be populated with values. + @param path A printf-style format string representing the search path. Subsequent + parameters, if any, are inserted into the format string to form the search path. + @return The number of values loaded into the osrfStringArray. + + Search the configuration for values specified by the search path. Load any values + found (either strings or numbers) into an existing osrfStringArray supplied by the + calling code. + + Make no effort to delete any strings that may already be in the osrfStringArray. + Ordinarily the calling code should ensure that the osrfStringArray is empty when passed. + + If the configuration includes a configContext, then prepend it to the path, like so: + "//". Hence the path should begin with a slash to separate it from + the context. Search for the resulting effective path at any level within the + configuration. + + If the configuration does @em not include a configContext, then start the search at the + root of the configuration. In this case the path should @em not begin with a slash. +*/ int osrfConfigGetValueList(const osrfConfig* cfg, osrfStringArray* arr, const char* path, ...) { if(!arr || !path) return 0; - if(!cfg) cfg = osrfConfigDefault; - if(!cfg) { osrfLogWarning( OSRF_LOG_MARK, "No Config object!"); return -1;} + if(!cfg) + cfg = osrfConfigDefault; + if(!cfg) { + osrfLogWarning( OSRF_LOG_MARK, "No Config object!"); + return -1; + } VA_LIST_TO_STRING(path); @@ -129,11 +262,10 @@ int osrfConfigGetValueList(const osrfConfig* cfg, osrfStringArray* arr, int i; for( i = 0; i < obj->size; i++ ) { - char* val = jsonObjectToSimpleString(jsonObjectGetIndex(obj, i)); + const char* val = jsonObjectGetString( jsonObjectGetIndex(obj, i) ); if(val) { count++; osrfStringArrayAdd(arr, val); - free(val); } } } @@ -141,4 +273,3 @@ int osrfConfigGetValueList(const osrfConfig* cfg, osrfStringArray* arr, jsonObjectFree(obj); return count; } - -- 2.43.2