1ee99ce653ae839e4774120c3f3923dc129c8533
angie
  Fri Mar 16 14:41:14 2018 -0700
Moved jsonStringEscape inside jsonWriteString because it's silly to have to remember to call it first every time.
tagStorm programs were doing their own limited escaping (double-quotes only); now they get the same escaping as everywhere else.
refs MLQ #21113

diff --git src/hg/lib/cartJson.c src/hg/lib/cartJson.c
index 86daf95..2d504ff 100644
--- src/hg/lib/cartJson.c
+++ src/hg/lib/cartJson.c
@@ -271,34 +271,31 @@
     return;
 struct slName *varList = slNameListFromComma(varString), *var;
 for (var = varList;  var != NULL;  var = var->next)
     {
     if (cartListVarExists(cj->cart, var->name))
 	{
 	// Use cartOptionalSlNameList and return a list:
 	struct slName *valList = cartOptionalSlNameList(cj->cart, var->name);
 	jsonWriteSlNameList(cj->jw, var->name, valList);
 	slFreeList(&valList);
 	}
     else
 	{
 	// Regular single-value variable (or not in the cart):
 	char *val = cartOptionalString(cj->cart, var->name);
-	//#*** TODO: move jsonStringEscape inside jsonWriteString
-	char *encoded = jsonStringEscape(val);
-	jsonWriteString(cj->jw, var->name, encoded);
-	freeMem(encoded);
+	jsonWriteString(cj->jw, var->name, val);
 	}
     }
 slFreeList(&varList);
 }
 
 INLINE boolean nameIsTdbField(char *name)
 /* Return TRUE if name is a tdb->{field}, e.g. "track" or "shortLabel" etc. */
 {
 static char *tdbFieldNames[] =
     { "track", "table", "shortLabel", "longLabel", "type", "priority", "grp", "parent",
       "subtracks", "visibility" };
 return (stringArrayIx(name, tdbFieldNames, ArraySize(tdbFieldNames)) >= 0);
 }
 
 INLINE boolean fieldOk(char *field, struct hash *fieldHash)
