src/hg/lib/hVarSubst.c 1.4

1.4 2009/06/04 19:13:55 hiram
Properly look for ClosestToHome variables during substitution and add chain linearGap matrix variable recognition
Index: src/hg/lib/hVarSubst.c
===================================================================
RCS file: /projects/compbio/cvsroot/kent/src/hg/lib/hVarSubst.c,v
retrieving revision 1.3
retrieving revision 1.4
diff -b -B -U 1000000 -r1.3 -r1.4
--- src/hg/lib/hVarSubst.c	12 Feb 2009 00:59:24 -0000	1.3
+++ src/hg/lib/hVarSubst.c	4 Jun 2009 19:13:55 -0000	1.4
@@ -1,266 +1,308 @@
 /* Handle variable substitutions in strings from trackDb and other
  * labels. See trackDb/README for descriptions of values that can be
  * substitute.  This code needs to do a special handle to remain compatibility
  * with behavior of the old substitution mechanism. */
 #include "common.h"
 #include "trackDb.h"
 #include "hdb.h"
 #include "sqlNum.h"
 #include "hVarSubst.h"
 
 static boolean isVarEnd(boolean inBraces, char c)
 /** does the character end a variable reference. */
 {
 if (inBraces)
     return (c == '}');
 else
     return !((c == '_') || isalnum(c));
 }
 
 static char *parseVarName(char *desc, char *varStart, char *varName, int varNameSize)
 /* parse substitution variable name out of a string, returning next position
  * after name. */
 {
 char *p = varStart+1;
 if (*p == '\0')
     errAbort("trailing `$' while doing variable substitution in %s", desc);
 boolean inBraces = (*p == '{');
 if (inBraces)
     p++;
 int nameIdx = 0;
 while ((nameIdx < varNameSize-1) && !isVarEnd(inBraces, *p))
     varName[nameIdx++] = *p++;
 if (nameIdx == 0)
     errAbort("empty variable name in %s", desc);
 if (nameIdx == varNameSize)
     errAbort("variable name in desc %s exceeds maximum length of %d, starting with: \"%.*s\"",
              desc, varNameSize-1, varNameSize-1, varName);
 varName[nameIdx] = '\0';
 if (inBraces)
     p++;
 return p;
 }
 
 static char *lookupTrackDbSubVar(char *desc, struct trackDb *tdb, char *settingName, char *varName)
 /* get the specified track setting to substitute or die trying; more useful
  * message than trackDbRequiredSetting when doing substitution */
 {
-char *val = trackDbSetting(tdb, settingName);
+char *val = trackDbSettingClosestToHome(tdb, settingName);
 if (val == NULL)
-   errAbort("trackDb setting \"%s\" not found for variable substitution of \"$%s\" in %s",
-            settingName, varName, desc);
+   errAbort("trackDb (%s) setting \"%s\" not found for variable substitution of \"$%s\" in %s",
+            tdb->tableName, settingName, varName, desc);
 return val;
 }
 
 static char *lookupOtherDb(char *desc, struct trackDb *tdb, char *varName)
 /* look up the otherDb variable, which is needed for substituting varName */
 {
 return lookupTrackDbSubVar(desc, tdb, "otherDb", varName);
 }
 
