]> git.wh0rd.org Git - nano.git/commitdiff
add DB's refactored search code and a few of his minor display code
authorDavid Lawrence Ramsey <pooka109@gmail.com>
Tue, 24 Feb 2004 20:41:39 +0000 (20:41 +0000)
committerDavid Lawrence Ramsey <pooka109@gmail.com>
Tue, 24 Feb 2004 20:41:39 +0000 (20:41 +0000)
changes, plus a few minor search and display fixes of mine

git-svn-id: svn://svn.savannah.gnu.org/nano/trunk/nano@1660 35c25a1d-7b9e-4130-9fde-d3aeb78583b8

ChangeLog
src/nano.c
src/proto.h
src/search.c
src/utils.c
src/winio.c

index 2a312549abfe9ecb036b729779dab86fc2454b65..f0d2dee18a7c155444d48c31c285b22c57505904 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -36,10 +36,17 @@ CVS code -
        - Remove the now-unneeded code to disable XON, XOFF, and
          suspend, since we now go into raw mode in
          get_verbatim_kbinput() and bypass them. (DLR)
-  do_spell(), do_int_speller(), do_alt_speller()
+  do_int_speller(), do_alt_speller(), do_spell()
        - Modify to write only the current selection from a file to the
          temporary file used for spell checking when the mark is on,
          and add a few miscellaneous cosmetic cleanups. (DLR)
+  do_int_spell_fix()
+       - Store the value of current_x in a size_t instead of an int,
+         and add a few minor efficiency tweaks. (David Benbennick)
+       - Remove comment explaining why findnextstr() is called with
+         bracket_mode set to TRUE even though we aren't doing a bracket
+         search, since after the above efficiency tweaks, it's now more
+         accurately called can_display_wrap. (DLR)
   signal_init()
        - Trap SIGQUIT in addition to turning it off via termios in
          main().  This is consistent with SIGINT, which we trap here
@@ -59,10 +66,76 @@ CVS code -
          curses setup routines, and turn the keypad on before setting
          the input mode. (DLR)
 - search.c:
+  regexp_cleanup()
+       - Only do anything if REGEXP_COMPILED is set. (David Benbennick)
+  search_abort()
+       - Only test if the mark is set when NANO_SMALL isn't defined.
+         (David Benbennick)
+  search_init()
+       - Add some more comments and comment tweaks, don't indicate that
+         the search has been canceled when we enter a blank string in
+         replace mode, only call regexp_init() when USE_REGEXP is set,
+         and return -1 instead of -3 since a canceled search and a
+         canceled replace should be mostly equivalent. (David
+         Benbennick)  DLR: Tweak to use the old behavior if we try to
+         search for invalid regexes.
+  findnextstr()
+       - Refactor to use a loop invariant, and tweak for greater
+         efficiency and simplicity.  Also modify so that all searches
+         start one character after (or before, if we're doing a
+         backwards search) the current one, as opposed to all searches
+         except for regex searches for "^" and the like, for
+         consistency with other searches. (David Benbennick)
+  do_search()
+       - Handle search_init()'s no longer returning -3 above. (David
+         Benbennick)
+       - Port the code from do_replace_loop() to skip the current line
+         if we're searching for a regex with "^" and/or "$" in it and
+         end up on the same line to this function.  This fixes a
+         problem where doing a forward search for "^" on a file with
+         more than one line would erroneously stop at the magicline and
+         indicate that that was the only occurrence. (DLR)
+  do_research()
+       - Port David Benbennick's efficiency tweaks and the
+         aforementioned code ported from do_replace_loop() to this
+         function. (DLR)
+  replace_regexp()
+       - Completely refactor for increased efficiency. (David
+         Benbennick)
+  replace_line()
+       - Use a char* parameter for the replacement string instead of
+         last_search, and add minor efficiency tweaks. (David
+         Benbennick)
   do_replace_loop()
        - Fix segfault when doing a regex replace of a string that
          matches inside a line (e.g. replace the "b" in "abc" with
          anything). (David Benbennick)
+       - If the mark is on at the beginning of the functio, turn it off
+         and turn it back on just before returning.  Also overhaul to
+         rely on the return value of findnextstr() instead of a loop
+         invariant, to not need to take an int* parameter, and store
+         the beginning x-coordinate in a size_t instead of an int.
+         (David Benbennick)
+  do_replace()
+       - Handle search_init()'s no longer returning -3 above, and add
+         efficiency tweaks. (David Benbennick)  DLR: Tweak to follow
+         the old behavior of adding non-blank strings entered at the
+         "Replace: " prompt to the search history. (DLR)
+  do_bracket()
+       - Add efficiency tweaks. (David Benbennick)  DLR: Remove
+         reliance on the hardcoded bracket string length; instead, only
+         require that the bracket string length be even.
+- utils.c:
+  regexec_safe()
+       - Wrap in HAVE_REGEX_H #ifdefs. (DLR)
+  regexp_bol_or_eol()
+       - New function used to check if a regex contains "^" and/or "$",
+         assuming that the regex would be found if the REG_NOT(BOL|EOL)
+         flags aren't used in the regexec() call; it replaces the
+         direct regexec()s used before. (DLR)
+  strstrwrapper()
+       - Refactor for increased efficiency, and eliminate the need for
+         the line_pos parameter. (David Benbennick)
 - winio.c:
   get_verbatim_kbinput()
        - Set keypad() to FALSE and switch to raw mode while reading
@@ -96,6 +169,16 @@ CVS code -
          (a) when we move onto the "$" at the end of the line on the
          first page and (b) when we move onto the character just before
          the "$" on subsequent pages. (DLR)
+  reset_cursor()
+       - Tweak for efficiency. (David Benbennick)
+  update_line()
+       - Move leaveok() calls here from edit_refresh(), since the
+         places where they were used in edit_refresh() mainly affected
+         the update_line()s. (DLR)
+  edit_refresh()
+       - Tweak for efficiency. (David Benbennick)
+       - Remove the aforementioned leaveok() calls from this function.
+         (DLR)
   do_credits()
        - Use nanosleep() instead of usleep().  The latter is only
          standard under BSD, whereas the former is POSIX compliant.
