about summary refs log tree commit diff stats
path: root/src/LYSearch.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/LYSearch.c')
-rw-r--r--src/LYSearch.c376
1 files changed, 376 insertions, 0 deletions
diff --git a/src/LYSearch.c b/src/LYSearch.c
new file mode 100644
index 00000000..421a40f0
--- /dev/null
+++ b/src/LYSearch.c
@@ -0,0 +1,376 @@
+/*
+ * $LynxId: LYSearch.c,v 1.23 2009/01/01 23:28:39 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>
+
+static BOOL link_has_target(int cur,
+			    char *target)
+{
+    LinkInfo *a = &links[cur];
+    OptionType *option;
+    char *stars = NULL;
+    const char *cp;
+    int count;
+
+    /*
+     * Search the hightext strings, if present, taking the case_sensitive
+     * setting into account.
+     */
+    for (count = 0;; ++count) {
+	const char *text = LYGetHiliteStr(cur, count);
+
+	if (text == NULL)
+	    break;
+	if (LYno_attr_strstr(text, target))
+	    return TRUE;
+    }
+
+    /*
+     * Search the relevant form fields, taking the case_sensitive setting into
+     * account.  - FM
+     */
+    if ((a->l_form != NULL && a->l_form->value != NULL) &&
+	a->l_form->type != F_HIDDEN_TYPE) {
+	if (a->l_form->type == F_PASSWORD_TYPE) {
+	    /*
+	     * Check the actual, hidden password, and then the displayed
+	     * string.  - FM
+	     */
+	    if (LYno_attr_strstr(a->l_form->value, target)) {
+		return TRUE;
+	    }
+	    StrAllocCopy(stars, a->l_form->value);
+	    memset(stars, '*', strlen(stars));
+	    if (LYno_attr_strstr(stars, target)) {
+		FREE(stars);
+		return TRUE;
+	    }
+	    FREE(stars);
+	} else if (a->l_form->type == F_OPTION_LIST_TYPE) {
+	    /*
+	     * Search the option strings that are displayed when the popup is
+	     * invoked.  - FM
+	     */
+	    option = a->l_form->select_list;
+	    while (option != NULL) {
+		if (LYno_attr_strstr(option->name, target)) {
+		    return TRUE;
+		}
+		option = option->next;
+	    }
+	} else if (a->l_form->type == F_RADIO_TYPE) {
+	    /*
+	     * Search for checked or unchecked parens.  - FM
+	     */
+	    if (a->l_form->num_value) {
+		cp = checked_radio;
+	    } else {
+		cp = unchecked_radio;
+	    }
+	    if (LYno_attr_strstr(cp, target)) {
+		return TRUE;
+	    }
+	} else if (a->l_form->type == F_CHECKBOX_TYPE) {
+	    /*
+	     * Search for checked or unchecked square brackets.  - FM
+	     */
+	    if (a->l_form->num_value) {
+		cp = checked_box;
+	    } else {
+		cp = unchecked_box;
+	    }
+	    if (LYno_attr_strstr(cp, target)) {
+		return TRUE;
+	    }
+	} else {
+	    /*
+	     * Check the values intended for display.  May have been found
+	     * already via the hightext search, but make sure here that the
+	     * entire value is searched.  - FM
+	     */
+	    if (LYno_attr_strstr(a->l_form->value, target)) {
+		return TRUE;
+	    }
+	}
+    }
+    return FALSE;
+}
+
+/*
+ * 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 'case_sensitive' global variable
+ */
+BOOL textsearch(DocInfo *cur_doc, char *prev_target,
+		int target_size,
+		int direction)
+{
+    int offset;
+    int oldcur = cur_doc->link;
+    static char prev_target_buffer[512];	/* Search string buffer */
+    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) {
+	*prev_target_buffer = '\0';
+	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.
+	 */
+	LYstrncpy(prev_target, prev_target_buffer, target_size);
+
+    if (strlen(prev_target) == 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 = LYgetstr(prev_target, VISIBLE, (unsigned) target_size, recall);
+	if (ch < 0) {
+	    /*
+	     * User cancelled the search via ^G.  Restore prev_target and
+	     * return.  - FM
+	     */
+	    LYstrncpy(prev_target, prev_target_buffer, target_size);
+	    HTInfoMsg(CANCELLED);
+	    return (FALSE);
+	}
+    }
+
+  check_recall:
+    if (strlen(prev_target) == 0 &&
+	!(recall && (ch == UPARROW || ch == DNARROW))) {
+	/*
+	 * 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) {
+	if (FirstRecall) {
+	    /*
+	     * Use the current string or last query in the list.  - FM
+	     */
+	    FirstRecall = FALSE;
+	    if (*prev_target_buffer) {
+		for (QueryNum = (QueryTotal - 1); QueryNum > 0; QueryNum--) {
+		    if ((cp = (char *) HTList_objectAt(search_queries,
+						       QueryNum)) != NULL &&
+			!strcmp(prev_target_buffer, 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) {
+	    LYstrncpy(prev_target, cp, target_size);
+	    if (*prev_target_buffer &&
+		!strcmp(prev_target_buffer, prev_target)) {
+		_statusline(EDIT_CURRENT_QUERY);
+	    } else if ((*prev_target_buffer && QueryTotal == 2) ||
+		       (!(*prev_target_buffer) && QueryTotal == 1)) {
+		_statusline(EDIT_THE_PREV_QUERY);
+	    } else {
+		_statusline(EDIT_A_PREV_QUERY);
+	    }
+	    ch = LYgetstr(prev_target, VISIBLE, (unsigned) target_size, recall);
+	    if (ch < 0) {
+		/*
+		 * User canceled the search via ^G.  Restore prev_target and
+		 * return.  - FM
+		 */
+		LYstrncpy(prev_target, prev_target_buffer, target_size);
+		HTInfoMsg(CANCELLED);
+		return (FALSE);
+	    }
+	    goto check_recall;
+	}
+    } else if (recall && ch == DNARROW) {
+	if (FirstRecall) {
+	    /*
+	     * Use the current string or first query in the list.  - FM
+	     */
+	    FirstRecall = FALSE;
+	    if (*prev_target_buffer) {
+		for (QueryNum = 0; QueryNum < (QueryTotal - 1); QueryNum++) {
+		    if ((cp = (char *) HTList_objectAt(search_queries,
+						       QueryNum)) != NULL &&
+			!strcmp(prev_target_buffer, 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) {
+	    LYstrncpy(prev_target, cp, target_size);
+	    if (*prev_target_buffer &&
+		!strcmp(prev_target_buffer, prev_target)) {
+		_statusline(EDIT_CURRENT_QUERY);
+	    } else if ((*prev_target_buffer && QueryTotal == 2) ||
+		       (!(*prev_target_buffer) && QueryTotal == 1)) {
+		_statusline(EDIT_THE_PREV_QUERY);
+	    } else {
+		_statusline(EDIT_A_PREV_QUERY);
+	    }
+	    ch = LYgetstr(prev_target, VISIBLE, (unsigned) target_size, recall);
+	    if (ch < 0) {
+		/*
+		 * User cancelled the search via ^G.  Restore prev_target and
+		 * return.  - FM
+		 */
+		LYstrncpy(prev_target, prev_target_buffer, target_size);
+		HTInfoMsg(CANCELLED);
+		return (FALSE);
+	    }
+	    goto check_recall;
+	}
+    }
+    /*
+     * Replace the search string buffer with the new target.  - FM
+     */
+    LYstrncpy(prev_target_buffer, prev_target, sizeof(prev_target_buffer) - 1);
+    HTAddSearchQuery(prev_target_buffer);
+
+    if (direction < 0) {
+	offset = 0;
+	if (check_prev_target_in_links(&cur_doc->link, prev_target)) {
+	    /*
+	     * Found in link, changed cur, we're done.
+	     */
+	    LYhighlight(OFF, oldcur, prev_target);
+	    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)) {
+	    /*
+	     * Found in link, changed cur, we're done.
+	     */
+	    LYhighlight(OFF, oldcur, prev_target);
+	    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, direction);
+    if (cur_doc->link != oldcur) {
+	LYhighlight(OFF, oldcur, prev_target);
+	return (TRUE);
+    }
+    return (BOOL) (www_search_result > 0);
+}