+static void insertLinearGapHtml(struct trackDb *tdb, char *linearGap,
+                             struct dyString *dest)
+/* Generate HTML table from chain linearGap variable */
+{
+if (sameWord("medium",linearGap))
+    {
+dyStringPrintf(dest, "<PRE>-linearGap=%s\n\n\
+tableSize    11\n\
+smallSize   111\n\
+position  1   2   3   11  111  2111  12111  32111   72111  152111  252111\n\
+qGap    350 425 450  600  900  2900  22900  57900  117900  217900  317900\n\
+tGap    350 425 450  600  900  2900  22900  57900  117900  217900  317900\n\
+bothGap 750 825 850 1000 1300  3300  23300  58300  118300  218300  318300\n\
+</PRE>", linearGap);
+    }
+else if (sameWord("loose", linearGap))
+    {
+dyStringPrintf(dest, "<PRE>-linearGap=%s\n\n\
+tablesize    11\n\
+smallSize   111\n\
+position  1   2   3   11  111  2111  12111  32111  72111  152111  252111\n\
+qGap    325 360 400  450  600  1100   3600   7600  15600   31600   56600\n\
+tGap    325 360 400  450  600  1100   3600   7600  15600   31600   56600\n\
+bothGap 625 660 700  750  900  1400   4000   8000  16000   32000   57000\n\
+</PRE>", linearGap);
+    }
+else
+    errAbort("Invalid chainLinearGap specified '%s', can only be 'medium' or 'loose'", linearGap);
+}
+
 static void insertMatrixHtml(struct trackDb *tdb, char *matrix,
                              char *matrixHeader, struct dyString *dest)
 /* Generate HTML table from matrix setting in trackDb. matrixHeader is
  * optional. */
 {
 char *words[100];
 char *headerWords[10];
 int size;
 int i, j, k;
 int wordCount = 0, headerCount = 0;
 
 wordCount = chopString(cloneString(matrix), ", \t", words, ArraySize(words));
 if (matrixHeader != NULL)
     headerCount = chopString(cloneString(matrixHeader), 
                     ", \t", headerWords, ArraySize(headerWords));
 errno = 0;
 size = sqrt(sqlDouble(words[0]));
 if (errno)
     errAbort("Invalid matrix size in for track %s: %s\n", tdb->tableName,
              words[0]);
 dyStringAppend(dest, "The following matrix was used:<P>\n");
 k = 1;
 dyStringAppend(dest, "<BLOCKQUOTE><TABLE BORDER=1 CELLPADDING=4 BORDERCOLOR=\"#aaaaaa\">\n");
 if (matrixHeader)
     {
     dyStringAppend(dest, "<TR ALIGN=right><TD></TD>");
     for (i = 0; i < size && i < headerCount; i++)
         dyStringPrintf(dest, "<TD><B>%s</B></TD>", headerWords[i]);
     dyStringAppend(dest, "</TR>\n");
     }
 for (i = 0; i < size; i++)
     {
     dyStringAppend(dest, "<TR ALIGN=right>");
     if (matrixHeader)
         dyStringPrintf(dest, "<TD><B>%s<B></TD>", headerWords[i]);
     for (j = 0; j < size && k < wordCount ; j++)
         dyStringPrintf(dest, "<TD>%s</TD>", words[k++]);
     dyStringAppend(dest, "</TR>\n");
     }
 dyStringAppend(dest, "</TABLE></BLOCKQUOTE></P>\n");
 }
 
