92ff3a19fc5cacf7b92a1a25086d9300f7df53e0
angie
  Tue Apr 16 14:02:52 2019 -0700
Added *Lm functions that optionally use lm to allocate memory.
Removed unused jsonFindName* functions -- if needed in the future,
jsonQuery will probably be easier to use.

diff --git src/lib/jsonParse.c src/lib/jsonParse.c
index a7bd90e..05cf8dc 100644
--- src/lib/jsonParse.c
+++ src/lib/jsonParse.c
@@ -1,81 +1,84 @@
 /* jsonParse - routines to parse JSON strings and traverse and pick things out of the
  * resulting object tree. */
 
 /* Copyright (C) 2014 The Regents of the University of California 
  * See README in this or parent directory for licensing information. */
 
 #include "common.h"
 #include "hash.h"
 #include "dystring.h"
 #include "sqlNum.h"
 #include "jsonParse.h"
 
-static struct jsonElement *newJsonElement(jsonElementType type)
+static struct jsonElement *newJsonElementLm(jsonElementType type, struct lm *lm)
 // generic constructor for a jsonElement; callers fill in the appropriate value
 {
 struct jsonElement *ele;
+if (lm)
+    lmAllocVar(lm, ele)
+else
     AllocVar(ele);
 ele->type = type;
 return ele;
 }
 
-struct jsonElement *newJsonString(char *str)
+struct jsonElement *newJsonStringLm(char *str, struct lm *lm)
 {
-struct jsonElement *ele = newJsonElement(jsonString);
-ele->val.jeString = cloneString(str);
+struct jsonElement *ele = newJsonElementLm(jsonString, lm);
+ele->val.jeString = lm ? lmCloneString(lm, str) : cloneString(str);
 return ele;
 }
 
-struct jsonElement *newJsonBoolean(boolean val)
+struct jsonElement *newJsonBooleanLm(boolean val, struct lm *lm)
 {
-struct jsonElement *ele = newJsonElement(jsonBoolean);
+struct jsonElement *ele = newJsonElementLm(jsonBoolean, lm);
 ele->val.jeBoolean = val;
 return ele;
 }
 
-struct jsonElement *newJsonNumber(long val)
+struct jsonElement *newJsonNumberLm(long val, struct lm *lm)
 {
-struct jsonElement *ele = newJsonElement(jsonNumber);
+struct jsonElement *ele = newJsonElementLm(jsonNumber, lm);
 ele->val.jeNumber = val;
 return ele;
 }
 
-struct jsonElement *newJsonDouble(double val)
+struct jsonElement *newJsonDoubleLm(double val, struct lm *lm)
 {
-struct jsonElement *ele = newJsonElement(jsonDouble);
+struct jsonElement *ele = newJsonElementLm(jsonDouble, lm);
 ele->val.jeDouble = val;
 return ele;
 }
 
-struct jsonElement *newJsonObject(struct hash *h)
+struct jsonElement *newJsonObjectLm(struct hash *h, struct lm *lm)
 {
-struct jsonElement *ele = newJsonElement(jsonObject);
+struct jsonElement *ele = newJsonElementLm(jsonObject, lm);
 ele->val.jeHash = h;
 return ele;
 }
 
-struct jsonElement *newJsonList(struct slRef *list)
+struct jsonElement *newJsonListLm(struct slRef *list, struct lm *lm)
 {
-struct jsonElement *ele = newJsonElement(jsonList);
+struct jsonElement *ele = newJsonElementLm(jsonList, lm);
 ele->val.jeList = list;
 return ele;
 }
 
