Allow Undo to go beyond the last block in the journal.

This commit is contained in:
Jonathan Moore Liles 2008-06-08 17:42:26 -05:00
parent fe941f7185
commit 4235e0ee05
3 changed files with 88 additions and 90 deletions

View File

@ -38,7 +38,8 @@ using std::max;
FILE *Loggable::_fp; FILE *Loggable::_fp;
int Loggable::_log_id = 0; int Loggable::_log_id = 0;
int Loggable::_level = 0; int Loggable::_level = 0;
int Loggable::_undo_index = 1;
off_t Loggable::_undo_offset = 0;
size_t Loggable::_loggables_size = 0; size_t Loggable::_loggables_size = 0;
Loggable ** Loggable::_loggables; Loggable ** Loggable::_loggables;
@ -82,6 +83,7 @@ Loggable::open ( const char *filename )
} }
fseek( fp, 0, SEEK_END ); fseek( fp, 0, SEEK_END );
_undo_offset = ftell( fp );
Loggable::_fp = fp; Loggable::_fp = fp;
@ -236,6 +238,8 @@ Loggable::do_this ( const char *s, bool reverse )
sscanf( s, "%s %*X %s%*[^\n<]<< %a[^\n]", classname, command, &arguments ); sscanf( s, "%s %*X %s%*[^\n<]<< %a[^\n]", classname, command, &arguments );
create = "destroy"; create = "destroy";
destroy = "create"; destroy = "create";
DMESSAGE( "undoing \"%s\"", s );
} }
else else
{ {
@ -286,104 +290,85 @@ Loggable::do_this ( const char *s, bool reverse )
return true; return true;
} }
static int
backwards_fgetc ( FILE *fp )
{
int c;
if ( fseek( fp, -1, SEEK_CUR ) != 0 )
return -1;
c = fgetc( fp );
fseek( fp, -1, SEEK_CUR );
return c;
}
static char *
backwards_fgets ( char *s, int size, FILE *fp )
{
if ( fseek( fp, -1, SEEK_CUR ) != 0 )
return NULL;
int c;
while ( ( c = backwards_fgetc( fp ) ) >= 0 )
if ( '\n' == c )
break;
long here = ftell( fp );
fseek( fp, 1, SEEK_CUR );
char *r = fgets( s, size, fp );
fseek( fp, here, SEEK_SET );
return r;
}
/** Reverse the last journal transaction */ /** Reverse the last journal transaction */
void void
Loggable::undo ( void ) Loggable::undo ( void )
{ {
char *buf = new char[ BUFSIZ ]; const int bufsiz = 1024;
char buf[bufsiz];
// fflush( _fp );
/* FIXME: handle more than the first block!!! */
fseek( _fp, 0, SEEK_END );
size_t len = ftell( _fp );
fseek( _fp, 0 - (BUFSIZ > len ? len : BUFSIZ), SEEK_END );
len = fread( buf, 1, BUFSIZ, _fp );
char *s = buf + len - 1;
int i = 1;
/* move back _undo_index items from the end */
for ( int j = _undo_index; j-- ; )
for ( --s; *s && s >= buf; --s, ++i )
{
if ( *s == '\n' )
{
if ( *(s + 1) == '\t' )
continue;
if ( *(s + 1) == '}' )
{
*(s + 1) = NULL;
continue;
}
break;
}
}
s++;
buf[ len ] = NULL;
if ( ! strlen( s ) )
{
WARNING( "corrupt undo file or no undo entries." );
return;
}
char *b = s;
s += strlen( s ) - 1;
if ( strtok( b, "\n" ) == NULL )
FATAL( "empty undo transaction!\n" );
int n = 1;
while ( strtok( NULL, "\n" ) )
++n;
int ui = _undo_index;
block_start(); block_start();
if ( strcmp( b, "{" ) ) long here = ftell( _fp );
fseek( _fp, _undo_offset, SEEK_SET );
backwards_fgets( buf, bufsiz, _fp );
if ( ! strcmp( buf, "}\n" ) )
{ {
/* It's a single undo, get rid of trailing messages in this block */ DMESSAGE( "undoing block" );
for ( ;; )
n = 1;
s = b + 2;
s += strlen( s ) - 1;
}
while ( n-- )
{ {
while ( s >= b && *(--s) ); backwards_fgets( buf, bufsiz, _fp );
s++; char *s = buf;
if ( *s != '\t' )
if ( ! strcmp( s, "{" ) )
break; break;
else
if ( *s == '\t' ) ++s;
s++;
DMESSAGE( "undoing \"%s\"", s );
do_this( s, true ); do_this( s, true );
s -= 2;
} }
}
else
do_this( buf, true );
off_t uo = ftell( _fp );
ASSERT( _undo_offset <= here, "WTF?" );
block_end(); block_end();
_undo_index = ui + 2; _undo_offset = uo;
delete[] buf;
} }
void void
@ -463,7 +448,8 @@ Loggable::compact ( void )
if ( ! snapshot( _fp ) ) if ( ! snapshot( _fp ) )
FATAL( "Could not write snapshot!" ); FATAL( "Could not write snapshot!" );
_undo_index = 1; fseek( _fp, 0, SEEK_END );
// _undo_index = 1;
} }
/** Buffered sprintf wrapper */ /** Buffered sprintf wrapper */
@ -512,10 +498,6 @@ Loggable::flush ( void )
int n = _transaction.size(); int n = _transaction.size();
if ( n )
/* something done, reset undo index */
_undo_index = 1;
if ( n > 1 ) if ( n > 1 )
fprintf( _fp, "{\n" ); fprintf( _fp, "{\n" );
@ -536,6 +518,9 @@ Loggable::flush ( void )
if ( n > 1 ) if ( n > 1 )
fprintf( _fp, "}\n" ); fprintf( _fp, "}\n" );
if ( n )
/* something done, reset undo index */
_undo_offset = ftell( _fp );
fflush( _fp ); fflush( _fp );
} }

View File

@ -68,7 +68,10 @@ class Loggable
static FILE *_fp; static FILE *_fp;
static int _log_id; static int _log_id;
static int _level; static int _level;
static int _undo_index;
/* static int _undo_index; */
static off_t _undo_offset;
static size_t _loggables_size; static size_t _loggables_size;
static Loggable ** _loggables; static Loggable ** _loggables;
@ -148,7 +151,9 @@ public:
static bool open ( const char *filename ); static bool open ( const char *filename );
static bool close ( void ); static bool close ( void );
static void undo ( void ); static void undo ( void );
static int undo_index ( void ) { return _undo_index; }
/* static int undo_index ( void ) { return _undo_index; } */
static void compact ( void ); static void compact ( void );
static static

View File

@ -220,18 +220,26 @@ public:
static void static void
delete_selected ( void ) delete_selected ( void )
{ {
Loggable::block_start();
while ( _selection.size() ) while ( _selection.size() )
delete _selection.front(); delete _selection.front();
Loggable::block_end();
} }
static void static void
select_none ( void ) select_none ( void )
{ {
Loggable::block_start();
while ( _selection.size() ) while ( _selection.size() )
{ {
_selection.front()->redraw(); _selection.front()->redraw();
_selection.pop_front(); _selection.pop_front();
} }
Loggable::block_end();
} }
static Sequence_Widget *current ( void ) { return Sequence_Widget::_current; } static Sequence_Widget *current ( void ) { return Sequence_Widget::_current; }