This update boosts the performance of the jsonFormatString function.
[OpenSRF.git] / src / libopensrf / osrf_json_tools.c
index 35ce3c9..91b3f26 100644 (file)
@@ -16,13 +16,16 @@ GNU General Public License for more details.
 #include <opensrf/osrf_json.h>
 #include <opensrf/osrf_json_utils.h>
 
+static jsonObject* findMultiPath( const jsonObject* o,
+               const char* root, const char* path );
+static jsonObject* findMultiPathRecurse( const jsonObject* o, const char* root );
 static jsonObject* _jsonObjectEncodeClass( const jsonObject* obj, int ignoreClass );
 
-static char* _tabs(int count) {
-       growing_buffer* buf = buffer_init(24);
-       int i;
-       for(i=0;i<count;i++) OSRF_BUFFER_ADD(buf, "  ");
-    return buffer_release(buf);
+static void append_indentation( growing_buffer* buf, int depth ) {
+       size_t n = 2 * depth;
+       char indent[ n ];
+       memset( indent, ' ', n );
+       buffer_add_n( buf, indent, n );
 }
 
 char* jsonFormatString( const char* string ) {
@@ -31,38 +34,31 @@ char* jsonFormatString( const char* string ) {
        growing_buffer* buf = buffer_init(64);
        int i;
        int depth = 0;
-       char* tab = NULL;
 
        char c;
-       for(i=0; i!= strlen(string); i++) {
+       for(i = 0; string[i]; i++) {
                c = string[i];
 
                if( c == '{' || c == '[' ) {
 
-                       tab = _tabs(++depth);
-                       buffer_fadd( buf, "%c\n%s", c, tab);
-                       free(tab);
+                       OSRF_BUFFER_ADD_CHAR( buf, c );
+                       OSRF_BUFFER_ADD_CHAR( buf, '\n' );
+                       append_indentation( buf, ++depth );
 
                } else if( c == '}' || c == ']' ) {
 
-                       tab = _tabs(--depth);
-                       buffer_fadd( buf, "\n%s%c", tab, c);
-                       free(tab);
-
-                       if(string[i+1] != ',') {
-                               tab = _tabs(depth);
-                               buffer_fadd( buf, "%s", tab );  
-                               free(tab);
-                       }
+                       OSRF_BUFFER_ADD_CHAR( buf, '\n' );
+                       append_indentation( buf, --depth );
+                       OSRF_BUFFER_ADD_CHAR( buf, c );
 
                } else if( c == ',' ) {
 
-                       tab = _tabs(depth);
-                       buffer_fadd(buf, ",\n%s", tab);
-                       free(tab);
-
-               } else { buffer_add_char(buf, c); }
+                       OSRF_BUFFER_ADD_CHAR( buf, ',' );
+                       OSRF_BUFFER_ADD_CHAR( buf, '\n' );
+                       append_indentation( buf, depth );
 
+               } else
+                       OSRF_BUFFER_ADD_CHAR(buf, c);
        }
 
     return buffer_release(buf);
@@ -168,7 +164,7 @@ static jsonObject* _jsonObjectEncodeClass( const jsonObject* obj, int ignoreClas
        return newObj;
 }
 
-jsonObject* jsonParseFile( char* filename ) {
+jsonObject* jsonParseFile( const char* filename ) {
        if(!filename) return NULL;
        char* data = file_to_string(filename);
        jsonObject* o = jsonParseString(data);
@@ -178,53 +174,56 @@ jsonObject* jsonParseFile( char* filename ) {
 
 
 
-jsonObject* jsonObjectFindPath( const jsonObject* obj, char* format, ...) {
+jsonObject* jsonObjectFindPath( const jsonObject* obj, const char* format, ...) {
        if(!obj || !format || strlen(format) < 1) return NULL;  
 
        VA_LIST_TO_STRING(format);
        char* buf = VA_BUF;
        char* token = NULL;
-       char* t = buf;
        char* tt; /* strtok storage */
 
-       /* copy the path before strtok_r destroys it */
-       char* pathcopy = strdup(buf);
+       /* special case where path starts with //  (start anywhere) */
+       if(buf[0] == '/' && buf[1] == '/' && buf[2] != '\0') {
+
+               /* copy the path before strtok_r destroys it */
+               char* pathcopy = strdup(buf);
 
-       /* grab the root of the path */
-       token = strtok_r(t, "/", &tt);
-       if(!token) return NULL;
+               /* grab the root of the path */
+               token = strtok_r(buf, "/", &tt);
+               if(!token) {
+                       free(pathcopy);
+                       return NULL;
+               }
 
-       /* special case where path starts with //  (start anywhere) */
-       if(strlen(pathcopy) > 2 && pathcopy[0] == '/' && pathcopy[1] == '/') {
-               jsonObject* it = _jsonObjectFindPathRecurse(obj, token, pathcopy + 1);
+               jsonObject* it = findMultiPath(obj, token, pathcopy + 1);
                free(pathcopy);
                return it;
        }
+       else
+       {
+               /* grab the root of the path */
+               token = strtok_r(buf, "/", &tt);
+               if(!token) return NULL;
 
-       free(pathcopy);
+               do {
+                       obj = jsonObjectGetKeyConst(obj, token);
+               } while( (token = strtok_r(NULL, "/", &tt)) && obj);
 
-       t = NULL;
-       do { 
-               obj = jsonObjectGetKeyConst(obj, token);
-       } while( (token = strtok_r(NULL, "/", &tt)) && obj);
-
-       return jsonObjectClone(obj);
+               return jsonObjectClone(obj);
+       }
 }
 
 /* --------------------------------------------------------------- */
 
-
-
-jsonObject* _jsonObjectFindPathRecurse(const jsonObject* obj, char* root, char* path) {
+/* Utility method. finds any object in the tree that matches the path.  
+       Use this for finding paths that start with '//' */
+static jsonObject* findMultiPath(const jsonObject* obj,
+               const char* root, const char* path) {
 
        if(!obj || ! root || !path) return NULL;
 
        /* collect all of the potential objects */
-       jsonObject* arr = __jsonObjectFindPathRecurse(obj, root);
-
-       /* container for fully matching objects */
-       jsonObject* newarr = jsonParseString("[]");
-       int i;
+       jsonObject* arr = findMultiPathRecurse(obj, root);
 
        /* path is just /root or /root/ */
        if( strlen(root) + 2 >= strlen(path) ) {
@@ -232,32 +231,37 @@ jsonObject* _jsonObjectFindPathRecurse(const jsonObject* obj, char* root, char*
 
        } else {
 
+               /* container for fully matching objects */
+               jsonObject* newarr = jsonNewObjectType(JSON_ARRAY);
+               int i;
+
                /* gather all of the sub-objects that match the full path */
                for( i = 0; i < arr->size; i++ ) {
                        const jsonObject* a = jsonObjectGetIndex(arr, i);
                        jsonObject* thing = jsonObjectFindPath(a , path + strlen(root) + 1); 
 
                        if(thing) { //jsonObjectPush(newarr, thing);
-               if(thing->type == JSON_ARRAY) {
-               int i;
+                               if(thing->type == JSON_ARRAY) {
+                       int i;
                                        for( i = 0; i != thing->size; i++ )
                                                jsonObjectPush(newarr, jsonObjectClone(jsonObjectGetIndex(thing,i)));
                                        jsonObjectFree(thing);
-
                                } else {
                                        jsonObjectPush(newarr, thing);
-                               }                                               
+                               }
                        }
                }
+
+               jsonObjectFree(arr);
+               return newarr;
        }
-       
-       jsonObjectFree(arr);
-       return newarr;
 }
 
-jsonObject* __jsonObjectFindPathRecurse(const jsonObject* obj, char* root) {
+/* returns a list of object whose key is 'root'.  These are used as
+       potential objects when doing a // search */
+static jsonObject* findMultiPathRecurse(const jsonObject* obj, const char* root) {
 
-       jsonObject* arr = jsonParseString("[]");
+       jsonObject* arr = jsonNewObjectType(JSON_ARRAY);
        if(!obj) return arr;
 
        int i;
@@ -273,7 +277,7 @@ jsonObject* __jsonObjectFindPathRecurse(const jsonObject* obj, char* root) {
 
        /* recurse through the children and find all potential nodes */
        while( (tmp = jsonIteratorNext(itr)) ) {
-               childarr = __jsonObjectFindPathRecurse(tmp, root);
+               childarr = findMultiPathRecurse(tmp, root);
                if(childarr && childarr->size > 0) {
                        for( i = 0; i!= childarr->size; i++ ) {
                                jsonObjectPush( arr, jsonObjectClone(jsonObjectGetIndex(childarr, i)) );
@@ -286,7 +290,3 @@ jsonObject* __jsonObjectFindPathRecurse(const jsonObject* obj, char* root) {
 
        return arr;
 }
-
-
-
-