-struct jsonElement *newJsonNull()
+struct jsonElement *newJsonNullLm(struct lm *lm)
 {
-struct jsonElement *ele = newJsonElement(jsonNull);
+struct jsonElement *ele = newJsonElementLm(jsonNull, lm);
 ele->val.jeNull = NULL;
 return ele;
 }
 
 void jsonObjectAdd(struct jsonElement *h, char *name, struct jsonElement *ele)
 // Add a new element to a jsonObject; existing values are replaced.
 {
 if(h->type != jsonObject)
     errAbort("jsonObjectAdd called on element with incorrect type (%d)", h->type);
 hashReplace(h->val.jeHash, name, ele);
 }
 
 void jsonListCat(struct jsonElement *listA, struct jsonElement *listB)
 /* Add all values of listB to the end of listA. Neither listA nor listB can be NULL. */
 {
@@ -109,61 +112,64 @@
 while ((hel = hashNext(&cookie)) != NULL)
     {
     struct jsonElement *elA = hashFindVal(objAHash, hel->name);
     struct jsonElement *elB = hel->val;
     if (elA == NULL || elA->type != elB->type)
         jsonObjectAdd(objA, hel->name, elB);
     else if (elA->type == jsonObject)
         jsonObjectMerge(elA, elB);
     else if (elA->type == jsonList)
         jsonListCat(elA, elB);
     else
         elA->val = elB->val;
     }
 }
 
-void jsonListAdd(struct jsonElement *list, struct jsonElement *ele)
+void jsonListAddLm(struct jsonElement *list, struct jsonElement *ele, struct lm *lm)
 {
 if(list->type != jsonList)
     errAbort("jsonListAdd called on element with incorrect type (%d)", list->type);
 struct slRef *el;
+if (lm)
+    lmAllocVar(lm, el)
+else
     AllocVar(el);
 el->val = ele;
 slAddHead(&list->val.jeList, el);
 }
 
 static void skipLeadingSpacesWithPos(char *s, int *posPtr)
 /* skip leading white space. */
 {
 for (;;)
     {
     char c = s[*posPtr];
     if (!isspace(c))
 	return;
     (*posPtr)++;
     }
 }
 
 static void getSpecificChar(char c, char *str, int *posPtr)
 {
 // get specified char from string or errAbort
 if(str[*posPtr] != c)
     errAbort("Unexpected character '%c' (expected '%c') - string position %d\n", str[*posPtr], c, *posPtr);
 (*posPtr)++;
 }
 
-static char *getString(char *str, int *posPtr)
+static char *getStringLm(char *str, int *posPtr, struct lm *lm)
 {
 // read a double-quote delimited string; we handle backslash escaping.
 // returns allocated string.
 boolean escapeMode = FALSE;
 int i;
 struct dyString *ds = dyStringNew(1024);
 getSpecificChar('"', str, posPtr);
 for(i = 0;; i++)
     {
     char c = str[*posPtr + i];
     if(!c)
         errAbort("Premature end of string (missing trailing double-quote); string position '%d'", *posPtr);
     else if(escapeMode)
         {
         // We support escape sequences listed in http://www.json.org,
@@ -197,186 +203,196 @@
         dyStringAppendC(ds, c);
         escapeMode = FALSE;
         }
     else if(c == '"')
         break;
     else if(c == '\\')
         escapeMode = TRUE;
     else
         {
         dyStringAppendC(ds, c);
         escapeMode = FALSE;
         }
     }
 *posPtr += i;
 getSpecificChar('"', str, posPtr);
+if (lm)
+    {
+    char *str = lmCloneString(lm, ds->string);
+    dyStringFree(&ds);
+    return str;
+    }
+else
     return dyStringCannibalize(&ds);
 }
 
-static struct jsonElement *jsonParseExpression(char *str, int *posPtr);
+static struct jsonElement *jsonParseExpressionLm(char *str, int *posPtr, struct lm *lm);
 