index 3fee0db1187a3b7f7990fe3edd013224c97b2f1c..228147825f947dfde07c1d7859133fae918a98f7 100644 (file)
@@ -1510,13 +1510,13 @@ int do_wrap(filestruct *inptr)
 
 #ifndef DISABLE_SPELLER
 /* A word is misspelled in the file.  Let the user replace it.  We
- * return False if the user cancels. */
+ * return zero if the user cancels. */
 int do_int_spell_fix(const char *word)
 {
     char *save_search;
     char *save_replace;
     filestruct *current_save = current;
-    int current_x_save = current_x;
+    size_t current_x_save = current_x;
     filestruct *edittop_save = edittop;
        /* Save where we are. */
     int i = 0;
@@ -1527,37 +1527,35 @@ int do_int_spell_fix(const char *word)
     int mark_set = ISSET(MARK_ISSET);
 
     SET(CASE_SENSITIVE);
-    /* Make sure the marking highlight is off during Spell Check */
+    /* Make sure the marking highlight is off during spell-check. */
     UNSET(MARK_ISSET);
 #endif
-    /* Make sure Spell Check goes forward only */
+    /* Make sure spell-check goes forward only. */
     UNSET(REVERSE_SEARCH);
 
-    /* save the current search/replace strings */
+    /* Save the current search/replace strings. */
     search_init_globals();
     save_search = last_search;
     save_replace = last_replace;
 
-    /* set search/replace strings to mis-spelt word */
+    /* Set search/replace strings to misspelled word. */
     last_search = mallocstrcpy(NULL, word);
     last_replace = mallocstrcpy(NULL, word);
 
-    /* start from the top of file */
+    /* Start from the top of the file. */
     current = fileage;
     current_x = -1;
 
     search_last_line = FALSE;
 
-    /* We find the first whole-word occurrence of word.  We call
-       findnextstr() with bracket_mode set to TRUE in order to disable
-       search wrapping. */
-    while (findnextstr(TRUE, TRUE, fileage, -1, word, 0))
+    /* Find the first whole-word occurrence of word. */
+    while (findnextstr(TRUE, TRUE, fileage, 0, word, FALSE) != 0)
        if (is_whole_word(current_x, current->data, word)) {
            edit_refresh();
 
            do_replace_highlight(TRUE, word);
 
-           /* allow replace word to be corrected */
+           /* Allow the replace word to be corrected. */
            i = statusq(0, spell_list, word,
 #ifndef NANO_SMALL
                        NULL,
@@ -1567,26 +1565,26 @@ int do_int_spell_fix(const char *word)
            do_replace_highlight(FALSE, word);
 
            if (i != -1 && strcmp(word, answer)) {
-               int j = 0;
-
                search_last_line = FALSE;
                current_x--;
-               do_replace_loop(word, current_save, &current_x_save, TRUE, &j);
+               do_replace_loop(word, current_save, &current_x_save, TRUE);
            }
 
            break;
        }
 
-    /* restore the search/replace strings */
-    free(last_search);    last_search=save_search;
-    free(last_replace);   last_replace=save_replace;
+    /* Restore the search/replace strings. */
+    free(last_search);
+    last_search = save_search;
+    free(last_replace);
+    last_replace = save_replace;
 
-    /* restore where we were */
+    /* Restore where we were. */
     current = current_save;
     current_x = current_x_save;
     edittop = edittop_save;
 
-    /* restore Search/Replace direction */
+    /* Restore search/replace direction. */
     if (reverse_search_set)
        SET(REVERSE_SEARCH);
 
@@ -1594,7 +1592,7 @@ int do_int_spell_fix(const char *word)
     if (!case_sens_set)
        UNSET(CASE_SENSITIVE);
 
-    /* restore marking highlight */
+    /* Restore marking highlight. */
     if (mark_set)
        SET(MARK_ISSET);
 #endif
index b09ed621111d6d16566807689f212b13e6c09fa0..8eb94bce15f3f810003b6f2efe919faff49d3a3c 100644 (file)
@@ -364,19 +364,19 @@ void not_found_msg(const char *str);
 void search_abort(void);
 void search_init_globals(void);
 int search_init(int replacing);
-int is_whole_word(int curr_pos, const char *datastr, const char *searchword);
-filestruct *findnextstr(int quiet, int bracket_mode,
-                       const filestruct *begin, int beginx,
-                       const char *needle, int no_sameline);
+int is_whole_word(int curr_pos, const char *datastr, const char
+       *searchword);
+int findnextstr(int can_display_wrap, int wholeword, const filestruct
+       *begin, size_t beginx, const char *needle, int no_sameline);
 int do_search(void);
 int do_research(void);
 void replace_abort(void);
 #ifdef HAVE_REGEX_H
 int replace_regexp(char *string, int create_flag);
 #endif
-char *replace_line(void);
-int do_replace_loop(const char *prevanswer, const filestruct *begin,
-                       int *beginx, int wholewords, int *i);
+char *replace_line(const char *needle);
+int do_replace_loop(const char *needle, const filestruct *real_current,
+       size_t *real_current_x, int wholewords);
 int do_replace(void);
 int do_gotoline(int line, int save_pos);
 int do_gotoline_void(void);
@@ -401,10 +401,13 @@ void save_history(void);
 #endif
 
 /* Public functions in utils.c */
+#ifdef HAVE_REGEX_H
 #ifdef BROKEN_REGEXEC
 int regexec_safe(const regex_t *preg, const char *string, size_t nmatch,
        regmatch_t pmatch[], int eflags);
 #endif
+int regexp_bol_or_eol(const regex_t *preg, const char *string);
+#endif
 int is_cntrl_char(int c);
 int num_of_digits(int n);
 void align(char **strp);
@@ -425,7 +428,7 @@ const char *revstristr(const char *haystack, const char *needle,
 #endif
 const char *stristr(const char *haystack, const char *needle);
 const char *strstrwrapper(const char *haystack, const char *needle,
-                       const char *rev_start, int line_pos);
+       const char *start);
 void nperror(const char *s);
 void *nmalloc(size_t howmuch);
 void *nrealloc(void *ptr, size_t howmuch);
index 69f9eba210fb38ef5c69f93f58df8e6b43bc1b2a..9ce635c39a45d4f8a40894b9f43a7bb43c251ccf 100644 (file)
@@ -23,8 +23,8 @@
 
 #include <stdlib.h>
 #include <string.h>
-#include <unistd.h>
 #include <stdio.h>
+#include <unistd.h>
 #include <ctype.h>
 #include <errno.h>
 #include <assert.h>
@@ -47,8 +47,10 @@ int regexp_init(const char *regexp)
 
 void regexp_cleanup(void)
 {
-    UNSET(REGEXP_COMPILED);
-    regfree(&search_regexp);
+    if (ISSET(REGEXP_COMPILED)) {
+       UNSET(REGEXP_COMPILED);
+       regfree(&search_regexp);
+    }
 }
 #endif
 
@@ -68,13 +70,12 @@ void not_found_msg(const char *str)
 void search_abort(void)
 {
     display_main_list();
-    wrefresh(bottomwin);
+#ifndef NANO_SMALL
     if (ISSET(MARK_ISSET))
-       edit_refresh_clearok();
-
+       edit_refresh();
+#endif
 #ifdef HAVE_REGEX_H
-    if (ISSET(REGEXP_COMPILED))
-       regexp_cleanup();
+    regexp_cleanup();
 #endif
 }
 
@@ -90,9 +91,11 @@ void search_init_globals(void)
     }
 }
 
-/* Set up the system variables for a search or replace.  Return -1 on
- * abort, 0 on success, and 1 on rerun calling program.  Return -2 to
- * run opposite program (search -> replace, replace -> search).
+/* Set up the system variables for a search or replace.  Return -1 if
+ * the search should be cancelled (due to Cancel, Go to Line, or a
+ * failed regcomp()).  Return 0 on success, and 1 on rerun calling
+ * program.  Return -2 to run opposite program (search -> replace,
+ * replace -> search).
  *
  * replacing = 1 if we call from do_replace(), 0 if called from
  * do_search(). */
@@ -101,9 +104,12 @@ int search_init(int replacing)
     int i = 0;
     char *buf;
     static char *backupstring = NULL;
-#ifdef HAVE_REGEX_H
-    const char *regex_error = _("Invalid regex \"%s\"");
-#endif /* HAVE_REGEX_H */
+
+    /* We display the search prompt below.  If the user types a partial
+     * search string and then Replace or a toggle, we will return to
+     * do_search() or do_replace() and be called again.  In that case,
+     * we should put the same search string back up.  backupstring holds
+     * this string. */
 
     search_init_globals();
 
@@ -119,7 +125,8 @@ int search_init(int replacing)
        char *disp = display_string(last_search, 0, COLS / 3);
 
        buf = charalloc(COLS / 3 + 7);
-       /* We use COLS / 3 here because we need to see more on the line */
+       /* We use COLS / 3 here because we need to see more on the
+        * line. */
        sprintf(buf, " [%s%s]", disp,
                strlenpt(last_search) > COLS / 3 ? "..." : "");
        free(disp);
