104810c1ffc3b9350af01e2f97f8e58328b9434d
tdreszer
  Mon Mar 28 12:33:39 2011 -0700
Addressed a bug in description searches and slightly streamlined.
diff --git src/hg/hgFileSearch/hgFileSearch.c src/hg/hgFileSearch/hgFileSearch.c
index 8dd6b68..f24d423 100644
--- src/hg/hgFileSearch/hgFileSearch.c
+++ src/hg/hgFileSearch/hgFileSearch.c
@@ -31,60 +31,95 @@
 #define TRACK_SEARCH_ON_DESCR    "tsDescr"
 #define TRACK_SEARCH_SORT        "tsSort"
 
 #define SUPPORT_COMPOSITE_SEARCH
 #ifdef SUPPORT_COMPOSITE_SEARCH
     //#define USE_TABS
 #endif///def SUPPORT_COMPOSITE_SEARCH
 
 #ifdef SUPPORT_COMPOSITE_SEARCH
 // make a matchString function to support "contains", "is" etc. and wildcards in contains
 
 //    ((sameString(op, "is") && !strcasecmp(track->shortLabel, str)) ||
 
 #define MATCH_ON_EACH_WORD
 #ifdef MATCH_ON_EACH_WORD
+#define MATCH_ON_WILDS
+static boolean matchToken(char *string, char *token)
+{
+if (string == NULL)
+    return (token == NULL);
+if (token == NULL)
+    return TRUE;
+
+if (!strchr(token,'*') && !strchr(token,'?'))
+    return (strcasestr(string,token) != NULL);
+
+#ifdef MATCH_ON_WILDS
+char wordWild[1024];
+safef(wordWild,sizeof wordWild,"*%s*",token);
+return wildMatch(wordWild, string);
+
+// do this with regex ? Would require all sorts of careful parsing for ()., etc.
+//safef(wordWild,sizeof wordWild,"^*%s*$",token);
+//regex_t regEx;
+//int err = regcomp(&regEx, token, REG_NOSUB | REG_ICASE);
+//if(err != 0)  // Compile the regular expression so that it can be used.  Use: REG_EXTENDED ?
+//    {
+//    char buffer[128];
+//    regerror(err, &regEx, buffer, sizeof buffer);
+//    warn("ERROR: Invalid regular expression: [%s] %s\n",token,buffer);
+//    regfree(&regEx);
+//    return FALSE;
+//    }
+//err = regexec(&regEx, mdbVar->val, 0, NULL, 0);
+//regfree(&regEx);
+//return (err == 0);
+
+#endif//def MATCH_ON_WILDS
+}
+
 static boolean doesNameMatch(struct trackDb *tdb, struct slName *wordList)
 // We parse str and look for every word at the start of any word in track description (i.e. google style).
 {
 if (tdb->html == NULL)
     return (wordList != NULL);
 
 struct slName *word = wordList;
 for(; word != NULL; word = word->next)
     {
-    char wordWild[256];
-    safef(wordWild,sizeof wordWild,"*%s*",word->name);
-    if (!wildMatch(wordWild, tdb->shortLabel)
-    &&  !wildMatch(wordWild, tdb->longLabel))
+    if (!matchToken(tdb->shortLabel,word->name)
+    &&  !matchToken(tdb->longLabel, word->name))
         return FALSE;
     }
 return TRUE;
 }
 
 static boolean doesDescriptionMatch(struct trackDb *tdb, struct slName *wordList)
 // We parse str and look for every word at the start of any word in track description (i.e. google style).
 {
+//static boolean tryitOneCycle=TRUE;
 if (tdb->html == NULL)
     return (wordList != NULL);
 
+if (strchr(tdb->html,'\n'))
+    strSwapChar(tdb->html,'\n',' ');   // DANGER: don't own memory.  However, this CGI will use html for no other purpose
+
 struct slName *word = wordList;
 for(; word != NULL; word = word->next)
     {
-    char wordWild[256];
-    safef(wordWild,sizeof wordWild,"*%s*",word->name);
-    if (!wildMatch(wordWild, tdb->html))
+    if (!matchToken(tdb->html,word->name))
         return FALSE;
     }
 return TRUE;
 }
 #endif///def MATCH_ON_EACH_WORD
 
 static struct trackDb *tdbFilterBy(struct trackDb **pTdbList, char *name, char *description, char *group)
 // returns tdbs that match supplied criterion, leaving unmatched in list passed in
 {
 #ifdef MATCH_ON_EACH_WORD
 // Set the word lists up once
 struct slName *nameList = NULL;
 if (name)
     nameList = slNameListOfUniqueWords(cloneString(name),TRUE); // TRUE means respect quotes
 struct slName *descList = NULL;
@@ -116,31 +151,30 @@
     else if (name && !doesNameMatch(tdb, nameList))
         slAddHead(&tdbRejects,tdb);
     else if (description && !doesDescriptionMatch(tdb, descList))
         slAddHead(&tdbRejects,tdb);
 #else///ifndef MATCH_ON_EACH_WORD
     else if (name && (!wildMatch(nameWild,tdb->shortLabel) && !wildMatch(nameWild,tdb->longLabel)))
         slAddHead(&tdbRejects,tdb);
     else if (description && (tdb->html == NULL || !wildMatch(descWild,tdb->html)))
         slAddHead(&tdbRejects,tdb);
 #endif///ndef MATCH_ON_EACH_WORD
     else
         slAddHead(&tdbMatched,tdb);
     }
 //slReverse(&tdbRejects); // Needed?
 //slReverse(&tdbMatched); // Needed?
-
 *pTdbList = tdbRejects;
 
 //warn("matched %d tracks",slCount(tdbMatched));
 return tdbMatched;
 }
 
 static boolean mdbSelectsAddFoundComposites(struct slPair **pMdbSelects,struct trackDb *tdbsFound)
 // Adds a composite mdbSelect (if found in tdbsFound) to the head of the pairs list.
 // If tdbsFound is NULL, then add dummy composite search criteria
 {
 // create comma separated list of composites
 struct dyString *dyComposites = dyStringNew(256);
 struct trackDb *tdb = tdbsFound;
 for(;tdb != NULL; tdb = tdb->next)
     {