cc9a6a6dcdca9811dfeb5ac6d9f588e836407f01
larrym
Tue Apr 17 23:16:38 2012 -0700
add jsonParse; refactor some existing code to accomodate parsed data
diff --git src/hg/lib/jsHelper.c src/hg/lib/jsHelper.c
index 5720a2e..dcf2124 100644
--- src/hg/lib/jsHelper.c
+++ src/hg/lib/jsHelper.c
@@ -467,30 +467,57 @@
void jsEndCollapsibleSection()
/* End the collapsible
. */
{
puts("
");
}
struct jsonStringElement *newJsonString(char *str)
{
struct jsonStringElement *ele;
AllocVar(ele);
ele->str = cloneString(str);
ele->type = jsonString;
return ele;
}
+struct jsonBooleanElement *newJsonBoolean(boolean val)
+{
+struct jsonBooleanElement *ele;
+AllocVar(ele);
+ele->val = val;
+ele->type = jsonBoolean;
+return ele;
+}
+
+struct jsonNumberElement *newJsonNumber(long val)
+{
+struct jsonNumberElement *ele;
+AllocVar(ele);
+ele->val = val;
+ele->type = jsonNumber;
+return ele;
+}
+
+struct jsonDoubleElement *newJsonDouble(double val)
+{
+struct jsonDoubleElement *ele;
+AllocVar(ele);
+ele->val = val;
+ele->type = jsonDouble;
+return ele;
+}
+
struct jsonHashElement *newJsonHash(struct hash *h)
{
struct jsonHashElement *ele;
AllocVar(ele);
ele->type = jsonHash;
ele->hash = h;
return ele;
}
struct jsonListElement *newJsonList(struct slRef *list)
{
struct jsonListElement *ele;
AllocVar(ele);
ele->type = jsonList;
ele->list = list;
@@ -500,91 +527,75 @@
void jsonHashAdd(struct jsonHashElement *h, char *name, struct jsonElement *ele)
{
if (h == NULL) // If hash isn't provided, assume global
{
if (jsonGlobalsHash == NULL)
jsonGlobalsHash = newJsonHash(newHash(8));
h = jsonGlobalsHash;
}
hashReplace(h->hash, name, ele);
}
void jsonHashAddString(struct jsonHashElement *h, char *name, char *val)
{
// Add a string to a hash which will be used to print a javascript object;
// existing values are replaced.
-val = javaScriptLiteralEncode(val);
-char *str = needMem(strlen(val) + 3);
-sprintf(str, "\"%s\"", val);
-freez(&val);
-jsonHashAdd(h, name, (struct jsonElement *) newJsonString(str));
+jsonHashAdd(h, name, (struct jsonElement *) newJsonString(val));
}
void jsonHashAddNumber(struct jsonHashElement *h, char *name, long val)
{
// Add a number to a hash which will be used to print a javascript object;
// existing values are replaced.
-char buf[256];
-safef(buf, sizeof(buf), "%ld", val);
-jsonHashAdd(h, name, (struct jsonElement *) newJsonString(buf));
+jsonHashAdd(h, name, (struct jsonElement *) newJsonNumber(val));
}
void jsonHashAddDouble(struct jsonHashElement *h, char *name, double val)
{
// Add a number to a hash which will be used to print a javascript object;
// existing values are replaced.
-char buf[256];
-safef(buf, sizeof(buf), "%.10f", val);
-jsonHashAdd(h, name, (struct jsonElement *) newJsonString(buf));
+jsonHashAdd(h, name, (struct jsonElement *) newJsonDouble(val));
}
void jsonHashAddBoolean(struct jsonHashElement *h, char *name, boolean val)
{
// Add a boolean to a hash which will be used to print a javascript object;
// existing values are replaced.
-jsonHashAdd(h, name, (struct jsonElement *) newJsonString(val ? "true" : "false"));
+jsonHashAdd(h, name, (struct jsonElement *) newJsonBoolean(val));
}
void jsonListAdd(struct slRef **list, struct jsonElement *ele)
{
struct slRef *e;
AllocVar(e);
e->val = ele;
slAddHead(list, e);
}
void jsonListAddString(struct slRef **list, char *val)
{
-val = javaScriptLiteralEncode(val);
-char *str = needMem(strlen(val) + 3);
-sprintf(str, "'%s'", val);
-freez(&val);
-jsonListAdd(list, (struct jsonElement *) newJsonString(str));
+jsonListAdd(list, (struct jsonElement *) newJsonString(val));
}
void jsonListAddNumber(struct slRef **list, long val)
{
-char buf[256];
-safef(buf, sizeof(buf), "%ld", val);
-jsonListAdd(list, (struct jsonElement *) newJsonString(buf));
+jsonListAdd(list, (struct jsonElement *) newJsonNumber(val));
}
void jsonListAddDouble(struct slRef **list, double val)
{
-char buf[256];
-safef(buf, sizeof(buf), "%.10f", val);
-jsonListAdd(list, (struct jsonElement *) newJsonString(buf));
+jsonListAdd(list, (struct jsonElement *) newJsonDouble(val));
}
void jsonListAddBoolean(struct slRef **list, boolean val)
{
jsonListAdd(list, (struct jsonElement *) newJsonString(val ? "true" : "false"));
}
static char *makeIndentBuf(int indentLevel)
{
if (indentLevel < 0)
return "";
char *indentBuf;
indentBuf = needMem(indentLevel + 1);
memset(indentBuf, '\t', indentLevel);
indentBuf[indentLevel] = 0;
@@ -633,31 +644,51 @@
if(rec->list)
{
for (el = rec->list; el != NULL; el = el->next)
{
struct jsonElement *val = (struct jsonElement *) el->val;
hPrintf("%s%s", indentBuf,tab);
jsonPrintRecurse(val, indentLevel);
hPrintf("%s%s", el->next == NULL ? "" : ",",nl);
}
}
hPrintf("%s]", indentBuf);
break;
}
case jsonString:
{
- hPrintf("%s", ((struct jsonStringElement *) json)->str);
+ char *val = javaScriptLiteralEncode(((struct jsonStringElement *) json)->str);
+ hPrintf("\"%s\"", val);
+ break;
+ }
+ case jsonBoolean:
+ {
+ hPrintf("%s", ((struct jsonBooleanElement *) json)->val ? "true" : "false");
+ break;
+ }
+ case jsonNumber:
+ {
+ char buf[256];
+ safef(buf, sizeof(buf), "%ld", ((struct jsonNumberElement *) json)->val);
+ hPrintf("%s", buf);
+ break;
+ }
+ case jsonDouble:
+ {
+ char buf[256];
+ safef(buf, sizeof(buf), "%.10f", ((struct jsonDoubleElement *) json)->val);
+ hPrintf("%s", buf);
break;
}
default:
{
errAbort("jsonPrintRecurse; invalid type: %d", json->type);
break;
}
}
if (indentLevel >= 0)
freez(&indentBuf);
}
void jsonPrint(struct jsonElement *json, char *name, int indentLevel)
{
// print out a jsonElement, indentLevel -1 means no indenting
@@ -695,15 +726,165 @@
}
void jsonErrPrintf(struct dyString *ds, char *format, ...)
// Printf a json error to a dyString for communicating with ajax code; format is:
// {"error": error message here}
{
va_list args;
va_start(args, format);
dyStringPrintf(ds, "{\"error\": \"");
struct dyString *buf = newDyString(1000);
dyStringVaPrintf(buf, format, args);
dyStringAppend(ds, javaScriptLiteralEncode(dyStringCannibalize(&buf)));
dyStringPrintf(ds, "\"}");
va_end(args);
}
+
+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 struct jsonElement *jsonParseExpression(char *str, int *posPtr);
+
+static struct jsonElement *jsonParseObject(char *str, int *posPtr)
+{
+struct hash *h = newHash(0);
+getSpecificChar('{', str, posPtr);
+while(str[*posPtr] != '}')
+ {
+ int i;
+ skipLeadingSpacesWithPos(str, posPtr);
+ getSpecificChar('"', str, posPtr);
+ for(i = 0; str[*posPtr + i] && str[*posPtr + i] != '"'; i++)
+ ;
+ char *name = cloneStringZ(str + *posPtr, i);
+ *posPtr += i;
+ getSpecificChar('"', str, posPtr);
+
+ skipLeadingSpacesWithPos(str, posPtr);
+ getSpecificChar(':', str, posPtr);
+ skipLeadingSpacesWithPos(str, posPtr);
+
+ hashAdd(h, name, jsonParseExpression(str, posPtr));
+ skipLeadingSpacesWithPos(str, posPtr);
+ if(str[*posPtr] == ',')
+ (*posPtr)++;
+ else
+ break;
+ }
+skipLeadingSpacesWithPos(str, posPtr);
+getSpecificChar('}', str, posPtr);
+return (struct jsonElement *) newJsonHash(h);
+}
+
+static struct jsonElement *jsonParseList(char *str, int *posPtr)
+{
+struct slRef *list = NULL;
+getSpecificChar('[', str, posPtr);
+while(str[*posPtr] != ']')
+ {
+ struct slRef *e;
+ AllocVar(e);
+ skipLeadingSpacesWithPos(str, posPtr);
+ e->val = jsonParseExpression(str, posPtr);
+ slAddHead(&list, e);
+ skipLeadingSpacesWithPos(str, posPtr);
+ if(str[*posPtr] == ',')
+ (*posPtr)++;
+ else
+ break;
+ }
+skipLeadingSpacesWithPos(str, posPtr);
+getSpecificChar(']', str, posPtr);
+slReverse(&list);
+return (struct jsonElement *) newJsonList(list);
+}
+
+static struct jsonElement *jsonParseString(char *str, int *posPtr)
+{
+int i;
+getSpecificChar('"', str, posPtr);
+for(i = 0; str[*posPtr + i] && str[*posPtr + i] != '"'; i++)
+ ;
+char *val = cloneStringZ(str + *posPtr, i);
+*posPtr += i;
+getSpecificChar('"', str, posPtr);
+return (struct jsonElement *) newJsonString(val);
+}
+
+static struct jsonElement *jsonParseBoolean(char *str, int *posPtr)
+{
+struct jsonBooleanElement *ele;
+int i;
+for(i = 0; str[*posPtr + i] && isalpha(str[*posPtr + i]); i++);
+ ;
+char *val = cloneStringZ(str + *posPtr, i);
+if(sameWord(val, "true"))
+ ele = newJsonBoolean(TRUE);
+else if(sameWord(val, "false"))
+ ele = newJsonBoolean(FALSE);
+else
+ errAbort("Invalid boolean value '%s'; pos: %d", val, *posPtr);
+*posPtr += i;
+return (struct jsonElement *) ele;
+}
+
+static struct jsonElement *jsonParseNumber(char *str, int *posPtr)
+{
+int i;
+for(i = 0;; i++)
+ {
+ char c = str[*posPtr + i];
+ if(!(c && (isdigit(c) || c == '.' || c == '-' || c == '+')))
+ break;
+ }
+char *val = cloneStringZ(str + *posPtr, i);
+*posPtr += i;
+if(strchr(val, '.') == NULL)
+ return (struct jsonElement *) newJsonNumber(sqlLongLong(val));
+else
+ return (struct jsonElement *) newJsonDouble(sqlDouble(val));
+}
+
+static struct jsonElement *jsonParseExpression(char *str, int *posPtr)
+{
+skipLeadingSpacesWithPos(str, posPtr);
+char c = str[*posPtr];
+if(c == '{')
+ return jsonParseObject(str, posPtr);
+else if (c == '[')
+ return jsonParseList(str, posPtr);
+else if (c == '"')
+ return jsonParseString(str, posPtr);
+else if (isdigit(c) || c == '-')
+ return jsonParseNumber(str, posPtr);
+else
+ return jsonParseBoolean(str, posPtr);
+// XXXX support null?
+}
+
+struct jsonElement *jsonParse(char *str)
+{
+// parse string into an in-memory json representation
+int pos = 0;
+struct jsonElement *ele = jsonParseExpression(str, &pos);
+skipLeadingSpacesWithPos(str, &pos);
+if(str[pos])
+ errAbort("Invalid JSON: unprocessed trailing string at position: %d: %s", pos, str + pos);
+return ele;
+}