27aa980683134b5ff14cbaf5bdcbe563eb4af207
tdreszer
  Wed Apr 6 08:19:34 2011 -0700
Moved common name and description matching code into search lib and removed it from hgFileSearch and hgTracks/searchTracks.c
diff --git src/hg/hgTracks/searchTracks.c src/hg/hgTracks/searchTracks.c
index 63268f6..4df1ff0 100644
--- src/hg/hgTracks/searchTracks.c
+++ src/hg/hgTracks/searchTracks.c
@@ -20,30 +20,32 @@
 #include "trix.h"
 #include "jsHelper.h"
 #include "imageV2.h"
 
 
 #define TRACK_SEARCH_FORM        "trackSearch"
 #define SEARCH_RESULTS_FORM      "searchResults"
 #define TRACK_SEARCH_CURRENT_TAB "tsCurTab"
 #define TRACK_SEARCH_SIMPLE      "tsSimple"
 #define TRACK_SEARCH_ON_NAME     "tsName"
 #define TRACK_SEARCH_ON_TYPE     "tsType"
 #define TRACK_SEARCH_ON_GROUP    "tsGroup"
 #define TRACK_SEARCH_ON_DESCR    "tsDescr"
 #define TRACK_SEARCH_SORT        "tsSort"
 
+#define SUPPORT_QUOTES_IN_NAME_SEARCH
+
 //#define FILES_SEARCH
 #ifdef FILES_SEARCH
     #define FILE_SEARCH_ON_FILETYPE "tsFileType"
 #endif///def FILES_SEARCH
 
 static int gCmpGroup(const void *va, const void *vb)
 /* Compare groups based on label. */
 {
 const struct group *a = *((struct group **)va);
 const struct group *b = *((struct group **)vb);
 return strcmp(a->label, b->label);
 }
 
 // Would like to do a radio button choice ofsorts
 enum sortBy
@@ -82,85 +84,31 @@
 const struct track *a = ((struct track *) aa->val);
 const struct track *b = ((struct track *) bb->val);
 return strcasecmp(a->longLabel, b->longLabel);
 }
 
 static void findTracksSort(struct slRef **pTrack, enum sortBy sortBy)
 {
 if (sortBy == sbHierarchy)
     slSort(pTrack, gCmpTrackHierarchy);
 else if (sortBy == sbAbc)
     slSort(pTrack, gCmpTrack);
 else
     slReverse(pTrack);
 }
 
-#define SUPPORT_QUOTES_IN_NAME_SEARCH
-#ifdef SUPPORT_QUOTES_IN_NAME_SEARCH
-// TODO replace with tdb version moved from hgFileSearch to search.c lib code.
-static boolean matchToken(char *string, char *token)
-{
-// do this with regex ? Would require all sorts of careful parsing for ()., etc.
-if (string == NULL)
-    return (token == NULL);
-if (token == NULL)
-    return TRUE;
-
-if (!strchr(token,'*') && !strchr(token,'?'))
-    return (strcasestr(string,token) != NULL);
-
-char wordWild[1024];
-safef(wordWild,sizeof wordWild,"*%s*",token);
-return wildMatch(wordWild, string);
-}
-
-static boolean doesNameMatchTrack(struct track *track, 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 (track->shortLabel == NULL || track->longLabel == NULL)
-    return (wordList != NULL);
-
-struct slName *word = wordList;
-for(; word != NULL; word = word->next)
-    {
-    if (!matchToken(track->shortLabel,word->name)
-    &&  !matchToken(track->longLabel, word->name))
-        return FALSE;
-    }
-return TRUE;
-}
-
-static boolean doesDescriptionMatchTrack(struct track *track, 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 (track->tdb->html == NULL)
-    return (wordList != NULL);
-
-if (strchr(track->tdb->html,'\n'))
-    strSwapChar(track->tdb->html,'\n',' ');   // DANGER: don't own memory.  However, this track search function will use html for no other purpose
-
-struct slName *word = wordList;
-for(; word != NULL; word = word->next)
-    {
-    if (!matchToken(track->tdb->html,word->name))
-        return FALSE;
-    }
-
-return TRUE;
-}
-
-#else///ifndef SUPPORT_QUOTES_IN_NAME_SEARCH
+#ifndef SUPPORT_QUOTES_IN_NAME_SEARCH
 
 // XXXX make a matchString function to support "contains", "is" etc. and wildcards in contains
 
 //    ((sameString(op, "is") && !strcasecmp(track->shortLabel, str)) ||
 
 static boolean isNameMatch(struct track *track, char *str, char *op)
 {
 return str && strlen(str) &&
     ((sameString(op, "is") && !strcasecmp(track->shortLabel, str)) ||
     (sameString(op, "is") && !strcasecmp(track->longLabel, str)) ||
     (sameString(op, "contains") && containsStringNoCase(track->shortLabel, str) != NULL) ||
     (sameString(op, "contains") && containsStringNoCase(track->longLabel, str) != NULL));
 }
 
 static boolean isDescriptionMatch(struct track *track, char **words, int wordCount)
