1. Add doxygen markup for documentation.
[OpenSRF.git] / src / libopensrf / osrf_json_object.c
index 0cab256..430cb32 100644 (file)
@@ -13,6 +13,17 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 */
 
+/**
+       @file osrf_json_object.c
+       @brief Implementation of the basic operations involving jsonObjects.
+
+       As a performance tweak: we maintain a free list of jsonObjects that have already
+       been allocated but are not currently in use.  When we need to create a jsonObject,
+       we can take one from the free list, if one is available, instead of calling
+       malloc().  Likewise when we free a jsonObject, we can stick it on the free list
+       for potential reuse instead of calling free().
+*/
+
 #include <stdlib.h>
 #include <ctype.h>
 #include <errno.h>
@@ -24,6 +35,19 @@ GNU General Public License for more details.
 
 /* cleans up an object if it is morphing another object, also
  * verifies that the appropriate storage container exists where appropriate */
+/**
+       @brief Coerce a jsonObj into a specified type, if it isn't already of that type.
+       @param _obj_ Pointer to the jsonObject to be coerced.
+       @param newtype The desired type.
+
+       If the old type and the new type don't match, discard and free the old contents.
+
+       If the old type is JSON_STRING or JSON_NUMBER, free the internal string buffer even
+       if the type is not changing.
+
+       If the new type is JSON_ARRAY or JSON_HASH, make sure there is an osrfList or osrfHash
+       in the jsonObject, respectively.
+*/
 #define JSON_INIT_CLEAR(_obj_, newtype)                \
        if( _obj_->type == JSON_HASH && newtype != JSON_HASH ) {                        \
                osrfHashFree(_obj_->value.h);                   \
@@ -46,11 +70,19 @@ GNU General Public License for more details.
                _obj_->value.l->freeItem = _jsonFreeListItem;\
        }
 
+/** Count of the times we put a freed jsonObject on the free list instead of calling free() */
 static int unusedObjCapture = 0;
+/** Count of the times we reused a jsonObject from the free list instead of calling malloc() */
 static int unusedObjRelease = 0;
+/** Count of the times we allocated a jsonObject with malloc() */
 static int mallocObjCreate = 0;
+/** Number of unused jsonObjects currently on the free list */
 static int currentListLen = 0;
 