+static void substLinearGap(struct trackDb *tdb, struct dyString *dest)
+/* Generate HTML table from matrix setting in trackDb.  Note: for
+ * compatibility, substitutes and empty string if matrix setting not found in
+ * trackDb. */
+{
+char *linearGap = trackDbSettingClosestToHome(tdb, "chainLinearGap");
+if (linearGap != NULL)
+    insertLinearGapHtml(tdb, linearGap, dest);
+}
+
 static void substMatrixHtml(struct trackDb *tdb, struct dyString *dest)
 /* Generate HTML table from matrix setting in trackDb.  Note: for
  * compatibility, substitutes and empty string if matrix setting not found in
  * trackDb. */
 {
-char *matrix = trackDbSetting(tdb, "matrix");
+char *matrix = trackDbSettingClosestToHome(tdb, "matrix");
 if (matrix != NULL)
-    insertMatrixHtml(tdb, matrix, trackDbSetting(tdb, "matrixHeader"), dest);
+    insertMatrixHtml(tdb, matrix, trackDbSettingClosestToHome(tdb, "matrixHeader"), dest);
 }
 
 static boolean isAbbrevScientificName(char *name)
 /* Return true if name looks like an abbreviated scientific name 
 * (e.g. D. yakuba). */
 {
 return (name != NULL && strlen(name) > 4 &&
 	isalpha(name[0]) &&
 	name[1] == '.' && name[2] == ' ' &&
 	isalpha(name[3]));
 }
 
 static boolean isDatabaseVar(char *varBase)
 /* Is this a variable that can be resolved only from the database name?
  * Specify the base name, excluding the o_ prefix. */
 {
 return (strcasecmp(varBase, "organism") == 0)
     || (strcasecmp(varBase, "date") == 0)
     || (strcasecmp(varBase, "db") == 0);
 }
 
 static char *valOrDb(char *val, char *database)
 /* return val if not-null, or a clone of database if it is null */
 {
 if (val == NULL)
     val = cloneString(database);
 return val;
 }
 
 static void substDatabaseVar(char *database, char *varBase,
                              struct dyString *dest)
 /* substitute a variable resolved from the database name.
  * Specify the base name, excluding the o_ prefix. If database
  * can be looked up, just substitute the database name. */
 {
 if (sameString(varBase, "Organism"))
     {
     char *org = valOrDb(hOrganism(database), database);
     dyStringAppend(dest, org);
     freeMem(org);
     }
 else if (sameString(varBase, "ORGANISM"))
     {
     char *org = hOrganism(database);
     if (org != NULL)
         touppers(org);
     else
         org = valOrDb(org, database);
     dyStringAppend(dest, org);
     freeMem(org);
     }
 else if (sameString(varBase, "organism"))
     {
     char *org = hOrganism(database);
     if ((org != NULL) && !isAbbrevScientificName(org))
             tolowers(org);
         else 
             org = valOrDb(org, database);
     dyStringAppend(dest, org);
     freeMem(org);
     }
 else if (sameString(varBase, "date"))
     {
     char *date = valOrDb(hFreezeDateOpt(database), database);
     dyStringAppend(dest, date);
     freeMem(date);
     }
 else if (sameString(varBase, "db"))
     dyStringAppend(dest, database);
 }
 
 static void substTrackDbVar(char *desc, struct trackDb *tdb, char *database,
                             char *varName, struct dyString *dest)
 /* substitute a variable value obtained from trackDb */
 {
 if (sameString(varName, "matrix"))
     substMatrixHtml(tdb, dest);
+else if (sameString(varName, "chainLinearGap"))
+    substLinearGap(tdb, dest);
 else
     dyStringAppend(dest, lookupTrackDbSubVar(desc, tdb, varName, varName));
 }
 
 static void substVar(char *desc, struct trackDb *tdb, char *database,
                      char *varName, struct dyString *dest)
 /* look up varName and insert value in output string.  Error if variable
  * can't be found */
 {
 if (isDatabaseVar(varName))
     substDatabaseVar(database, varName, dest);
 else if (tdb == NULL)
     errAbort("invalid variable \"%s\" to substitute in %s",
              varName, desc);
 else if (startsWith("o_", varName) && isDatabaseVar(varName+2))
     substDatabaseVar(lookupOtherDb(desc, tdb, varName), varName+2, dest);
 else
     substTrackDbVar(desc, tdb, database, varName, dest);
 }
 
 char *hVarSubst(char *desc, struct trackDb *tdb, char *database, char *src)
 /* Parse a string and substitute variable references.  Return NULL if
  * no variable references were found.  Error on missing variables (except
  * $matrix).  desc is a brief description to print on an error to help with
  * debugging. tdb maybe NULL to only do substitutions based on database
  * and organism. See trackDb/README for more information.*/
 {
 struct dyString *dest = NULL;
 char *start = src;  // start of current static string in src
 char *next = src;   // cursor
 char varName[65];
 
 while ((next = strchr(next, '$')) != NULL)
     {
     if (dest == NULL)
         dest = dyStringNew(strlen(src));
     dyStringAppendN(dest, start, next-start);
     if (*(next+1) == '$')
         {
         // $$ is a literal $
         dyStringAppendC(dest, '$');
         start = next = next + 2;
         }
     else
         {
         // variable reference
         start = next = parseVarName(desc, next, varName, sizeof(varName));
         substVar(desc, tdb, database, varName, dest);
         }
     }
 if (dest != NULL)
     {
     dyStringAppend(dest, start);
     return dyStringCannibalize(&dest);
     }
 else
     return NULL; // no substitutions
 }
 
 void hVarSubstInVar(char *desc, struct trackDb *tdb, char *database, char **varPtr)
 /* hVarSubst on a dynamically allocated string, replacing string in substitutions
  * occur, freeing the old memory if necessary.  See hVarSubst for details.
  */
 {
 char *dest = hVarSubst(desc, tdb, database, *varPtr);
 if (dest != NULL)
     {
     freez(varPtr);
     *varPtr = dest;
     }
 }
                        
 void hVarSubstTrackDb(struct trackDb *tdb, char *database)
 /* Substitute variables in trackDb shortLabel, longLabel, and html fields. */
 {
 hVarSubstInVar(tdb->tableName, tdb, database, &tdb->shortLabel);
 hVarSubstInVar(tdb->tableName, tdb, database, &tdb->longLabel);
 hVarSubstInVar(tdb->tableName, tdb, database, &tdb->html);
 }