]> git.wh0rd.org Git - nano.git/commitdiff
avoid infinite loop when doing a forward regex replace of "$"
authorDavid Lawrence Ramsey <pooka109@gmail.com>
Fri, 31 Oct 2003 17:53:38 +0000 (17:53 +0000)
committerDavid Lawrence Ramsey <pooka109@gmail.com>
Fri, 31 Oct 2003 17:53:38 +0000 (17:53 +0000)
git-svn-id: svn://svn.savannah.gnu.org/nano/trunk/nano@1580 35c25a1d-7b9e-4130-9fde-d3aeb78583b8

ChangeLog
src/search.c

index b3a002b3bc2143d799d1bfca06900cfd61e93f40..6fa836d70d1985b5f4821af806f267c139ca39ce 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,8 @@
 CVS code -
+search.c:
+  do_replace_loop()
+       - Fix potential infinite loop when doing a forward regex replace
+         of "$". (DLR; found by Mike Frysinger)
 
 GNU nano 1.3.0 - 2003.10.22
 - General:
index 0d7dca9a2807be7479e3d86c24e6f941af1c3617..2553e762ecee26276b0121bab63b3c0fc8e5e14e 100644 (file)
@@ -608,22 +608,25 @@ int do_replace_loop(const char *prevanswer, const filestruct *begin,
                        int *beginx, int wholewords, int *i)
 {
     int replaceall = 0, numreplaced = -1;
-
+#ifdef HAVE_REGEX_H
+    int dollarreplace = 0;
+       /* Whether we're doing a forward regex replace of "$". */
+#endif
     filestruct *fileptr = NULL;
     char *copy;
 
     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 */
+       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;
@@ -634,7 +637,7 @@ int do_replace_loop(const char *prevanswer, const filestruct *begin,
     while (1) {
        size_t match_len;
 
-       /* Sweet optimization by Rocco here */
+       /* Sweet optimization by Rocco here. */
        fileptr = findnextstr(fileptr || replaceall || search_last_line,
                                FALSE, begin, *beginx, prevanswer);
 
@@ -646,11 +649,11 @@ int do_replace_loop(const char *prevanswer, const filestruct *begin,
        if (fileptr == NULL)
            break;
 
-       /* Make sure only whole words are found */
+       /* 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 we're here, we've found the search string. */
        if (numreplaced == -1)
            numreplaced = 0;
 
@@ -695,9 +698,18 @@ 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;
-           else
+               /* 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
 #endif
                match_len = strlen(prevanswer);
 
@@ -725,7 +737,7 @@ int do_replace_loop(const char *prevanswer, const filestruct *begin,
 #endif
                current_x += match_len + length_change - 1;
 
-           /* Cleanup */
+           /* Cleanup. */
            totsize += length_change;
            free(current->data);
            current->data = copy;
@@ -733,8 +745,28 @@ int do_replace_loop(const char *prevanswer, const filestruct *begin,
            edit_refresh();
            set_modified();
            numreplaced++;
-       } else if (*i == -1)    /* Abort, else do nothing and continue
-                                  loop */
+
+#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;
     }