1 /* e_undo.cpp
2 *
3 * Copyright (c) 1994-1996, Marko Macek
4 *
5 * You may distribute under the terms of either the GNU General Public
6 * License or the Artistic License, as specified in the README file.
7 *
8 */
9
10 #include "e_undo.h"
11
12 #include "o_buflist.h"
13 #include "s_util.h"
14 #include "sysdep.h"
15
16 #include <stdio.h>
17
NextCommand()18 int EBuffer::NextCommand() {
19 if (Match.Row != -1) {
20 Draw(Match.Row, Match.Row);
21 Match.Col = Match.Row = -1;
22 }
23 if (View)
24 View->SetMsg(0);
25 #ifdef CONFIG_UNDOREDO
26 return BeginUndo();
27 #else
28 return 1;
29 #endif
30 }
31
32 #ifdef CONFIG_UNDOREDO
33
PushBlockData()34 int EBuffer::PushBlockData() {
35 if (BFI(this, BFI_Undo) == 0) return 1;
36 if (PushULong(BB.Col) == 0) return 0;
37 if (PushULong(BB.Row) == 0) return 0;
38 if (PushULong(BE.Col) == 0) return 0;
39 if (PushULong(BE.Row) == 0) return 0;
40 if (PushULong(BlockMode) == 0) return 0;
41 if (PushUChar(ucBlock) == 0) return 0;
42 return 1;
43 }
44
BeginUndo()45 int EBuffer::BeginUndo() {
46 US.NextCmd = 1;
47 return 1;
48 }
49
EndUndo()50 int EBuffer::EndUndo() {
51 int N = US.Num - 1;
52
53 assert(N >= 0);
54 if (N >= 1) {
55 int Order = 1;
56
57 while (Order < N) Order <<= 1;
58
59 US.Data = (void **) realloc(US.Data, sizeof(void *) * Order);
60 US.Top = (int *) realloc(US.Top, sizeof(int) * Order);
61 US.Num--;
62 } else {
63 free(US.Data); US.Data = 0;
64 free(US.Top); US.Top = 0;
65 US.Num = 0;
66 }
67 return 1;
68 }
69
PushULong(unsigned long l)70 int EBuffer::PushULong(unsigned long l) {
71 // static unsigned long x = l;
72 return PushUData(&l, sizeof(unsigned long));
73 }
74
PushUChar(unsigned char ch)75 int EBuffer::PushUChar(unsigned char ch) {
76 return PushUData(&ch, sizeof(unsigned char));
77 }
78
79
PushUData(const void * data,size_t len)80 int EBuffer::PushUData(const void *data, size_t len) {
81 int N;
82 int Order = 1;
83
84 // printf("UPUSH: %d %c\n", len, *(char *)data); fflush(stdout);
85
86 if (BFI(this, BFI_Undo) == 0) return 0;
87 if (US.Record == 0) return 1;
88 if (US.NextCmd || US.Num == 0 || US.Data == 0 || US.Top == 0) {
89 N = US.Num;
90 if ((BFI(this, BFI_UndoLimit) == -1) || (US.Undo) || (US.Num < BFI(this, BFI_UndoLimit))) {
91 N++;
92 US.Data = (void **) realloc(US.Data, sizeof(void *) * (N | 255));
93 US.Top = (int *) realloc(US.Top, sizeof(int) * (N | 255));
94 if (US.Num == US.UndoPtr && !US.Undo)
95 US.UndoPtr++;
96 US.Num++;
97 } else {
98 N = US.Num;
99 free(US.Data[0]);
100 memmove(US.Data, US.Data + 1, (N - 1) * sizeof(US.Data[0]));
101 memmove(US.Top, US.Top + 1, (N - 1) * sizeof(US.Top[0]));
102 }
103 assert(US.Data);
104 assert(US.Top);
105 N = US.Num - 1;
106 US.Data[N] = 0;
107 US.Top[N] = 0;
108 if (US.NextCmd == 1) {
109 US.NextCmd = 0;
110 // puts("\x7");
111 if (PushULong(CP.Col) == 0) return 0;
112 if (PushULong(CP.Row) == 0) return 0;
113 if (PushUChar(ucPosition) == 0) return 0;
114 // puts("\x7");
115 }
116 US.NextCmd = 0;
117 }
118
119 N = US.Num - 1;
120 assert(N >= 0);
121
122 if (US.Undo == 0) US.UndoPtr = US.Num;
123
124 while (Order < (US.Top[N] + len)) Order <<= 1;
125 US.Data[N] = realloc(US.Data[N], Order);
126 memcpy((char *) US.Data[N] + US.Top[N], data, len);
127 US.Top[N] += len;
128 return 1;
129 }
130
GetUData(int No,int pos,void ** data,size_t len)131 int EBuffer::GetUData(int No, int pos, void **data, size_t len) {
132 int N;
133
134 if (No == -1)
135 N = US.Num - 1;
136 else
137 N = No;
138
139 if (BFI(this, BFI_Undo) == 0) return 0;
140 if (N < 0) return 0;
141 if (US.Data[N] == 0) return 0;
142 if (US.Top[N] == 0) return 0;
143
144 if (pos == -1)
145 pos = US.Top[N];
146
147
148 if (pos == 0)
149 return 0;
150 // printf("N,pos = %d,%d len = %d\n", N, pos, len);
151
152 assert(pos >= len);
153 *data = ((char *) US.Data[N]) + pos - len;
154 return 1;
155 }
156
157 #define UGETC(rc,no,pos,what) \
158 do { void *d; \
159 rc = GetUData(no, pos, &d, sizeof(unsigned char)); \
160 *(unsigned char *)&what = *(unsigned char *)d; \
161 pos -= (int) sizeof(unsigned char); \
162 } while (0)
163
164 #define UGET(rc,no,pos,what) \
165 do { void *d; \
166 rc = GetUData(no, pos, &d, sizeof(what)); \
167 memcpy(&what, d, sizeof(what)); \
168 pos -= (int) sizeof(what); \
169 } while (0)
170
Undo(int undo)171 int EBuffer::Undo(int undo) {
172 unsigned char UndoCmd;
173 int rc;
174 unsigned long Line;
175 unsigned long Len;
176 unsigned long ACount;
177 unsigned long Col;
178 void *data;
179
180 int No;
181 int Pos;
182
183 if (BFI(this, BFI_Undo) == 0)
184 return 0;
185
186 if (undo)
187 No = US.UndoPtr - 1;
188 else
189 No = US.Num - 1;
190
191 Pos = US.Top[No];
192
193 if (No == 0 && Pos == 0) {
194 //puts("bottom");
195 return 0;
196 }
197 // for (int i = 0; i < Pos; i++) {
198 // printf("%d: %d\n", i, ((char *)US.Data[No])[i]);
199 // }
200
201 // printf("Undo %d %d,%d\n", undo, No, Pos); fflush(stdout);
202
203 // fprintf(stderr, "\nNo = %d, Num = %d\n", No, US.Num);
204 UGETC(rc, No, Pos, UndoCmd);
205 while (rc == 1) {
206 // printf("%d Undo %d %d,%d\n", UndoCmd, undo, No, Pos); fflush(stdout);
207 // for (int i = 0; i < Pos; i++) {
208 // printf("%d: %d\n", i, ((char *)US.Data[No])[i]);
209 // }
210 switch (UndoCmd) {
211 case ucInsLine:
212 UGET(rc, No, Pos, Line); if (rc == 0) return 0;
213 // printf("\tDelLine %d\n", Line);
214 if (DelLine(Line) == 0) return 0;
215 break;
216
217 case ucDelLine:
218 UGET(rc, No, Pos, Line); if (rc == 0) return 0;
219 UGET(rc, No, Pos, Len); if (rc == 0) return 0;
220 if (GetUData(No, Pos, &data, Len) == 0) return 0;
221 // printf("\tInsLine %d\n", Line);
222 if (InsLine(Line, 0) == 0) return 0;
223 // printf("\tInsText %d - %d\n", Line, Len);
224 if (InsText(Line, 0, Len, (char *) data) == 0) return 0;
225 Pos -= Len;
226 break;
227
228 case ucInsChars:
229 UGET(rc, No, Pos, ACount); if (rc == 0) return 0;
230 UGET(rc, No, Pos, Col); if (rc == 0) return 0;
231 UGET(rc, No, Pos, Line); if (rc == 0) return 0;
232 // printf("\tDelChars %d %d %d\n", Line, Col, ACount);
233 if (DelChars(Line, Col, ACount) == 0) return 0;
234 break;
235
236 case ucDelChars:
237 UGET(rc, No, Pos, Line); if (rc == 0) return 0;
238 UGET(rc, No, Pos, Col); if (rc == 0) return 0;
239 UGET(rc, No, Pos, ACount); if (rc == 0) return 0;
240 if (GetUData(No, Pos, &data, ACount) == 0) return 0;
241 // printf("\tInsChars %d %d %d\n", Line, Col, ACount);
242 if (InsChars(Line, Col, ACount, (char *) data) == 0) return 0;
243 Pos -= ACount;
244 break;
245
246 case ucPosition:
247 UGET(rc, No, Pos, Line); if (rc == 0) return 0;
248 UGET(rc, No, Pos, Col); if (rc == 0) return 0;
249 // printf("\tSetPos %d %d\n", Line, Col);
250 if (SetPos(Col, Line) == 0) return 0;
251 break;
252
253 case ucBlock:
254 {
255 EPoint P;
256 unsigned long l;
257
258 // printf("\tBlock\n");
259 UGET(rc, No, Pos, l); if (rc == 0) return 0;
260 if (BlockMode != (int)l) BlockRedraw();
261 BlockMode = (int)l;
262 UGET(rc, No, Pos, l); if (rc == 0) return 0; P.Row = (int)l;
263 UGET(rc, No, Pos, l); if (rc == 0) return 0; P.Col = (int)l;
264 if (SetBE(P) == 0) return 0;
265 UGET(rc, No, Pos, l); if (rc == 0) return 0; P.Row = (int)l;
266 UGET(rc, No, Pos, l); if (rc == 0) return 0; P.Col = (int)l;
267 if (SetBB(P) == 0) return 0;
268 }
269 break;
270
271 case ucFoldCreate:
272 // puts("ucFoldCreate");
273 UGET(rc, No, Pos, Line); if (rc == 0) return 0;
274 if (FoldDestroy(Line) == 0) return 0;
275 break;
276
277 case ucFoldDestroy:
278 // puts("ucFoldDestroy");
279 {
280 unsigned int level;
281 int ff;
282
283 UGET(rc, No, Pos, Line); if (rc == 0) return 0;
284 UGET(rc, No, Pos, level); if (rc == 0) return 0;
285 if (FoldCreate(Line) == 0) return 0;
286
287 ff = FindFold(Line);
288 assert(ff != -1);
289 FF[ff].level = (unsigned char) level;
290 }
291 break;
292 case ucFoldPromote:
293 // puts("ucFoldPromote");
294 UGET(rc, No, Pos, Line); if (rc == 0) return 0;
295 if (FoldDemote(Line) == 0) return 0;
296 break;
297
298 case ucFoldDemote:
299 // puts("ucFoldDemote");
300 UGET(rc, No, Pos, Line); if (rc == 0) return 0;
301 if (FoldPromote(Line) == 0) return 0;
302 break;
303
304 case ucFoldOpen:
305 // puts("ucFoldOpen");
306 UGET(rc, No, Pos, Line); if (rc == 0) return 0;
307 if (FoldClose(Line) == 0) return 0;
308 break;
309
310 case ucFoldClose:
311 // puts("ucFoldClose");
312 UGET(rc, No, Pos, Line); if (rc == 0) return 0;
313 if (FoldOpen(Line) == 0) return 0;
314 break;
315
316 case ucModified:
317 // printf("\tModified\n");
318 Modified = 0;
319 break;
320
321 case ucPlaceUserBookmark:
322 //puts ("ucPlaceUserBookmark");
323 UGET(rc, No, Pos, ACount); if (rc == 0) return 0;
324 if (GetUData(No, Pos, &data, ACount) == 0) return 0;
325 Pos -= ACount;
326 UGET(rc, No, Pos, Col); if (rc == 0) return 0;
327 UGET(rc, No, Pos, Line); if (rc == 0) return 0;
328 // if (Col == -1 || Line == -1) {
329 if (Col == (unsigned long)-1 || Line == (unsigned long)-1) {
330 if (RemoveUserBookmark ((const char *)data)==0) return 0;
331 } else {
332 if (PlaceUserBookmark ((const char *)data,EPoint (Line,Col))==0) return 0;
333 }
334 break;
335
336 case ucRemoveUserBookmark:
337 //puts("ucRemoveUserBookmark");
338 UGET(rc, No, Pos, ACount); if (rc == 0) return 0;
339 if (GetUData(No, Pos, &data, ACount) == 0) return 0;
340 Pos -= ACount;
341 UGET(rc, No, Pos, Col); if (rc == 0) return 0;
342 UGET(rc, No, Pos, Line); if (rc == 0) return 0;
343 if (PlaceUserBookmark ((const char *)data,EPoint (Line,Col))==0) return 0;
344 break;
345
346 default:
347 fprintf(stderr, "Oops: invalid undo command %d.\n", UndoCmd);
348 return 0;
349 //assert(1 == "Oops: invalid undo command.\n"[0]);
350 }
351 // puts("\tok");
352
353 // fprintf(stderr, "\nNo = %d, Num = %d\n", No, US.Num);
354 UGETC(rc, No, Pos, UndoCmd);
355 }
356
357 if (undo)
358 US.UndoPtr--;
359 else {
360 US.UndoPtr++;
361 free(US.Data[No]);
362 if (EndUndo() == 0) return 0;
363 }
364
365 return 1;
366 }
367
Redo()368 int EBuffer::Redo() {
369 int rc;
370
371 if (BFI(this, BFI_Undo) == 0) return 0;
372
373 // US.NextCmd = 0; // disable auto push position
374
375 if (US.Num == 0 || US.UndoPtr == US.Num) {
376 Msg(S_INFO, "Nothing to redo.");
377 return 0;
378 }
379
380 US.Record = 0;
381 rc = Undo(0);
382 US.Record = 1;
383 return rc;
384 }
385
Undo()386 int EBuffer::Undo() {
387 int rc;
388
389 if (BFI(this, BFI_Undo) == 0) return 0;
390
391 assert(US.Num >= 0);
392 assert(US.UndoPtr >= 0);
393 if (US.Num == 0 || US.UndoPtr == 0) {
394 Msg(S_INFO, "Nothing to undo.");
395 return 0;
396 }
397
398 US.Undo = 1;
399 rc = Undo(1);
400 US.Undo = 0;
401 return rc;
402 }
403 #endif
404