7df3ba2728fb2b20ac6159bb4935b9ccd829e695
galt
  Thu Feb 6 13:31:32 2025 -0800
squashed hgEncodeVocab-ra-danger-fix. fixes #287

diff --git src/hg/hgc/peakClusters.c src/hg/hgc/peakClusters.c
index 7d754849564..d2b764c0745 100644
--- src/hg/hgc/peakClusters.c
+++ src/hg/hgc/peakClusters.c
@@ -18,30 +18,31 @@
 #include "jksql.h"
 #include "obscure.h"
 #include "hCommon.h"
 #include "hdb.h"
 #include "web.h"
 #include "cart.h"
 #include "trackDb.h"
 #include "hui.h"
 #include "hgc.h"
 #include "encode/encodePeak.h"
 #include "expRecord.h"
 #include "bed6FloatScore.h"
 #include "ra.h"
 #include "jsHelper.h"
 #include "factorSource.h"
+#include "cv.h"
 
 static void printClusterTableHeader(struct slName *otherCols, 
 	boolean withAbbreviation, boolean withDescription, boolean withSignal)
 /* Print out header fields table of tracks in cluster */
 {
 webPrintLabelCell("#");
 if (withSignal)
     webPrintLabelCell("signal");
 if (withAbbreviation)
     webPrintLabelCell("abr");
 struct slName *col;
 for (col = otherCols; col != NULL; col = col->next)
     webPrintLabelCell(col->name);
 if (withDescription)
     webPrintLabelCell("description");
@@ -73,38 +74,39 @@
 hFreeConn(&conn);
 if (count > 0)
     return sum/count;
 else
     return 0;
 }
 
 static void printControlledVocabFields(char **row, int fieldCount, 
 	struct slName *fieldList, char *vocabFile, struct hash *vocabHash)
 /* Print out fields from row, linking them to controlled vocab if need be. 
  * If vocabFile is NULL, the vocabHash is not ENCODE, so links + mouseovers are
  * generated differently */
 {
 int i;
 struct slName *field;
+
 for (i=0, field = fieldList; i<fieldCount; ++i, field = field->next)
     {
     char *link = NULL;
     char *fieldVal = row[i];
     if (vocabFile && hashLookup(vocabHash, field->name))
         {
         // controlled vocabulary
-        link = wgEncodeVocabLink(vocabFile, "term", fieldVal, fieldVal, fieldVal, "");
+        link = wgEncodeVocabLink("term", fieldVal, fieldVal, fieldVal, "");
         }
     else if (!vocabFile && vocabHash != NULL)
         {
         // meta tables
         struct hash *fieldHash = hashFindVal(vocabHash, field->name);
         if (fieldHash != NULL)
             link = vocabLink(fieldHash, fieldVal, fieldVal);
 
         }
     webPrintLinkCell(link != NULL ? link : fieldVal);
     }
 }
 
 static void printMetadataForTable(char *table)
 /* If table exists, _and_ tdb associated with it exists, print out
@@ -155,30 +157,33 @@
 hashAdd(hash, "cellType", NULL);	/* Will the kludge never end, no, never! */
 return hash;
 }
 
 static void getVocab(struct trackDb *tdb, struct cart *cart, 
                         char **vocabFile, struct hash **vocabHash)
 /* Get vocabulary info from trackDb settings (CV or vocab tables) */
 {
 
 char *file = NULL;
 struct hash *hash = NULL;
 char *vocab = trackDbSetting(tdb, "controlledVocabulary");
 if (vocabSettingIsEncode(vocab))
     {
     file = cloneFirstWord(vocab);
+    if (!sameString(file, "encode/cv.ra"))
+	errAbort("expected encode/cv.ra in trackDb settings for controlledVocabulary.");
+    file = (char *)cvFile();  // use the library location
     hash = getVocabHash(file);
     }
 else
     {
     hash = vocabBasicFromSetting(tdb, cart);
     }
 if (vocabFile != NULL)
     *vocabFile = file;
 if (hash != NULL)
     *vocabHash = hash;
 }
 
 static void printPeakClusterInfo(struct trackDb *tdb, struct cart *cart,
                                 struct sqlConnection *conn, char *inputTrackTable, 
                                 struct slName *fieldList, struct bed *cluster)
@@ -208,50 +213,45 @@
         if (signal == 0)
             continue;
         }
     printf("</TR><TR>\n");
     webPrintIntCell(++displayNo);
     if (signal != 0)
 	webPrintDoubleCell(signal);
     printControlledVocabFields(row+1, fieldCount, fieldList, vocabFile, vocabHash);
     printMetadataForTable(row[0]);
     }
 sqlFreeResult(&sr);
 freez(&vocabFile);
 dyStringFree(&query);
 }
 
