diff --git a/ChangeLog b/ChangeLog
index 2a312549abfe9ecb036b729779dab86fc2454b65..f0d2dee18a7c155444d48c31c285b22c57505904 100644
--- 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.
diff --git a/src/nano.c b/src/nano.c
index 3fee0db1187a3b7f7990fe3edd013224c97b2f1c..228147825f947dfde07c1d7859133fae918a98f7 100644
--- a/src/nano.c
+++ b/src/nano.c
@@ -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
diff --git a/src/proto.h b/src/proto.h
index b09ed621111d6d16566807689f212b13e6c09fa0..8eb94bce15f3f810003b6f2efe919faff49d3a3c 100644
--- a/src/proto.h
+++ b/src/proto.h
@@ -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);
diff --git a/src/search.c b/src/search.c
index 69f9eba210fb38ef5c69f93f58df8e6b43bc1b2a..9ce635c39a45d4f8a40894b9f43a7bb43c251ccf 100644
--- a/src/search.c
+++ b/src/search.c
@@ -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;
 }
diff --git a/src/utils.c b/src/utils.c
index af53c2eda994152c549e6ab899475108b6e2d810..37d0bcff95fc1515d0a19f90bdb1b07f42a9bcaa 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -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 
diff --git a/src/winio.c b/src/winio.c
index 51c734a47f16e968f06368fefb73049f31eabb87..fc9359b1117046e3edcff05f24d81fa5b975a4c4 100644
--- a/src/winio.c
+++ b/src/winio.c
@@ -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);
     }
 }