a10db7a1565e78a8eeece4272103115418aa5693
angie
  Wed Jan 7 12:00:16 2015 -0800
Extended jsonWriteObjectStart to support an optional preceding tag;added jsonWriteStringf, jsonWriteBoolean, jsonWriteValueLabelList, and
jsonWriteSlNameList.  To be used by cartJson and hgAi.

diff --git src/lib/jsonWrite.c src/lib/jsonWrite.c
index cef09dc..e2fa0cf 100644
--- src/lib/jsonWrite.c
+++ src/lib/jsonWrite.c
@@ -1,27 +1,33 @@
 /* jsonWrite - Helper routines for writing out JSON.  */
 
 /* 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"
 #include "jsonWrite.h"
 
+// Separator between elements; set this to "\n" to see elements on separate lines.
+// Newlines are fine in Javascript, e.g. in an embedded <script>.
+// However, unescaped \n is illegal in JSON and web browsers may reject it.
+// Web browser plugins can pretty-print JSON nicely.
+#define JW_SEP " "
+
 struct jsonWrite *jsonWriteNew()
 /* Return new empty jsonWrite struct. */
 {
 struct jsonWrite *jw;
 AllocVar(jw);
 jw->dy = dyStringNew(0);
 return jw;
 }
 
 void jsonWriteFree(struct jsonWrite **pJw)
 /* Free up a jsonWrite object. */
 {
 struct jsonWrite *jw = *pJw;
 if (jw != NULL)
     {
@@ -37,48 +43,60 @@
 if (stackIx >= ArraySize(jw->objStack))
     errAbort("Stack overflow in jsonWritePush");
 jw->objStack[stackIx] = val;
 jw->stackIx = stackIx;
 }
 
 static void jsonWritePopObjStack(struct jsonWrite *jw)
 /* pop object stack and just discard val. */
 {
 int stackIx = jw->stackIx - 1;
 if (stackIx < 0)
     errAbort("Stack underflow in jsonWritePopObjStack");
 jw->stackIx = stackIx;
 }
 
-void jsonWriteTag(struct jsonWrite *jw, char *var)
-/* Print out quoted tag followed by colon. Print out preceding comma if need be.  */
+INLINE void jsonWriteMaybeComma(struct jsonWrite *jw)
+/* If this is not the first item added to an object or list, write a comma. */
 {
-struct dyString *dy = jw->dy;
 if (jw->objStack[jw->stackIx] != 0)
-    dyStringAppend(dy, ",\n");
+    dyStringAppend(jw->dy, ","JW_SEP);
 else
     jw->objStack[jw->stackIx] = 1;
+}
+
+void jsonWriteTag(struct jsonWrite *jw, char *var)
+/* Print out quoted tag followed by colon. Print out preceding comma if need be.  */
+{
 if (var != NULL)
+    {
+    jsonWriteMaybeComma(jw);
     dyStringPrintf(jw->dy, "\"%s\": ", var);
     }
+}
 
 void jsonWriteString(struct jsonWrite *jw, char *var, char *string)
-/* Print out "var": "val".  If var is NULL then just print out "val" */
+/* Print out "var": "val".  If var is NULL, print val only.  If string is NULL, "var": null . */
 {
-struct dyString *dy = jw->dy;
+if (var)
     jsonWriteTag(jw, var);
-dyStringPrintf(dy, "\"%s\"", string);
+else
+    jsonWriteMaybeComma(jw);
+if (string)
+    dyStringPrintf(jw->dy, "\"%s\"", string);
+else
+    dyStringAppend(jw->dy, "null");
 }
 
 void jsonWriteDateFromUnix(struct jsonWrite *jw, char *var, long long unixTimeVal)
 /* Add "var": YYYY-MM-DDT-HH:MM:SSZ given a Unix time stamp. Var may be NULL. */
 {
 struct dyString *dy = jw->dy;
 time_t timeStamp = unixTimeVal;
 struct tm tm;
 gmtime_r(&timeStamp, &tm);
 jsonWriteTag(jw, var);
 dyStringPrintf(dy, "\"%d:%02d:%02dT%02d:%02d:%02dZ\"",
     1900+tm.tm_year, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
 }
 
 void jsonWriteNumber(struct jsonWrite *jw, char *var, long long val)
@@ -100,43 +118,94 @@
 
 void jsonWriteLinkNum(struct jsonWrite *jw, char *var, char *objRoot, long long id)
 /* Print out the jsony type link to another object with a numerical id.  objRoot will start 
  * and end with a '/' and may have additional slashes in this usage. Var may be NULL */
 {
 struct dyString *dy = jw->dy;
 jsonWriteTag(jw, var);
 dyStringPrintf(dy, "\"%s%lld\"", objRoot, id);
 }
 
 void jsonWriteListStart(struct jsonWrite *jw, char *var)
 /* Start an array in JSON. Var may be NULL */
 {
 struct dyString *dy = jw->dy;
 jsonWriteTag(jw, var);
-dyStringAppend(dy, "[\n");
+dyStringAppend(dy, "["JW_SEP);
 jsonWritePushObjStack(jw, FALSE);
 }
 
 void jsonWriteListEnd(struct jsonWrite *jw)
 /* End an array in JSON */
 {
 struct dyString *dy = jw->dy;
-dyStringAppend(dy, "]\n");
+dyStringAppend(dy, "]"JW_SEP);
 jsonWritePopObjStack(jw);
 }
 
-void jsonWriteObjectStart(struct jsonWrite *jw)
-/* Print start of object */
+void jsonWriteObjectStart(struct jsonWrite *jw, char *var)
+/* Print start of object, preceded by tag if var is non-NULL. */
 {
+if (var)
+    jsonWriteTag(jw, var);
+else
+    jsonWriteMaybeComma(jw);
 struct dyString *dy = jw->dy;
-dyStringAppend(dy, "{\n");
+dyStringAppend(dy, "{"JW_SEP);
 jsonWritePushObjStack(jw, FALSE);
 }
 
 void jsonWriteObjectEnd(struct jsonWrite *jw)
 /* End object in JSON */
 {
 struct dyString *dy = jw->dy;
-dyStringAppend(dy, "}\n");
+dyStringAppend(dy, "}"JW_SEP);
 jsonWritePopObjStack(jw);
 }
 
+void jsonWriteStringf(struct jsonWrite *jw, char *var, char *format, ...)
+/* Write "var": "val" where val is jsonStringEscape'd formatted string. */
+{
+// Since we're using jsonStringEscape(), we need to use a temporary dyString
+// instead of jw->dy.
+struct dyString *tmpDy = dyStringNew(0);
+va_list args;
+va_start(args, format);
+dyStringVaPrintf(tmpDy, format, args);
+va_end(args);
+char *escaped = jsonStringEscape(tmpDy->string);
+jsonWriteString(jw, var, escaped);
+freeMem(escaped);
+dyStringFree(&tmpDy);
+}
+
+void jsonWriteBoolean(struct jsonWrite *jw, char *var, boolean val)
+/* Write out "var": true or "var": false depending on val (no quotes around true/false). */
+{
+jsonWriteTag(jw, var);
+dyStringAppend(jw->dy, val ? "true" : "false");
+}
+
+void jsonWriteValueLabelList(struct jsonWrite *jw, char *var, struct slPair *pairList)
+/* Print out a named list of {"value": "<pair->name>", "label": "<pair->val>"} objects. */
+{
+jsonWriteListStart(jw, var);
+struct slPair *pair;
+for (pair = pairList;  pair != NULL;  pair = pair->next)
+    {
+    jsonWriteObjectStart(jw, NULL);
+    jsonWriteString(jw, "value", pair->name);
+    jsonWriteString(jw, "label", (char *)(pair->val));
+    jsonWriteObjectEnd(jw);
+    }
+jsonWriteListEnd(jw);
+}
+
+void jsonWriteSlNameList(struct jsonWrite *jw, char *var, struct slName *slnList)
+/* Print out a named list of strings from slnList. */
+{
+jsonWriteListStart(jw, var);
+struct slName *sln;
+for (sln = slnList;  sln != NULL;  sln = sln->next)
+    jsonWriteString(jw, NULL, sln->name);
+jsonWriteListEnd(jw);
+}