-static struct jsonElement *jsonParseObject(char *str, int *posPtr)
+static struct jsonElement *jsonParseObjectLm(char *str, int *posPtr, struct lm *lm)
 {
-struct hash *h = newHash(5);
+struct hash *h = hashNewLm(5, lm);
 getSpecificChar('{', str, posPtr);
 while(str[*posPtr] != '}')
     {
     // parse out a name : val pair
     skipLeadingSpacesWithPos(str, posPtr);
-    char *name = getString(str, posPtr);
+    char *name = getStringLm(str, posPtr, lm);
     skipLeadingSpacesWithPos(str, posPtr);
     getSpecificChar(':', str, posPtr);
     skipLeadingSpacesWithPos(str, posPtr);
-    hashAdd(h, name, jsonParseExpression(str, posPtr));
+    hashAdd(h, name, jsonParseExpressionLm(str, posPtr, lm));
     skipLeadingSpacesWithPos(str, posPtr);
     if(str[*posPtr] == ',')
         (*posPtr)++;
     else
         break;
     }
 skipLeadingSpacesWithPos(str, posPtr);
 getSpecificChar('}', str, posPtr);
-return newJsonObject(h);
+return newJsonObjectLm(h, lm);
 }
 
-static struct jsonElement *jsonParseList(char *str, int *posPtr)
+static struct jsonElement *jsonParseListLm(char *str, int *posPtr, struct lm *lm)
 {
 struct slRef *list = NULL;
 getSpecificChar('[', str, posPtr);
 while(str[*posPtr] != ']')
     {
     struct slRef *e;
+    if (lm)
+        lmAllocVar(lm, e)
+    else
         AllocVar(e);
     skipLeadingSpacesWithPos(str, posPtr);
-    e->val = jsonParseExpression(str, posPtr);
+    e->val = jsonParseExpressionLm(str, posPtr, lm);
     slAddHead(&list, e);
     skipLeadingSpacesWithPos(str, posPtr);
     if(str[*posPtr] == ',')
         (*posPtr)++;
     else
         break;
     }
 skipLeadingSpacesWithPos(str, posPtr);
 getSpecificChar(']', str, posPtr);
 slReverse(&list);
-return newJsonList(list);
+return newJsonListLm(list, lm);
 }
 
-static struct jsonElement *jsonParseString(char *str, int *posPtr)
+static struct jsonElement *jsonParseStringLm(char *str, int *posPtr, struct lm *lm)
 {
-return newJsonString(getString(str, posPtr));
+return newJsonStringLm(getStringLm(str, posPtr, lm), lm);
 }
 
-static struct jsonElement *jsonParseNumber(char *str, int *posPtr)
+static struct jsonElement *jsonParseNumberLm(char *str, int *posPtr, struct lm *lm)
 {
 int i;
 boolean integral = TRUE;
 struct jsonElement *retVal = NULL;
 
 for(i = 0;; i++)
     {
     char c = str[*posPtr + i];
     if(c == 'e' || c == 'E' || c == '.')
         integral = FALSE;
     else if(!c || (!isdigit(c) && c != '-'))
         break;
     }
-char *val = cloneStringZ(str + *posPtr, i);
+char val[i+1];
+safencpy(val, sizeof val, str + *posPtr, i);
 *posPtr += i;
 if(integral)
-    retVal = newJsonNumber(sqlLongLong(val));
+    retVal = newJsonNumberLm(sqlLongLong(val), lm);
 else
     {
     double d;
     if(sscanf(val, "%lf", &d))
-        retVal = newJsonDouble(d);
+        retVal = newJsonDoubleLm(d, lm);
     else
         errAbort("Invalid JSON Double: %s", val);
     }
-freez(&val);
 return retVal;
 }
 
 static boolean startsWithWordAlpha(const char *firstWord, const char *string)
 /* Return TRUE if string starts with firstWord and then either ends or continues with
  * non-alpha characters. */
 {
 return startsWith(firstWord, string) && !isalpha(string[strlen(firstWord)]);
 }
 
 #define JSON_KEYWORD_TRUE "true"
 #define JSON_KEYWORD_FALSE "false"
 #define JSON_KEYWORD_NULL "null"
 