@@ -320,35 +317,31 @@
     jsonWriteString(jw, "longLabel", tdb->longLabel);
 if (fieldOk("type", fieldHash))
     jsonWriteString(jw, "type", tdb->type);
 if (fieldOk("priority", fieldHash))
     jsonWriteDouble(jw, "priority", tdb->priority);
 if (fieldOk("grp", fieldHash))
     jsonWriteString(jw, "grp", tdb->grp);
 // NOTE: if you add a new field here, then also add it to nameIsTdbField above.
 if (tdb->settingsHash)
     {
     struct hashEl *hel;
     struct hashCookie cookie = hashFirst(tdb->settingsHash);
     while ((hel = hashNext(&cookie)) != NULL)
         {
         if (! nameIsTdbField(hel->name) && fieldOk(hel->name, fieldHash))
-            {
-            //#*** TODO: move jsonStringEscape inside jsonWriteString
-            char *encoded = jsonStringEscape((char *)hel->val);
-            jsonWriteString(jw, hel->name, encoded);
-            }
+            jsonWriteString(jw, hel->name, (char *)hel->val);
         }
     if (fieldOk("noGenome", fieldHash))
         {
         if ((hel = hashLookup(tdb->settingsHash, "tableBrowser")) != NULL)
             {
             if (startsWithWord("noGenome", (char *)(hel->val)))
                 jsonWriteBoolean(jw, "noGenome", TRUE);
             }
         }
     }
 }
 
 static int trackDbViewCmp(const void *va, const void *vb)
 /* *** I couldn't find anything like this in hgTracks or hui, but clearly views end up
  * *** being ordered alphabetically somehow.  Anyway...
@@ -607,32 +600,31 @@
     }
 return htmlString;
 }
 
 static void getAssemblyInfo(struct cartJson *cj, struct hash *paramHash)
 /* Return useful things from dbDb (or track hub) and assembly description html (possibly NULL).
  * If db param is NULL, use db from cart. */
 {
 char *db = cartJsonOptionalParam(paramHash, "db");
 if (db == NULL)
     db = cartString(cj->cart, "db");
 jsonWriteString(cj->jw, "db", db);
 jsonWriteString(cj->jw, "commonName", hGenome(db));
 jsonWriteString(cj->jw, "scientificName", hScientificName(db));
 jsonWriteString(cj->jw, "dbLabel", hFreezeDate(db));
-//#*** TODO: move jsonStringEscape inside jsonWriteString
-jsonWriteString(cj->jw, "assemblyDescription", jsonStringEscape(hAssemblyDescription(db)));
+jsonWriteString(cj->jw, "assemblyDescription", hAssemblyDescription(db));
 }
 
 static void getHasCustomTracks(struct cartJson *cj, struct hash *paramHash)
 /* Tell whether cart has custom tracks for db.  If db param is NULL, use db from cart. */
 {
 char *db = cartJsonOptionalParam(paramHash, "db");
 if (db == NULL)
     db = cartString(cj->cart, "db");
 jsonWriteBoolean(cj->jw, "hasCustomTracks", customTracksExistDb(cj->cart, db, NULL));
 }
 
 static void getIsSpecialHost(struct cartJson *cj, struct hash *paramHash)
 /* Tell whether we're on a development host, preview, gsid etc. */
 {
 jsonWriteBoolean(cj->jw, "isPrivateHost", hIsPrivateHost());
@@ -731,33 +723,31 @@
 if (isEmpty(position))
     position = hDefaultPos(db);
 jsonWriteString(cj->jw, "position", position);
 printGeneSuggestTrack(cj, db);
 }
 
 static void getStaticHtml(struct cartJson *cj, struct hash *paramHash)
 /* Read HTML text from a relative path under browser.documentRoot and
  * write it as an encoded JSON string */
 {
 char *tag = cartJsonOptionalParam(paramHash, "tag");
 if (isEmpty(tag))
     tag = "html";
 char *file = cartJsonRequiredParam(paramHash, "file", cj->jw, "getStaticHtml");
 char *html = hFileContentsOrWarning(file);
-//#*** TODO: move jsonStringEscape inside jsonWriteString
-char *encoded = jsonStringEscape(html);
-jsonWriteString(cj->jw, tag, encoded);
+jsonWriteString(cj->jw, tag, html);
 }
 
 void cartJsonRegisterHandler(struct cartJson *cj, char *command, CartJsonHandler *handler)
 /* Associate handler with command; when javascript sends command, handler will be executed. */
 {
 hashAdd(cj->handlerHash, command, handler);
 }
 
 struct cartJson *cartJsonNew(struct cart *cart)
 /* Allocate and return a cartJson object with default handlers.
  * cart must have "db" set already. */
 {
 struct cartJson *cj;
 AllocVar(cj);
 cj->handlerHash = hashNew(0);
@@ -821,36 +811,31 @@
 }
 
 // Accumulate warnings so they can be JSON-ified:
 static struct dyString *dyWarn = NULL;
 
 static void cartJsonVaWarn(char *format, va_list args)
 /* Save warnings for later. */
 {
 dyStringVaPrintf(dyWarn, format, args);
 }
 
 static void cartJsonPrintWarnings(struct jsonWrite *jw)
 /* If there are warnings, write them out as JSON: */
 {
 if (dyWarn && dyStringLen(dyWarn) > 0)
-    {
-    //#*** TODO: move jsonStringEscape inside jsonWriteString
-    char *encoded = jsonStringEscape(dyWarn->string);
-    jsonWriteString(jw, "warning", encoded);
-    freeMem(encoded);
-    }
+    jsonWriteString(jw, "warning", dyWarn->string);
 }
 
 static void cartJsonAbort()
 /* Print whatever warnings we have accumulated and exit. */
 {
 if (dyWarn)
     puts(dyWarn->string);
 exit(0);
 }
 
 static void cartJsonPushErrHandlers()
 /* Push warn and abort handlers for errAbort. */
 {
 if (dyWarn == NULL)
     dyWarn = dyStringNew(0);
@@ -889,27 +874,25 @@
         // change* commands need to go first!  Really we need an ordered map type here...
         // for now, just make a list and sort to put change commands at the front.
         struct slPair *commandList = NULL, *cmd;
         struct hashCookie cookie = hashFirst(commandHash);
         struct hashEl *hel;
         while ((hel = hashNext(&cookie)) != NULL)
             slAddHead(&commandList, slPairNew(hel->name, hel->val));
         slSort(&commandList, commandCmp);
         for (cmd = commandList;  cmd != NULL;  cmd = cmd->next)
             doOneCommand(cj, cmd->name, (struct jsonElement *)cmd->val);
         }
     errCatchEnd(errCatch);
     if (errCatch->gotError)
         {
         jsonWritePopToLevel(cj->jw, 1);
-        //#*** TODO: move jsonStringEscape inside jsonWriteString
-        char *encoded = jsonStringEscape(errCatch->message->string);
-        jsonWriteString(cj->jw, "error", encoded);
+        jsonWriteString(cj->jw, "error", errCatch->message->string);
         }
     errCatchFree(&errCatch);
     }
 
 cartJsonPrintWarnings(cj->jw);
 jsonWriteObjectEnd(cj->jw);
 puts(cj->jw->dy->string);
 cartJsonPopErrHandlers();
 }