]> git.wh0rd.org Git - nano.git/commitdiff
Reverse Search by Ken Tyler
authorChris Allegretta <chrisa@asty.org>
Wed, 13 Jun 2001 02:35:44 +0000 (02:35 +0000)
committerChris Allegretta <chrisa@asty.org>
Wed, 13 Jun 2001 02:35:44 +0000 (02:35 +0000)
git-svn-id: svn://svn.savannah.gnu.org/nano/trunk/nano@685 35c25a1d-7b9e-4130-9fde-d3aeb78583b8

ChangeLog
global.c
nano.h
proto.h
search.c
utils.c

index fb137a8a102be72d75480c74b87f292ac1462f39..edeadaf4067e0fc74b2c55667eb8f10221be1c36 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -35,6 +35,11 @@ Cvs code -
          insert and write routines can't share shortcut lists anymore), 
          new args to do_writeout and write_file called append, and of source
          code changes to those functions.
+       - Allow backwards searching.  Drastic rewrite of the search prompt
+         string by Chris.  All other code by Ken Tyler.  New globals
+         nano_reverse_msg, new functions revstrstr and revstrcasestr,
+         many changes to search functions.  Not too big a code size
+         increase!
 - configure.in:
        - New option, --enable-nanorc, which allows people to have a .nanorc
          initialization file and set options normally used on the command
index 01794f87c5a7fd0cf007dd917531d133a3785ed9..7dea333eeadb2e0d8f183f456e2b73cbb0eeecd8 100644 (file)
--- a/global.c
+++ b/global.c
@@ -194,7 +194,7 @@ void shortcut_init(int unjustify)
        "", *nano_backspace_msg = "", *nano_tab_msg =
        "", *nano_enter_msg = "", *nano_case_msg =
        "", *nano_cancel_msg = "", *nano_unjustify_msg = 
-       "", *nano_append_msg = "";
+       "", *nano_append_msg = "", *nano_reverse_msg = "";
 
 #ifndef NANO_SMALL
     char *nano_tofiles_msg = "";
@@ -236,6 +236,7 @@ void shortcut_init(int unjustify)
     nano_gotodir_msg = _("Goto Directory");
     nano_cancel_msg = _("Cancel the current function");
     nano_append_msg = _("Append to the current file");
+    nano_reverse_msg = _("Search Backwards");
 #endif
 
        sc_init_one(&main_list[0], NANO_HELP_KEY, _("Get Help"),
@@ -369,9 +370,11 @@ void shortcut_init(int unjustify)
                _("Goto Line"), nano_goto_msg, 0, 0, 0, VIEW,
                do_gotoline_void);
 
-    sc_init_one(&whereis_list[5], NANO_CANCEL_KEY, _("Cancel"),
-               nano_cancel_msg, 0, 0, 0, VIEW, 0);
+    sc_init_one(&whereis_list[5], NANO_REVERSESEARCH_KEY, _("Backward"),
+               nano_reverse_msg, 0, 0, 0, VIEW, 0);
 
+    sc_init_one(&whereis_list[6], NANO_CANCEL_KEY, _("Cancel"),
+               nano_cancel_msg, 0, 0, 0, VIEW, 0);
 
     sc_init_one(&replace_list[0], NANO_FIRSTLINE_KEY, _("First Line"),
                nano_firstline_msg, 0, 0, 0, VIEW, do_first_line);
@@ -389,9 +392,11 @@ void shortcut_init(int unjustify)
                _("Goto Line"), nano_goto_msg, 0, 0, 0, VIEW,
                do_gotoline_void);
 
-    sc_init_one(&replace_list[5], NANO_CANCEL_KEY, _("Cancel"),
-               nano_cancel_msg, 0, 0, 0, VIEW, 0);
+    sc_init_one(&replace_list[5], NANO_REVERSESEARCH_KEY, _("Backward"),
+               nano_reverse_msg, 0, 0, 0, VIEW, 0);
 
