371 lines
10 KiB
C++
371 lines
10 KiB
C++
/* e_undo.cpp
|
|
*
|
|
* Copyright (c) 1994-1996, Marko Macek
|
|
*
|
|
* You may distribute under the terms of either the GNU General Public
|
|
* License or the Artistic License, as specified in the README file.
|
|
*
|
|
*/
|
|
|
|
#include "fte.h"
|
|
|
|
int EBuffer::NextCommand() {
|
|
if (Match.Row != -1) {
|
|
Draw(Match.Row, Match.Row);
|
|
Match.Col = Match.Row = -1;
|
|
}
|
|
if (View)
|
|
View->SetMsg(0);
|
|
#ifdef CONFIG_UNDOREDO
|
|
return BeginUndo();
|
|
#else
|
|
return 1;
|
|
#endif
|
|
}
|
|
|
|
#ifdef CONFIG_UNDOREDO
|
|
|
|
int EBuffer::PushBlockData() {
|
|
if (BFI(this, BFI_Undo) == 0) return 1;
|
|
if (PushULong(BB.Col) == 0) return 0;
|
|
if (PushULong(BB.Row) == 0) return 0;
|
|
if (PushULong(BE.Col) == 0) return 0;
|
|
if (PushULong(BE.Row) == 0) return 0;
|
|
if (PushULong(BlockMode) == 0) return 0;
|
|
if (PushUChar(ucBlock) == 0) return 0;
|
|
return 1;
|
|
}
|
|
|
|
int EBuffer::BeginUndo() {
|
|
US.NextCmd = 1;
|
|
return 1;
|
|
}
|
|
|
|
int EBuffer::EndUndo() {
|
|
int N = US.Num - 1;
|
|
|
|
assert(N >= 0);
|
|
if (N >= 1) {
|
|
int Order = 1;
|
|
|
|
while (Order < N) Order <<= 1;
|
|
|
|
US.Data = (void **) realloc(US.Data, sizeof(void *) * Order);
|
|
US.Top = (int *) realloc(US.Top, sizeof(int) * Order);
|
|
US.Num--;
|
|
} else {
|
|
free(US.Data); US.Data = 0;
|
|
free(US.Top); US.Top = 0;
|
|
US.Num = 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int EBuffer::PushULong(unsigned long l) {
|
|
// static unsigned long x = l;
|
|
return PushUData(&l, sizeof(unsigned long));
|
|
}
|
|
|
|
int EBuffer::PushUChar(unsigned char ch) {
|
|
return PushUData(&ch, sizeof(unsigned char));
|
|
}
|
|
|
|
|
|
int EBuffer::PushUData(void *data, int len) {
|
|
int N;
|
|
int Order = 1;
|
|
|
|
// printf("UPUSH: %d %c\n", len, *(char *)data); fflush(stdout);
|
|
|
|
if (BFI(this, BFI_Undo) == 0) return 0;
|
|
if (US.Record == 0) return 1;
|
|
if (US.NextCmd || US.Num == 0 || US.Data == 0 || US.Top == 0) {
|
|
N = US.Num;
|
|
if ((BFI(this, BFI_UndoLimit) == -1) || (US.Undo) || (US.Num < BFI(this, BFI_UndoLimit))) {
|
|
N++;
|
|
US.Data = (void **) realloc(US.Data, sizeof(void *) * (N | 255));
|
|
US.Top = (int *) realloc(US.Top, sizeof(int) * (N | 255));
|
|
if (US.Num == US.UndoPtr && !US.Undo)
|
|
US.UndoPtr++;
|
|
US.Num++;
|
|
} else {
|
|
N = US.Num;
|
|
free(US.Data[0]);
|
|
memmove(US.Data, US.Data + 1, (N - 1) * sizeof(US.Data[0]));
|
|
memmove(US.Top, US.Top + 1, (N - 1) * sizeof(US.Top[0]));
|
|
}
|
|
assert(US.Data);
|
|
assert(US.Top);
|
|
N = US.Num - 1;
|
|
US.Data[N] = 0;
|
|
US.Top[N] = 0;
|
|
if (US.NextCmd == 1) {
|
|
US.NextCmd = 0;
|
|
// puts("\x7");
|
|
if (PushULong(CP.Col) == 0) return 0;
|
|
if (PushULong(CP.Row) == 0) return 0;
|
|
if (PushUChar(ucPosition) == 0) return 0;
|
|
// puts("\x7");
|
|
}
|
|
US.NextCmd = 0;
|
|
}
|
|
|
|
N = US.Num - 1;
|
|
assert(N >= 0);
|
|
|
|
if (US.Undo == 0) US.UndoPtr = US.Num;
|
|
|
|
while (Order < (US.Top[N] + len)) Order <<= 1;
|
|
US.Data[N] = realloc(US.Data[N], Order);
|
|
memcpy((char *) US.Data[N] + US.Top[N], data, len);
|
|
US.Top[N] += len;
|
|
return 1;
|
|
}
|
|
|
|
int EBuffer::GetUData(int No, int pos, void **data, int len) {
|
|
int N;
|
|
|
|
if (No == -1)
|
|
N = US.Num - 1;
|
|
else
|
|
N = No;
|
|
|
|
if (BFI(this, BFI_Undo) == 0) return 0;
|
|
if (N < 0) return 0;
|
|
if (US.Data[N] == 0) return 0;
|
|
if (US.Top[N] == 0) return 0;
|
|
|
|
if (pos == -1)
|
|
pos = US.Top[N];
|
|
|
|
|
|
if (pos == 0)
|
|
return 0;
|
|
// printf("N,pos = %d,%d len = %d\n", N, pos, len);
|
|
|
|
assert(pos >= len);
|
|
*data = ((char *) US.Data[N]) + pos - len;
|
|
return 1;
|
|
}
|
|
|
|
#define UGETC(rc,no,pos,what) \
|
|
do { void *d; \
|
|
rc = GetUData(no, pos, &d, sizeof(unsigned char)); \
|
|
*(unsigned char *)&what = *(unsigned char *)d; \
|
|
pos -= sizeof(unsigned char); \
|
|
} while (0)
|
|
|
|
#define UGET(rc,no,pos,what) \
|
|
do { void *d; \
|
|
rc = GetUData(no, pos, &d, sizeof(what)); \
|
|
memcpy((void *)&what, d, sizeof(what)); \
|
|
pos -= sizeof(what); \
|
|
} while (0)
|
|
|
|
int EBuffer::Undo(int undo) {
|
|
unsigned char UndoCmd;
|
|
int rc;
|
|
unsigned long Line;
|
|
unsigned long Len;
|
|
unsigned long ACount;
|
|
unsigned long Col;
|
|
void *data;
|
|
|
|
int No;
|
|
int Pos;
|
|
|
|
if (BFI(this, BFI_Undo) == 0)
|
|
return 0;
|
|
|
|
if (undo)
|
|
No = US.UndoPtr - 1;
|
|
else
|
|
No = US.Num - 1;
|
|
|
|
Pos = US.Top[No];
|
|
|
|
if (No == 0 && Pos == 0) {
|
|
//puts("bottom");
|
|
return 0;
|
|
}
|
|
// for (int i = 0; i < Pos; i++) {
|
|
// printf("%d: %d\n", i, ((char *)US.Data[No])[i]);
|
|
// }
|
|
|
|
// printf("Undo %d %d,%d\n", undo, No, Pos); fflush(stdout);
|
|
|
|
// fprintf(stderr, "\nNo = %d, Num = %d\n", No, US.Num);
|
|
UGETC(rc, No, Pos, UndoCmd);
|
|
while (rc == 1) {
|
|
// printf("%d Undo %d %d,%d\n", UndoCmd, undo, No, Pos); fflush(stdout);
|
|
// for (int i = 0; i < Pos; i++) {
|
|
// printf("%d: %d\n", i, ((char *)US.Data[No])[i]);
|
|
// }
|
|
switch (UndoCmd) {
|
|
case ucInsLine:
|
|
UGET(rc, No, Pos, Line); if (rc == 0) return 0;
|
|
// printf("\tDelLine %d\n", Line);
|
|
if (DelLine(Line) == 0) return 0;
|
|
break;
|
|
|
|
case ucDelLine:
|
|
UGET(rc, No, Pos, Line); if (rc == 0) return 0;
|
|
UGET(rc, No, Pos, Len); if (rc == 0) return 0;
|
|
if (GetUData(No, Pos, &data, Len) == 0) return 0;
|
|
// printf("\tInsLine %d\n", Line);
|
|
if (InsLine(Line, 0) == 0) return 0;
|
|
// printf("\tInsText %d - %d\n", Line, Len);
|
|
if (InsText(Line, 0, Len, (char *) data) == 0) return 0;
|
|
Pos -= Len;
|
|
break;
|
|
|
|
case ucInsChars:
|
|
UGET(rc, No, Pos, ACount); if (rc == 0) return 0;
|
|
UGET(rc, No, Pos, Col); if (rc == 0) return 0;
|
|
UGET(rc, No, Pos, Line); if (rc == 0) return 0;
|
|
// printf("\tDelChars %d %d %d\n", Line, Col, ACount);
|
|
if (DelChars(Line, Col, ACount) == 0) return 0;
|
|
break;
|
|
|
|
case ucDelChars:
|
|
UGET(rc, No, Pos, Line); if (rc == 0) return 0;
|
|
UGET(rc, No, Pos, Col); if (rc == 0) return 0;
|
|
UGET(rc, No, Pos, ACount); if (rc == 0) return 0;
|
|
if (GetUData(No, Pos, &data, ACount) == 0) return 0;
|
|
// printf("\tInsChars %d %d %d\n", Line, Col, ACount);
|
|
if (InsChars(Line, Col, ACount, (char *) data) == 0) return 0;
|
|
Pos -= ACount;
|
|
break;
|
|
|
|
case ucPosition:
|
|
UGET(rc, No, Pos, Line); if (rc == 0) return 0;
|
|
UGET(rc, No, Pos, Col); if (rc == 0) return 0;
|
|
// printf("\tSetPos %d %d\n", Line, Col);
|
|
if (SetPos(Col, Line) == 0) return 0;
|
|
break;
|
|
|
|
case ucBlock:
|
|
{
|
|
EPoint P;
|
|
unsigned long l;
|
|
|
|
// printf("\tBlock\n");
|
|
UGET(rc, No, Pos, l); if (rc == 0) return 0;
|
|
if (BlockMode != (int)l) BlockRedraw();
|
|
BlockMode = l;
|
|
UGET(rc, No, Pos, l); if (rc == 0) return 0; P.Row = l;
|
|
UGET(rc, No, Pos, l); if (rc == 0) return 0; P.Col = l;
|
|
if (SetBE(P) == 0) return 0;
|
|
UGET(rc, No, Pos, l); if (rc == 0) return 0; P.Row = l;
|
|
UGET(rc, No, Pos, l); if (rc == 0) return 0; P.Col = l;
|
|
if (SetBB(P) == 0) return 0;
|
|
}
|
|
break;
|
|
|
|
case ucFoldCreate:
|
|
// puts("ucFoldCreate");
|
|
UGET(rc, No, Pos, Line); if (rc == 0) return 0;
|
|
if (FoldDestroy(Line) == 0) return 0;
|
|
break;
|
|
|
|
case ucFoldDestroy:
|
|
// puts("ucFoldDestroy");
|
|
{
|
|
unsigned long level;
|
|
int ff;
|
|
|
|
UGET(rc, No, Pos, Line); if (rc == 0) return 0;
|
|
UGET(rc, No, Pos, level); if (rc == 0) return 0;
|
|
if (FoldCreate(Line) == 0) return 0;
|
|
|
|
ff = FindFold(Line);
|
|
assert(ff != -1);
|
|
FF[ff].level = (unsigned char) level;
|
|
}
|
|
break;
|
|
case ucFoldPromote:
|
|
// puts("ucFoldPromote");
|
|
UGET(rc, No, Pos, Line); if (rc == 0) return 0;
|
|
if (FoldDemote(Line) == 0) return 0;
|
|
break;
|
|
|
|
case ucFoldDemote:
|
|
// puts("ucFoldDemote");
|
|
UGET(rc, No, Pos, Line); if (rc == 0) return 0;
|
|
if (FoldPromote(Line) == 0) return 0;
|
|
break;
|
|
|
|
case ucFoldOpen:
|
|
// puts("ucFoldOpen");
|
|
UGET(rc, No, Pos, Line); if (rc == 0) return 0;
|
|
if (FoldClose(Line) == 0) return 0;
|
|
break;
|
|
|
|
case ucFoldClose:
|
|
// puts("ucFoldClose");
|
|
UGET(rc, No, Pos, Line); if (rc == 0) return 0;
|
|
if (FoldOpen(Line) == 0) return 0;
|
|
break;
|
|
|
|
case ucModified:
|
|
// printf("\tModified\n");
|
|
Modified = 0;
|
|
break;
|
|
|
|
default:
|
|
assert(1 == "Oops: invalid undo command.\n"[0]);
|
|
}
|
|
// puts("\tok");
|
|
|
|
// fprintf(stderr, "\nNo = %d, Num = %d\n", No, US.Num);
|
|
UGETC(rc, No, Pos, UndoCmd);
|
|
}
|
|
|
|
if (undo)
|
|
US.UndoPtr--;
|
|
else {
|
|
US.UndoPtr++;
|
|
free(US.Data[No]);
|
|
if (EndUndo() == 0) return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
int EBuffer::Redo() {
|
|
int rc;
|
|
|
|
if (BFI(this, BFI_Undo) == 0) return 0;
|
|
|
|
// US.NextCmd = 0; // disable auto push position
|
|
|
|
if (US.Num == 0 || US.UndoPtr == US.Num) {
|
|
Msg(S_INFO, "Nothing to redo.");
|
|
return 0;
|
|
}
|
|
|
|
US.Record = 0;
|
|
rc = Undo(0);
|
|
US.Record = 1;
|
|
return rc;
|
|
}
|
|
|
|
int EBuffer::Undo() {
|
|
int rc;
|
|
|
|
if (BFI(this, BFI_Undo) == 0) return 0;
|
|
|
|
assert(US.Num >= 0);
|
|
assert(US.UndoPtr >= 0);
|
|
if (US.Num == 0 || US.UndoPtr == 0) {
|
|
Msg(S_INFO, "Nothing to undo.");
|
|
return 0;
|
|
}
|
|
|
|
US.Undo = 1;
|
|
rc = Undo(1);
|
|
US.Undo = 0;
|
|
return rc;
|
|
}
|
|
#endif
|