@@ -128,7 +135,7 @@ int search_init(int replacing)
        buf[0] = '\0';
     }
 
-    /* This is now one simple call.  It just does a lot */
+    /* This is now one simple call.  It just does a lot. */
     i = statusq(0, replacing ? replace_list : whereis_list, backupstring,
 #ifndef NANO_SMALL
        &search_history,
@@ -137,19 +144,19 @@ int search_init(int replacing)
        _("Search"),
 
 #ifndef NANO_SMALL
-       /* This string is just a modifier for the search prompt,
-          no grammar is implied */
+       /* This string is just a modifier for the search prompt; no
+        * grammar is implied. */
        ISSET(CASE_SENSITIVE) ? _(" [Case Sensitive]") :
 #endif
                "",
 
-       /* This string is just a modifier for the search prompt,
-          no grammar is implied */
+       /* This string is just a modifier for the search prompt; no
+        * grammar is implied. */
        ISSET(USE_REGEXP) ? _(" [Regexp]") : "",
 
 #ifndef NANO_SMALL
-       /* This string is just a modifier for the search prompt,
-          no grammar is implied */
+       /* This string is just a modifier for the search prompt; no
+        * grammar is implied. */
        ISSET(REVERSE_SEARCH) ? _(" [Backwards]") :
 #endif
                "",
@@ -157,14 +164,15 @@ int search_init(int replacing)
        replacing ? _(" (to replace)") : "",
        buf);
 
-    /* Release buf now that we don't need it anymore */
+    /* Release buf now that we don't need it anymore. */
     free(buf);
 
     free(backupstring);
     backupstring = NULL;
 
-    /* Cancel any search, or just return with no previous search */
-    if (i == -1 || (i < 0 && last_search[0] == '\0')) {
+    /* Cancel any search, or just return with no previous search. */
+    if (i == -1 || (i < 0 && last_search[0] == '\0') ||
+           (!replacing && i == 0 && answer[0] == '\0')) {
        statusbar(_("Search Cancelled"));
        reset_cursor();
 #ifndef NANO_SMALL
@@ -173,29 +181,24 @@ int search_init(int replacing)
        return -1;
     } else {
        switch (i) {
-       case -2:        /* Same string */
+       case -2:        /* It's the same string. */
 #ifdef HAVE_REGEX_H
-           if (ISSET(USE_REGEXP))
-               /* If answer is "", use last_search! */
-               if (regexp_init(last_search) == 0) {
-                   statusbar(regex_error, last_search);
-                   reset_cursor();
-                   return -3;
-               }
+           /* Since answer is "", use last_search! */
+           if (ISSET(USE_REGEXP) && regexp_init(last_search) == 0) {
+               statusbar(_("Invalid regex \"%s\""), last_search);
+               reset_cursor();
+               return -1;
+           }
 #endif
            break;
-       case 0:         /* They entered something new */
+       case 0:         /* They entered something new. */
            last_replace[0] = '\0';
 #ifdef HAVE_REGEX_H
-           if (ISSET(USE_REGEXP))
-               if (regexp_init(answer) == 0) {
-                   statusbar(regex_error, answer);
-                   reset_cursor();
-#ifndef NANO_SMALL
-                   search_history.current = search_history.next;
-#endif
-                   return -3;
-               }
+           if (ISSET(USE_REGEXP) && regexp_init(answer) == 0) {
+               statusbar(_("Invalid regex \"%s\""), answer);
+               reset_cursor();
+               return -1;
+           }
 #endif
            break;
 #ifndef NANO_SMALL
@@ -216,226 +219,194 @@ int search_init(int replacing)
 #endif /* !NANO_SMALL */
        case NANO_OTHERSEARCH_KEY:
            backupstring = mallocstrcpy(backupstring, answer);
-           return -2;          /* Call the opposite search function */
+           return -2;  /* Call the opposite search function. */
        case NANO_FROMSEARCHTOGOTO_KEY:
 #ifndef NANO_SMALL
            search_history.current = search_history.next;
 #endif
-           i = (int)strtol(answer, &buf, 10);  /* Just testing answer here */
+           i = (int)strtol(answer, &buf, 10);  /* Just testing answer here. */
            if (!(errno == ERANGE || *answer == '\0' || *buf != '\0'))
                do_gotoline(-1, 0);
            else
                do_gotoline_void();
-           return -3;
+           /* Fall through. */
        default:
-           do_early_abort();
-           return -3;
+           return -1;
        }
     }
     return 0;
 }
 
-int is_whole_word(int curr_pos, const char *datastr, const char *searchword)
+int is_whole_word(int curr_pos, const char *datastr, const char
+       *searchword)
 {
     size_t sln = curr_pos + strlen(searchword);
 
-    /* start of line or previous character not a letter and end of line
-       or next character not a letter */
+    /* Start of line or previous character is not a letter and end of
+     * line or next character is not a letter. */
     return (curr_pos < 1 || !isalpha((int)datastr[curr_pos - 1])) &&
        (sln == strlen(datastr) || !isalpha((int)datastr[sln]));
 }
 
