summaryrefslogtreecommitdiff
path: root/app/bin/cundo.c
diff options
context:
space:
mode:
Diffstat (limited to 'app/bin/cundo.c')
-rw-r--r--app/bin/cundo.c72
1 files changed, 68 insertions, 4 deletions
diff --git a/app/bin/cundo.c b/app/bin/cundo.c
index b58d541..4f302ee 100644
--- a/app/bin/cundo.c
+++ b/app/bin/cundo.c
@@ -96,12 +96,15 @@ static int rbuff_record = 0;
EXPORT void Rdump( FILE * outf )
{
- fprintf( outf, "Record Buffer:\n" );
+ time_t clock;
+ time(&clock);
+ fprintf( outf, "Record Buffer %s:\n", ctime(&clock) );
rbuff[RBUFF_SIZE] = '\0';
fprintf( outf, "%s", rbuff+roff );
rbuff[roff] = '\0';
fprintf( outf, "%s", rbuff );
memset( rbuff, 0, sizeof rbuff );
+ fflush( outf );
roff = 0;
}
@@ -152,6 +155,7 @@ typedef struct {
track_p * oldTail;
track_p * newTail;
char * label;
+ dynArr_t deferFree_da;
} undoStack_t, *undoStack_p;
static undoStack_t undoStack[UNDO_STACK_SIZE];
@@ -794,8 +798,6 @@ void UndoStart(
int inx;
int usp;
- LOG( log_undo, 1, ( "UndoStart[%d] (%s) d:%d u:%d us:"SLOG_FMT"\n", undoHead,
- label, undoHead, doCount, undoCount, undoStream.end ) )
if (recordUndo) {
va_start( ap, format );
vsprintf( buff, format, ap );
@@ -817,6 +819,8 @@ void UndoStart(
}
INC_UNDO_INX(undoHead);
+ LOG( log_undo, 1, ( "UndoStart[%d] (%s) d:%d u:%d us:"SLOG_FMT"\n", undoHead,
+ label, doCount, undoCount, undoStream.end ) )
us = &undoStack[undoHead];
SetFileChanged();
@@ -832,6 +836,29 @@ void UndoStart(
if (!TrimStream( &undoStream, us->undoEnd )) {
return;
}
+#ifdef UNDO_DEFER_FREE
+ // We keep a list of objects to be freed when this undoStack entry
+ // is expired, and then free the objects when they can not be referenced
+ // This is tricky
+ // Consider
+ // - Modify the text field of TextNote
+ // - The old text field is added to the deferFree list
+ // - Undo which restores the previous version of the text field
+ // - Modify the text field again
+ // - The old text field is added to the deferFree list again
+ // - Later when the UndoStack expires, we delete the old text field twice!
+ // This is one example of the issues we can hit
+ //
+ // So to resolve this issue, we don't free the old text object,
+ // but live with the memory leak (old versions of text fields)
+ //
+ for ( int inx=0; inx < us->deferFree_da.cnt; inx++ ) {
+ void * p = DYNARR_N( void*, us->deferFree_da, inx );
+ LOG( log_undo, 2, ( " deferFree free: "SLOG_FMT"\n", p ) );
+ MyFree( p );
+ }
+#endif
+ DYNARR_RESET( void*, us->deferFree_da );
} else if (undoCount != 0) {
if (recordUndo) { Rprintf( " Undid N:%d M:%d D:%d\n", us->newCnt, us->modCnt, us->delCnt ); }
/* reusing an undid entry */
@@ -866,6 +893,8 @@ void UndoStart(
undoStack[inx].newTail = NULL;
}
us->newTrks = NULL;
+
+
undoStack[undoHead].trackCount = trackCount;
undoCount = 0;
undoActive = TRUE;
@@ -881,6 +910,39 @@ void UndoStart(
/**
+ * Special free() for embedded objects that should preserved for Undo
+ *
+ * See BUG 555, 527
+ *
+ * Scenario:
+ * Some track types (compound) contain references (.title) in their extraData
+ * which Undo doesn't know about.
+ * The caller free's the reference and updates the reference to a new version of the data.
+ * The old data is reallocated
+ * When we Undo the track, the reference is restored to the old data
+ * so the reference (.title) now points to garbage
+ *
+ * The fix is to not free the old data immediately,
+ * but save a reference in UndoStack[].deferFree_da
+ * When the UndoStack[] is reused (in UndoStart) we then free the old memory
+ * (Since is won't be used any more)
+ *
+ * This mechanism can be used for other objects which now use StoreTrackData/ReplaceTrackData
+ *
+ */
+void UndoDeferFree( void * p )
+{
+ undoStack_p us;
+ if ( p == NULL ) {
+ return;
+ }
+ us = &undoStack[undoHead];
+ DYNARR_APPEND( void*, us->deferFree_da, 10 );
+ DYNARR_LAST( void*, us->deferFree_da ) = p;
+ LOG( log_undo, 2, ( " deferFree defer: "SLOG_FMT"\n", p ) );
+}
+
+/**
* Record Modify'd track for Undo
* \param trk
*
@@ -1040,7 +1102,9 @@ void UndoClear( void )
ClearStream( &undoStream );
ClearStream( &redoStream );
for (inx=0; inx<UNDO_STACK_SIZE; inx++) {
- undoStack[inx].undoStart = undoStack[inx].undoEnd = 0;
+ undoStack_p us = &undoStack[inx];
+ us->undoStart = us->undoEnd = 0;
+ DYNARR_INIT( void*, us->deferFree_da );
}
SetButtons( FALSE, FALSE );
}