@@ -342,56 +290,56 @@
     #endif///def SUPPORT_QUOTES_IN_NAME_SEARCH
 
         struct group *group;
         for (group = groupList; group != NULL; group = group->next)
             {
             if(groupSearch == NULL || sameString(group->name, groupSearch))
                 {
                 if (group->trackList != NULL)
                     {
                     struct trackRef *tr;
                     for (tr = group->trackList; tr != NULL; tr = tr->next)
                         {
                         struct track *track = tr->track;
                         char *trackType = cloneFirstWord(track->tdb->type); // will be spilled
                 #ifdef SUPPORT_QUOTES_IN_NAME_SEARCH
-                        if((isEmpty(nameSearch) || doesNameMatchTrack(track, nameList))
-                        && (isEmpty(descSearch) || doesDescriptionMatchTrack(track, descList))
+                        if((isEmpty(nameSearch) || searchNameMatches(track->tdb, nameList))
+                        && (isEmpty(descSearch) || searchDescriptionMatches(track->tdb, descList))
                 #else///ifndef SUPPORT_QUOTES_IN_NAME_SEARCH
                         if((isEmpty(nameSearch) || isNameMatch(track, nameSearch, "contains"))
                         && (isEmpty(descSearch) || isDescriptionMatch(track, descWords, descWordCount))
                 #endif///ndef SUPPORT_QUOTES_IN_NAME_SEARCH
                         && (isEmpty(typeSearch) || (sameWord(typeSearch, trackType) && !tdbIsComposite(track->tdb)))
                         && (matchingTracks == NULL || hashLookup(matchingTracks, track->track) != NULL))
                             {
                             if (track != NULL)
                                 {
                                 tracksFound++;
                                 refAdd(&tracks, track);
                                 }
                             else
                                 warn("found group track is NULL.");
                             }
                         if (track->subtracks != NULL)
                             {
                             struct track *subTrack;
                             for (subTrack = track->subtracks; subTrack != NULL; subTrack = subTrack->next)
                                 {
                                 trackType = cloneFirstWord(subTrack->tdb->type); // will be spilled
                         #ifdef SUPPORT_QUOTES_IN_NAME_SEARCH
-                                if((isEmpty(nameSearch) || doesNameMatchTrack(subTrack, nameList))
-                                && (isEmpty(descSearch) || doesDescriptionMatchTrack(subTrack, descList))
+                                if((isEmpty(nameSearch) || searchNameMatches(subTrack->tdb, nameList))
+                                && (isEmpty(descSearch) || searchDescriptionMatches(subTrack->tdb, descList))
                         #else///ifndef SUPPORT_QUOTES_IN_NAME_SEARCH
                                 if((isEmpty(nameSearch) || isNameMatch(subTrack, nameSearch, "contains"))
                                 && (isEmpty(descSearch) || isDescriptionMatch(subTrack, descWords, descWordCount))
                         #endif///ndef SUPPORT_QUOTES_IN_NAME_SEARCH
                                 && (isEmpty(typeSearch) || sameWord(typeSearch, trackType))
                                 && (matchingTracks == NULL || hashLookup(matchingTracks, subTrack->track) != NULL))
                                     {
                                     if (track != NULL)
                                         {
                                         tracksFound++;
                                         refAdd(&tracks, subTrack);
                                         }
                                     else
                                         warn("found subtrack is NULL.");
                                     }
@@ -681,31 +629,34 @@
     freez(&nameSearch);
     }
 else if(sameString(currentTab, "advancedTab"))
     {
     selectedTab = advancedTab;
     descSearch = cartOptionalString(cart, TRACK_SEARCH_ON_DESCR);
     }
 #ifdef FILES_SEARCH
 else if(sameString(currentTab, "filesTab"))
     {
     selectedTab = filesTab;
     descSearch = cartOptionalString(cart, TRACK_SEARCH_ON_DESCR);
     }
 #endif///def FILES_SEARCH
 
-#ifndef SUPPORT_QUOTES_IN_NAME_SEARCH
+#ifdef SUPPORT_QUOTES_IN_NAME_SEARCH
+if(descSearch && selectedTab == simpleTab) // TODO: could support quotes in simple tab by detecting quotes and choosing to use doesNameMatch() || doesDescriptionMatch()
+    stripChar(descSearch, '"');
+#else///ifndef SUPPORT_QUOTES_IN_NAME_SEARCH
 if(descSearch)
     stripChar(descSearch, '"');
 #endif///ndef SUPPORT_QUOTES_IN_NAME_SEARCH
 trackList = getTrackList(&groupList, -2); // global
 makeGlobalTrackHash(trackList);
 
 // NOTE: This is necessary when container cfg by '*' results in vis changes
 // This will handle composite/view override when subtrack specific vis exists, AND superTrack reshaping.
 parentChildCartCleanup(trackList,cart,oldVars); // Subtrack settings must be removed when composite/view settings are updated
 
 getSearchTrixFile(database, trixFile, sizeof(trixFile));
 trix = trixOpen(trixFile);
 slSort(&groupList, gCmpGroup);
 for (group = groupList; group != NULL; group = group->next)
     {