Implement reverse searching (via ^R, of course).
authorsimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Sun, 21 Nov 2004 10:25:03 +0000 (10:25 +0000)
committersimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Sun, 21 Nov 2004 10:25:03 +0000 (10:25 +0000)
git-svn-id: svn://svn.tartarus.org/sgt/tweak@4858 cda61777-01e9-0310-a592-d414129be87e

actions.c
main.c
rcfile.c
search.c
tweak.h

index c65c3e4..3160e4a 100644 (file)
--- a/actions.c
+++ b/actions.c
@@ -31,6 +31,7 @@ static void act_susp (void);
 static void act_goto (void);
 static void act_togstat (void);
 static void act_search (void);
+static void act_search_backwards (void);
 static void act_recentre (void);
 static void act_width (void);
 static void act_offset (void);
@@ -38,6 +39,8 @@ static void act_offset (void);
 static void act_diagnostics (void);
 #endif
 
+static Search *last_search = NULL;
+
 keyact parse_action (char *name) {
     char *names[] = {
        "exit", "top-of-file", "page-up", "move-up",
@@ -45,8 +48,8 @@ keyact parse_action (char *name) {
        "move-down", "page-down", "bottom-of-file", "toggle-insert",
        "change-mode", "delete-left", "delete-right", "mark-place",
        "cut", "copy", "paste", "suspend", "goto-position",
-       "toggle-status", "search", "save-file", "exit-and-save",
-       "screen-recentre", "new-width", "new-offset"
+       "toggle-status", "search", "search-back", "save-file",
+       "exit-and-save", "screen-recentre", "new-width", "new-offset"
 #ifdef TEST_BUFFER
        , "diagnostics"
 #endif
@@ -56,8 +59,8 @@ keyact parse_action (char *name) {
        act_right, act_end, act_down, act_pgdn, act_bottom,
        act_togins, act_chmode, act_delete, act_delch, act_mark,
        act_cut, act_copy, act_paste, act_susp, act_goto,
-       act_togstat, act_search, act_save, act_exitsave,
-       act_recentre, act_width, act_offset
+       act_togstat, act_search, act_search_backwards, act_save,
+       act_exitsave, act_recentre, act_width, act_offset
 #ifdef TEST_BUFFER
        , act_diagnostics
 #endif
@@ -526,35 +529,47 @@ static void act_togstat (void) {
        statfmt = decstatus;
 }
 
-static void act_search (void) {
+static int search_prompt(char *withdef, char *withoutdef)
+{
     char buffer[80];
-    int len, posn, dfapos;
-    DFA dfa;
-    static unsigned char sblk[SEARCH_BLK];
-    static char withdef[] = "Search for (default=last): ";
-    static char withoutdef[] = "Search for: ";
+    int len;
 
-    dfa = last_dfa();
-
-    if (!get_str(dfa ? withdef : withoutdef, buffer, TRUE))
-       return;                        /* user break */
-    if (!dfa && !*buffer) {
+    if (!get_str(last_search ? withdef : withoutdef, buffer, TRUE))
+       return 0;                      /* user break */
+    if (!last_search && !*buffer) {
        strcpy (message, "Search aborted.");
-       return;
+       return 0;
     }
 
     if (!*buffer) {
-       len = last_len();
+       len = last_search->len;
     } else {
        len = parse_quoted (buffer);
        if (len == -1) {
            display_beep();
            strcpy (message, "Invalid escape sequence in search string");
-           return;
+           return 0;
        }
-       dfa = build_dfa (buffer, len);
+       if (last_search)
+           free_search(last_search);
+       last_search = build_search (buffer, len);
     }
 
+    return 1;
+}
+
+static void act_search (void) {
+    int len, posn, dfapos;
+    DFA dfa;
+    static unsigned char sblk[SEARCH_BLK];
+    static char withdef[] = "Search forward (default=last): ";
+    static char withoutdef[] = "Search forward: ";
+
+    if (!search_prompt(withdef, withoutdef))
+       return;
+
+    dfa = last_search->forward;
+    len = last_search->len;
     dfapos = 0;
 
     for (posn = cur_pos+1; posn < file_size; posn++) {
@@ -584,6 +599,51 @@ static void act_search (void) {
     strcpy (message, "Not found.");
 }
 
+static void act_search_backwards (void) {
+    int len, posn, dfapos;
+    DFA dfa;
+    static unsigned char sblk[SEARCH_BLK];
+    static char withdef[] = "Search backward (default=last): ";
+    static char withoutdef[] = "Search backward: ";
+
+    if (!search_prompt(withdef, withoutdef))
+       return;
+
+    dfa = last_search->reverse;
+    len = last_search->len;
+    dfapos = 0;
+
+    posn = cur_pos + len - 1;
+    if (posn >= file_size)
+       posn = file_size;
+
+    for (; posn >= 0; posn--) {
+       unsigned char *q;
+       int size = SEARCH_BLK;
+
+       if (size > posn)
+           size = posn;
+       buf_fetch_data (filedata, sblk, size, posn-size);
+       q = sblk + size;
+       while (size--) {
+           posn--;
+           dfapos = dfa[dfapos][*--q];
+           if (dfapos == len) {
+               int new_top;
+
+               cur_pos = posn;
+               edit_type = !!edit_type;
+               new_top = cur_pos - (scrlines-1) * width;
+               new_top = begline(new_top);
+               if (top_pos > new_top)
+                   top_pos = new_top;
+               return;
+           }
+       }
+    }
+    strcpy (message, "Not found.");
+}
+
 static void act_recentre (void) {
     top_pos = cur_pos - (display_rows-2)/2 * width;
     if (top_pos < 0)
diff --git a/main.c b/main.c
index adae913..2e7d179 100644 (file)
--- a/main.c
+++ b/main.c
  *      an undo chain attached; so, in particular, the cut buffer
  *      shouldn't be one. Sort that out.
  * 
- *  - Reverse search.
- *     + need to construct a reverse DFA.
- *     + probably should construct both every time, so that you can
- *      search forward for a thing and then immediately change
- *      your mind and search backward for the same thing.
- * 
  *  - In-place editing.
  *     + this is an extra option when running in Fix mode. It
  *      causes a change of semantics when saving: instead of
index 146c8c2..6f5de8f 100644 (file)
--- a/rcfile.c
+++ b/rcfile.c
@@ -111,6 +111,7 @@ static char *default_rc[] = {
     "",
     "# Key bindings: additional movement keys",
     "bind search ^S",
+    "bind search-back ^R",
     "bind goto-position ^XG",
     "bind goto-position ^Xg",
     "bind screen-recentre ^L",
index 9616f64..f99de2d 100644 (file)
--- a/search.c
+++ b/search.c
@@ -4,23 +4,16 @@
 
 #include "tweak.h"
 
-static DFA dfa = NULL;
-static char *tmp = NULL;
-static int dfa_size = 0, dfa_len = 0;
-
-DFA build_dfa (char *pattern, int len) {
+static DFA build_dfa (char *pattern, int len)
+{
     int i, j, k, b;
+    char *tmp = malloc(len);
+    DFA dfa = malloc(len * sizeof(*dfa));
 
-    if (dfa_size < len) {
-       dfa_size = len;
-       dfa = (dfa ? realloc(dfa, dfa_size * sizeof(*dfa)) :
-              malloc(dfa_size * sizeof(*dfa)));
-       if (!dfa)
-           return NULL;
-       tmp = (tmp ? realloc(tmp, dfa_size) : malloc(dfa_size));
-       if (!tmp)
-           return NULL;
-    }
+    if (!dfa)
+       return NULL;
+    if (!tmp)
+       return NULL;
 
     memcpy (tmp, pattern, len);
 
@@ -36,14 +29,28 @@ DFA build_dfa (char *pattern, int len) {
            }
        }
     }
-    dfa_len = len;
+
     return dfa;
 }
 
-DFA last_dfa (void) {
-    return dfa;
+Search *build_search(char *pattern, int len)
+{
+    Search *ret = malloc(sizeof(Search));
+    char *revpat = malloc(len);
+    int i;
+
+    ret->len = len;
+    ret->forward = build_dfa(pattern, len);
+    for (i = 0; i < len; i++)
+       revpat[i] = pattern[len-1-i];
+    ret->reverse = build_dfa(revpat, len);
+
+    return ret;
 }
 
-int last_len (void) {
-    return dfa_len;
+void free_search(Search *s)
+{
+    free(s->forward);
+    free(s->reverse);
+    free(s);
 }
diff --git a/tweak.h b/tweak.h
index 2a8507a..f9ea9eb 100644 (file)
--- a/tweak.h
+++ b/tweak.h
 #define NULL256 NULL64,NULL64,NULL64,NULL64
 
 typedef int (*DFA)[256];
+typedef struct {
+    int len;
+    DFA forward, reverse;
+} Search;
+
 typedef void (*keyact) (void);
 
 typedef struct buffer buffer;
@@ -65,9 +70,8 @@ extern keyact parse_action (char *);
 extern void proc_key (void);
 extern void bind_key (char *, int, keyact);
 
-extern DFA build_dfa (char *, int);
-extern DFA last_dfa (void);
-extern int last_len (void);
+extern Search *build_search (char *, int);
+void free_search(Search *s);
 
 extern int get_str (char *, char *, int);
 extern int parse_quoted (char *);