-static struct jsonElement *jsonParseKeyword(char *str, int *posPtr)
+static struct jsonElement *jsonParseKeywordLm(char *str, int *posPtr, struct lm *lm)
 /* If str+*posPtr starts with a keyword token (true, false, null), return a new
  * jsonElement for it; otherwise return NULL. */
 {
 char *s = str + *posPtr;
 if (startsWithWordAlpha(JSON_KEYWORD_TRUE, s))
     {
     *posPtr += strlen(JSON_KEYWORD_TRUE);
-    return newJsonBoolean(TRUE);
+    return newJsonBooleanLm(TRUE, lm);
     }
 if (startsWithWordAlpha(JSON_KEYWORD_FALSE, s))
     {
     *posPtr += strlen(JSON_KEYWORD_FALSE);
-    return newJsonBoolean(FALSE);
+    return newJsonBooleanLm(FALSE, lm);
     }
 if (startsWithWordAlpha(JSON_KEYWORD_NULL, s))
     {
     *posPtr += strlen(JSON_KEYWORD_NULL);
-    return newJsonNull();
+    return newJsonNullLm(lm);
     }
 return NULL;
 }
 
 // Maximum number of characters from the current position to display in error message:
 #define MAX_LEN_FOR_ERROR 100
 
-static struct jsonElement *jsonParseExpression(char *str, int *posPtr)
+static struct jsonElement *jsonParseExpressionLm(char *str, int *posPtr, struct lm *lm)
 {
 skipLeadingSpacesWithPos(str, posPtr);
 char c = str[*posPtr];
 struct jsonElement *ele = NULL;
 if(c == '{')
-    return jsonParseObject(str, posPtr);
+    return jsonParseObjectLm(str, posPtr, lm);
 else if (c == '[')
-    return jsonParseList(str, posPtr);
+    return jsonParseListLm(str, posPtr, lm);
 else if (c == '"')
-    return jsonParseString(str, posPtr);
+    return jsonParseStringLm(str, posPtr, lm);
 else if (isdigit(c) || c == '-')
-    return jsonParseNumber(str, posPtr);
-else if ((ele = jsonParseKeyword(str, posPtr)) != NULL)
+    return jsonParseNumberLm(str, posPtr, lm);
+else if ((ele = jsonParseKeywordLm(str, posPtr, lm)) != NULL)
     return ele;
 else
     {
     const char *s = str + *posPtr;
     int len = strlen(s);
     if (len > MAX_LEN_FOR_ERROR)
         errAbort("Invalid JSON token: %.*s...", MAX_LEN_FOR_ERROR, s);
     else
         errAbort("Invalid JSON token: %s", s);
     }
 return NULL;
 }
 
-struct jsonElement *jsonParse(char *str)
+struct jsonElement *jsonParseLm(char *str, struct lm *lm)
 {
 // parse string into an in-memory json representation
 int pos = 0;
-struct jsonElement *ele = jsonParseExpression(str, &pos);
+struct jsonElement *ele = jsonParseExpressionLm(str, &pos, lm);
 skipLeadingSpacesWithPos(str, &pos);
 if(str[pos])
     errAbort("Invalid JSON: unprocessed trailing string at position: %d: %s", pos, str + pos);
 return ele;
 }
 
 int jsonStringEscapeSize(char *inString)
 /* Return the size in bytes including terminal '\0' for escaped string. */
 {
 if (inString == NULL)
     // Empty string
     return 1;
 int outSize = 0;
 char *in = inString, c;
 while ((c = *in++) != 0)
@@ -437,114 +453,41 @@
         case '\t':
             *out++ = '\\';
             *out++ = 't';
             break;
         case '\n':
             *out++ = '\\';
             *out++ = 'n';
             break;
         default:
             *out++ = c;
         }
     }
 *out++ = 0;
 }
 
