From: David Lawrence Ramsey Date: Wed, 24 Dec 2003 03:13:44 +0000 (+0000) Subject: fix search/replace misbehaviors for good (I hope) X-Git-Tag: v1.3.1~15 X-Git-Url: https://git.wh0rd.org/?a=commitdiff_plain;h=18394ac6211c797d74aa4ef45e366ad839d4bcaa;p=nano.git fix search/replace misbehaviors for good (I hope) git-svn-id: svn://svn.savannah.gnu.org/nano/trunk/nano@1598 35c25a1d-7b9e-4130-9fde-d3aeb78583b8 --- diff --git a/ChangeLog b/ChangeLog index 59825ec5..d3fcc6bb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -32,11 +32,12 @@ CVS code - - Allow WHEREIS_NEXT_KEY to be used in view mode. (DLR) - search.c: findnextstr(), do_replace_loop() - - Fix potential infinite loops when doing certain forward regex - replacements, where we end up either perpetually adding to the - end of one line (e. g. replace "$" with anything non-blank) or - not moving at all (e. g. replace "^" or "^$" with anything - blank). (DLR; found by Mike Frysinger and DLR) + - Fix potential infinite loops and other misbehavior when doing + certain zero-length regex replacements ("^", "$", and "^$"). + Add a no_sameline parameter to findnextstr(), and set it in + the calls in do_replace_loop() when such regexes are found, so + that such regexes are only found once per line. (DLR; found by + Mike Frysinger and DLR) - winio.c: get_accepted_kbinput() - Translate Ctrl-8 into NANO_DELETE_KEY, since it apparently is diff --git a/src/proto.h b/src/proto.h index ddf08cc8..ea59974d 100644 --- a/src/proto.h +++ b/src/proto.h @@ -363,7 +363,7 @@ 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_same_loc); + const char *needle, int no_sameline); int do_search(void); int do_research(void); void replace_abort(void); diff --git a/src/search.c b/src/search.c index ce587de9..cbfa2986 100644 --- a/src/search.c +++ b/src/search.c @@ -247,7 +247,7 @@ 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_same_loc) + const char *needle, int no_sameline) { filestruct *fileptr = current; const char *searchstr, *rev_start = NULL, *found = NULL; @@ -266,11 +266,11 @@ filestruct *findnextstr(int quiet, int bracket_mode, searchstr = &fileptr->data[current_x_find]; /* Look for needle in searchstr. Keep going until we find it - * and, if no_same_loc is set, until it isn't the one at - * current[current_x]. If we don't find it, we'll end up at - * current[current_x] regardless of whether no_same_loc is + * 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_same_loc && fileptr == current && current_x_find == current_x)) { + while ((found = strstrwrapper(searchstr, needle, rev_start, current_x_find)) == NULL || (no_sameline && fileptr == current)) { /* finished processing file, get out */ if (search_last_line) { @@ -325,11 +325,11 @@ filestruct *findnextstr(int quiet, int bracket_mode, searchstr = fileptr->data; /* Look for needle in searchstr. Keep going until we find it - * and, if no_same_loc is set, until it isn't the one at - * current[current_x]. If we don't find it, we'll end up at - * current[current_x] regardless of whether no_same_loc is + * 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_same_loc && fileptr == current && current_x_find == current_x)) { + while ((found = strstrwrapper(searchstr, needle, rev_start, current_x_find)) == NULL || (no_sameline && fileptr == current)) { /* finished processing file, get out */ if (search_last_line) { @@ -618,8 +618,8 @@ int do_replace_loop(const char *prevanswer, const filestruct *begin, { int replaceall = 0, numreplaced = -1; #ifdef HAVE_REGEX_H - /* The special case regex flags. */ - int old_bol = 0, old_eol = 0; + /* The starting-line match and zero-length regex flags. */ + int beginline = 0, caretdollar = 0; #endif filestruct *fileptr = NULL; char *copy; @@ -646,37 +646,35 @@ int do_replace_loop(const char *prevanswer, const filestruct *begin, while (1) { size_t match_len; -#ifdef HAVE_REGEX_H - /* Check the special case regex flags. If the last (forward, - * zero-length) regex replace left us at the beginning or end of - * the line as it was before replacement, move to the beginning - * or end of the line as it is now. */ - if (old_bol) - current_x = 0; - if (old_eol) - current_x = strlen(current->data); -#endif - /* Sweet optimization by Rocco here. */ fileptr = findnextstr(fileptr || replaceall || search_last_line, FALSE, begin, *beginx, prevanswer, #ifdef HAVE_REGEX_H - old_bol || old_eol + /* We should find a zero-length regex only once per + * line. If the caretdollar 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. */ + caretdollar #else 0 #endif ); #ifdef HAVE_REGEX_H - /* If either of the special case regex flags are set and we're - * back where we started, it means we've wrapped around, so + /* If the caretdollar 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 ((old_bol || old_eol) && fileptr == begin && current_x == *beginx) + if (caretdollar && beginline && fileptr == begin) fileptr = NULL; - /* Otherwise, reset the flags and continue. */ + /* Otherwise, set the beginline flag if we've found a match on + * the beginning line, reset the caretdollar flag, and + * continue. */ else { - old_bol = 0; - old_eol = 0; + if (fileptr == begin) + beginline = 1; + caretdollar = 0; } #endif @@ -720,6 +718,13 @@ int do_replace_loop(const char *prevanswer, const filestruct *begin, curs_set(1); } +#ifdef HAVE_REGEX_H + /* Set the caretdollar flag if we're doing a zero-length regex + * replace (such as "^", "$", or "^$"). */ + if (ISSET(USE_REGEXP) && match_len == 0) + caretdollar = 1; +#endif + if (*i > 0 || replaceall) { /* Yes, replace it!!!! */ long length_change; size_t match_len; @@ -763,24 +768,9 @@ int do_replace_loop(const char *prevanswer, const filestruct *begin, * text, so searching will resume after the replacement * text. Note that current_x might be set to -1 here. */ #ifndef NANO_SMALL - if (!ISSET(REVERSE_SEARCH)) { -#endif -#ifdef HAVE_REGEX_H - /* Set the special case regex flags if we're at the - * beginning or end of the line before a (forward, - * zero-length) regex replace. Note that they can both - * be set if we're replacing the magicline. */ - if (ISSET(USE_REGEXP) && match_len == 0) { - if (current_x <= 0) - old_bol = 1; - if (current_x == strlen(current->data)) - old_eol = 1; - } + if (!ISSET(REVERSE_SEARCH)) #endif current_x += match_len + length_change - 1; -#ifndef NANO_SMALL - } -#endif /* Cleanup. */ totsize += length_change;