7976e2588e92dca0567231cf3998759bf6f1827f
max
  Thu May 7 03:27:42 2015 -0700
implementing the external tools "send to" menu, refs #15113

diff --git src/hg/hgc/hgc.c src/hg/hgc/hgc.c
index 38fa392..8d111d9 100644
--- src/hg/hgc/hgc.c
+++ src/hg/hgc/hgc.c
@@ -879,48 +879,30 @@
 
     printf("<BR>\n");
     }
 }
 
 
 void genericHeader(struct trackDb *tdb, char *item)
 /* Put up generic track info. */
 {
 if (item != NULL && item[0] != 0)
     cartWebStart(cart, database, "%s (%s)", tdb->longLabel, item);
 else
     cartWebStart(cart, database, "%s", tdb->longLabel);
 }
 
-static struct dyString *subMulti(char *orig, int subCount,
-                                 char *in[], char *out[])
-/* Perform multiple substitions on orig. */
-{
-int i;
-struct dyString *s = newDyString(256), *d = NULL;
-
-dyStringAppend(s, orig);
-for (i=0; i<subCount; ++i)
-    {
-    d = dyStringSub(s->string, in[i], out[i]);
-    dyStringFree(&s);
-    s = d;
-    d = NULL;
-    }
-return s;
-}
-
 void printItemDetailsHtml(struct trackDb *tdb, char *itemName)
 /* if track has an itemDetailsHtml, retrieve and print the HTML */
 {
 char *tableName = trackDbSetting(tdb, "itemDetailsHtmlTable");
 if (tableName != NULL)
     {
     struct sqlConnection *conn = hAllocConn(database);
     struct itemDetailsHtml *html, *htmls;
     // if the details table has chrom/start/end columns, then use these to lookup html
     if (sqlColumnExists(conn, tableName, "chrom"))
         {
         char *chrom = cgiString("c");
         int start   = cgiInt("o");
         int end     = cgiInt("t");
 
@@ -948,117 +930,46 @@
  * return itemName. */
 {
 char *sql = trackDbSetting(tdb, "idInUrlSql");
 char *id = itemName;
 if (sql != NULL)
     {
     char query[1024];
     sqlSafef(query, sizeof(query), sql, itemName);
     struct sqlConnection *conn = hAllocConn(database);
     id = sqlQuickString(conn, query);
     hFreeConn(&conn);
     }
 return id;
 }
 
-char* replaceInUrl(struct trackDb *tdb, char *url, char *idInUrl, boolean encode) 
-/* replace $$ in url with idInUrl. Supports many other wildchards */
-{
-struct dyString *uUrl = NULL;
-struct dyString *eUrl = NULL;
-char startString[64], endString[64];
-char begItem[64], endItem[64];
-char *ins[11], *outs[11];
-char *eItem = (encode ? cgiEncode(idInUrl) : cloneString(idInUrl));
-
-safef(startString, sizeof startString, "%d", winStart);
-safef(endString, sizeof endString, "%d", winEnd);
-ins[0] = "$$";
-outs[0] = idInUrl;
-ins[1] = "$T";
-outs[1] = tdb->track;
-ins[2] = "$S";
-outs[2] = seqName;
-ins[3] = "$[";
-outs[3] = startString;
-ins[4] = "$]";
-outs[4] = endString;
-ins[5] = "$s";
-outs[5] = skipChr(seqName);
-ins[6] = "$D";
-outs[6] = database;
-ins[7] = "$P";  /* for an item name of the form:  prefix:suffix */
-ins[8] = "$p";	/* the P is the prefix, the p is the suffix */
-if (stringIn(":", idInUrl)) {
-    char *itemClone = cloneString(idInUrl);
-    char *suffix = stringIn(":", itemClone);
-    char *suffixClone = cloneString(suffix+1); /* +1 skip the : */
-    char *nextColon = stringIn(":", suffixClone+1);
-    if (nextColon)	/* terminate suffixClone suffix */
-        *nextColon = '\0';	/* when next colon is present */
-    *suffix = '\0';   /* terminate itemClone prefix */
-    outs[7] = itemClone;
-    outs[8] = suffixClone;
-    /* small memory leak here for these cloned strings */
-    /* not important for a one-time operation in a CGI that will exit */
-} else {
-    outs[7] = idInUrl;	/* otherwise, these are not expected */
-    outs[8] = idInUrl;	/* to be used */
-}
-
-// URL may now contain item boundaries
-ins[9] = "${";
-ins[10] = "$}";
-if (cartOptionalString(cart, "o") && cartOptionalString(cart, "t"))
-    {
-    int itemBeg = cartIntExp(cart, "o") + 1; // Should strip any unexpected commas
-    int itemEnd = cartIntExp(cart, "t");
-    safef(begItem, sizeof begItem, "%d", itemBeg);
-    safef(endItem, sizeof endItem, "%d", itemEnd);
-    outs[9] = begItem;
-    outs[10] = endItem;
-    }
-else // should never be but I am unwilling to bet the farm
-    {
-    outs[9] = startString;
-    outs[10] = endString;
-    }
-
-uUrl = subMulti(url, ArraySize(ins), ins, outs);
-outs[0] = eItem;
-eUrl = subMulti(url, ArraySize(ins), ins, outs);
-freeDyString(&uUrl);
-freeMem(eItem);
-return eUrl->string;
-}
-
 char* constructUrl(struct trackDb *tdb, char *urlSetting, char *idInUrl, boolean encode) 
 {
 /* construct the url by replacing $$, etc in the url given by urlSetting.
  * Replace $$ with itemName.  */
 
 // check the url setting prefix and get the correct url setting from trackDb 
 char *url;
 if (sameWord(urlSetting, "url"))
     url = tdb->url;
 else
     url = trackDbSetting(tdb, urlSetting);
 
 if (url == NULL || url[0] == 0)
     return NULL;
 
-char* eUrl = replaceInUrl(tdb, url, idInUrl, encode);
+char* eUrl = replaceInUrl(url, idInUrl, cart, database, seqName, winStart, winEnd, tdb->track, encode);
 return eUrl;
 }
 
 void printIframe(struct trackDb *tdb, char *itemName)
 /* print an iframe with the URL specified in trackDb (iframeUrl), can have 
  * the standard codes in it (like $$ for itemName, etc)
  */
 {
 char* eUrl = constructUrl(tdb, "iframeUrl", itemName, FALSE);
 if (eUrl==NULL)
     return;
 
 char *iframeOptions = trackDbSettingOrDefault(tdb, "iframeOptions", "width='100%%' height='1024'");
 // Resizing requires the hgcDetails pages to include a bit of javascript.
 //
@@ -1571,31 +1482,32 @@
 int nameCount;
 char **idNames = getIdNameMap(tdb, col, &nameCount);
 
 printf("<td>");
 for (itemId = slIds; itemId!=NULL; itemId = itemId->next) 
     {
     if (itemId != slIds)
         printf(", ");
     char *itemName = itemId->name;
     if (idNames)
         {
         unsigned int id = sqlUnsigned(itemName);
         if (id < nameCount)
             itemName = idNames[sqlUnsigned(itemName)];
         }
-    char *idUrl = replaceInUrl(tdb, url, trimSpaces(itemName), TRUE);
+    char *idUrl = replaceInUrl(url, trimSpaces(itemName), cart, database, seqName, winStart, 
+                    winEnd, tdb->track, TRUE);
     printf("<a href=\"%s\" target=\"_blank\">%s</a>", idUrl, itemName);
     } 
 printf("</td></tr>\n");
 freeMem(slIds);
 //freeMem(idNames);
 }
 
 int extraFieldsPrint(struct trackDb *tdb,struct sqlResult *sr,char **fields,int fieldCount)
 // Any extra bed or bigBed fields (defined in as and occurring after N in bed N + types.
 // sr may be null for bigBeds.
 // Returns number of extra fields actually printed.
 {
 struct sqlConnection *conn = NULL ;
 if (!trackHubDatabase(database))
     conn = hAllocConnTrack(database, tdb);
@@ -10984,31 +10896,30 @@
     printf("<td><img src=\"%s\">", imgPath);
 
 /* add text column, if exists */
 safef(textPath, sizeof(textPath), "../htdocs/geneExtra/%s.txt", geneFileBase);
 if (access(textPath, R_OK) == 0)
     {
     FILE *fh = mustOpen(textPath, "r");
     printf("<td valign=\"center\">");
     copyOpenFile(fh, stdout);
     fclose(fh);
     }
 }
 
 int gbCdnaGetVersion(struct sqlConnection *conn, char *acc)
 /* return mrna/est version, or 0 if not available */
-//  define hHasTable(db,table) hTableExists(db,table) // like hFieldExists
 
 {
 int ver = 0;
 if (!hTableExists(database, "gbCdnaInfo"))
     {
     warn("Genbank information not shown below, the table %s.gbCdnaInfo is not installed "
         "on this server. ", database);
     //"The information below is a shortened version of the one shown on the "
     //"<a href=\"http://genome.ucsc.edu\">UCSC site</a>", database);
     return 0;
     }
 
 if (hHasField(database, "gbCdnaInfo", "version"))
     {
     char query[128];