d3752edc12da1bf08427946150f564dbdd5d2254
angie
  Thu Oct 24 13:55:51 2019 -0700
bigDbSnp track handler code - initial commit.  refs #23283
* dnautil: Added trimRefAltLeft to get left-justified trimming (a la VCF not HGVS).
* bigBedClick: do hReplaceGbdb up front in parseDetailsTablUrls instead of waiting until endpoint.
* trackDbCustom.c: consolidating type-handling for wig/bigWig vs. bigBed-based big*.

diff --git src/hg/hgc/bigBedClick.c src/hg/hgc/bigBedClick.c
index 9a4986cb..091bfb3 100644
--- src/hg/hgc/bigBedClick.c
+++ src/hg/hgc/bigBedClick.c
@@ -193,36 +193,34 @@
 	"    return false;\n"
     	"}\n"
 	);
     }
 }
 
 static void detailsTabPrintSpecial(char *name, char *val, struct slPair *extraFields)
 /* some extra fields require special printing code, they all start with '_'  */
 {
 if (sameWord(name, "_mismatchCounts"))
     extFieldMismatchCounts(val);
 else if (sameWord(name, "_crisprOfftargets"))
     extFieldCrisprOfftargets(val, extraFields);
 }
 
-static void seekAndPrintTable(char *url, off_t offset, struct slPair *extraFields)
+static void seekAndPrintTable(char *detailsUrl, off_t offset, struct slPair *extraFields)
 /* seek to 0 at url, get headers, then seek to offset, read tab-sep fields and output 
  * (extraFields are needed for some special field handlers) */
 {
-char *detailsUrl = hReplaceGbdb(replaceChars(url, "$db", database));
-
 // open the URL
 struct lineFile *lf = lineFileUdcMayOpen(detailsUrl, TRUE);
 if (lf==NULL)
     {
     printf("Error: Could not open the URL referenced in detailsTabUrls, %s", detailsUrl);
     return;
     }
 
 // get the headers
 char *headLine = NULL;
 int lineSize = 0;
 lineFileNext(lf, &headLine, &lineSize);
 char *headers[1024];
 int headerCount = chopTabs(headLine, headers);
 
@@ -258,54 +256,62 @@
 {
     char *name = headers[i];
     char *val  = fields[i];
     
     if (startsWith("_", name))
         detailsTabPrintSpecial(name, val, extraFields);
     else
         {
         printf("<tr><td>%s</td>\n", name);
         printf("<td>%s</td></tr>\n", val);
         }
 }
 printf("</table>\n");
 
 lineFileClose(&lf);
-freez(&detailsUrl);
 }
 
-static void printAllExternalExtraFields(struct trackDb *tdb, struct slPair *extraFields)
-/* handle the "detailsTabUrls" trackDb setting: 
- * For each field, print a separate html table with all field names and values
- * from the external tab-sep file */
-
+struct slPair *parseDetailsTablUrls(struct trackDb *tdb)
+/* Parse detailsTabUrls setting string into an slPair list of {offset column name, fileOrUrl} */
 {
 char *detailsUrlsStr = trackDbSetting(tdb, "detailsTabUrls");
 if (!detailsUrlsStr)
-    return;
+    return NULL;
 
 struct slPair *detailsUrls = slPairListFromString(detailsUrlsStr, TRUE);
 if (!detailsUrls)
     {
     printf("Problem when parsing trackDb setting detailsTabUrls<br>\n");
     printf("Expected: a space-separated key=val list, like 'fieldName1=URL1 fieldName2=URL2'<br>\n");
     printf("But got: '%s'<br>", detailsUrlsStr);
-    return;
+    return NULL;
     }
-
 struct slPair *pair;
 for (pair = detailsUrls;  pair != NULL;  pair = pair->next)
+    pair->val = hReplaceGbdb(replaceChars(pair->val, "$db", database));
+
+return detailsUrls;
+}
+
+static void printAllExternalExtraFields(struct trackDb *tdb, struct slPair *extraFields)
+/* handle the "detailsTabUrls" trackDb setting: 
+ * For each field, print a separate html table with all field names and values
+ * from the external tab-sep file */
+
+{
+struct slPair *detailsUrls = parseDetailsTablUrls(tdb), *pair;
+for (pair = detailsUrls; pair != NULL; pair = pair->next)
     {
     char *fieldName = pair->name;
     char *detailsUrl = pair->val;
 
     // get extra bigBed field (=the offset) and seek to it
     void *p = slPairFindVal(extraFields, fieldName);
     if (p==NULL)
         {
         printf("Error when parsing trackDb detailsTabUrls statement:<br>\n");
         printf("Cannot find extra bigBed field with name %s\n", fieldName);
         return;
         }
     char *offsetStr = (char*)p;
 
     if (offsetStr==NULL || sameWord(offsetStr, "0"))