+/**
+       Union overlaying a jsonObject with a pointer.  When the jsonObject is not in use as a
+       jsonObject, we use the overlaid pointer to maintain a linked list of unused jsonObjects.
+*/
 union unusedObjUnion{
 
        union unusedObjUnion* next;
@@ -58,19 +90,20 @@ union unusedObjUnion{
 };
 typedef union unusedObjUnion unusedObj;
 
-// We maintain a free list of jsonObjects that are available
-// for use, in order to reduce the churning through
-// malloc() and free().
-
+/** Pointer to the head of the free list */
 static unusedObj* freeObjList = NULL;
 
 static void add_json_to_buffer( const jsonObject* obj,
        growing_buffer * buf, int do_classname, int second_pass );
 
 /**
- * Return all unused jsonObjects to the heap
- * @return Nothing
- */
+       @brief Return all jsonObjects in the free list to the heap.
+
+       Reclaims memory occupied by unused jsonObjects in the free list.  It is never really
+       necessary to call this function, assuming that we don't run out of memory.  However
+       it might be worth calling if we have built and destroyed a lot of jsonObjects that
+       we don't expect to need again, in order to reduce our memory footprint.
+*/
 void jsonObjectFreeUnused( void ) {
 
        unusedObj* temp;
@@ -81,10 +114,22 @@ void jsonObjectFreeUnused( void ) {
        }
 }
 
+/**
+       @brief Create a new jsonObject, optionally containing a string.
+       @param data Pointer to a string to be stored in the jsonObject; may be NULL.
+       @return Pointer to a newly allocate jsonObject.
+
+       If @a data is NULL, create a jsonObject of type JSON_NULL.  Otherwise create
+       a jsonObject of type JSON_STRING, containing the specified string.
+
+       The calling code is responsible for freeing the jsonObject by calling jsonObjectFree().
+*/
 jsonObject* jsonNewObject(const char* data) {
 
        jsonObject* o;
 
+       // Allocate a jsonObject; from the free list if possible,
+       // or from the heap if necessary.
        if( freeObjList ) {
                o = (jsonObject*) freeObjList;
                freeObjList = freeObjList->next;
@@ -110,6 +155,17 @@ jsonObject* jsonNewObject(const char* data) {
        return o;
 }
 
+/**
+       @brief Create a jsonObject, optionally containing a formatted string.
+       @param data Pointer to a printf-style format string; may be NULL.  Subsequent parameters,
+       if any, will be formatted and inserted into the resulting string.
+       @return Pointer to a newly created jsonObject.
+
+       If @a data is NULL, create a jsonObject of type JSON_NULL, and ignore any extra parameters.
+       Otherwise create a jsonObject of type JSON_STRING, containing the formatted string.
+
+       The calling code is responsible for freeing the jsonObject by calling jsonObjectFree().
+ */
 jsonObject* jsonNewObjectFmt(const char* data, ...) {
 
        jsonObject* o;
@@ -141,6 +197,16 @@ jsonObject* jsonNewObjectFmt(const char* data, ...) {
        return o;
 }
 
+/**
+       @brief Create a new jsonObject of type JSON_NUMBER.
+       @param num The number to store in the jsonObject.
+       @return Pointer to the newly created jsonObject.
+
+       The number is stored internally as a character string, as formatted by
+       doubleToString().
+
+       The calling code is responsible for freeing the jsonObject by calling jsonObjectFree().
+*/
 jsonObject* jsonNewNumberObject( double num ) {
        jsonObject* o = jsonNewObject(NULL);
        o->type = JSON_NUMBER;
@@ -149,8 +215,15 @@ jsonObject* jsonNewNumberObject( double num ) {
 }
 
 /**
- * Creates a new number object from a numeric string
- */
+       @brief Create a new jsonObject of type JSON_NUMBER from a numeric string.
+       @param numstr Pointer to a numeric character string.
+       @return Pointer to a newly created jsonObject containing the numeric value, or NULL
+               if the string is not numeric.
+
+       The jsonIsNumeric() function determines whether the input string is numeric.
+
+       The calling code is responsible for freeing the jsonObject by calling jsonObjectFree().
+*/
 jsonObject* jsonNewNumberStringObject( const char* numstr ) {
        if( !numstr )
                numstr = "0";
@@ -163,6 +236,17 @@ jsonObject* jsonNewNumberStringObject( const char* numstr ) {
        return o;
 }
 
+/**
+       @brief Create a new jsonObject of type JSON_BOOL, with a specified boolean value.
+       @param val An int used as a boolean value.
+       @return Pointer to the new jsonObject.
+
+       Zero represents false, and non-zero represents true, according to the usual convention.
+       In practice the value of @a val is stored unchanged, but the calling code should not try to
+       take advantage of that fact, because future versions may behave differently.
+
+       The calling code is responsible for freeing the jsonObject by calling jsonObjectFree().
+*/
 jsonObject* jsonNewBoolObject(int val) {
     jsonObject* o = jsonNewObject(NULL);
     o->type = JSON_BOOL;
@@ -170,12 +254,35 @@ jsonObject* jsonNewBoolObject(int val) {
     return o;
 }
 
+/**
+       @brief Create a new jsonObject of a specified type, with a default value.
+       @param type One of the 6 JSON types, as specified by the JSON_* macros.
+       @return Pointer to the new jsonObject.
+
+       An invalid type parameter will go unnoticed, and may lead to unpleasantness.
+
+       The default value is equivalent to an empty string (for a JSON_STRING), zero (for a
+       JSON_NUMBER), an empty hash (for a JSON_HASH), an empty array (for a JSON_ARRAY), or
+       false (for a JSON_BOOL).  A JSON_NULL, of course, has no value, but can still be
+       useful.
+
+       The calling code is responsible for freeing the jsonObject by calling jsonObjectFree().
+*/
 jsonObject* jsonNewObjectType(int type) {
        jsonObject* o = jsonNewObject(NULL);
        o->type = type;
+       if( JSON_BOOL == type )
+               o->value.b = 0;
        return o;
 }
 
+/**
+       @brief Free a jsonObject and everything in it.
+       @param o Pointer to the jsonObject to be freed.
+
+       Any jsonObjects stored inside the jsonObject (in hashes or arrays) will be freed as
+       well, and so one, recursively.
+*/
 void jsonObjectFree( jsonObject* o ) {
 
        if(!o || o->parent) return;
@@ -204,12 +311,26 @@ void jsonObjectFree( jsonObject* o ) {
                        mallocObjCreate, unusedObjCapture, unusedObjRelease, currentListLen );
 }
 
+/**
+       @brief Free a jsonObject through a void pointer.
+       @param key Not used.
+       @param item Pointer to the jsonObject to be freed, cast to a void pointer.
+
+       This function is a callback for freeing jsonObjects stored in an osrfHash.
+*/
 static void _jsonFreeHashItem(char* key, void* item){
        if(!item) return;
        jsonObject* o = (jsonObject*) item;
        o->parent = NULL; /* detach the item */
        jsonObjectFree(o);
 }
+
+/**
+       @brief Free a jsonObject through a void pointer.
+       @param item Pointer to the jsonObject to be freed, cast to a void pointer.
+
+       This function is a callback for freeing jsonObjects stored in an osrfList.
+ */
 static void _jsonFreeListItem(void* item){
        if(!item) return;
        jsonObject* o = (jsonObject*) item;
@@ -217,12 +338,39 @@ static void _jsonFreeListItem(void* item){
        jsonObjectFree(o);
 }
 
+/**
+       @brief Assign a boolean value to a jsonObject of type JSON_BOOL.
+       @param bl Pointer to the jsonObject.
+       @param val The boolean value to be applied, encoded as an int.
+
+       If the jsonObject is not already of type JSON_BOOL, it is converted to one, and
+       any previous contents are freed.
+
+       Zero represents false, and non-zero represents true, according to the usual convention.
+       In practice the value of @a val is stored unchanged, but the calling code should not try to
+       take advantage of that fact, because future versions may behave differently.
+*/
 void jsonSetBool(jsonObject* bl, int val) {
     if(!bl) return;
     JSON_INIT_CLEAR(bl, JSON_BOOL);
     bl->value.b = val;
 }
 
+/**
+       @brief Insert one jsonObject into a jsonObect of type JSON_ARRAY, at the end of the array.
+       @param o Pointer to the outer jsonObject that will receive additional payload.
+       @param newo Pointer to the inner jsonObject, or NULL.
+       @return The number of jsonObjects directly subordinate to the outer jsonObject,
+               or -1 for error.
+
+       If the pointer to the outer jsonObject is NULL, jsonObjectPush returns -1.
+
+       If the outer jsonObject is not already of type JSON_ARRAY, it is converted to one, and
+       any previous contents are freed.
+
+       If the pointer to the inner jsonObject is NULL, jsonObjectPush creates a new jsonObject
+       of type JSON_NULL, and appends it to the array.
+*/
 unsigned long jsonObjectPush(jsonObject* o, jsonObject* newo) {
     if(!o) return -1;
     if(!newo) newo = jsonNewObject(NULL);
@@ -233,9 +381,31 @@ unsigned long jsonObjectPush(jsonObject* o, jsonObject* newo) {
        return o->size;
 }
 
+/**
+       @brief Insert a jsonObject at a specified position in a jsonObject of type JSON_ARRAY.
+       @param dest Pointer to the outer jsonObject that will receive the new payload.
+       @param index A zero-based subscript specifying the position of the new jsonObject.
+       @param newObj Pointer to the new jsonObject to be inserted, or NULL.
+       @return The size of the internal osrfList where the array is stored, or -1 on error.
+
+       If @a dest is NULL, jsonObjectSetIndex returns -1.
+
+       If the outer jsonObject is not already of type JSON_ARRAY, it is converted to one, and
+       any previous contents are freed.
+
+       If @a newObj is NULL, jsonObject creates a new jsonObject of type JSON_NULL and
+       inserts it into the array.
+
+       If there is already a jsonObject at the specified location, it is freed and replaced.
+
+       Depending on the placement of the inner jsonObject, it may leave unoccupied holes in the
+       array that are included in the reported size.  As a result of this and other peculiarities
+       of the underlying osrfList within the jsonObject, the reported size may not reflect the
+       number of jsonObjects in the array.  See osrf_list.c for further details.
+*/
 unsigned long jsonObjectSetIndex(jsonObject* dest, unsigned long index, jsonObject* newObj) {
-    if(!dest) return -1;
-    if(!newObj) newObj = jsonNewObject(NULL);
+       if(!dest) return -1;
+       if(!newObj) newObj = jsonNewObject(NULL);
        JSON_INIT_CLEAR(dest, JSON_ARRAY);
        newObj->parent = dest;
        osrfListSet( dest->value.l, newObj, index );
@@ -243,6 +413,26 @@ unsigned long jsonObjectSetIndex(jsonObject* dest, unsigned long index, jsonObje
        return dest->value.l->size;
 }
 
+/**
+       @brief Insert a jsonObject into a jsonObject of type JSON_HASH, for a specified key.
+       @param o Pointer to the outer jsonObject that will receive the new payload.
+       @param key Pointer to a string that will serve as the key.
+       @param newo Pointer to the new jsonObject that will be inserted, or NULL.
+       @return The number of items stored in the first level of the hash.
+
+       If the @a o parameter is NULL, jsonObjectSetKey returns -1.
+
+       If the outer jsonObject is not already of type JSON_HASH, it will be converted to one,
+       and any previous contents will be freed.
+
+       If @a key is NULL, jsonObjectSetKey returns the size of the hash without doing anything
+       (apart from possibly converting the outer jsonObject as described above).
+
+       If @a newo is NULL, jsonObjectSetKey creates a new jsonObject of type JSON_NULL and inserts
+       it with the specified key.
+
+       If a previous jsonObject is already stored with the same key, it is freed and replaced.
+*/
 unsigned long jsonObjectSetKey( jsonObject* o, const char* key, jsonObject* newo) {
     if(!o) return -1;
     if(!newo) newo = jsonNewObject(NULL);
@@ -253,31 +443,52 @@ unsigned long jsonObjectSetKey( jsonObject* o, const char* key, jsonObject* newo
        return o->size;
 }
 
+/**
+       @brief From a jsonObject of type JSON_HASH, find the inner jsonObject for a specified key.
+       @param obj Pointer to the outer jsonObject.
+       @param key The key for the associated item to be found.
+       @return A pointer to the inner jsonObject, if found, or NULL if not.
+
+       Returns NULL if either parameter is NULL, or if @a obj points to a jsonObject not of type
+       JSON_HASH, or if the specified key is not found in the outer jsonObject.
+
+       The returned pointer (if not NULL) points to the interior of the outer jsonObject.  The
+       calling code should @em not try to free it, but it may change its contents.
+*/
 jsonObject* jsonObjectGetKey( jsonObject* obj, const char* key ) {
        if(!(obj && obj->type == JSON_HASH && obj->value.h && key)) return NULL;
        return osrfHashGet( obj->value.h, key);
 }
 
+/**
+       @brief From a jsonObject of type JSON_HASH, find the inner jsonObject for a specified key.
+       @param obj Pointer to the outer jsonObject.
+       @param key The key for the associated item to be found.
+       @return A pointer to the inner jsonObject, if found, or NULL if not.
+
+       This function is identical to jsonObjectGetKey(), except that the outer jsonObject may be
+       const, and the pointer returned points to const.  As a result, the calling code is put on
+       notice that it should not try to modify the contents of the inner jsonObject.
+ */
 const jsonObject* jsonObjectGetKeyConst( const jsonObject* obj, const char* key ) {
        if(!(obj && obj->type == JSON_HASH && obj->value.h && key)) return NULL;
        return osrfHashGet( obj->value.h, key);
 }
 
 /**
- * Recursively traverse a jsonObject, formatting it into a JSON string.
- *
- * The last two parameters are booleans.
- *
- * If do_classname is true, examine each node for a classname, and if you
- * find one, pretend that the node is under an extra layer of JSON_HASH, with
- * JSON_CLASS_KEY and JSON_DATA_KEY as keys.
- *
- * second_pass should always be false except for some recursive calls.  It
- * is used when expanding classnames, to distinguish between the first and
- * second passes through a given node.
- *
- * @return Nothing
- */
+       @brief Recursively traverse a jsonObject, translating it into a JSON string.
+       @param obj Pointer to the jsonObject to be translated.
+       @param buf Pointer to a growing_buffer that will receive the JSON string.
+       @param do_classname Boolean; if true, expand class names.
+       @param second_pass Boolean; should always be false except for some recursive calls.
+       If @a do_classname is true, expand any class names, as described in the discussion of
+       jsonObjectToJSON().
+
+       @a second_pass should always be false except for some recursive calls.  It is used
+       when expanding classnames, to distinguish between the first and second passes
+       through a given node.
+*/
 static void add_json_to_buffer( const jsonObject* obj,
        growing_buffer * buf, int do_classname, int second_pass ) {
 
@@ -366,6 +577,13 @@ static void add_json_to_buffer( const jsonObject* obj,
        }
 }
 
+/**
+       @brief Translate a jsonObject into a JSON string, without expanding class names.
+       @param obj Pointer to the jsonObject to be translated.
+       @return A pointer to a newly allocated string containing the JSON.
+
+       The calling code is responsible for freeing the resulting string.
+*/
 char* jsonObjectToJSONRaw( const jsonObject* obj ) {
        if(!obj) return NULL;
        growing_buffer* buf = buffer_init(32);
@@ -373,6 +591,17 @@ char* jsonObjectToJSONRaw( const jsonObject* obj ) {
        return buffer_release( buf );
 }
 
+/**
+       @brief Translate a jsonObject into a JSON string, with expansion of class names.
+       @param obj Pointer to the jsonObject to be translated.
+       @return A pointer to a newly allocated string containing the JSON.
+
+       At every level, any jsonObject containing a class name will be translated as if it were
+       under an extra layer of JSON_HASH, with JSON_CLASS_KEY as the key for the class name and
+       JSON_DATA_KEY as the key for the jsonObject.
+
+       The calling code is responsible for freeing the resulting string.
+ */
 char* jsonObjectToJSON( const jsonObject* obj ) {
        if(!obj) return NULL;
        growing_buffer* buf = buffer_init(32);
@@ -380,6 +609,18 @@ char* jsonObjectToJSON( const jsonObject* obj ) {
        return buffer_release( buf );
 }
 
+/**
+       @brief Create a new jsonIterator for traversing a specified jsonObject.
+       @param obj Pointer to the jsonObject to be traversed.
+       @return A pointer to the newly allocated jsonIterator, or NULL upon error.
+
+       jsonNewIterator returns NULL if @a obj is NULL.
+
+       The new jsonIterator does not point to any particular position within the jsonObject to
+       be traversed.  The next call to jsonIteratorNext() will position it at the beginning.
+
+       The calling code is responsible for freeing the jsonIterator by calling jsonIteratorFree().
+*/
 jsonIterator* jsonNewIterator(const jsonObject* obj) {
        if(!obj) return NULL;
        jsonIterator* itr;
@@ -397,12 +638,42 @@ jsonIterator* jsonNewIterator(const jsonObject* obj) {
        return itr;
 }
 
+/**
+       @brief Free a jsonIterator and everything in it.
+       @param itr Pointer to the jsonIterator to be freed.
+*/
 void jsonIteratorFree(jsonIterator* itr) {
        if(!itr) return;
        osrfHashIteratorFree(itr->hashItr);
        free(itr);
 }
 
+/**
+       @brief Advance a jsonIterator to the next position within a jsonObject.
+       @param itr Pointer to the jsonIterator to be advanced.
+       @return A Pointer to the next jsonObject within the jsonObject being traversed; or NULL.
+
+       If the jsonObject being traversed is of type JSON_HASH, jsonIteratorNext returns a pointer
+       to the next jsonObject within the internal osrfHash.  The associated key string is available
+       via the pointer member itr->key.
+
+       If the jsonObject being traversed is of type JSON_ARRAY, jsonIteratorNext returns a pointer
+       to the next jsonObject within the internal osrfList.
+
+       In either case, the jsonIterator remains at the same level within the jsonObject that it is
+       traversing.  It does @em not descend to traverse deeper levels recursively.
+
+       If there is no next jsonObject within the jsonObject being traversed, jsonIteratorNext
+       returns NULL.  It also returns NULL if @a itr is NULL, or if the jsonIterator is
+       detectably corrupted, or if the jsonObject to be traversed is of a type other than
+       JSON_HASH or JSON_ARRAY.
+
+       Once jsonIteratorNext has returned NULL, subsequent calls using the same iterator will
+       continue to return NULL.  There is no available function to start over at the beginning.
+
+       The pointer returned, if not NULL, points to an internal element of the jsonObject being
+       traversed.  The calling code should @em not try to free it, but it may modify its contents.
+*/
 jsonObject* jsonIteratorNext(jsonIterator* itr) {
        if(!(itr && itr->obj)) return NULL;
        if( itr->obj->type == JSON_HASH ) {
@@ -420,6 +691,14 @@ jsonObject* jsonIteratorNext(jsonIterator* itr) {
        }
 }
 
+/**
+       @brief Determine whether a jsonIterator is positioned at the last element of a jsonObject.
+       @param itr Pointer to the jsonIterator whose position is to be tested.
+       @return An int, as boolean: 0 if the iterator is positioned at the end, or 1 if it isn't.
+
+       If the jsonIterator is positioned where a call to jsonIteratorNext() would return NULL,
+       then jsonIteratorHasNext returns 0.  Otherwise it returns 1.
+*/
 int jsonIteratorHasNext(const jsonIterator* itr) {
        if(!(itr && itr->obj)) return 0;
        if( itr->obj->type == JSON_HASH )
@@ -427,14 +706,34 @@ int jsonIteratorHasNext(const jsonIterator* itr) {
        return (itr->index < itr->obj->size) ? 1 : 0;
 }
 
+/**
+       @brief Fetch a pointer to a specified element within a jsonObject of type JSON_ARRAY.
+       @param obj Pointer to the outer jsonObject.
+       @param index A zero-based index identifying the element to be fetched.
+       @return A pointer to the element at the specified location, if any, or NULL.
+
+       The return value is NULL if @a obj is null, or if the outer jsonObject is not of type
+       JSON_ARRAY, or if there is no element at the specified location.
+
+       If not NULL, the pointer returned points to an element within the outer jsonObject.  The
+       calling code should @em not try to free it, but it may modify its contents.
+*/
 jsonObject* jsonObjectGetIndex( const jsonObject* obj, unsigned long index ) {
        if(!obj) return NULL;
        return (obj->type == JSON_ARRAY) ? 
         (OSRF_LIST_GET_INDEX(obj->value.l, index)) : NULL;
 }
 
-
-
+/**
+       @brief Remove a specified element from a jsonObject of type JSON_ARRAY.
+       @param dest Pointer to the jsonObject from which the element is to be removed.
+       @param index A zero-based index identifying the element to be removed.
+       @return The number of elements remaining at the top level, or -1 upon error.
+
+       The return value is -1 if @a dest is NULL, or if it points to a jsonObject not of type
+       JSON_ARRAY.  Otherwise it reflects the number of elements remaining in the top level of
+       the outer jsonObject, not counting any at lower levels.
+*/
 unsigned long jsonObjectRemoveIndex(jsonObject* dest, unsigned long index) {
        if( dest && dest->type == JSON_ARRAY ) {
                osrfListRemove(dest->value.l, index);
@@ -443,15 +742,41 @@ unsigned long jsonObjectRemoveIndex(jsonObject* dest, unsigned long index) {
        return -1;
 }
 
+/**
+       @brief Extract a specified element from a jsonObject of type JSON_ARRAY.
+       @param dest Pointer to the jsonObject from which the element is to be extracted.
+       @param index A zero-based index identifying the element to be extracted.
+       @return A pointer to the extracted element, if successful; otherwise NULL.
+
+       THe return value is NULL if @a dest is NULL, or if it points to a jsonObject not of type
+       JSON_ARRAY, or if there is no element at the specified location.
+
+       Otherwise, the calling code assumes ownership of the jsonObject to which the return value
+       points, and is responsible for freeing it by calling jsonObjectFree().  The original outer
+       jsonObject remains unchanged except for the removal of the specified element.
 
+       This function is sijmilar to jsonObjectRemoveIndex(), except that it returns a pointer to
+       the removed sub-object instead of destroying it.
+*/
 jsonObject* jsonObjectExtractIndex(jsonObject* dest, unsigned long index) {
        if( dest && dest->type == JSON_ARRAY ) {
-               return osrfListExtract(dest->value.l, index);
+               jsonObject* obj = osrfListExtract(dest->value.l, index);
+               if( obj )
+                       obj->parent = NULL;
+               return obj;
        } else
                return NULL;
 }
 
+/**
+       @brief Remove an element, specified by key, from a jsonObject of type JSON_HASH.
+       @param dest Pointer to the outer jsonObject from which an element is to be removed.
+       @param key The key for the associated element to be removed.
+       @return 1 if successful, or -1 if not.
 
+       The operation is considered successful if @a dest and @a key are both non-NULL, and
+       @a dest points to a jsonObject of type JSON_HASH, even if the specified key is not found.
+*/
 unsigned long jsonObjectRemoveKey( jsonObject* dest, const char* key) {
        if( dest && key && dest->type == JSON_HASH ) {
                osrfHashRemove(dest->value.h, key);
@@ -461,11 +786,17 @@ unsigned long jsonObjectRemoveKey( jsonObject* dest, const char* key) {
 }
 
 /**
- Allocate a buffer and format a specified numeric value into it.
- Caller is responsible for freeing the buffer.
-**/
+       @brief Format a double into a character string.
+       @param num The double to be formatted.
+       @return A newly allocated character string containing the formatted number.
+
+       The number is formatted according to the printf-style format specification "%.30g". and
+       will therefore contain no more than 30 significant digits.
+
+       The calling code is responsible for freeing the resulting string.
+*/
 char* doubleToString( double num ) {
-       
+
        char buf[ 64 ];
        size_t len = snprintf(buf, sizeof( buf ), "%.30g", num) + 1;
        if( len < sizeof( buf ) )
@@ -480,6 +811,19 @@ char* doubleToString( double num ) {
        }
 }
 
+/**
+       @brief Fetch a pointer to the string stored in a jsonObject, if any.
+       @param obj Pointer to the jsonObject.
+       @return Pointer to the string stored internally, or NULL.
+
+       If @a obj points to a jsonObject of type JSON_STRING or JSON_NUMBER, the returned value
+       points to the string stored internally (a numeric string in the case of a JSON_NUMBER).
+       Otherwise the returned value is NULL.
+
+       The returned pointer should be treated as a pointer to const.  In particular it should
+       @em not be freed.  In a future release, the returned pointer may indeed be a pointer
+       to const.
+*/
 char* jsonObjectGetString(const jsonObject* obj) {
        if(obj)
        {
@@ -494,11 +838,29 @@ char* jsonObjectGetString(const jsonObject* obj) {
                return NULL;
 }
 
+/**
+       @brief Translate a jsonObject to a double.
+       @param @obj Pointer to the jsonObject.
+       @return The numeric value stored in the jsonObject.
+
+       If @a obj is NULL, or if it points to a jsonObject not of type JSON_NUMBER, the value
+       returned is zero.
+*/
 double jsonObjectGetNumber( const jsonObject* obj ) {
        return (obj && obj->type == JSON_NUMBER && obj->value.s)
                        ? strtod( obj->value.s, NULL ) : 0;
 }
 
+/**
+       @brief Store a copy of a specified character string in a jsonObject of type JSON_STRING.
+       @param dest Pointer to the jsonObject in which the string will be stored.
+       @param string Pointer to the string to be stored.
+
+       Both @a dest and @a string must be non-NULL.
+
+       If the jsonObject is not already of type JSON_STRING, it is converted to a JSON_STRING,
+       with any previous contents freed.
+*/
 void jsonObjectSetString(jsonObject* dest, const char* string) {
        if(!(dest && string)) return;
        JSON_INIT_CLEAR(dest, JSON_STRING);
@@ -510,6 +872,19 @@ void jsonObjectSetString(jsonObject* dest, const char* string) {
  a specified numeric string in it.  If the string is not numeric,
  store the equivalent of zero, and return an error status.
 **/
+/**
+       @brief Store a copy of a numeric character string in a jsonObject of type JSON_NUMBER.
+       @param dest Pointer to the jsonObject in which the number will be stored.
+       @param string Pointer to the numeric string to be stored.
+
+       Both @a dest and @a string must be non-NULL.
+
+       If the jsonObject is not already of type JSON_NUMBER, it is converted to a JSON_STRING,
+       with any previous contents freed.
+
+       If the input string is not numeric as determined by jsonIsNumeric(), the number stored
+       is zero.
+ */
 int jsonObjectSetNumberString(jsonObject* dest, const char* string) {
        if(!(dest && string)) return -1;
        JSON_INIT_CLEAR(dest, JSON_NUMBER);
@@ -524,22 +899,53 @@ int jsonObjectSetNumberString(jsonObject* dest, const char* string) {
        }
 }
 
+/**
+       @brief Store a number in a jsonObject of type JSON_NUMBER.
+       @param dest Pointer to the jsonObject in which the number will be stored.
+       @param num The number to be stored.
+
+       If the jsonObject is not already of type JSON_NUMBER, it is converted to one, with any
+       previous contents freed.
+*/
 void jsonObjectSetNumber(jsonObject* dest, double num) {
        if(!dest) return;
        JSON_INIT_CLEAR(dest, JSON_NUMBER);
        dest->value.s = doubleToString( num );
 }
 
+/**
+       @brief Assign a class name to a jsonObject.
+       @param dest Pointer to the jsonObject.
+       @param classname Pointer to a string containing the class name.
+
+       Both dest and classname must be non-NULL.
+*/
 void jsonObjectSetClass(jsonObject* dest, const char* classname ) {
        if(!(dest && classname)) return;
        free(dest->classname);
        dest->classname = strdup(classname);
 }
+
+/**
+       @brief Fetch a pointer to the class name of a jsonObject, if any.
+       @param dest Pointer to the jsonObject.
+       @return Pointer to a string containing the class name, if there is one; or NULL.
+
+       If not NULL, the pointer returned points to a string stored internally within the
+       jsonObject.  The calling code should @em not try to free it.
+*/
 const char* jsonObjectGetClass(const jsonObject* dest) {
     if(!dest) return NULL;
     return dest->classname;
 }
 
+/**
+       @brief Create a copy of an existing jsonObject, including all internal sub-objects.
+       @param o Pointer to the jsonObject to be copied.
+       @return A pointer to the newly created copy.
+
+       The calling code is responsible for freeing the copy of the original.
+*/
 jsonObject* jsonObjectClone( const jsonObject* o ) {
     if(!o) return jsonNewObject(NULL);
 
@@ -586,6 +992,14 @@ jsonObject* jsonObjectClone( const jsonObject* o ) {
     return result;
 }
 
+/**
+       @brief Return the truth or falsity of a jsonObject of type JSON_BOOL.
+       @param boolObj Pointer to the jsonObject.
+       @return 1 or 0, depending on whether the stored boolean is true or false.
+
+       If @a boolObj is NULL, or if it points to a jsonObject not of type JSON_BOOL, the
+       returned value is zero.
+*/
 int jsonBoolIsTrue( const jsonObject* boolObj ) {
     if( boolObj && boolObj->type == JSON_BOOL && boolObj->value.b )
         return 1;
@@ -593,6 +1007,16 @@ int jsonBoolIsTrue( const jsonObject* boolObj ) {
 }
 
 
+/**
+       @brief Create a copy of the string stored in a jsonObject.
+       @param o Pointer to the jsonObject whose string is to be copied.
+       @return Pointer to a newly allocated string copied from the jsonObject.
+
+       If @a o is NULL, or if it points to a jsonObject not of type JSON_STRING or JSON_NUMBER,
+       the returned value is NULL.  In the case of a JSON_NUMBER, the string created is numeric.
+
+       The calling code is responsible for freeing the newly created string.
+*/
 char* jsonObjectToSimpleString( const jsonObject* o ) {
        if(!o) return NULL;
 
@@ -616,6 +1040,29 @@ char* jsonObjectToSimpleString( const jsonObject* o ) {
  This validation follows the rules defined by the grammar at:
  http://www.json.org/
  **/
+/**
+       @brief Determine whether a specified character string is a valid JSON number.
+       @param s Pointer to the string to be examined.
+       @return 1 if the string is numeric, or 0 if not.
+
+       This function defines numericity according to JSON rules; see http://json.org/.  This
+       determination is based purely on the lexical properties of the string.  In particular
+       there is no guarantee that the number in a numeric string is representable in C as a
+       long long, a long double, or any other built-in type.
+
+       A numeric string consists of:
+
+       - An optional leading minus sign (but not a plus sign)
+       - One or more decimal digits.  The first digit may be a zero only if it is the only
+         digit to the left of the decimal.
+       - Optionally, a decimal point followed by one or more decimal digits.
+       - An optional exponent, consisting of:
+               - The letter E, in upper or lower case
+               - An optional plus or minus sign
+               - One or more decimal digits
+
+       See also jsonScrubNumber().
+*/
 int jsonIsNumeric( const char* s ) {
 
        if( !s || !*s ) return 0;
@@ -699,10 +1146,23 @@ int jsonIsNumeric( const char* s ) {
 }
 
 /**
- Allocate and reformat a numeric string into one that is valid
- by JSON rules.  If the string is not numeric, return NULL.
- Caller is responsible for freeing the buffer.
- **/
+       @brief Edit a string into a valid JSON number, if possible.
+       @param s Pointer to the string to be edited.
+       @return A pointer to a newly created numeric string, if possible; otherwise NULL.
+
+       JSON has rather exacting requirements about what constitutes a valid numeric string (see
+       jsonIsNumeric()).  Real-world input may be a bit sloppy.  jsonScrubNumber accepts numeric
+       strings in a less formal format and reformats them, where possible, according to JSON
+       rules.  It removes leading white space, a leading plus sign, and extraneous leading zeros.
+       It adds a leading zero as needed when the absolute value is less than 1.  It also accepts
+       scientific notation in the form of a bare exponent (e.g. "E-3"), supplying a leading factor
+       of "1".
+
+       If the input string is non-numeric even according to these relaxed rules, the return value
+       is NULL.
+
+       The calling code is responsible for freeing the newly created numeric string.
+*/
 char* jsonScrubNumber( const char* s ) {
        if( !s || !*s ) return NULL;