-filestruct *findnextstr(int quiet, int bracket_mode,
-                       const filestruct *begin, int beginx,
-                       const char *needle, int no_sameline)
+/* Look for needle, starting at current, column current_x.  If
+ * no_sameline is nonzero, skip over begin when looking for needle.
+ * begin is the line where we first started searching, at column beginx.
+ * If can_display_wrap is nonzero, we put messages on the statusbar, and
+ * wrap around the file boundaries.  The return value specifies whether
+ * we found anything. */
+int findnextstr(int can_display_wrap, int wholeword, const filestruct
+       *begin, size_t beginx, const char *needle, int no_sameline)
 {
     filestruct *fileptr = current;
-    const char *searchstr, *rev_start = NULL, *found = NULL;
-    int current_x_find = 0;
-
-    search_offscreen = 0;
-
-    if (!ISSET(REVERSE_SEARCH)) {              /* forward search */
-       /* Argh, current_x is set to -1 by nano.c:do_int_spell_fix(), and
-        * strlen returns size_t, which is unsigned. */
-       assert(current_x < 0 || current_x <= strlen(fileptr->data));
-       current_x_find = current_x;
-       if (current_x_find < 0 || fileptr->data[current_x_find] != '\0')
-           current_x_find++;
-
-       searchstr = &fileptr->data[current_x_find];
-
-       /* Look for needle in searchstr.  Keep going until we find it
-        * and, if no_sameline is set, until it isn't on the current
-        * line.  If we don't find it, we'll end up at
-        * current[current_x] regardless of whether no_sameline is
-        * set. */
-       while ((found = strstrwrapper(searchstr, needle, rev_start, current_x_find)) == NULL || (no_sameline && fileptr == current)) {
-
-           /* finished processing file, get out */
-           if (search_last_line) {
-               if (!quiet)
-                   not_found_msg(needle);
-               update_line(fileptr, current_x);
-               return NULL;
-           }
-
-           update_line(fileptr, 0);
-
-           /* reset current_x_find between lines */
-           current_x_find = 0;
-
-           fileptr = fileptr->next;
-
-           if (fileptr == editbot)
-               search_offscreen = 1;
-
-           /* EOF reached?, wrap around once */
-           if (fileptr == NULL) {
-               /* don't wrap if looking for bracket match */
-               if (bracket_mode)
-                   return NULL;
-               fileptr = fileage;
-               search_offscreen = 1;
-               if (!quiet)
-                   statusbar(_("Search Wrapped"));
-           }
+    const char *rev_start = NULL, *found = NULL;
+    size_t current_x_find = 0;
+       /* Where needle was found. */
+
+    /* rev_start might end up 1 character before the start or after the
+     * end of the line.  This won't be a problem because strstrwrapper()
+     * will return immediately and say that no match was found, and
+     * rev_start will be properly set when the search continues on the
+     * previous or next line. */
+#ifndef NANO_SMALL
+    if (ISSET(REVERSE_SEARCH))
+       rev_start = fileptr->data + (current_x - 1);
+    else
+#endif
+       rev_start = fileptr->data + (current_x + 1);
 
-           /* Original start line reached */
-           if (fileptr == begin)
-               search_last_line = 1;
+    /* Look for needle in searchstr. */
+    while (1) {
+       found = strstrwrapper(fileptr->data, needle, rev_start);
 
-           searchstr = fileptr->data;
+       if (found != NULL && (!wholeword || is_whole_word(found -
+               fileptr->data, fileptr->data, needle))) {
+           if (!no_sameline || fileptr != current)
+               break;
        }
 
-       /* 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)
+       /* Finished processing file, get out. */
+       if (search_last_line) {
+           if (can_display_wrap)
                not_found_msg(needle);
-           return NULL;
+           return 0;
        }
-    }
+       fileptr =
 #ifndef NANO_SMALL
-    else {     /* reverse search */
-       current_x_find = current_x - 1;
-       /* Make sure we haven't passed the beginning of the string */
-       rev_start = &fileptr->data[current_x_find];
-       searchstr = fileptr->data;
-
-       /* Look for needle in searchstr.  Keep going until we find it
-        * and, if no_sameline is set, until it isn't on the current
-        * line.  If we don't find it, we'll end up at
-        * current[current_x] regardless of whether no_sameline is
-        * set. */
-       while ((found = strstrwrapper(searchstr, needle, rev_start, current_x_find)) == NULL || (no_sameline && fileptr == current)) {
-
-           /* finished processing file, get out */
-           if (search_last_line) {
-               if (!quiet)
-                   not_found_msg(needle);
-               return NULL;
-           }
-
-           update_line(fileptr, 0);
-
-           /* reset current_x_find between lines */
-           current_x_find = 0;
+               ISSET(REVERSE_SEARCH) ? fileptr->prev :
+#endif
+               fileptr->next;
 
-           fileptr = fileptr->prev;
+       /* Start or end of buffer reached; wrap around. */
+       if (fileptr == NULL) {
+           if (!can_display_wrap)
+               return 0;
+           fileptr =
+#ifndef NANO_SMALL
+               ISSET(REVERSE_SEARCH) ? filebot :
+#endif
+               fileage;
+           if (can_display_wrap)
+               statusbar(_("Search Wrapped"));
+       }
 
-           if (fileptr == edittop->prev)
-               search_offscreen = 1;
+       /* Original start line reached. */
+       if (fileptr == begin)
+           search_last_line = 1;
+       rev_start = fileptr->data;
+#ifndef NANO_SMALL
+       if (ISSET(REVERSE_SEARCH))
+           rev_start += strlen(fileptr->data);
+#endif
+    }
 
-           /* SOF reached?, wrap around once */
-/* ? */            if (fileptr == NULL) {
-               if (bracket_mode)
-                  return NULL;
-               fileptr = filebot;
-               search_offscreen = 1;
-               if (!quiet)
-                   statusbar(_("Search Wrapped"));
-           }
-           /* Original start line reached */
-           if (fileptr == begin)
-               search_last_line = 1;
+    /* We found an instance. */
+    current_x_find = found - fileptr->data;
 
-           searchstr = fileptr->data;
-           rev_start = fileptr->data + strlen(fileptr->data);
-       }
+    /* Ensure we haven't wrapped around again! */
+    if (search_last_line &&
+#ifndef NANO_SMALL
+       ((!ISSET(REVERSE_SEARCH) && current_x_find > beginx) ||
+       (ISSET(REVERSE_SEARCH) && current_x_find < beginx))
+#else
+       current_x_find > beginx
+#endif
+       ) {
 
-       /* 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;
-       }
+       if (can_display_wrap)
+           not_found_msg(needle);
+       return 0;
     }
-#endif /* !NANO_SMALL */
 
-    /* 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;
 
-    if (!bracket_mode) {
-       update_line(current, current_x);
-       placewewant = xplustabs();
-       reset_cursor();
-    }
-    return fileptr;
+    return 1;
 }
 
 /* Search for a string. */
 int do_search(void)
 {
     int i;
-    filestruct *fileptr = current, *didfind;
-    int fileptr_x = current_x;
+    filestruct *fileptr = current;
+    int fileptr_x = current_x, didfind;
 
 #ifndef DISABLE_WRAPPING
     wrap_reset();
 #endif
     i = search_init(0);
-    switch (i) {
-    case -1:
-       current = fileptr;
-       search_abort();
-       return 0;
-    case -3:
+    if (i == -1)       /* Cancel, Go to Line, blank search string, or
+                        * regcomp() failed. */
        search_abort();
-       return 0;
-    case -2:
+    else if (i == -2)  /* Replace. */
        do_replace();
-       return 0;
-    case 1:
+#ifndef NANO_SMALL
+    else if (i == 1)   /* Case Sensitive, Backwards, or Regexp search
+                        * toggle. */
        do_search();
-       search_abort();
-       return 1;
-    }
+#endif
 
-     /* If answer is now "", copy last_search into answer... */
+    if (i != 0)
+       return 0;
+
+    /* If answer is now "", copy last_search into answer. */
     if (answer[0] == '\0')
        answer = mallocstrcpy(answer, last_search);
     else
        last_search = mallocstrcpy(last_search, answer);
 
 #ifndef NANO_SMALL
-    /* add this search string to the search history list */
+    /* If answer is not "", add this search string to the search history
+     * list. */
     if (answer[0] != '\0')
        update_history(&search_history, answer);
-#endif /* !NANO_SMALL */
+#endif
 
     search_last_line = 0;
-    didfind = findnextstr(FALSE, FALSE, current, current_x, answer, 0);
+    didfind = findnextstr(TRUE, FALSE, current, current_x, answer, FALSE);
+    edit_refresh();
+    placewewant = xplustabs();
 
-    if (fileptr == current && fileptr_x == current_x && didfind != NULL)
-       statusbar(_("This is the only occurrence"));
-    else if (current->lineno <= edittop->lineno
-       || current->lineno >= editbot->lineno)
-        edit_update(current, CENTER);
+    /* Check to see if there's only one occurrence of the string and
+     * we're on it now. */
+    if (fileptr == current && fileptr_x == current_x && didfind) {
+#ifdef HAVE_REGEX_H
+       /* Do the search again, skipping over the current line, if we're
+        * doing a bol and/or eol regex search ("^", "$", or "^$"), so
+        * that we find one only once per line.  We should only end up
+        * back at the same position if the string isn't found again, in
+        * which case it's the only occurrence. */
+       if (ISSET(USE_REGEXP) && regexp_bol_or_eol(&search_regexp, last_search)) {
+           didfind = findnextstr(TRUE, FALSE, current, current_x, answer, TRUE);
+           if (fileptr == current && fileptr_x == current_x && !didfind)
+               statusbar(_("This is the only occurrence"));
+       } else {
+#endif
+           statusbar(_("This is the only occurrence"));
+#ifdef HAVE_REGEX_H
+       }
+#endif
+    }
 
     search_abort();
 
@@ -445,11 +416,8 @@ int do_search(void)
 /* Search for the next string without prompting. */
 int do_research(void)
 {
-    filestruct *fileptr = current, *didfind;
-    int fileptr_x = current_x;
-#ifdef HAVE_REGEX_H
-    const char *regex_error = _("Invalid regex \"%s\"");
-#endif /* HAVE_REGEX_H */
+    filestruct *fileptr = current;
+    int fileptr_x = current_x, didfind;
 
 #ifndef DISABLE_WRAPPING
     wrap_reset();
@@ -459,23 +427,39 @@ int do_research(void)
     if (last_search[0] != '\0') {
 
 #ifdef HAVE_REGEX_H
-       if (ISSET(USE_REGEXP))
-           if (regexp_init(last_search) == 0) {
-               statusbar(regex_error, last_search);
+       /* Since answer is "", use last_search! */
+       if (ISSET(USE_REGEXP) && regexp_init(last_search) == 0) {
+               statusbar(_("Invalid regex \"%s\""), last_search);
                reset_cursor();
-               return -3;
+               return -1;
            }
 #endif
 
        search_last_line = 0;
-       didfind = findnextstr(FALSE, FALSE, current, current_x, last_search, 0);
-
-       if (fileptr == current && fileptr_x == current_x && didfind != NULL)
-           statusbar(_("This is the only occurrence"));
-       else if (current->lineno <= edittop->lineno
-           || current->lineno >= editbot->lineno)
-           edit_update(current, CENTER);
+       didfind = findnextstr(TRUE, FALSE, current, current_x, last_search, FALSE);
+       edit_refresh();
+       placewewant = xplustabs();
 
+       /* Check to see if there's only one occurrence of the string and
+        * we're on it now. */
+       if (fileptr == current && fileptr_x == current_x && didfind) {
+#ifdef HAVE_REGEX_H
+           /* Do the search again, skipping over the current line, if
+            * we're doing a bol and/or eol regex search ("^", "$", or
+            * "^$"), so that we find one only once per line.  We should
+            * only end up back at the same position if the string isn't
+            * found again, in which case it's the only occurrence. */
+           if (ISSET(USE_REGEXP) && regexp_bol_or_eol(&search_regexp, last_search)) {
+               didfind = findnextstr(TRUE, FALSE, current, current_x, answer, TRUE);
+               if (fileptr == current && fileptr_x == current_x && !didfind)
+                   statusbar(_("This is the only occurrence"));
+           } else {
+#endif
+               statusbar(_("This is the only occurrence"));
+#ifdef HAVE_REGEX_H
+           }
+#endif
+       }
     } else
         statusbar(_("No current search pattern"));
 
@@ -486,9 +470,9 @@ int do_research(void)
 
 void replace_abort(void)
 {
-    /* Identical to search_abort, so we'll call it here.  If it
-       does something different later, we can change it back.  For now
-       it's just a waste to duplicate code */
+    /* Identical to search_abort(), so we'll call it here.  If it does
+     * something different later, we can change it back.  For now, it's
+     * just a waste to duplicate code. */
     search_abort();
     placewewant = xplustabs();
 }
@@ -496,57 +480,39 @@ void replace_abort(void)
 #ifdef HAVE_REGEX_H
 int replace_regexp(char *string, int create_flag)
 {
-    /* Split personality here - if create_flag is NULL, just calculate
+    /* Split personality here - if create_flag is zero, just calculate
      * the size of the replacement line (necessary because of
-     * subexpressions like \1 \2 \3 in the replaced text). */
+     * subexpressions \1 to \9 in the replaced text). */
 
-    char *c;
-    int new_size = strlen(current->data) + 1;
+    const char *c = last_replace;
     int search_match_count = regmatches[0].rm_eo - regmatches[0].rm_so;
-
-    new_size -= search_match_count;
+    int new_size = strlen(current->data) + 1 - search_match_count;
 
     /* Iterate through the replacement text to handle subexpression
      * replacement using \1, \2, \3, etc. */
-
-    c = last_replace;
     while (*c != '\0') {
-       if (*c != '\\') {
+       int num = (int)(*(c + 1) - '0');
+
+       if (*c != '\\' || num < 1 || num > 9 || num > search_regexp.re_nsub) {
            if (create_flag)
                *string++ = *c;
            c++;
            new_size++;
        } else {
-           int num = (int) *(c + 1) - (int) '0';
-           if (num >= 1 && num <= 9) {
-
-               int i = regmatches[num].rm_eo - regmatches[num].rm_so;
-
-               if (num > search_regexp.re_nsub) {
-                   /* Ugh, they specified a subexpression that doesn't
-                    * exist. */
-                   return -1;
-               }
-
-               /* Skip over the replacement expression */
-               c += 2;
+           int i = regmatches[num].rm_eo - regmatches[num].rm_so;
 
-               /* But add the length of the subexpression to new_size */
-               new_size += i;
+           /* Skip over the replacement expression. */
+           c += 2;
 
-               /* And if create_flag is set, append the result of the
-                * subexpression match to the new line */
-               if (create_flag) {
-                   strncpy(string, current->data + current_x +
-                           regmatches[num].rm_so, i);
-                   string += i;
-               }
+           /* But add the length of the subexpression to new_size. */
+           new_size += i;
 
-           } else {
-               if (create_flag)
-                   *string++ = *c;
-               c++;
-               new_size++;
+           /* And if create_flag is nonzero, append the result of the
+            * subexpression match to the new line. */
+           if (create_flag) {
+               strncpy(string, current->data + current_x +
+                       regmatches[num].rm_so, i);
+               string += i;
            }
        }
     }
@@ -558,146 +524,116 @@ int replace_regexp(char *string, int create_flag)
 }
 #endif
 
-char *replace_line(void)
+char *replace_line(const char *needle)
 {
-    char *copy, *tmp;
+    char *copy;
     int new_line_size;
     int search_match_count;
 
-    /* Calculate size of new line */
+    /* Calculate the size of the new line. */
 #ifdef HAVE_REGEX_H
     if (ISSET(USE_REGEXP)) {
-       search_match_count = regmatches[0].rm_eo - regmatches[0].rm_so;
+       search_match_count = regmatches[0].rm_eo - regmatches[0].rm_so;
        new_line_size = replace_regexp(NULL, 0);
-       /* If they specified an invalid subexpression in the replace
-        * text, return NULL, indicating an error */
-       if (new_line_size < 0)
-           return NULL;
     } else {
-#else
-    {
 #endif
-       search_match_count = strlen(last_search);
-       new_line_size = strlen(current->data) - strlen(last_search) +
-           strlen(last_replace) + 1;
+       search_match_count = strlen(needle);
+       new_line_size = strlen(current->data) - search_match_count +
+           strlen(answer) + 1;
+#ifdef HAVE_REGEX_H
     }
+#endif
 
-    /* Create buffer */
+    /* Create the buffer. */
     copy = charalloc(new_line_size);
 
-    /* Head of Original Line */
+    /* The head of the original line. */
     strncpy(copy, current->data, current_x);
-    copy[current_x] = '\0';
 
-    /* Replacement Text */
-    if (!ISSET(USE_REGEXP))
-       strcat(copy, last_replace);
+    /* The replacement text. */
 #ifdef HAVE_REGEX_H
+    if (ISSET(USE_REGEXP))
+       replace_regexp(copy + current_x, TRUE);
     else
-       replace_regexp(copy + current_x, 1);
 #endif
+       strcpy(copy + current_x, answer);
 
-    /* The tail of the original line */
-
-    /* This may expose other bugs, because it no longer goes through
-     * each character in the string and tests for string goodness.  But
-     * because we can assume the invariant that current->data is less
-     * than current_x + strlen(last_search) long, this should be safe. 
-     * Or it will expose bugs ;-) */
-    tmp = current->data + current_x + search_match_count;
-    strcat(copy, tmp);
+    /* The tail of the original line. */
+    assert(current_x + search_match_count <= strlen(current->data));
+    strcat(copy, current->data + current_x + search_match_count);
 
     return copy;
 }
 
-/* Step through each replace word and prompt user before replacing
- * word.  Return -1 if the string to replace isn't found at all.
- * Otherwise, return the number of replacements made. */
-int do_replace_loop(const char *prevanswer, const filestruct *begin,
-                       int *beginx, int wholewords, int *i)
+/* Step through each replace word and prompt user before replacing.
+ * Parameters real_current and real_current_x are needed by the internal
+ * speller, to allow the cursor position to be updated when a word
+ * before the cursor is replaced by a shorter word.
+ *
+ * needle is the string to seek.  We replace it with answer.  Return -1
+ * if needle isn't found, else the number of replacements performed. */
+int do_replace_loop(const char *needle, const filestruct *real_current,
+       size_t *real_current_x, int wholewords)
 {
     int replaceall = 0, numreplaced = -1;
+    const filestruct *current_save = current;
+    size_t current_x_save = current_x;
 #ifdef HAVE_REGEX_H
     /* The starting-line match and bol/eol regex flags. */
-    int beginline = 0, bol_eol = 0;
+    int begin_line = 0, bol_or_eol = 0;
 #endif
-    filestruct *fileptr = NULL;
-
-    switch (*i) {
-       case -1:        /* Aborted enter. */
-           if (last_replace[0] != '\0')
-               answer = mallocstrcpy(answer, last_replace);
-           statusbar(_("Replace Cancelled"));
-           replace_abort();
-           return 0;
-       case 0:         /* They actually entered something. */
-           break;
-       default:
-       if (*i != -2) { /* First page, last page, for example, could
-                        * get here. */
-           do_early_abort();
-           replace_abort();
-           return 0;
-        }
-    }
+#ifndef NANO_SMALL
+    int mark_set = ISSET(MARK_ISSET);
 
-    last_replace = mallocstrcpy(last_replace, answer);
-    while (1) {
-       size_t match_len;
+    UNSET(MARK_ISSET);
+    edit_refresh();
+#endif
 
-       /* Sweet optimization by Rocco here. */
-       fileptr = findnextstr(fileptr || replaceall || search_last_line,
-               FALSE, begin, *beginx, prevanswer,
+    while (findnextstr(TRUE, wholewords, current_save, current_x_save,
+       needle,
 #ifdef HAVE_REGEX_H
-               /* We should find a bol and/or eol regex only once per
-                * line.  If the bol_eol flag is set, it means that the
-                * last search found one on the beginning line, so we
-                * should skip over the beginning line when doing this
-                * search. */
-               bol_eol
+       /* We should find a bol and/or eol regex only once per line.  If
+        * the bol_or_eol flag is set, it means that the last search
+        * found one on the beginning line, so we should skip over the
+        * beginning line when doing this search. */
+       bol_or_eol
 #else
-               0
+       FALSE
 #endif
-               );
+       ) != 0) {
+
+       int i = 0;
+       size_t match_len;
 
 #ifdef HAVE_REGEX_H
-       /* If the bol_eol flag is set, we've found a match on the
+       /* If the bol_or_eol flag is set, we've found a match on the
         * beginning line already, and we're still on the beginning line
         * after the search, it means that we've wrapped around, so
         * we're done. */
-       if (bol_eol && beginline && fileptr == begin)
-           fileptr = NULL;
-       /* Otherwise, set the beginline flag if we've found a match on
-        * the beginning line, reset the bol_eol flag, and continue. */
+       if (bol_or_eol && begin_line && current == real_current)
+           break;
+       /* Otherwise, set the begin_line flag if we've found a match on
+        * the beginning line, reset the bol_or_eol flag, and
+        * continue. */
        else {
-           if (fileptr == begin)
-               beginline = 1;
-           bol_eol = 0;
+           if (current == real_current)
+               begin_line = 1;
+           bol_or_eol = 0;
        }
 #endif
 
-       if (current->lineno <= edittop->lineno
-           || current->lineno >= editbot->lineno)
-           edit_update(current, CENTER);
-
-       /* No more matches.  Done! */
-       if (fileptr == NULL)
-           break;
-
-       /* Make sure only whole words are found. */
-       if (wholewords && !is_whole_word(current_x, fileptr->data, prevanswer))
-           continue;
-
-       /* If we're here, we've found the search string. */
-       if (numreplaced == -1)
-           numreplaced = 0;
+       edit_refresh();
 
 #ifdef HAVE_REGEX_H
        if (ISSET(USE_REGEXP))
            match_len = regmatches[0].rm_eo - regmatches[0].rm_so;
        else
 #endif
-           match_len = strlen(prevanswer);
+           match_len = strlen(needle);
+
+       /* Record for the return value that we found the search string. */
+       if (numreplaced == -1)
+           numreplaced = 0;
 
        if (!replaceall) {
            char *exp_word;
@@ -709,36 +645,32 @@ int do_replace_loop(const char *prevanswer, const filestruct *begin,
            curs_set(0);
            do_replace_highlight(TRUE, exp_word);
 
-           *i = do_yesno(1, _("Replace this instance?"));
+           i = do_yesno(1, _("Replace this instance?"));
 
            do_replace_highlight(FALSE, exp_word);
            free(exp_word);
            curs_set(1);
 
-           if (*i == -1)       /* We canceled the replace. */
+           if (i == -1)        /* We canceled the replace. */
                break;
        }
 
 #ifdef HAVE_REGEX_H
-       /* Set the bol_eol flag if we're doing a bol and/or eol regex
+       /* Set the bol_or_eol flag if we're doing a bol and/or eol regex
         * replace ("^", "$", or "^$"). */
-       if (ISSET(USE_REGEXP) && regexec(&search_regexp, prevanswer, 0, NULL, REG_NOTBOL | REG_NOTEOL) == REG_NOMATCH)
-           bol_eol = 1;
+       if (ISSET(USE_REGEXP) && regexp_bol_or_eol(&search_regexp,
+               needle))
+           bol_or_eol = 1;
 #endif
 
-       if (*i > 0 || replaceall) {     /* Yes, replace it!!!! */
+       if (i > 0 || replaceall) {      /* Yes, replace it!!!! */
            char *copy;
            int length_change;
 
-           if (*i == 2)
+           if (i == 2)
                replaceall = 1;
 
-           copy = replace_line();
-           if (copy == NULL) {
-               statusbar(_("Replace failed: unknown subexpression!"));
-               replace_abort();
-               return 0;
-           }
+           copy = replace_line(needle);
 
            length_change = strlen(copy) - strlen(current->data);
 
@@ -752,10 +684,10 @@ int do_replace_loop(const char *prevanswer, const filestruct *begin,
 #endif
 
            assert(0 <= match_len + length_change);
-           if (current == begin && current_x <= *beginx) {
-               if (*beginx < current_x + match_len)
-                   *beginx = current_x + match_len;
-               *beginx += length_change;
+           if (current == real_current && current_x <= *real_current_x) {
+               if (*real_current_x < current_x + match_len)
+                   *real_current_x = current_x + match_len;
+               *real_current_x += length_change;
            }
 
            /* Set the cursor at the last character of the replacement
@@ -781,15 +713,20 @@ int do_replace_loop(const char *prevanswer, const filestruct *begin,
     if (filebot->data[0] != '\0')
        new_magicline();
 
+#ifndef NANO_SMALL
+    if (mark_set)
+       SET(MARK_ISSET);
+#endif
+
     return numreplaced;
 }
 
 /* Replace a string. */
 int do_replace(void)
 {
-    int i, numreplaced, beginx;
-    filestruct *begin;
-    char *prevanswer = NULL;
+    int i, numreplaced;
+    filestruct *edittop_save, *begin;
+    size_t beginx;
 
     if (ISSET(VIEW_MODE)) {
        print_view_warning();
@@ -798,35 +735,28 @@ int do_replace(void)
     }
 
     i = search_init(1);
-    switch (i) {
-    case -1:
-       statusbar(_("Replace Cancelled"));
+    if (i == -1) {             /* Cancel, Go to Line, blank search
+                                * string, or regcomp() failed. */
        replace_abort();
        return 0;
-    case 1:
-       do_replace();
-       return 1;
-    case -2:
+    } else if (i == -2) {      /* No Replace. */
        do_search();
        return 0;
-    case -3:
-       replace_abort();
+    } else if (i == 1)         /* Case Sensitive, Backwards, or Regexp
+                                * search toggle. */
+       do_replace();
+
+    if (i != 0)
        return 0;
-    }
 
+    /* If answer is not "", add answer to the search history list and
+     * copy answer into last_search. */
+    if (answer[0] != '\0') {
 #ifndef NANO_SMALL
-    if (answer[0] != '\0')
        update_history(&search_history, answer);
-#endif /* !NANO_SMALL */
-
-    /* If answer is now == "", copy last_search into answer 
-       (and prevanswer)...  */
-    if (answer[0] == '\0')
-       answer = mallocstrcpy(answer, last_search);
-    else
+#endif
        last_search = mallocstrcpy(last_search, answer);
-
-    prevanswer = mallocstrcpy(prevanswer, last_search);
+    }
 
 #ifndef NANO_SMALL
     replace_history.current = (historytype *)&replace_history.next;
@@ -840,29 +770,42 @@ int do_replace(void)
                _("Replace with"));
 
 #ifndef NANO_SMALL
-    if (i == 0 && answer[0] != '\0')
+    /* Add this replace string to the replace history list.  i == 0
+     * means that the string is not "". */
+    if (i == 0)
        update_history(&replace_history, answer);
-#endif /* !NANO_SMALL */
+#endif
+
+    if (i != 0 && i != -2) {
+       if (i == -1) {          /* Cancel. */
+           if (last_replace[0] != '\0')
+               answer = mallocstrcpy(answer, last_replace);
+           statusbar(_("Replace Cancelled"));
+       }
+       replace_abort();
+       return 0;
+    }
+
+    last_replace = mallocstrcpy(last_replace, answer);
 
+    /* Save where we are. */
     begin = current;
     beginx = current_x;
-    search_last_line = 0;
+    edittop_save = edittop;
+    search_last_line = FALSE;
 
-    numreplaced = do_replace_loop(prevanswer, begin, &beginx, FALSE, &i);
+    numreplaced = do_replace_loop(last_search, begin, &beginx, FALSE);
 
-    /* restore where we were */
+    /* Restore where we were. */
     current = begin;
     current_x = beginx;
     renumber_all();
-    edit_update(current, CENTER);
+    edit_update(edittop_save, TOP);
 
     if (numreplaced >= 0)
        statusbar(P_("Replaced %d occurrence", "Replaced %d occurrences",
                numreplaced), numreplaced);
-    else
-       not_found_msg(prevanswer);
 
-    free(prevanswer);
     replace_abort();
     return 1;
 }
@@ -940,65 +883,56 @@ int do_find_bracket(void)
     char ch_under_cursor, wanted_ch;
     const char *pos, *brackets = "([{<>}])";
     char regexp_pat[] = "[  ]";
-    int offset, have_search_offscreen = 0, flagsave, current_x_save, count = 1;
+    int flagsave, current_x_save, count = 1;
     filestruct *current_save;
 
     ch_under_cursor = current->data[current_x];
 
-/*    if ((!(pos = strchr(brackets, ch_under_cursor))) || (!((offset = pos - brackets) < 8))) { */
-
-    if (((pos = strchr(brackets, ch_under_cursor)) == NULL) || (((offset = pos - brackets) < 8) == 0)) {
+    pos = strchr(brackets, ch_under_cursor);
+    if (ch_under_cursor == '\0' || pos == NULL) {
        statusbar(_("Not a bracket"));
        return 1;
     }
 
-    blank_statusbar_refresh();
-
-    wanted_ch = *(brackets + ((strlen(brackets) - (offset + 1))));
+    assert(strlen(brackets) % 2 == 0);
+    wanted_ch = brackets[(strlen(brackets) - 1) - (pos - brackets)];
 
     current_x_save = current_x;
     current_save = current;
     flagsave = flags;
     SET(USE_REGEXP);
 
-/* apparent near redundancy with regexp_pat[] here is needed, [][] works, [[]] doesn't */
+    /* Apparent near redundancy with regexp_pat[] here is needed.
+     * "[][]" works, "[[]]" doesn't. */
 
-    if (offset < (strlen(brackets) / 2)) {                     /* on a left bracket */
+    if (pos < brackets + (strlen(brackets) / 2)) {     /* On a left bracket. */
        regexp_pat[1] = wanted_ch;
        regexp_pat[2] = ch_under_cursor;
        UNSET(REVERSE_SEARCH);
-    } else {                                                   /* on a right bracket */
+    } else {                   /* On a right bracket. */
        regexp_pat[1] = ch_under_cursor;
        regexp_pat[2] = wanted_ch;
        SET(REVERSE_SEARCH);
     }
 
     regexp_init(regexp_pat);
+    /* We constructed regexp_pat to be a valid expression. */
+    assert(ISSET(REGEXP_COMPILED));
 
+    search_last_line = 0;
     while (1) {
-       search_last_line = 0;
-       if (findnextstr(TRUE, TRUE, current, current_x, regexp_pat, 0) != NULL) {
-           have_search_offscreen |= search_offscreen;
-
-           /* found identical bracket */
+       if (findnextstr(FALSE, FALSE, current, current_x, regexp_pat, FALSE) != 0) {
+           /* Found identical bracket. */
            if (current->data[current_x] == ch_under_cursor)
                count++;
-           else {
-
-               /* found complementary bracket */
-               if (!(--count)) {
-                   if (have_search_offscreen)
-                       edit_update(current, CENTER);
-                   else
-                       update_line(current, current_x);
-                   placewewant = xplustabs();
-                   reset_cursor();
-                   break;
-               }
+           /* Found complementary bracket. */
+           else if (--count == 0) {
+               edit_refresh();
+               placewewant = xplustabs();
+               break;
            }
        } else {
-
-           /* didn't find either left or right bracket */
+           /* Didn't find either a left or right bracket. */
            statusbar(_("No matching bracket"));
            current_x = current_x_save;
            current = current_save;
@@ -1007,8 +941,7 @@ int do_find_bracket(void)
        }
     }
 
-    if (ISSET(REGEXP_COMPILED))
-       regexp_cleanup();
+    regexp_cleanup();
     flags = flagsave;
     return 0;
 }
index af53c2eda994152c549e6ab899475108b6e2d810..37d0bcff95fc1515d0a19f90bdb1b07f42a9bcaa 100644 (file)
@@ -30,6 +30,7 @@
 #include "proto.h"
 #include "nano.h"
 
+#ifdef HAVE_REGEX_H
 #ifdef BROKEN_REGEXEC
 #undef regexec
 int regexec_safe(const regex_t *preg, const char *string, size_t nmatch,
@@ -40,7 +41,16 @@ int regexec_safe(const regex_t *preg, const char *string, size_t nmatch,
     return REG_NOMATCH;
 }
 #define regexec(preg, string, nmatch, pmatch, eflags) regexec_safe(preg, string, nmatch, pmatch, eflags)
-#endif
+#endif /* BROKEN_REGEXEC */
+
+/* Assume that string will be found by regexec() if the REG_NOTBOL and
+ * REG_NOTEOL glags are not set. */
+int regexp_bol_or_eol(const regex_t *preg, const char *string)
+{
+    return (regexec(preg, string, 0, NULL, REG_NOTBOL | REG_NOTEOL) ==
+       REG_NOMATCH);
+}
+#endif /* HAVE_REGEX_H */
 
 int is_cntrl_char(int c)
 {
@@ -182,29 +192,32 @@ const char *stristr(const char *haystack, const char *needle)
     return NULL;
 }
 
-/* If we are searching backwards, we will find the last match
- * that starts no later than rev_start.  If we are doing a regexp search,
- * then line_pos should be 0 if haystack starts at the beginning of a
- * line, and positive otherwise.  In the regexp case, we fill in the
- * global variable regmatches with at most 9 subexpression matches.  Also,
- * all .rm_so elements are relative to the start of the whole match, so
- * regmatches[0].rm_so == 0. */
+/* If we are searching backwards, we will find the last match that
+ * starts no later than start.  Otherwise we find the first match
+ * starting no earlier than start.  If we are doing a regexp search, we
+ * fill in the global variable regmatches with at most 9 subexpression
+ * matches.  Also, all .rm_so elements are relative to the start of the
+ * whole match, so regmatches[0].rm_so == 0. */
 const char *strstrwrapper(const char *haystack, const char *needle,
-                       const char *rev_start, int line_pos)
+       const char *start)
 {
+    /* start can be 1 character before the start or after the end of the
+     * line.  In either case, we just say there is no match found. */
+    if ((start > haystack && *(start - 1) == '\0') || start < haystack)
+       return NULL;
+    assert(haystack != NULL && needle != NULL && start != NULL);
 #ifdef HAVE_REGEX_H
     if (ISSET(USE_REGEXP)) {
 #ifndef NANO_SMALL
        if (ISSET(REVERSE_SEARCH)) {
-               /* When doing a backwards search, haystack is a whole line. */
-           if (regexec(&search_regexp, haystack, 1, regmatches, 0) == 0 &&
-                   haystack + regmatches[0].rm_so <= rev_start) {
+           if (regexec(&search_regexp, haystack, 1, regmatches, 0) == 0
+               && haystack + regmatches[0].rm_so <= start) {
                const char *retval = haystack + regmatches[0].rm_so;
 
                /* Search forward until there is no more match. */
                while (regexec(&search_regexp, retval + 1, 1, regmatches,
-                           REG_NOTBOL) == 0 &&
-                       retval + 1 + regmatches[0].rm_so <= rev_start)
+                       REG_NOTBOL) == 0 && retval + 1 +
+                       regmatches[0].rm_so <= start)
                    retval += 1 + regmatches[0].rm_so;
                /* Finally, put the subexpression matches in global
                 * variable regmatches.  The REG_NOTBOL flag doesn't
@@ -214,9 +227,9 @@ const char *strstrwrapper(const char *haystack, const char *needle,
            }
        } else
 #endif /* !NANO_SMALL */
-       if (regexec(&search_regexp, haystack, 10, regmatches,
-                       line_pos > 0 ? REG_NOTBOL : 0) == 0) {
-           const char *retval = haystack + regmatches[0].rm_so;
+       if (regexec(&search_regexp, start, 10, regmatches,
+               start > haystack ? REG_NOTBOL : 0) == 0) {
+           const char *retval = start + regmatches[0].rm_so;
 
            regexec(&search_regexp, retval, 10, regmatches, 0);
            return retval;
@@ -224,16 +237,21 @@ const char *strstrwrapper(const char *haystack, const char *needle,
        return NULL;
     }
 #endif /* HAVE_REGEX_H */
-#ifndef NANO_SMALL
+#if !defined(DISABLE_SPELLER) || !defined(NANO_SMALL)
     if (ISSET(CASE_SENSITIVE)) {
+#ifndef NANO_SMALL
        if (ISSET(REVERSE_SEARCH))
-           return revstrstr(haystack, needle, rev_start);
+           return revstrstr(haystack, needle, start);
        else
+#endif
            return strstr(haystack, needle);
-    } else if (ISSET(REVERSE_SEARCH))
-       return revstristr(haystack, needle, rev_start);
+    }
+#endif /* !DISABLE_SPELLER || !NANO_SMALL */
+#ifndef NANO_SMALL
+    else if (ISSET(REVERSE_SEARCH))
+       return revstristr(haystack, needle, start);
 #endif
-    return stristr(haystack, needle);
+    return stristr(start, needle);
 }
 
 /* This is a wrapper for the perror function.  The wrapper takes care of 
index 51c734a47f16e968f06368fefb73049f31eabb87..fc9359b1117046e3edcff05f24d81fa5b975a4c4 100644 (file)
@@ -1523,23 +1523,17 @@ size_t get_page_start(size_t column)
  * cursor at (current_y, current_x). */
 void reset_cursor(void)
 {
-    const filestruct *ptr = edittop;
-    size_t x;
-
     /* Yuck.  This condition can be true after open_file() when opening
      * the first file. */
     if (edittop == NULL)
        return;
 
-    current_y = 0;
-
-    while (ptr != current && ptr != editbot && ptr->next != NULL) {
-       ptr = ptr->next;
-       current_y++;
-    }
+    current_y = current->lineno - edittop->lineno;
+    if (current_y < editwinrows) {
+       size_t x = xplustabs();
 
-    x = xplustabs();
-    wmove(edit, current_y, x - get_page_start(x));
+       wmove(edit, current_y, x - get_page_start(x));
+     }
 }
 
 /* edit_add() takes care of the job of actually painting a line into the
@@ -1878,6 +1872,9 @@ void update_line(const filestruct *fileptr, size_t index)
     if (line < 0 || line >= editwinrows)
        return;
 
+    /* Don't make the cursor jump around the screen while updating. */
+    leaveok(edit, TRUE);
+
     /* First, blank out the line (at a minimum) */
     mvwaddstr(edit, line, 0, hblank);
 
@@ -1898,6 +1895,9 @@ void update_line(const filestruct *fileptr, size_t index)
        mvwaddch(edit, line, 0, '$');
     if (strlenpt(fileptr->data) > page_start + COLS)
        mvwaddch(edit, line, COLS - 1, '$');
+
+    /* Let the cursor jump around the screen again. */
+    leaveok(edit, FALSE);
 }
 
 /* This function updates current, based on where current_y is;
@@ -1948,27 +1948,27 @@ void edit_refresh(void)
        edit_update(current, CENTER);
     else {
        int nlines = 0;
+       const filestruct *foo = edittop;
 
-       /* Don't make the cursor jump around the screen whilst
-        * updating. */
-       leaveok(edit, TRUE);
+#ifdef DEBUG
+       fprintf(stderr, "edit_refresh(): edittop->lineno = %ld\n", edittop->lineno);
+#endif
 
-       editbot = edittop;
        while (nlines < editwinrows) {
-           update_line(editbot, current_x);
+           update_line(foo, current_x);
            nlines++;
-           if (editbot->next == NULL)
+           if (foo->next == NULL)
                break;
-           editbot = editbot->next;
+           foo = foo->next;
        }
        while (nlines < editwinrows) {
            mvwaddstr(edit, nlines, 0, hblank);
            nlines++;
        }
+       reset_cursor();
        /* What the hell are we expecting to update the screen if this
         * isn't here?  Luck? */
        wrefresh(edit);
-       leaveok(edit, FALSE);
     }
 }