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) {