-char *jsonStringEscape(char *inString)
+char *jsonStringEscapeLm(char *inString, struct lm *lm)
 /* backslash escape a string for use in a double quoted json string.
  * More conservative than javaScriptLiteralEncode because
  * some json parsers complain if you escape & or ' */
 {
 int outSize = jsonStringEscapeSize(inString);
-char *outString = needMem(outSize);
+char *outString = lm ? lmAlloc(lm, outSize) : needMem(outSize);
 jsonStringEscapeBuf(inString, outString, outSize);
 return outString;
 }
 
-void jsonFindNameRecurse(struct jsonElement *ele, char *jName, struct slName **pList)
-// Search the JSON tree recursively to find all the values associated to
-// the name, and add them to head of the list.  
-{
-switch (ele->type)
-    {
-    case jsonObject:
-        {
-        if(hashNumEntries(ele->val.jeHash))
-            {
-            struct hashEl *el, *list = hashElListHash(ele->val.jeHash);
-            slSort(&list, hashElCmp);
-            for (el = list; el != NULL; el = el->next)
-                {
-                struct jsonElement *val = el->val;
-                if sameString(el->name, jName)
-                    slNameAddHead(pList, jsonStringEscape(val->val.jeString));
-                jsonFindNameRecurse(val, jName, pList);
-                }
-            hashElFreeList(&list);
-            }
-        break;
-        }
-    case jsonList:
-        {
-        struct slRef *el;
-        if(ele->val.jeList)
-            {
-            for (el = ele->val.jeList; el != NULL; el = el->next)
-                {
-                struct jsonElement *val = el->val;
-                jsonFindNameRecurse(val, jName, pList);
-                }
-            }
-        break;
-        }
-    case jsonString:
-    case jsonBoolean:
-    case jsonNumber:
-    case jsonDouble:
-    case jsonNull:
-        {
-        break;
-        }
-    default:
-        {
-        errAbort("jsonFindNameRecurse; invalid type: %d", ele->type);
-        break;
-        }
-    }
-}
-
-struct slName *jsonFindName(struct jsonElement *json, char *jName)
-// Search the JSON tree to find all the values associated to the name
-// and add them to head of the list.  
-{
-struct slName *list = NULL;
-jsonFindNameRecurse(json, jName, &list);
-slReverse(&list);
-return list;
-}
-
-struct slName *jsonFindNameUniq(struct jsonElement *json, char *jName)
-// Search the JSON tree to find all the unique values associated to the name
-// and add them to head of the list. 
-{
-struct slName *list = NULL;
-jsonFindNameRecurse(json, jName, &list);
-slUniqify(&list, slNameCmp, slNameFree);
-slReverse(&list);
-return list;
-}
-
 void jsonElementRecurse(struct jsonElement *ele, char *name, boolean isLast,
     void (*startCallback)(struct jsonElement *ele, char *name, boolean isLast, void *context),  
     // Called at element start
     void (*endCallback)(struct jsonElement *ele, char *name, boolean isLast, void *context),    
     // Called at element end
     void *context)
 /* Recurse through JSON tree calling callback functions with element and context.
  * Either startCallback or endCallback may be NULL*/
 {
 if (startCallback != NULL)
     startCallback(ele, name, isLast, context);
 switch (ele->type)
     {
     case jsonObject:
         {
@@ -605,31 +548,31 @@
     }
 switch (ele->type)
     {
     case jsonObject:
         {
 	fprintf(f, "{\n");
         break;
         }
     case jsonList:
         {
 	fprintf(f, "[\n");
         break;
         }
     case jsonString:
         {
-	char *escaped = jsonStringEscape(ele->val.jeString);
+	char *escaped = jsonStringEscapeLm(ele->val.jeString, NULL);
 	fprintf(f, "\"%s\"",  escaped);
         freez(&escaped);
 	break;
 	}
     case jsonBoolean:
         {
 	char *val = (ele->val.jeBoolean ? "true" : "false");
 	fprintf(f, "%s", val);
 	break;
 	}
     case jsonNumber:
         {
 	fprintf(f, "%ld", ele->val.jeNumber);
 	break;
 	}