diff options
Diffstat (limited to 'src/LYSearch.c')
-rw-r--r-- | src/LYSearch.c | 379 |
1 files changed, 379 insertions, 0 deletions
diff --git a/src/LYSearch.c b/src/LYSearch.c new file mode 100644 index 0000000..a56de21 --- /dev/null +++ b/src/LYSearch.c @@ -0,0 +1,379 @@ +/* + * $LynxId: LYSearch.c,v 1.40 2013/10/13 20:23:07 tom Exp $ + */ +#include <HTUtils.h> +#include <HTAlert.h> +#include <LYUtils.h> +#include <LYStrings.h> +#include <LYSearch.h> +#include <LYGlobalDefs.h> +#include <GridText.h> + +#include <LYLeaks.h> + +#define MATCH(a,b) (BOOL)(LYno_attr_strstr(a, b) != 0) + +/* + * Handle special field-related comparisons for anchor_has_target() and + * link_has_target(). + */ +BOOL field_has_target(FormInfo * field, const char *target) +{ + BOOL result = FALSE; + OptionType *option; + char *stars = NULL; + const char *cp; + + if ((field != NULL && field->value != NULL) && + field->type != F_HIDDEN_TYPE) { + if (field->type == F_PASSWORD_TYPE) { + /* + * Check the actual (hidden password), and then the displayed + * string - FM + */ + if (MATCH(field->value, target)) { + result = TRUE; + } else { + StrAllocCopy(stars, field->value); + memset(stars, '*', strlen(stars)); + result = MATCH(stars, target); + FREE(stars); + } + } else if (field->type == F_OPTION_LIST_TYPE) { + /* + * Search the option strings that are displayed when the popup is + * invoked - FM + */ + for (option = field->select_list; option != NULL; option = option->next) { + if (MATCH(option->name, target)) { + result = TRUE; + break; + } + } + } else if (field->type == F_RADIO_TYPE) { + /* + * Search for checked or unchecked parens - FM + */ + cp = ((field->num_value) + ? checked_radio + : unchecked_radio); + result = MATCH(cp, target); + } else if (field->type == F_CHECKBOX_TYPE) { + /* + * Search for checked or unchecked square brackets - FM + */ + cp = ((field->num_value) + ? checked_box + : unchecked_box); + result = MATCH(cp, target); + } else { + result = MATCH(field->value, target); + } + } + return result; +} + +/* + * see also anchor_has_target + */ +static BOOL link_has_target(int cur, + char *target) +{ + LinkInfo *a = &links[cur]; + char *text = NULL; + const char *last = "?"; + int count; + + /* + * Combine the parts of the link's text using the highlighting information, + * and compare the target against that. + */ + for (count = 0; count < 10; ++count) { + const char *part = LYGetHiliteStr(cur, count); + + if (part == NULL || part == last) { + if (MATCH(text, target)) { + return TRUE; + } + break; + } + StrAllocCat(text, part); + last = part; + } + + return field_has_target(a->l_form, target); +} + +/* + * Search for the target string inside of the links that are currently + * displayed on the screen beginning with the one after the currently selected + * one. If found set cur to the new value and return TRUE. If not found do + * not reset cur and return FALSE. + */ + +static int check_next_target_in_links(int *cur, + char *target) +{ + int i; + + if (nlinks != 0) { + for (i = *cur + 1; i < nlinks; ++i) { + if (link_has_target(i, target)) { + *cur = i; + return TRUE; + } + } + } + return FALSE; +} + +static int check_prev_target_in_links(int *cur, + char *target) +{ + int i; + + if (nlinks != 0) { + for (i = *cur - 1; i >= 0; --i) { + if (link_has_target(i, target)) { + *cur = i; + return TRUE; + } + } + } + return FALSE; +} + +/* + * Textsearch checks the prev_target variable to see if it is empty. If it is + * then it requests a new search string. It then searches the current file for + * the next instance of the search string and finds the line number that the + * string is on + * + * This is the primary USER search engine and is case sensitive or case + * insensitive depending on the 'LYcase_sensitive' global variable + */ +BOOL textsearch(DocInfo *cur_doc, + bstring **prev_target, + int direction) +{ + int offset; + int oldcur = cur_doc->link; + static bstring *my_prev_target = NULL; + static BOOL first = TRUE; + char *cp; + int ch = 0; + RecallType recall; + int QueryTotal; + int QueryNum; + BOOLEAN FirstRecall = TRUE; + + /* + * Initialize the search string buffer. - FM + */ + if (first) { + BStrCopy0(my_prev_target, ""); + first = FALSE; + } + + QueryTotal = (search_queries ? HTList_count(search_queries) : 0); + recall = ((QueryTotal >= 1) ? RECALL_URL : NORECALL); + QueryNum = QueryTotal; + + if (direction != 0) { + /* + * LYK_NEXT or LYK_PREV was pressed, so copy the buffer into + * prev_target. + */ + BStrCopy(*prev_target, my_prev_target); + } else if (*prev_target == 0) { + BStrCopy0(*prev_target, ""); + } + + if (strlen((*prev_target)->str) == 0) { + /* + * This is a new WHEREIS search ('/'), or LYK_NEXT was pressed but + * there was no previous search, so we need to get a search string from + * the user. - FM + */ + _statusline(ENTER_WHEREIS_QUERY); + + ch = LYgetBString(prev_target, FALSE, 0, recall); + if (ch < 0) { + /* + * User cancelled the search via ^G. Restore prev_target and + * return. - FM + */ + BStrCopy(*prev_target, my_prev_target); + HTInfoMsg(CANCELLED); + return (FALSE); + } + } + + check_recall: + if (strlen((*prev_target)->str) == 0 && + !(recall && (ch == UPARROW_KEY || ch == DNARROW_KEY))) { + /* + * No entry. Simply return, retaining the current buffer. Because + * prev_target is now reset, highlighting of the previous search string + * will no longer occur, but it can be used again via LYK_NEXT or + * LYK_PREV. + */ + HTInfoMsg(CANCELLED); + return (FALSE); + } + + if (recall && ch == UPARROW_KEY) { + if (FirstRecall) { + /* + * Use the current string or last query in the list. - FM + */ + FirstRecall = FALSE; + if (!isBEmpty(my_prev_target)) { + for (QueryNum = (QueryTotal - 1); QueryNum > 0; QueryNum--) { + if ((cp = (char *) HTList_objectAt(search_queries, + QueryNum)) != NULL && + !strcmp(my_prev_target->str, cp)) { + break; + } + } + } else { + QueryNum = 0; + } + } else { + /* + * Go back to the previous query in the list. - FM + */ + QueryNum++; + } + if (QueryNum >= QueryTotal) + /* + * Roll around to the last query in the list. - FM + */ + QueryNum = 0; + if ((cp = (char *) HTList_objectAt(search_queries, + QueryNum)) != NULL) { + BStrCopy0(*prev_target, cp); + if (!isBEmpty(my_prev_target) && + !strcmp(my_prev_target->str, (*prev_target)->str)) { + _statusline(EDIT_CURRENT_QUERY); + } else if ((!isBEmpty(my_prev_target) && QueryTotal == 2) || + (isBEmpty(my_prev_target) && QueryTotal == 1)) { + _statusline(EDIT_THE_PREV_QUERY); + } else { + _statusline(EDIT_A_PREV_QUERY); + } + ch = LYgetBString(prev_target, FALSE, 0, recall); + if (ch < 0) { + /* + * User canceled the search via ^G. Restore prev_target and + * return. - FM + */ + BStrCopy(*prev_target, my_prev_target); + HTInfoMsg(CANCELLED); + return (FALSE); + } + goto check_recall; + } + } else if (recall && ch == DNARROW_KEY) { + if (FirstRecall) { + /* + * Use the current string or first query in the list. - FM + */ + FirstRecall = FALSE; + if (!isBEmpty(my_prev_target)) { + for (QueryNum = 0; QueryNum < (QueryTotal - 1); QueryNum++) { + if ((cp = (char *) HTList_objectAt(search_queries, + QueryNum)) != NULL && + !strcmp(my_prev_target->str, cp)) { + break; + } + } + } else { + QueryNum = QueryTotal - 1; + } + } else { + /* + * Advance to the next query in the list. - FM + */ + QueryNum--; + } + if (QueryNum < 0) + /* + * Roll around to the first query in the list. - FM + */ + QueryNum = QueryTotal - 1; + if ((cp = (char *) HTList_objectAt(search_queries, + QueryNum)) != NULL) { + BStrCopy0(*prev_target, cp); + if (!isBEmpty(my_prev_target) && + !strcmp(my_prev_target->str, (*prev_target)->str)) { + _statusline(EDIT_CURRENT_QUERY); + } else if ((!isBEmpty(my_prev_target) && QueryTotal == 2) || + (isBEmpty(my_prev_target) && QueryTotal == 1)) { + _statusline(EDIT_THE_PREV_QUERY); + } else { + _statusline(EDIT_A_PREV_QUERY); + } + ch = LYgetBString(prev_target, FALSE, 0, recall); + if (ch < 0) { + /* + * User cancelled the search via ^G. Restore prev_target and + * return. - FM + */ + BStrCopy(*prev_target, my_prev_target); + HTInfoMsg(CANCELLED); + return (FALSE); + } + goto check_recall; + } + } + /* + * Replace the search string buffer with the new target. - FM + */ + BStrCopy(my_prev_target, *prev_target); + HTAddSearchQuery(my_prev_target->str); + + if (direction < 0) { + offset = 0; + if (check_prev_target_in_links(&cur_doc->link, (*prev_target)->str)) { + /* + * Found in link, changed cur, we're done. + */ + LYhighlight(FALSE, oldcur, (*prev_target)->str); + return (TRUE); + } + } else { + + /* + * Search the links on the currently displayed page for the string, + * starting after the current link. - FM + */ + if (check_next_target_in_links(&cur_doc->link, (*prev_target)->str)) { + /* + * Found in link, changed cur, we're done. + */ + LYhighlight(FALSE, oldcur, (*prev_target)->str); + return (TRUE); + } + + /* + * We'll search the text starting from the link we are on, or the next + * page. + */ + if (nlinks == 0) + offset = (display_lines - 1); + else + offset = links[cur_doc->link].ly - 1; + } + + /* + * Resume search, this time for all text. Set www_search_result if string + * found, and position the hit near top of screen. + */ + www_user_search((cur_doc->line + offset), cur_doc, (*prev_target)->str, direction); + if (cur_doc->link != oldcur) { + LYhighlight(FALSE, oldcur, (*prev_target)->str); + return (TRUE); + } + return (BOOL) (www_search_result > 0); +} |