From: David Lawrence Ramsey Date: Fri, 28 Nov 2003 16:04:24 +0000 (+0000) Subject: replace the old fix for infinite regex replacement loops with something X-Git-Tag: v1.3.1~18 X-Git-Url: https://git.wh0rd.org/?a=commitdiff_plain;h=45cfbece4c8da93dca352970b865e608cd1574d5;p=nano.git replace the old fix for infinite regex replacement loops with something that works better and is less hackish git-svn-id: svn://svn.savannah.gnu.org/nano/trunk/nano@1595 35c25a1d-7b9e-4130-9fde-d3aeb78583b8 --- diff --git a/ChangeLog b/ChangeLog index 47161f3e..f4420cc7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -8,9 +8,12 @@ CVS code - shortcut_init() - Allow WHEREIS_NEXT_KEY to be used in view mode. (DLR) - search.c: - do_replace_loop() - - Fix potential infinite loop when doing a forward regex replace - of "$". (DLR; found by Mike Frysinger) + 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) - winio.c: get_accepted_kbinput() - Translate Ctrl-8 into NANO_DELETE_KEY, since it apparently is diff --git a/src/nano.c b/src/nano.c index 8f3fe594..d44ed931 100644 --- a/src/nano.c +++ b/src/nano.c @@ -1548,7 +1548,7 @@ int do_int_spell_fix(const char *word) search_last_line = FALSE; /* We find the first whole-word occurrence of word. */ - while (findnextstr(TRUE, TRUE, fileage, -1, word)) + while (findnextstr(TRUE, TRUE, fileage, -1, word, 0)) if (is_whole_word(current_x, current->data, word)) { edit_refresh(); diff --git a/src/proto.h b/src/proto.h index 43556c46..417aef30 100644 --- a/src/proto.h +++ b/src/proto.h @@ -362,7 +362,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); + const char *needle, int no_same_loc); int do_search(void); int do_research(void); void replace_abort(void); diff --git a/src/search.c b/src/search.c index 2553e762..ce587de9 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) + const char *needle, int no_same_loc) { filestruct *fileptr = current; const char *searchstr, *rev_start = NULL, *found = NULL; @@ -265,8 +265,12 @@ filestruct *findnextstr(int quiet, int bracket_mode, searchstr = &fileptr->data[current_x_find]; - /* Look for needle in searchstr */ - while ((found = strstrwrapper(searchstr, needle, rev_start, current_x_find)) == NULL) { + /* 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 + * set. */ + while ((found = strstrwrapper(searchstr, needle, rev_start, current_x_find)) == NULL || (no_same_loc && fileptr == current && current_x_find == current_x)) { /* finished processing file, get out */ if (search_last_line) { @@ -320,8 +324,13 @@ filestruct *findnextstr(int quiet, int bracket_mode, rev_start = &fileptr->data[current_x_find]; searchstr = fileptr->data; - /* Look for needle in searchstr */ - while ((found = strstrwrapper(searchstr, needle, rev_start, current_x_find)) == NULL) { + /* 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 + * set. */ + while ((found = strstrwrapper(searchstr, needle, rev_start, current_x_find)) == NULL || (no_same_loc && fileptr == current && current_x_find == current_x)) { + /* finished processing file, get out */ if (search_last_line) { if (!quiet) @@ -420,7 +429,7 @@ int do_search(void) #endif /* !NANO_SMALL */ search_last_line = 0; - didfind = findnextstr(FALSE, FALSE, current, current_x, answer); + didfind = findnextstr(FALSE, FALSE, current, current_x, answer, 0); if (fileptr == current && fileptr_x == current_x && didfind != NULL) statusbar(_("This is the only occurrence")); @@ -459,7 +468,7 @@ int do_research(void) #endif search_last_line = 0; - didfind = findnextstr(FALSE, FALSE, current, current_x, last_search); + 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")); @@ -609,8 +618,8 @@ int do_replace_loop(const char *prevanswer, const filestruct *begin, { int replaceall = 0, numreplaced = -1; #ifdef HAVE_REGEX_H - int dollarreplace = 0; - /* Whether we're doing a forward regex replace of "$". */ + /* The special case regex flags. */ + int old_bol = 0, old_eol = 0; #endif filestruct *fileptr = NULL; char *copy; @@ -637,9 +646,39 @@ 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); + FALSE, begin, *beginx, prevanswer, +#ifdef HAVE_REGEX_H + old_bol || old_eol +#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 + * we're done. */ + if ((old_bol || old_eol) && fileptr == begin && current_x == *beginx) + fileptr = NULL; + /* Otherwise, reset the flags and continue. */ + else { + old_bol = 0; + old_eol = 0; + } +#endif if (current->lineno <= edittop->lineno || current->lineno >= editbot->lineno) @@ -698,18 +737,9 @@ int do_replace_loop(const char *prevanswer, const filestruct *begin, length_change = strlen(copy) - strlen(current->data); #ifdef HAVE_REGEX_H - if (ISSET(USE_REGEXP)) { + if (ISSET(USE_REGEXP)) match_len = regmatches[0].rm_eo - regmatches[0].rm_so; - /* If we're on the line we started the replace on, the - * match length is 0, and current_x is at the end of the - * the line, we're doing a forward regex replace of "$". - * We have to handle this as a special case so that we - * don't end up infinitely tacking the replace string - * onto the end of the line. */ - if (current == begin && match_len == 0 && current_x == - strlen(current->data)) - dollarreplace = 1; - } else + else #endif match_len = strlen(prevanswer); @@ -730,12 +760,27 @@ int do_replace_loop(const char *prevanswer, const filestruct *begin, } /* Set the cursor at the last character of the replacement - * text, so searching will resume after the replacement text. - * Note that current_x might be set to -1 here. */ + * 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)) + 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; + } #endif current_x += match_len + length_change - 1; +#ifndef NANO_SMALL + } +#endif /* Cleanup. */ totsize += length_change; @@ -746,25 +791,6 @@ int do_replace_loop(const char *prevanswer, const filestruct *begin, set_modified(); numreplaced++; -#ifdef HAVE_REGEX_H - if (dollarreplace == 1) { - /* If we're here, we're doing a forward regex replace of - * "$", and the replacement's just been made. Avoid - * infinite replacement by manually moving the search to - * the next line, wrapping to the first line if we're on - * the last line of the file. Afterwards, if we're back - * on the line where we started, manually break out of - * the loop. */ - current_x = 0; - if (current->next != NULL) - current = current->next; - else - current = fileage; - if (current == begin) - break; - } -#endif - } else if (*i == -1) /* Break out of the loop, else do * nothing and continue loop. */ break; @@ -970,7 +996,7 @@ int do_find_bracket(void) while (1) { search_last_line = 0; - if (findnextstr(1, 1, current, current_x, regexp_pat) != NULL) { + if (findnextstr(1, 1, current, current_x, regexp_pat, 0) != NULL) { have_search_offscreen |= search_offscreen; /* found identical bracket */