[nano/f20] Resolves: #1166666 - fix intermittent crashes with undo/redo

Kamil Dudka kdudka at fedoraproject.org
Fri Nov 21 16:29:55 UTC 2014


commit ffaa1a2a594dc4330dc311d91c99b3a84907d6c8
Author: Kamil Dudka <kdudka at redhat.com>
Date:   Fri Nov 21 16:51:42 2014 +0100

    Resolves: #1166666 - fix intermittent crashes with undo/redo

 ...e-correct-positions-for-undoing-and-redoi.patch |  658 ++++++++++++++++++++
 nano.spec                                          |    9 +-
 2 files changed, 666 insertions(+), 1 deletions(-)
---
diff --git a/0004-Going-to-the-correct-positions-for-undoing-and-redoi.patch b/0004-Going-to-the-correct-positions-for-undoing-and-redoi.patch
new file mode 100644
index 0000000..3a93635
--- /dev/null
+++ b/0004-Going-to-the-correct-positions-for-undoing-and-redoi.patch
@@ -0,0 +1,658 @@
+From b6965b6e07ae42b1bae33948a42f3ce90fd1074e Mon Sep 17 00:00:00 2001
+From: bens <bens at ac9c2fa3-95a5-41e5-9206-2167041ecc6c>
+Date: Thu, 15 May 2014 20:00:46 +0000
+Subject: [PATCH] Going to the correct positions for undoing and redoing cuts
+ and pastes. This fixes many undo problems and Savannah bug #25585. *Patch by
+ Mark Majeres.*
+
+git-svn-id: file:///home/kdudka/git/nano-svn/nano@4893 ac9c2fa3-95a5-41e5-9206-2167041ecc6c
+Signed-off-by: Kamil Dudka <kdudka at redhat.com>
+---
+ src/cut.c    |   9 ++-
+ src/move.c   |   2 +-
+ src/nano.c   |   6 +-
+ src/nano.h   |   2 +-
+ src/proto.h  |   1 +
+ src/search.c |  14 ++++
+ src/text.c   | 215 +++++++++++++++++++++++++++++++++--------------------------
+ src/utils.c  |   5 +-
+ 8 files changed, 152 insertions(+), 102 deletions(-)
+
+diff --git a/src/cut.c b/src/cut.c
+index 8c21c8e..9739751 100644
+--- a/src/cut.c
++++ b/src/cut.c
+@@ -44,6 +44,9 @@ void cutbuffer_reset(void)
+  * current line. */
+ void cut_line(void)
+ {
++    if(!openfile->mark_begin)
++	openfile->mark_begin = openfile->current;
++
+     if (openfile->current != openfile->filebot)
+ 	move_to_filestruct(&cutbuffer, &cutbottom, openfile->current, 0,
+ 		openfile->current->next, 0);
+@@ -205,7 +208,7 @@ void do_cut_text(
+ 	if (!old_no_newlines)
+ 	    UNSET(NO_NEWLINES);
+     } else if (!undoing)
+-	update_undo(CUT);
++	update_undo(cut_till_end ? CUT_EOF : CUT);
+ #endif
+ 	/* Leave the text in the cutbuffer, and mark the file as
+ 	 * modified. */
+@@ -248,7 +251,7 @@ void do_copy_text(void)
+ void do_cut_till_end(void)
+ {
+ #ifndef NANO_TINY
+-    add_undo(CUT);
++    add_undo(CUT_EOF);
+ #endif
+     do_cut_text(FALSE, TRUE, FALSE);
+ }
+@@ -264,7 +267,7 @@ void do_uncut_text(void)
+ 	return;
+ 
+ #ifndef NANO_TINY
+-     update_undo(UNCUT);
++    add_undo(PASTE);
+ #endif
+ 
+     /* Add a copy of the text in the cutbuffer to the current filestruct
+diff --git a/src/move.c b/src/move.c
+index b5bd082..e82f5f1 100644
+--- a/src/move.c
++++ b/src/move.c
+@@ -566,7 +566,7 @@ void do_down(
+     bool onlastline = FALSE;
+ 
+     /* If we're at the bottom of the file, get out. */
+-    if (openfile->current == openfile->filebot)
++    if (openfile->current == openfile->filebot || !openfile->current->next)
+ 	return;
+ 
+ 
+diff --git a/src/nano.c b/src/nano.c
+index c315768..ebce05b 100644
+--- a/src/nano.c
++++ b/src/nano.c
+@@ -1993,7 +1993,7 @@ void do_output(char *output, size_t output_len, bool allow_cntrls)
+ 	set_modified();
+ 
+ #ifndef NANO_TINY
+-	update_undo(ADD);
++	add_undo(ADD);
+ 
+ 	/* Note that current_x has not yet been incremented. */
+ 	if (openfile->mark_set && openfile->current ==
+@@ -2004,6 +2004,10 @@ void do_output(char *output, size_t output_len, bool allow_cntrls)
+ 
+ 	openfile->current_x += char_buf_len;
+ 
++#ifndef NANO_TINY
++	update_undo(ADD);
++#endif
++
+ #ifndef DISABLE_WRAPPING
+ 	/* If we're wrapping text, we need to call edit_refresh(). */
+ 	if (!ISSET(NO_WRAP))
+diff --git a/src/nano.h b/src/nano.h
+index bbe9532..0d64e86 100644
+--- a/src/nano.h
++++ b/src/nano.h
+@@ -188,7 +188,7 @@ typedef enum {
+ }  function_type;
+ 
+ typedef enum {
+-    ADD, DEL, REPLACE, SPLIT, UNSPLIT, CUT, UNCUT, ENTER, INSERT, OTHER
++    ADD, DEL, REPLACE, SPLIT, UNSPLIT, CUT, CUT_EOF, PASTE, ENTER, INSERT, OTHER
+ } undo_type;
+ 
+ #ifdef ENABLE_COLOR
+diff --git a/src/proto.h b/src/proto.h
+index a041d42..e752c96 100644
+--- a/src/proto.h
++++ b/src/proto.h
+@@ -611,6 +611,7 @@ void do_gotolinecolumn_void(void);
+ void do_gotopos(ssize_t pos_line, size_t pos_x, ssize_t pos_y, size_t
+ 	pos_pww);
+ #endif
++void goto_line_posx(ssize_t line, size_t pos_x);
+ #ifndef NANO_TINY
+ bool find_bracket_match(bool reverse, const char *bracket_set);
+ void do_find_bracket(void);
+diff --git a/src/search.c b/src/search.c
+index 77b2097..8c040a8 100644
+--- a/src/search.c
++++ b/src/search.c
+@@ -1008,6 +1008,20 @@ void do_replace(void)
+     search_replace_abort();
+ }
+ 
++/* Go to the specified line and x position. */
++void goto_line_posx(ssize_t line, size_t pos_x)
++{
++    for (openfile->current = openfile->fileage; openfile->current != openfile->filebot &&
++					openfile->current->next != NULL && line > 1; line--)
++	openfile->current = openfile->current->next;
++
++    openfile->current_x = pos_x;
++    openfile->placewewant = xplustabs();
++
++    edit_refresh_needed = TRUE;
++    edit_refresh();
++}
++
+ /* Go to the specified line and column, or ask for them if interactive
+  * is TRUE.  Save the x-coordinate and y-coordinate if save_pos is TRUE.
+  * Update the screen afterwards if allow_update is TRUE.  Note that both
+diff --git a/src/text.c b/src/text.c
+index cdd1159..9e91bbb 100644
+--- a/src/text.c
++++ b/src/text.c
+@@ -112,9 +112,8 @@ void do_delete(void)
+ 	    edit_refresh_needed = TRUE;
+ 
+ 	openfile->current->data = charealloc(openfile->current->data,
+-		openfile->current_x + strlen(foo->data) + 1);
+-	strcpy(openfile->current->data + openfile->current_x,
+-		foo->data);
++		strlen(openfile->current->data) + strlen(foo->data) + 1);
++	strcat(openfile->current->data, foo->data);
+ #ifndef NANO_TINY
+ 	if (openfile->mark_set && openfile->mark_begin ==
+ 		openfile->current->next) {
+@@ -360,6 +359,9 @@ void do_unindent(void)
+     do_indent(-tabsize);
+ }
+ 
++#define redo_paste undo_cut
++#define undo_paste redo_cut
++
+ /* undo a cut, or re-do an uncut */
+ void undo_cut(undo *u)
+ {
+@@ -374,10 +376,7 @@ void undo_cut(undo *u)
+ 	;
+ 
+     /* Get to where we need to uncut from */
+-    if (u->mark_set && u->mark_begin_lineno < u->lineno)
+-	do_gotolinecolumn(u->mark_begin_lineno, u->mark_begin_x+1, FALSE, FALSE, FALSE, FALSE);
+-    else
+-	do_gotolinecolumn(u->lineno, u->begin+1, FALSE, FALSE, FALSE, FALSE);
++    goto_line_posx(u->mark_begin_lineno, u->mark_begin_x);
+ 
+     copy_from_filestruct(cutbuffer, cutbottom);
+     free_filestruct(cutbuffer);
+@@ -387,40 +386,26 @@ void undo_cut(undo *u)
+ 
+ /* Re-do a cut, or undo an uncut */
+ void redo_cut(undo *u) {
+-    int i;
+-    filestruct *t, *c;
+-
+     /* If we cut the magicline may was well not crash :/ */
+     if (!u->cutbuffer)
+ 	return;
+ 
+-    do_gotolinecolumn(u->lineno, u->begin+1, FALSE, FALSE, FALSE, FALSE);
++    goto_line_posx(u->lineno, u->begin);
++
++    if (ISSET(NO_NEWLINES) && openfile->current->lineno != u->lineno) {
++	openfile->current_x = strlen(openfile->current->data);
++	openfile->placewewant = xplustabs();
++    }
++
+     openfile->mark_set = u->mark_set;
+     if (cutbuffer)
+ 	free(cutbuffer);
+     cutbuffer = NULL;
+ 
+-    /* Move ahead the same # lines we had if a marked cut */
+-    if (u->mark_set) {
+-	for (i = 1, t = openfile->fileage; i != u->mark_begin_lineno; i++)
+-	    t = t->next;
+-	openfile->mark_begin = t;
+-    } else if (!u->to_end) {
+-	/* Here we have a regular old potentially multi-line ^K cut.  We'll
+-	   need to trick nano into thinking it's a marked cut to cut more
+-	   than one line again */
+-	for (c = u->cutbuffer, t = openfile->current; c->next != NULL && t->next != NULL; ) {
++    openfile->mark_begin = fsfromline(u->mark_begin_lineno);
+ 
+-#ifdef DEBUG
+-	fprintf(stderr, "Advancing, lineno  = %lu, data = \"%s\"\n", (unsigned long) t->lineno, t->data);
+-#endif
+-	    c = c->next;
+-	    t = t->next;
+-	 }
+-	openfile->mark_begin = t;
+- 	openfile->mark_begin_x = 0;
++    if (!ISSET(CUT_TO_END))
+ 	openfile->mark_set = TRUE;
+-    }
+ 
+     openfile->mark_begin_x = u->mark_begin_x;
+     do_cut_text(FALSE, u->to_end, TRUE);
+@@ -433,8 +418,9 @@ void redo_cut(undo *u) {
+ /* Undo the last thing(s) we did */
+ void do_undo(void)
+ {
++    bool gotolinecolumn = FALSE;
+     undo *u = openfile->current_undo;
+-    filestruct *f = openfile->current, *t;
++    filestruct *t = NULL;
+     int len = 0;
+     char *undidmsg, *data;
+     filestruct *oldcutbuffer = cutbuffer, *oldcutbottom = cutbottom;
+@@ -445,14 +431,9 @@ void do_undo(void)
+     }
+ 
+ 
+-    if (u->lineno <= f->lineno)
+-        for (; f->prev != NULL && f->lineno != u->lineno; f = f->prev)
+-	    ;
+-    else
+-        for (; f->next != NULL && f->lineno != u->lineno; f = f->next)
+-	    ;
+-    if (f->lineno != u->lineno) {
+-        statusbar(_("Internal error: can't match line %d.  Please save your work"), u->lineno);
++    filestruct *f = fsfromline(u->mark_begin_lineno);
++    if (!f) {
++	statusbar(_("Internal error: can't match line %d.  Please save your work."), u->mark_begin_lineno);
+ 	return;
+     }
+ #ifdef DEBUG
+@@ -470,6 +451,7 @@ void do_undo(void)
+ 	strcpy(&data[u->begin], &f->data[u->begin + strlen(u->strdata)]);
+ 	free(f->data);
+ 	f->data = data;
++	goto_line_posx(u->lineno, u->begin);
+ 	break;
+     case DEL:
+ 	undidmsg = _("text delete");
+@@ -483,6 +465,7 @@ void do_undo(void)
+ 	f->data = data;
+ 	if (u->xflags == UNdel_backspace)
+ 	    openfile->current_x += strlen(u->strdata);
++	goto_line_posx(u->mark_begin_lineno, u->mark_begin_x + 1);
+ 	break;
+ #ifndef DISABLE_WRAPPING
+     case SPLIT:
+@@ -497,26 +480,28 @@ void do_undo(void)
+ 	    delete_node(foo);
+ 	}
+ 	renumber(f);
++	gotolinecolumn = TRUE;
+ 	break;
+ #endif /* DISABLE_WRAPPING */
+     case UNSPLIT:
+ 	undidmsg = _("line join");
+ 	t = make_new_node(f);
+ 	t->data = mallocstrcpy(NULL, u->strdata);
+-	data = mallocstrncpy(NULL, f->data, u->begin);
++	data = mallocstrncpy(NULL, f->data, u->begin + 1);
+ 	data[u->begin] = '\0';
+ 	free(f->data);
+ 	f->data = data;
+ 	splice_node(f, t, f->next);
+-	renumber(f);
++	gotolinecolumn = TRUE;
+ 	break;
++    case CUT_EOF:
+     case CUT:
+ 	undidmsg = _("text cut");
+         undo_cut(u);
+ 	break;
+-    case UNCUT:
++    case PASTE:
+ 	undidmsg = _("text uncut");
+-	redo_cut(u);
++	undo_paste(u);
+ 	break;
+     case ENTER:
+ 	undidmsg = _("line break");
+@@ -527,6 +512,7 @@ void do_undo(void)
+ 	    unlink_node(foo);
+ 	    delete_node(foo);
+ 	}
++	goto_line_posx(u->lineno, u->begin);
+ 	break;
+     case INSERT:
+ 	undidmsg = _("text insert");
+@@ -538,7 +524,7 @@ void do_undo(void)
+ 	openfile->mark_begin = fsfromline(u->lineno + u->mark_begin_lineno - 1);
+ 	openfile->mark_begin_x = 0;
+ 	openfile->mark_set = TRUE;
+-	do_gotolinecolumn(u->lineno, u->begin+1, FALSE, FALSE, FALSE, FALSE);
++	goto_line_posx(u->lineno, u->begin);
+ 	cut_marked();
+ 	u->cutbuffer = cutbuffer;
+ 	u->cutbottom = cutbottom;
+@@ -548,6 +534,7 @@ void do_undo(void)
+ 	break;
+     case REPLACE:
+ 	undidmsg = _("text replace");
++	goto_line_posx(u->lineno, u->begin);
+ 	data = u->strdata;
+ 	u->strdata = f->data;
+ 	f->data = data;
+@@ -559,16 +546,18 @@ void do_undo(void)
+ 
+     }
+     renumber(f);
+-    do_gotolinecolumn(u->lineno, u->begin, FALSE, FALSE, FALSE, TRUE);
++    if (gotolinecolumn)
++	do_gotolinecolumn(u->lineno, u->begin, FALSE, FALSE, FALSE, TRUE);
+     statusbar(_("Undid action (%s)"), undidmsg);
+     openfile->current_undo = openfile->current_undo->next;
+     openfile->last_action = OTHER;
++    set_modified();
+ }
+ 
+ void do_redo(void)
+ {
++    bool gotolinecolumn = FALSE;
+     undo *u = openfile->undotop;
+-    filestruct *f = openfile->current;
+     int len = 0;
+     char *undidmsg, *data;
+ 
+@@ -583,14 +572,9 @@ void do_redo(void)
+ 	return;
+     }
+ 
+-    if (u->lineno <= f->lineno)
+-        for (; f->prev != NULL && f->lineno != u->lineno; f = f->prev)
+-	    ;
+-    else
+-        for (; f->next != NULL && f->lineno != u->lineno; f = f->next)
+-	    ;
+-    if (f->lineno != u->lineno) {
+-        statusbar(_("Internal error: can't match line %d.  Please save your work"), u->lineno);
++    filestruct *f = fsfromline(u->mark_begin_lineno);
++    if (!f) {
++	statusbar(_("Internal error: can't match line %d.  Please save your work."), u->mark_begin_lineno);
+ 	return;
+     }
+ #ifdef DEBUG
+@@ -608,6 +592,7 @@ void do_redo(void)
+ 	strcpy(&data[u->begin + strlen(u->strdata)], &f->data[u->begin]);
+ 	free(f->data);
+ 	f->data = data;
++	goto_line_posx(u->mark_begin_lineno, u->mark_begin_x);
+ 	break;
+     case DEL:
+ 	undidmsg = _("text delete");
+@@ -617,10 +602,13 @@ void do_redo(void)
+ 	strcpy(&data[u->begin], &f->data[u->begin + strlen(u->strdata)]);
+ 	free(f->data);
+ 	f->data = data;
++	openfile->current_x = u->begin;
++	openfile->placewewant = xplustabs();
++	goto_line_posx(u->lineno, u->begin);
+ 	break;
+     case ENTER:
+ 	undidmsg = _("line break");
+-	do_gotolinecolumn(u->lineno, u->begin+1, FALSE, FALSE, FALSE, FALSE);
++	goto_line_posx(u->lineno, u->begin);
+ 	do_enter(TRUE);
+ 	break;
+ #ifndef DISABLE_WRAPPING
+@@ -630,54 +618,56 @@ void do_redo(void)
+ 	    prepend_wrap = TRUE;
+         do_wrap(f, TRUE);
+ 	renumber(f);
++	gotolinecolumn = TRUE;
+ 	break;
+ #endif /* DISABLE_WRAPPING */
+     case UNSPLIT:
+ 	undidmsg = _("line join");
+-	len = strlen(f->data) + strlen(u->strdata + 1);
+-	data = charalloc(len);
+-	strcpy(data, f->data);
+-	strcat(data, u->strdata);
+-	free(f->data);
+-	f->data = data;
++	len = strlen(f->data) + strlen(u->strdata) + 1;
++	f->data = charealloc(f->data, len);
++	strcat(f->data, u->strdata);
+ 	if (f->next != NULL) {
+ 	    filestruct *tmp = f->next;
+ 	    unlink_node(tmp);
+ 	    delete_node(tmp);
+ 	}
+ 	renumber(f);
++	gotolinecolumn = TRUE;
+ 	break;
++    case CUT_EOF:
+     case CUT:
+ 	undidmsg = _("text cut");
+ 	redo_cut(u);
+ 	break;
+-    case UNCUT:
++    case PASTE:
+ 	undidmsg = _("text uncut");
+-	undo_cut(u);
++	redo_paste(u);
+ 	break;
+     case REPLACE:
+ 	undidmsg = _("text replace");
+ 	data = u->strdata;
+ 	u->strdata = f->data;
+ 	f->data = data;
++	goto_line_posx(u->lineno, u->begin);
+ 	break;
+     case INSERT:
+ 	undidmsg = _("text insert");
+-	do_gotolinecolumn(u->lineno, u->begin+1, FALSE, FALSE, FALSE, FALSE);
++	goto_line_posx(u->lineno, u->begin);
+         copy_from_filestruct(u->cutbuffer, u->cutbottom);
+-	openfile->placewewant = xplustabs();
+ 	break;
+     default:
+ 	undidmsg = _("Internal error: unknown type.  Please save your work");
+ 	break;
+-
+     }
+-    do_gotolinecolumn(u->lineno, u->begin, FALSE, FALSE, FALSE, TRUE);
++
++    if (gotolinecolumn)
++	do_gotolinecolumn(u->lineno, u->begin, FALSE, FALSE, FALSE, TRUE);
+     statusbar(_("Redid action (%s)"), undidmsg);
+ 
+     openfile->current_undo = u;
+     openfile->last_action = OTHER;
+ 
++    set_modified();
+ }
+ #endif /* !NANO_TINY */
+ 
+@@ -846,7 +836,6 @@ void add_undo(undo_type current_action)
+     undo *u;
+     char *data;
+     openfilestruct *fs = openfile;
+-    static undo *last_cutu = NULL; /* Last thing we cut to set up the undo for uncut */
+     ssize_t wrap_loc;	/* For calculating split beginning */
+ 
+     if (!ISSET(UNDOABLE))
+@@ -855,9 +844,10 @@ void add_undo(undo_type current_action)
+     /* Ugh, if we were called while cutting not-to-end, non-marked and on the same lineno,
+        we need to  abort here */
+     u = fs->current_undo;
+-    if (current_action == CUT && u && u->type == CUT
+-	&& !u->mark_set && u->lineno == fs->current->lineno)
+-	return;
++    if (u && u->mark_begin_lineno == fs->current->lineno &&
++	((current_action == CUT && u->type == CUT && !u->mark_set) ||
++	(current_action == ADD && u->type == ADD && u->mark_begin_x == fs->current_x)))
++ 	return;
+ 
+     /* Blow away the old undo stack if we are starting from the middle */
+     while (fs->undotop != NULL && fs->undotop != fs->current_undo) {
+@@ -883,8 +873,8 @@ void add_undo(undo_type current_action)
+     u->cutbuffer = NULL;
+     u->cutbottom  = NULL;
+     u->mark_set = 0;
+-    u->mark_begin_lineno = 0;
+-    u->mark_begin_x = 0;
++    u->mark_begin_lineno = fs->current->lineno;
++    u->mark_begin_x =  fs->current_x;
+     u->xflags = 0;
+     u->to_end = FALSE;
+ 
+@@ -893,8 +883,7 @@ void add_undo(undo_type current_action)
+        to restore it later */
+     case ADD:
+         data = charalloc(2);
+-        data[0] = fs->current->data[fs->current_x];
+-        data[1] = '\0';
++	data[0] = '\0';
+         u->strdata = data;
+ 	break;
+     case DEL:
+@@ -932,21 +921,43 @@ void add_undo(undo_type current_action)
+ 	data = mallocstrcpy(NULL, fs->current->data);
+ 	u->strdata = data;
+ 	break;
++    case CUT_EOF:
++	u->to_end = TRUE;
+     case CUT:
+ 	u->mark_set = openfile->mark_set;
+ 	if (u->mark_set) {
+ 	    u->mark_begin_lineno = openfile->mark_begin->lineno;
+ 	    u->mark_begin_x = openfile->mark_begin_x;
+ 	}
+-	u->to_end = (ISSET(CUT_TO_END)) ? TRUE : FALSE;
+-	last_cutu = u;
++	else if (!ISSET(CUT_TO_END) && !u->to_end) {
++	    /* The entire line is being cut regardless of the cursor position. */
++	    u->begin = 0;
++	    u->mark_begin_x = 0;
++	}
+ 	break;
+-    case UNCUT:
+-	if (!last_cutu)
++    case PASTE:
++	if (!cutbuffer)
+ 	    statusbar(_("Internal error: can't setup uncut.  Please save your work."));
+-	else if (last_cutu->type == CUT) {
+-	    u->cutbuffer = last_cutu->cutbuffer;
+-	    u->cutbottom = last_cutu->cutbottom;
++	else {
++	    if (u->cutbuffer)
++		free(u->cutbuffer);
++	    u->cutbuffer = copy_filestruct(cutbuffer);
++	    u->mark_begin_lineno = fs->current->lineno;
++	    u->mark_begin_x =  fs->current_x;
++	    u->lineno =  fs->current->lineno + cutbottom->lineno - cutbuffer->lineno;
++
++	    filestruct *fs_buff = cutbuffer;
++	    if (fs_buff->lineno == cutbottom->lineno)
++		u->begin = fs->current_x +  get_totsize(fs_buff,cutbottom);
++	    else {
++		/* Advance fs_buff to the last line in the cutbuffer. */
++		while (fs_buff->lineno != cutbottom->lineno && fs_buff->next != NULL)
++		    fs_buff = fs_buff->next;
++		assert(fs_buff->next != NULL);
++		u->begin = get_totsize(fs_buff,cutbottom);
++	    }
++
++	    u->mark_set = TRUE;
+ 	}
+ 	break;
+     case ENTER:
+@@ -1008,12 +1019,14 @@ void update_undo(undo_type action)
+ #endif
+         len = strlen(u->strdata) + 2;
+         data = (char *) nrealloc((void *) u->strdata, len * sizeof(char *));
+-        data[len-2] = fs->current->data[fs->current_x];
++        data[len-2] = fs->current->data[fs->current_x - 1];
+         data[len-1] = '\0';
+         u->strdata = (char *) data;
+ #ifdef DEBUG
+ 	fprintf(stderr, "current undo data now \"%s\"\n", u->strdata);
+ #endif
++	u->mark_begin_lineno = fs->current->lineno;
++	u->mark_begin_x =  fs->current_x;
+ 	break;
+     case DEL:
+ 	len = strlen(u->strdata) + 2;
+@@ -1055,18 +1068,37 @@ void update_undo(undo_type action)
+ 	fprintf(stderr, "current undo data now \"%s\"\nu->begin = %d\n", u->strdata, u->begin);
+ #endif
+ 	break;
++    case CUT_EOF:
+     case CUT:
+ 	if (!cutbuffer)
+ 	    break;
+ 	if (u->cutbuffer)
+ 	    free(u->cutbuffer);
+ 	u->cutbuffer = copy_filestruct(cutbuffer);
+-        /* Compute cutbottom for the uncut using out copy */
+-        for (u->cutbottom = u->cutbuffer; u->cutbottom->next != NULL; u->cutbottom = u->cutbottom->next)
+-            ;
++	if (u->mark_set) {
++	    /* If the "marking" operation was from right-->left or
++	     * bottom-->top, then swap the mark points. */
++	    if ((u->lineno == u->mark_begin_lineno && u->begin < u->mark_begin_x)
++			|| u->lineno < u->mark_begin_lineno) {
++		size_t x_loc = u->begin;
++		u->begin = u->mark_begin_x;
++		u->mark_begin_x = x_loc;
++
++		ssize_t line = u->lineno;
++		u->lineno = u->mark_begin_lineno;
++		u->mark_begin_lineno = line;
++	    }
++	} else if (!ISSET(CUT_TO_END)) {
++	    /* Compute cutbottom for the uncut using our copy. */
++	    u->cutbottom = u->cutbuffer;
++	    while (u->cutbottom->next != NULL)
++		u->cutbottom = u->cutbottom->next;
++	    if (!u->to_end)
++		u->lineno++;
++	}
+ 	break;
+     case REPLACE:
+-    case UNCUT:
++    case PASTE:
+ 	add_undo(action);
+ 	break;
+     case INSERT:
+@@ -1087,15 +1119,8 @@ void update_undo(undo_type action)
+     }
+ 
+ #ifdef DEBUG
+-    fprintf(stderr, "Done in udpate_undo (type was %d)\n", action);
++    fprintf(stderr, "Done in update_undo (type was %d)\n", action);
+ #endif
+-    if (fs->last_action != action) {
+-#ifdef DEBUG
+-	fprintf(stderr, "Starting add_undo for new action as it does not match last_action\n");
+-#endif
+-	add_undo(action);
+-    }
+-    fs->last_action = action;
+ }
+ 
+ #endif /* !NANO_TINY */
+diff --git a/src/utils.c b/src/utils.c
+index 675a70a..cb02328 100644
+--- a/src/utils.c
++++ b/src/utils.c
+@@ -476,7 +476,10 @@ size_t get_page_start(size_t column)
+  * current_x. */
+ size_t xplustabs(void)
+ {
+-    return strnlenpt(openfile->current->data, openfile->current_x);
++    if (openfile->current)
++	return strnlenpt(openfile->current->data, openfile->current_x);
++    else
++	return 0;
+ }
+ 
+ /* Return the index in s of the character displayed at the given column,
+-- 
+2.1.0
+
diff --git a/nano.spec b/nano.spec
index 167a0c9..96c5cc6 100644
--- a/nano.spec
+++ b/nano.spec
@@ -1,7 +1,7 @@
 Summary:         A small text editor
 Name:            nano
 Version:         2.3.2
-Release:         4%{?dist}
+Release:         5%{?dist}
 License:         GPLv3+
 Group:           Applications/Editors
 URL:             http://www.nano-editor.org
@@ -18,6 +18,9 @@ Patch2:          0002-use-futimens-if-available-instead-of-utime.patch
 # http://thread.gmane.org/gmane.editors.nano.devel/3081
 Patch3:          0003-Document-the-poslog-P-option-in-nano.1-man-page.patch
 
+# fix intermittent crashes with undo/redo (#1166666)
+Patch4:          0004-Going-to-the-correct-positions-for-undoing-and-redoi.patch
+
 BuildRoot:       %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
 BuildRequires:   autoconf
 BuildRequires:   file-devel
@@ -38,6 +41,7 @@ GNU nano is a small and friendly text editor.
 %patch1 -p1
 %patch2 -p1
 %patch3 -p1
+%patch4 -p1
 
 for f in doc/man/fr/{nano.1,nanorc.5,rnano.1} ; do
   iconv -f iso-8859-1 -t utf-8 -o $f.tmp $f && mv $f.tmp $f
@@ -93,6 +97,9 @@ exit 0
 %{_datadir}/nano
 
 %changelog
+* Fri Nov 21 2014 Kamil Dudka <kdudka at redhat.com> - 2.3.2-5
+- fix intermittent crashes with undo/redo (#1166666)
+
 * Fri Aug 09 2013 Kamil Dudka <kdudka at redhat.com> - 2.3.2-4
 - document the --poslog (-P) option in nano.1 man page
 


More information about the scm-commits mailing list