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-d3aeb78583b8master
parent
895e65ce1a
commit
45cfbece4c
|
@ -8,9 +8,12 @@ CVS code -
|
||||||
shortcut_init()
|
shortcut_init()
|
||||||
- Allow WHEREIS_NEXT_KEY to be used in view mode. (DLR)
|
- Allow WHEREIS_NEXT_KEY to be used in view mode. (DLR)
|
||||||
- search.c:
|
- search.c:
|
||||||
do_replace_loop()
|
findnextstr(), do_replace_loop()
|
||||||
- Fix potential infinite loop when doing a forward regex replace
|
- Fix potential infinite loops when doing certain forward regex
|
||||||
of "$". (DLR; found by Mike Frysinger)
|
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:
|
- winio.c:
|
||||||
get_accepted_kbinput()
|
get_accepted_kbinput()
|
||||||
- Translate Ctrl-8 into NANO_DELETE_KEY, since it apparently is
|
- Translate Ctrl-8 into NANO_DELETE_KEY, since it apparently is
|
||||||
|
|
|
@ -1548,7 +1548,7 @@ int do_int_spell_fix(const char *word)
|
||||||
search_last_line = FALSE;
|
search_last_line = FALSE;
|
||||||
|
|
||||||
/* We find the first whole-word occurrence of word. */
|
/* 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)) {
|
if (is_whole_word(current_x, current->data, word)) {
|
||||||
edit_refresh();
|
edit_refresh();
|
||||||
|
|
||||||
|
|
|
@ -362,7 +362,7 @@ int search_init(int replacing);
|
||||||
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);
|
||||||
filestruct *findnextstr(int quiet, int bracket_mode,
|
filestruct *findnextstr(int quiet, int bracket_mode,
|
||||||
const filestruct *begin, int beginx,
|
const filestruct *begin, int beginx,
|
||||||
const char *needle);
|
const char *needle, int no_same_loc);
|
||||||
int do_search(void);
|
int do_search(void);
|
||||||
int do_research(void);
|
int do_research(void);
|
||||||
void replace_abort(void);
|
void replace_abort(void);
|
||||||
|
|
114
src/search.c
114
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,
|
filestruct *findnextstr(int quiet, int bracket_mode,
|
||||||
const filestruct *begin, int beginx,
|
const filestruct *begin, int beginx,
|
||||||
const char *needle)
|
const char *needle, int no_same_loc)
|
||||||
{
|
{
|
||||||
filestruct *fileptr = current;
|
filestruct *fileptr = current;
|
||||||
const char *searchstr, *rev_start = NULL, *found = NULL;
|
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];
|
searchstr = &fileptr->data[current_x_find];
|
||||||
|
|
||||||
/* Look for needle in searchstr */
|
/* Look for needle in searchstr. Keep going until we find it
|
||||||
while ((found = strstrwrapper(searchstr, needle, rev_start, current_x_find)) == NULL) {
|
* 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 */
|
/* finished processing file, get out */
|
||||||
if (search_last_line) {
|
if (search_last_line) {
|
||||||
|
@ -320,8 +324,13 @@ filestruct *findnextstr(int quiet, int bracket_mode,
|
||||||
rev_start = &fileptr->data[current_x_find];
|
rev_start = &fileptr->data[current_x_find];
|
||||||
searchstr = fileptr->data;
|
searchstr = fileptr->data;
|
||||||
|
|
||||||
/* Look for needle in searchstr */
|
/* Look for needle in searchstr. Keep going until we find it
|
||||||
while ((found = strstrwrapper(searchstr, needle, rev_start, current_x_find)) == NULL) {
|
* 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 */
|
/* finished processing file, get out */
|
||||||
if (search_last_line) {
|
if (search_last_line) {
|
||||||
if (!quiet)
|
if (!quiet)
|
||||||
|
@ -420,7 +429,7 @@ int do_search(void)
|
||||||
#endif /* !NANO_SMALL */
|
#endif /* !NANO_SMALL */
|
||||||
|
|
||||||
search_last_line = 0;
|
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)
|
if (fileptr == current && fileptr_x == current_x && didfind != NULL)
|
||||||
statusbar(_("This is the only occurrence"));
|
statusbar(_("This is the only occurrence"));
|
||||||
|
@ -459,7 +468,7 @@ int do_research(void)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
search_last_line = 0;
|
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)
|
if (fileptr == current && fileptr_x == current_x && didfind != NULL)
|
||||||
statusbar(_("This is the only occurrence"));
|
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;
|
int replaceall = 0, numreplaced = -1;
|
||||||
#ifdef HAVE_REGEX_H
|
#ifdef HAVE_REGEX_H
|
||||||
int dollarreplace = 0;
|
/* The special case regex flags. */
|
||||||
/* Whether we're doing a forward regex replace of "$". */
|
int old_bol = 0, old_eol = 0;
|
||||||
#endif
|
#endif
|
||||||
filestruct *fileptr = NULL;
|
filestruct *fileptr = NULL;
|
||||||
char *copy;
|
char *copy;
|
||||||
|
@ -637,9 +646,39 @@ int do_replace_loop(const char *prevanswer, const filestruct *begin,
|
||||||
while (1) {
|
while (1) {
|
||||||
size_t match_len;
|
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. */
|
/* Sweet optimization by Rocco here. */
|
||||||
fileptr = findnextstr(fileptr || replaceall || search_last_line,
|
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
|
if (current->lineno <= edittop->lineno
|
||||||
|| current->lineno >= editbot->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);
|
length_change = strlen(copy) - strlen(current->data);
|
||||||
|
|
||||||
#ifdef HAVE_REGEX_H
|
#ifdef HAVE_REGEX_H
|
||||||
if (ISSET(USE_REGEXP)) {
|
if (ISSET(USE_REGEXP))
|
||||||
match_len = regmatches[0].rm_eo - regmatches[0].rm_so;
|
match_len = regmatches[0].rm_eo - regmatches[0].rm_so;
|
||||||
/* If we're on the line we started the replace on, the
|
else
|
||||||
* 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
|
|
||||||
#endif
|
#endif
|
||||||
match_len = strlen(prevanswer);
|
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
|
/* Set the cursor at the last character of the replacement
|
||||||
* text, so searching will resume after the replacement text.
|
* text, so searching will resume after the replacement
|
||||||
* Note that current_x might be set to -1 here. */
|
* text. Note that current_x might be set to -1 here. */
|
||||||
#ifndef NANO_SMALL
|
#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
|
#endif
|
||||||
current_x += match_len + length_change - 1;
|
current_x += match_len + length_change - 1;
|
||||||
|
#ifndef NANO_SMALL
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Cleanup. */
|
/* Cleanup. */
|
||||||
totsize += length_change;
|
totsize += length_change;
|
||||||
|
@ -746,25 +791,6 @@ int do_replace_loop(const char *prevanswer, const filestruct *begin,
|
||||||
set_modified();
|
set_modified();
|
||||||
numreplaced++;
|
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
|
} else if (*i == -1) /* Break out of the loop, else do
|
||||||
* nothing and continue loop. */
|
* nothing and continue loop. */
|
||||||
break;
|
break;
|
||||||
|
@ -970,7 +996,7 @@ int do_find_bracket(void)
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
search_last_line = 0;
|
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;
|
have_search_offscreen |= search_offscreen;
|
||||||
|
|
||||||
/* found identical bracket */
|
/* found identical bracket */
|
||||||
|
|
Loading…
Reference in New Issue