+    sc_init_one(&replace_list[6], NANO_CANCEL_KEY, _("Cancel"),
+               nano_cancel_msg, 0, 0, 0, VIEW, 0);
 
 
     sc_init_one(&replace_list_2[0], NANO_FIRSTLINE_KEY, _("First Line"),
diff --git a/nano.h b/nano.h
index ca07b242c7edf260b85d001806c2539dbbda9bb7..23c928fe0e81ffd1119c1218d78fbdb726783379 100644 (file)
--- a/nano.h
+++ b/nano.h
@@ -123,6 +123,7 @@ typedef struct rcoption {
 #define TEMP_OPT               (1<<16)
 #define CUT_TO_END             (1<<17)
 #define DISABLE_CURPOS                 (1<<18)
+#define REVERSE_SEARCH         (1<<19)
 
 /* Control key sequences, changing these would be very very bad */
 
@@ -205,6 +206,7 @@ know what you're doing */
 #define NANO_REPLACE_FKEY      KEY_F(14)
 #define NANO_ALT_REPLACE_KEY   NANO_ALT_R
 #define NANO_OTHERSEARCH_KEY   NANO_CONTROL_R
+#define NANO_REVERSESEARCH_KEY NANO_CONTROL_B
 #define NANO_PREVPAGE_KEY      NANO_CONTROL_Y
 #define NANO_PREVPAGE_FKEY     KEY_F(7)
 #define NANO_NEXTPAGE_KEY      NANO_CONTROL_V
@@ -253,8 +255,8 @@ know what you're doing */
 
 #define MAIN_LIST_LEN 26
 #define MAIN_VISIBLE 12
-#define WHEREIS_LIST_LEN 6
-#define REPLACE_LIST_LEN 6
+#define WHEREIS_LIST_LEN 7
+#define REPLACE_LIST_LEN 7
 #define REPLACE_LIST_2_LEN 3
 #define GOTO_LIST_LEN 3
 #define GOTODIR_LIST_LEN 1
diff --git a/proto.h b/proto.h
index 39e86d3851f33a004e92e1b65642f3db188797bb..766d8725ef9ec98ab5afb5af55be38e3b4b97687 100644 (file)
--- a/proto.h
+++ b/proto.h
@@ -71,8 +71,10 @@ extern toggle toggles[TOGGLE_LEN];
 
 /* Programs we want available */
 
+char *revstrstr(char *haystack, char *needle, char *rev_start);
 char *strcasestr(char *haystack, char *needle);
-char *strstrwrapper(char *haystack, char *needle);
+char *revstrcasestr(char *haystack, char *needle, char *rev_start);
+char *strstrwrapper(char *haystack, char *needle, char *rev_start);
 int search_init(int replacing);
 int renumber(filestruct * fileptr);
 int free_filestruct(filestruct * src);
index 4b1eef93fd71c3575c5b01dedf00c9720d2af00a..584c138361169c90fac9bbdc259d87e1386d2f4d 100644 (file)
--- a/search.c
+++ b/search.c
@@ -74,7 +74,7 @@ int search_init(int replacing)
 {
     int i = 0;
     char *buf;
-    char *prompt, *reprompt = "";
+    char *prompt;
     static char *backupstring = NULL;
 
     search_init_globals();
@@ -114,22 +114,21 @@ int search_init(int replacing)
     else
        strcpy(buf, "");
 
-    if (ISSET(USE_REGEXP) && ISSET(CASE_SENSITIVE))
-       prompt = _("Case Sensitive Regexp Search%s%s");
-    else if (ISSET(USE_REGEXP))
-       prompt = _("Regexp Search%s%s");
-    else if (ISSET(CASE_SENSITIVE))
-       prompt = _("Case Sensitive Search%s%s");
-    else
-       prompt = _("Search%s%s");
-
-    if (replacing)
-       reprompt = _(" (to replace)");
+     /* Instead of having a million if statements here to determine
+       the prompt, we instead just have a hundred "? :" calls in
+       the statusq call.  I hope no one ever has to modify this :-) */
+    prompt = "%s%s%s%s%s%s";
 
     /* This is now one simple call.  It just does a lot */
     i = statusq(0, replacing ? replace_list : whereis_list,
        replacing ? REPLACE_LIST_LEN : WHEREIS_LIST_LEN, backupstring,
-       prompt, reprompt, buf);
+       prompt, 
+       ISSET(CASE_SENSITIVE) ? _("Case Sensitive ") : "",
+       ISSET(USE_REGEXP) ? _("Regexp ") : "",
+       _("Search"),
+       ISSET(REVERSE_SEARCH) ? _(" Backwards") : "",
+       replacing ? _(" (to replace)") : "",
+       buf);
 
     /* Cancel any search, or just return with no previous search */
     if ((i == -1) || (i < 0 && !last_search[0])) {
@@ -173,6 +172,17 @@ int search_init(int replacing)
     } else if (i == NANO_OTHERSEARCH_KEY) {
        backupstring = mallocstrcpy(backupstring, answer);
        return -2;              /* Call the opposite search function */
+    } else if (i == NANO_REVERSESEARCH_KEY) {
+       free(backupstring);
+       backupstring = NULL;
+       backupstring = mallocstrcpy(backupstring, answer);
+
+       if (ISSET(REVERSE_SEARCH))
+           UNSET(REVERSE_SEARCH);
+       else
+           SET(REVERSE_SEARCH);
+
+       return 1;
     } else if (i == NANO_FROMSEARCHTOGOTO_KEY) {
        free(backupstring);
        backupstring = NULL;
@@ -207,68 +217,124 @@ filestruct *findnextstr(int quiet, filestruct * begin, int beginx,
                        char *needle)
 {
     filestruct *fileptr;
-    char *searchstr, *found = NULL, *tmp;
+    char *searchstr, *rev_start = NULL, *found = NULL;
     int past_editbot = 0, current_x_find;
 
     fileptr = current;
 
-    current_x_find = current_x + 1;
+    if (!ISSET(REVERSE_SEARCH)) {              /* forward search */
 
-    /* Are we searching the last line? (i.e. the line where search started) */
-    if ((fileptr == begin) && (current_x_find < beginx))
-       search_last_line = 1;
+       current_x_find = current_x + 1;
 
-    /* Make sure we haven't passed the end of the string */
-    if (strlen(fileptr->data) < current_x_find)
-       current_x_find--;
+       /* Are we now back to the line where the search started) */
+       if ((fileptr == begin) && (current_x_find < beginx))
+           search_last_line = 1;
 
-    searchstr = &fileptr->data[current_x_find];
+       /* Make sure we haven't passed the end of the string */
+       if (strlen(fileptr->data) < current_x_find)
+           current_x_find--;
 
-    /* Look for needle in searchstr */
-    while ((found = strstrwrapper(searchstr, needle)) == NULL) {
+       searchstr = &fileptr->data[current_x_find];
 
-       /* finished processing file, get out */
-       if (search_last_line) {
-           if (!quiet)
-               not_found_msg(needle);
-           return NULL;
-       }
+       /* Look for needle in searchstr */
+       while ((found = strstrwrapper(searchstr, needle, rev_start)) == NULL) {
+
+           /* finished processing file, get out */
+           if (search_last_line) {
+               if (!quiet)
+                   not_found_msg(needle);
+               return NULL;
+           }
+
+           fileptr = fileptr->next;
 
-       fileptr = fileptr->next;
+           if (!past_editbot && (fileptr == editbot))
+               past_editbot = 1;
 
-       if (!past_editbot && (fileptr == editbot))
-           past_editbot = 1;
+           /* EOF reached ?, wrap around once */
+           if (fileptr == NULL) {
+               fileptr = fileage;
+               past_editbot = 1;
+               if (!quiet)
+                   statusbar(_("Search Wrapped"));
+           }
 
-       /* EOF reached, wrap around once */
-       if (fileptr == NULL) {
-           fileptr = fileage;
+           /* Original start line reached */
+           if (fileptr == begin)
+               search_last_line = 1;
+
+           searchstr = fileptr->data;
+       }
 
-           past_editbot = 1;
+       /* We found an instance */
+       current_x_find = found - fileptr->data;
 
+       /* Ensure we haven't wrapped around again! */
+       if ((search_last_line) && (current_x_find >= beginx)) {
            if (!quiet)
-               statusbar(_("Search Wrapped"));
+               not_found_msg(needle);
+           return NULL;
        }
 
-       /* Original start line reached */
-       if (fileptr == begin)
+    } else {   /* reverse search */
+
+       current_x_find = current_x - 1;
+
+       /* Are we now back to the line where the search started) */
+       if ((fileptr == begin) && (current_x_find > beginx))
            search_last_line = 1;
 
+       /* Make sure we haven't passed the begining of the string */
+#if 0  /* Is this required here ? */
+       if (!(&fileptr->data[current_x_find] - fileptr->data))      
+           current_x_find++;
+#endif
+       rev_start = &fileptr->data[current_x_find];
        searchstr = fileptr->data;
-    }
 
-    /* We found an instance */
-    current_x_find = 0;
-    for (tmp = fileptr->data; tmp != found; tmp++)
-       current_x_find++;
+       /* Look for needle in searchstr */
+       while ((found = strstrwrapper(searchstr, needle, rev_start)) == NULL) {
+
+           /* finished processing file, get out */
+           if (search_last_line) {
+               if (!quiet)
+                   not_found_msg(needle);
+               return NULL;
+           }
+
+           fileptr = fileptr->prev;
+
+/* ? */            if (!past_editbot && (fileptr == edittop->prev))
+               past_editbot = 1;
 
-    /* Ensure we haven't wrapped around again! */
-    if ((search_last_line) && (current_x_find >= beginx)) {
-       if (!quiet)
-           not_found_msg(needle);
-       return NULL;
+           /* SOF reached ?, wrap around once */
+/* ? */            if (fileptr == NULL) {
+               fileptr = filebot;
+               past_editbot = 1;
+               if (!quiet)
+                   statusbar(_("Search Wrapped"));
+           }
+
+           /* Original start line reached */
+           if (fileptr == begin)
+               search_last_line = 1;
+
+           searchstr = fileptr->data;
+           rev_start = fileptr->data + strlen(fileptr->data);
+       }
+
+       /* We found an instance */
+       current_x_find = found - fileptr->data;
+
+       /* Ensure we haven't wrapped around again! */
+       if ((search_last_line) && (current_x_find < beginx)) {
+           if (!quiet)
+               not_found_msg(needle);
+           return NULL;
+       }
     }
 
-    /* Set globals, now that we are sure we found something */
+    /* Set globals now that we are sure we found something */
     current = fileptr;
     current_x = current_x_find;
 
diff --git a/utils.c b/utils.c
index d97b773edeb2e1a7a53530af05b52bc375334df7..1e6c251895b013581b253ed34c0b498976102ba4 100644 (file)
--- a/utils.c
+++ b/utils.c
@@ -47,6 +47,31 @@ void lowercase(char *src)
     }
 }
 
+char *revstrstr(char *haystack, char *needle, char *rev_start)
+{
+    char *p, *q, *r;
+
+    for(p = rev_start ; p >= haystack ; --p) {
+       for (r = p, q = needle ; (*q == *r) && (*q != '\0') ; r++, q++)
+           ;
+       if (*q == '\0')
+           return p;
+    }
+    return 0;
+}
+
+char *revstrcasestr(char *haystack, char *needle, char *rev_start)
+{
+    char *p, *q, *r;
+
+    for(p = rev_start ; p >= haystack ; --p) {
+       for (r = p, q = needle ; (tolower(*q) == tolower(*r)) && (*q != '\0') ; r++, q++)
+           ;
+       if (*q == '\0')
+           return p;
+    }
+    return 0;
+}
 
 /* This is now mutt's version (called mutt_stristr) because it doesn't
    use memory allocation to do a simple search (yuck). */
@@ -59,31 +84,55 @@ char *strcasestr(char *haystack, char *needle)
     if (!needle)  
        return (haystack);
     
-    while (*(p = haystack))
-    {
+    while (*(p = haystack)) {
        for (q = needle; *p && *q && tolower (*p) == tolower (*q); p++, q++)
            ;
        if (!*q)
            return (haystack);
-        haystack++;
+       haystack++;
     }
     return NULL;
 }
 
-char *strstrwrapper(char *haystack, char *needle)
+char *strstrwrapper(char *haystack, char *needle, char *rev_start)
 {
+
 #ifdef HAVE_REGEX_H
+
+    int  result;
+    char *i, *j;
+
     if (ISSET(USE_REGEXP)) {
-       int result = regexec(&search_regexp, haystack, 10, regmatches, 0);
-       if (!result)
-           return haystack + regmatches[0].rm_so;
+       if (!ISSET(REVERSE_SEARCH)) {
+           result = regexec(&search_regexp, haystack, 10, regmatches, 0);
+           if (!result)
+               return haystack + regmatches[0].rm_so;
+       } else {
+           /* do quick check first */
+           if (!(regexec(&search_regexp, haystack, 10, regmatches, 0))) {
+               /* there is a match */
+               for(i = rev_start ; i >= haystack ; --i)
+                   if (!(result = regexec(&search_regexp, i, 10, regmatches, 0))) {
+                       j = i + regmatches[0].rm_so;
+                       if (j <= rev_start)
+                           return j;
+                   }
+           }
+       }
        return 0;
     }
 #endif
-    if (ISSET(CASE_SENSITIVE))
-       return strstr(haystack, needle);
-    else
-       return strcasestr(haystack, needle);
+    if (ISSET(CASE_SENSITIVE)) {
+       if (!ISSET(REVERSE_SEARCH))
+           return strstr(haystack,needle);
+        else
+           return revstrstr(haystack, needle, rev_start);
+    } else {
+       if (!ISSET(REVERSE_SEARCH))
+           return strcasestr(haystack, needle);
+       else
+           return revstrcasestr(haystack, needle, rev_start);
+    }
 }
 
 /* Thanks BG, many ppl have been asking for this... */