-static char *factorSourceVocabLink(char *vocabFile, char *fieldName, char *fieldVal)
+static char *factorSourceVocabLink(char *fieldName, char *fieldVal)
 /* Add link to show controlled vocabulary entry for term.
  * Handles 'target' (factor) which is a special case, derived from Antibody entries */
 {
 char *vocabType = (sameString(fieldName, "target") || sameString(fieldName, "factor")) ?
                     "target" : "term";
-return wgEncodeVocabLink(vocabFile, vocabType, fieldVal, fieldVal, fieldVal, "");
+return wgEncodeVocabLink(vocabType, fieldVal, fieldVal, fieldVal, "");
 }
 
 static void printFactorSourceTableHits(struct factorSource *cluster, struct sqlConnection *conn,
 	char *sourceTable, char *inputTrackTable, 
 	struct slName *fieldList, boolean invert, char *vocab, struct hash *fieldToUrl)
 /* Put out a lines in an html table that shows assayed sources that have hits in this
  * cluster, or if invert is set, that have misses. */
 {
-char *vocabFile = NULL;
-if (vocab)
-    {
-    vocabFile = cloneFirstWord(vocab);
-    }
 
 /* Make the monster SQL query to get all assays*/
 struct dyString *query = dyStringNew(0);
 sqlDyStringPrintf(query, "select %s.id,%s.name,%s.tableName", sourceTable, sourceTable, 
 	inputTrackTable);
 struct slName *field;
 for (field = fieldList; field != NULL; field = field->next)
     sqlDyStringPrintf(query, ",%s.%s", inputTrackTable, field->name);
 sqlDyStringPrintf(query, " from %s,%s ", inputTrackTable, sourceTable);
 sqlDyStringPrintf(query, " where %s.source = %s.description", inputTrackTable, sourceTable);
 sqlDyStringPrintf(query, " and factor='%s' order by %s.source", cluster->name, inputTrackTable);
 
 boolean encodeStanford = FALSE;
 if (startsWith("enc", sourceTable))
     encodeStanford = TRUE;
@@ -280,31 +280,31 @@
 	printf("</TR><TR>\n");
 	webPrintIntCell(++displayNo);
 	if (!invert)
 	    webPrintDoubleCell(signal);
 	webPrintLinkCell(row[1]);
 	int i = 0;
         // find position of CV metadata in field list
         int offset = 3;
         struct slName *field = fieldList;
 	for (i=0; i<fieldCount && field != NULL; ++i, field = field->next)
 	    {
 	    char *fieldVal = row[i+offset];
             char *link = NULL;
 	    if (vocab)
 	        {
-                link = cloneString(factorSourceVocabLink(vocabFile, field->name, fieldVal));
+                link = cloneString(factorSourceVocabLink(field->name, fieldVal));
 		}
             else if (fieldToUrl != NULL)
                 {
                 // (outside) links on vocab items
                 char *urlPattern = hashFindVal(fieldToUrl, field->name);
                 if (urlPattern != NULL)
                     {
                     char *url = replaceInUrl(urlPattern, fieldVal, cart, database, seqName, 
                                                 winStart, winEnd, NULL, TRUE, NULL);
                     if (url != NULL)
                         {
                         struct dyString *ds = dyStringCreate("<a target='_blank' href='%s'>%s</a>\n",
                                                                 url, fieldVal);
                         link = dyStringCannibalize(&ds);
                         }
@@ -319,31 +319,30 @@
             if (!file)
                 webPrintLinkCell(table);
             else
                 {
                 webPrintLinkCellStart();
                 printf("<A target='_blank'"
                         "href='https://www.encodeproject.org/files/%s'>%s</A>", file, file);
                 webPrintLinkCellEnd();
                } 
             }
         else
             printMetadataForTable(table);
 	}
     }
 sqlFreeResult(&sr);
-freez(&vocabFile);
 dyStringFree(&query);
 }
 
 void doPeakClusterListItemsAssayed()
 /* Put up a page that shows all experiments associated with a cluster track. */
 {
 struct trackDb *clusterTdb = tdbForTableArg();
 cartWebStart(cart, database, "List of items assayed in %s", clusterTdb->shortLabel);
 struct sqlConnection *conn = hAllocConn(database);
 
 char *inputTableFieldDisplay = trackDbSetting(clusterTdb, "inputTableFieldDisplay");
 webPrintLinkTableStart();
 if (inputTableFieldDisplay)
     {
     struct slName *fieldList = stringToSlNames(inputTableFieldDisplay);
@@ -512,33 +511,33 @@
 char **row = sqlNextRow(sr);
 struct factorSource *cluster = NULL;
 if (row != NULL)
     cluster = factorSourceLoad(row + rowOffset);
 sqlFreeResult(&sr);
 
 if (cluster == NULL)
     errAbort("Error loading cluster from track %s", tdb->track);
 
 char *sourceTable = trackDbRequiredSetting(tdb, "sourceTable");
 
 char *factorLink = cluster->name;
 char *vocab = trackDbSetting(tdb, "controlledVocabulary");
 if (vocab != NULL)
     {
-    char *file = cloneFirstWord(vocab);
-    factorLink = wgEncodeVocabLink(file, "term", factorLink, factorLink, factorLink, "");
+    factorLink = wgEncodeVocabLink("term", factorLink, factorLink, factorLink, "");
     }
+
 printf("<B>Factor:</B> %s<BR>\n", factorLink);
 printf("<B>Cluster Score (out of 1000):</B> %d<BR>\n", cluster->score);
 printPos(cluster->chrom, cluster->chromStart, cluster->chromEnd, NULL, TRUE, item);
 
 /* Get list of tracks we'll look through for input. */
 char *inputTrackTable = trackDbRequiredSetting(tdb, "inputTrackTable");
 char query[256];
 sqlSafef(query, sizeof(query), "select tableName from %s where factor='%s' order by source", 
                 inputTrackTable, 
     cluster->name);
 
 /* Next do the lists of hits and misses.  We have the hits from the non-zero signals in
  * cluster->expScores.  We need to figure out the sources actually assayed though
  * some other way.  We'll do this by one of two techniques. */
 char *inputTableFieldDisplay = trackDbSetting(tdb, "inputTableFieldDisplay");