This repository has been archived on 2023-07-11. You can view files and clone it, but cannot push or open issues or pull requests.
fte/e_undo.cpp

371 lines
10 KiB
C++
Raw Normal View History

/* 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