joe-3.1jupp31.tgz (die zweite Klappe…)
[alioth/jupp.git] / undo.c
1 /* $MirOS: contrib/code/jupp/undo.c,v 1.3 2010/04/08 15:31:05 tg Exp $ */
2 /*
3  *      UNDO system
4  *      Copyright
5  *              (C) 1992 Joseph H. Allen
6  *
7  *      This file is part of JOE (Joe's Own Editor)
8  */
9 #include "config.h"
10 #include "types.h"
11
12 #ifdef HAVE_STDLIB_H
13 #include <stdlib.h>
14 #endif
15
16 #include "b.h"
17 #include "blocks.h"
18 #include "queue.h"
19 #include "ublock.h"
20 #include "utils.h"
21 #include "w.h"
22
23 #define SMALL 1024
24
25 static UNDO undos = { {&undos, &undos} };
26 static UNDO frdos = { {&frdos, &frdos} };
27
28 int inundo = 0;
29 int inredo = 0;
30
31 extern int dostaupd;
32
33 UNDOREC yanked = { {&yanked, &yanked} };
34 int nyanked = 0;
35 int inyank = 0;
36 int justkilled = 0;
37
38 UNDOREC frrecs = { {&frrecs, &frrecs} };
39
40 static UNDOREC *alrec(void)
41 {
42         UNDOREC *rec = (UNDOREC *) alitem(&frrecs, sizeof(UNDOREC));
43
44         return rec;
45 }
46
47 static void frrec(UNDOREC *rec)
48 {
49         if (rec->del) {
50                 if (rec->len < SMALL)
51                         joe_free(rec->small);
52                 else {
53                         B *b = rec->big;
54
55                         bonline(b);
56                         brm(b);
57                 }
58         }
59         enquef(UNDOREC, link, &frrecs, rec);
60 }
61
62 UNDO *undomk(B *b)
63 {
64         UNDO *undo = (UNDO *) alitem(&frdos, sizeof(UNDO));
65
66         undo->nrecs = 0;
67         undo->ptr = NULL;
68         undo->last = NULL;
69         undo->first = NULL;
70         undo->b = b;
71         izque(UNDOREC, link, &undo->recs);
72         enquef(UNDO, link, &undos, undo);
73         return undo;
74 }
75
76 void undorm(UNDO *undo)
77 {
78         frchn(&frrecs, &undo->recs);
79         demote(UNDO, link, &frdos, undo);
80 }
81
82 static void doundo(BW *bw, UNDOREC *ptr)
83 {
84         dostaupd = 1;
85
86         if (ptr->del) {
87                 if (ptr->len < SMALL)
88                         binsm(bw->cursor, ptr->small, (int) ptr->len);
89                 else {
90                         B *b = ptr->big;
91
92                         bonline(b);
93                         binsb(bw->cursor, bcpy(b->bof, b->eof));
94                         boffline(b);
95                 }
96         } else {
97                 P *q = pdup(bw->cursor);
98
99                 pfwrd(q, ptr->len);
100                 bdel(bw->cursor, q);
101                 prm(q);
102         }
103         bw->b->changed = ptr->changed;
104 }
105
106 int uundo(BW *bw)
107 {
108         UNDOREC *upto;
109         UNDO *undo = bw->b->undo;
110
111         if (!undo)
112                 return -1;
113         if (!undo->nrecs)
114                 return -1;
115         if (!undo->ptr) {
116                 pgoto(bw->cursor, undo->recs.link.prev->where);
117                 undo->ptr = &undo->recs;
118                 /* If this return is uncommented, then uundo will jump
119                    to where the undo is about to occur before actually
120                    undoing anything */
121                 /* return 0; */
122         }
123         if (undo->ptr->link.prev == &undo->recs)
124                 return -1;
125         upto = undo->ptr->link.prev->unit;
126       loop:
127         undo->ptr = undo->ptr->link.prev;
128         pgoto(bw->cursor, undo->ptr->where);
129         inundo = 1;
130         doundo(bw, undo->ptr);
131         inundo = 0;
132         if (upto && upto != undo->ptr)
133                 goto loop;
134         return 0;
135 }
136
137 int uredo(BW *bw)
138 {
139         UNDOREC *upto;
140         UNDOREC *ptr;
141         UNDO *undo = bw->b->undo;
142
143         if (!undo)
144                 return -1;
145         if (!undo->ptr)
146                 return -1;
147         if (undo->ptr == &undo->recs)
148                 return -1;
149         upto = undo->recs.link.prev->unit;
150         do {
151                 ptr = undo->recs.link.prev;
152                 pgoto(bw->cursor, ptr->where);
153                 inredo = 1;
154                 doundo(bw, ptr);
155                 inredo = 0;
156                 frrec(deque_f(UNDOREC, link, ptr));
157                 undo->ptr = undo->ptr->link.next;
158         } while (upto && upto != ptr);
159         return 0;
160 }
161
162 void umclear(void)
163 {
164         UNDO *undo;
165
166         for (undo = undos.link.next; undo != &undos; undo = undo->link.next) {
167                 UNDOREC *rec;
168
169                 for (rec = undo->recs.link.next; rec != &undo->recs; rec = rec->link.next)
170                         rec->min = 0;
171         }
172 }
173
174 /* Eliminate excess undo records */
175
176 static void undogc(UNDO *undo)
177 {
178         UNDOREC *unit = undo->recs.link.next->unit;
179         int flg = 0;
180
181         if (undo->ptr && undo->ptr->link.prev == &undo->recs)
182                 flg = 1;
183         if (unit)
184                 while (unit != undo->recs.link.next)
185                         frrec(deque_f(UNDOREC, link, undo->recs.link.next));
186         frrec(deque_f(UNDOREC, link, undo->recs.link.next));
187         --undo->nrecs;
188         if (flg)
189                 undo->ptr = undo->recs.link.next;
190 }
191
192 void undomark(void)
193 {
194         UNDO *undo;
195
196         for (undo = undos.link.next; undo != &undos; undo = undo->link.next)
197                 if (undo->first) {
198                         undo->first->unit = undo->last;
199                         undo->last->unit = undo->first;
200                         undo->first = undo->last = 0;
201                         if (++undo->nrecs == UNDOKEEP)
202                                 undogc(undo);
203                 }
204 }
205
206 /* Delete the alternate time-line after the user has resumed editing after
207  * undoing some number of changes
208  */
209
210 static void undoover(UNDO *undo)
211 {
212         undo->ptr = NULL;
213 }
214
215 void undoins(UNDO *undo, P *p, long size)
216 {
217         UNDOREC *rec;
218
219         if (inredo)
220                 return;
221         if (!inundo)
222                 if (undo->ptr && undo->ptr != &undo->recs)
223                         undoover(undo);
224         rec = undo->recs.link.prev;
225         if (rec != &undo->recs && rec->min && !rec->del && (p->byte == rec->where + rec->len || p->byte == rec->where))
226                 rec->len += size;
227         else {
228                 rec = alrec();
229                 rec->del = 0;
230                 if (!undo->first)
231                         undo->first = rec;
232                 undo->last = rec;
233                 rec->where = p->byte;
234                 rec->min = 1;
235                 rec->unit = NULL;
236                 rec->len = size;
237                 rec->changed = undo->b->changed;
238                 enqueb(UNDOREC, link, &undo->recs, rec);
239         }
240 }
241
242
243 int uyapp(BW *bw)
244 {
245         UNDOREC *rec = yanked.link.prev;
246
247         if (rec != &yanked)
248                 rec->where = bw->cursor->byte;
249         return 0;
250 }
251
252 static void yankdel(long where, B *b)
253 {
254         UNDOREC *rec;
255         long size = b->eof->byte;
256
257         /* Store in yank buffer */
258         rec = yanked.link.prev;
259         if (!inyank) {
260                 if (rec != &yanked && where == rec->where && justkilled) {
261                         if (rec->len + size >= SMALL) {
262                                 if (rec->len < SMALL) {
263                                         rec->big = bmk(NULL);
264                                         binsm(rec->big->bof, rec->small, (int) rec->len);
265                                         boffline(rec->big);
266                                         joe_free(rec->small);
267                                 }
268                                 bonline(rec->big);
269                                 binsb(rec->big->eof, bcpy(b->bof, b->eof));
270                                 boffline(rec->big);
271                         } else {
272                                 rec->small = (unsigned char *) joe_realloc(rec->small, rec->len + size);
273                                 brmem(b->bof, rec->small + rec->len, (int) size);
274                         }
275                         rec->len += size;
276                 } else if (rec != &yanked && where + size == rec->where && justkilled) {
277                         if (rec->len + size >= SMALL) {
278                                 if (rec->len < SMALL) {
279                                         rec->big = bmk(NULL);
280                                         binsm(rec->big->bof, rec->small, (int) rec->len);
281                                         boffline(rec->big);
282                                         joe_free(rec->small);
283                                 }
284                                 bonline(rec->big);
285                                 binsb(rec->big->bof, bcpy(b->bof, b->eof));
286                                 boffline(rec->big);
287                         } else {
288                                 rec->small = (unsigned char *) joe_realloc(rec->small, rec->len + size);
289                                 mmove(rec->small + size, rec->small, (int) rec->len);
290                                 brmem(b->bof, rec->small, (int) size);
291                         }
292                         rec->len += size;
293                         rec->where = where;
294                 } else {
295                         if (++nyanked == 100) {
296                                 frrec(deque_f(UNDOREC, link, yanked.link.next));
297                                 --nyanked;
298                         }
299                         rec = alrec();
300                         if (size < SMALL) {
301                                 rec->small = (unsigned char *) joe_malloc(size);
302                                 brmem(b->bof, rec->small, (int) b->eof->byte);
303                         } else {
304                                 rec->big = bcpy(b->bof, b->eof);
305                                 boffline(rec->big);
306                         }
307                         rec->where = where;
308                         rec->len = size;
309                         rec->del = 1;
310                         enqueb(UNDOREC, link, &yanked, rec);
311                 }
312         }
313 }
314
315 void undodel(UNDO *undo, long where, B *b)
316 {
317         UNDOREC *rec;
318         long size = b->eof->byte;
319
320         if (inredo) {
321                 brm(b);
322                 return;
323         }
324         if (!inundo)
325                 if (undo->ptr && undo->ptr != &undo->recs)
326                         undoover(undo);
327
328         yankdel(where, b);
329
330         /* Store in undo buffer */
331         rec = undo->recs.link.prev;
332         if (rec != &undo->recs && rec->min && rec->del && where == rec->where) {
333                 if (rec->len + size >= SMALL) {
334                         if (rec->len < SMALL) {
335                                 rec->big = bmk(NULL);
336                                 binsm(rec->big->bof, rec->small, (int) rec->len);
337                                 boffline(rec->big);
338                                 joe_free(rec->small);
339                         }
340                         bonline(rec->big);
341                         binsb(rec->big->eof, b);
342                         boffline(rec->big);
343                 } else {
344                         rec->small = (unsigned char *) joe_realloc(rec->small, rec->len + size);
345                         brmem(b->bof, rec->small + rec->len, (int) size);
346                         brm(b);
347                 }
348                 rec->len += size;
349         } else if (rec != &undo->recs && rec->min && rec->del && where + size == rec->where) {
350                 if (rec->len + size >= SMALL) {
351                         if (rec->len < SMALL) {
352                                 rec->big = bmk(NULL);
353                                 binsm(rec->big->bof, rec->small, (int) rec->len);
354                                 boffline(rec->big);
355                                 joe_free(rec->small);
356                         }
357                         bonline(rec->big);
358                         binsb(rec->big->bof, b);
359                         boffline(rec->big);
360                 } else {
361                         rec->small = (unsigned char *) joe_realloc(rec->small, rec->len + size);
362                         mmove(rec->small + size, rec->small, (int) rec->len);
363                         brmem(b->bof, rec->small, (int) size);
364                         brm(b);
365                 }
366                 rec->len += size;
367                 rec->where = where;
368         } else {
369                 rec = alrec();
370                 if (size < SMALL) {
371                         rec->small = (unsigned char *) joe_malloc(size);
372                         brmem(b->bof, rec->small, (int) b->eof->byte);
373                         brm(b);
374                 } else {
375                         rec->big = b;
376                         boffline(b);
377                 }
378                 if (!undo->first)
379                         undo->first = rec;
380                 undo->last = rec;
381                 rec->where = where;
382                 rec->min = 1;
383                 rec->unit = NULL;
384                 rec->len = size;
385                 rec->del = 1;
386                 rec->changed = undo->b->changed;
387                 enqueb(UNDOREC, link, &undo->recs, rec);
388         }
389 }
390
391 B *yankbuf = NULL;
392 long yankwhere = -1;
393
394 int uyank(BW *bw)
395 {
396         UNDOREC *ptr = yanked.link.prev;
397
398         if (ptr != &yanked) {
399                 if (ptr->len < SMALL)
400                         binsm(bw->cursor, ptr->small, (int) ptr->len);
401                 else {
402                         B *b = ptr->big;
403
404                         bonline(b);
405                         binsb(bw->cursor, bcpy(b->bof, b->eof));
406                         boffline(b);
407                 }
408                 pfwrd(bw->cursor, ptr->len);
409                 yankbuf = bw->b;
410                 yankwhere = bw->cursor->byte;
411                 return 0;
412         } else
413                 return -1;
414 }
415
416 int uyankpop(BW *bw)
417 {
418         if (bw->b == yankbuf && bw->cursor->byte == yankwhere) {
419                 P *q;
420                 UNDOREC *ptr = yanked.link.prev;
421
422                 deque(UNDOREC, link, &yanked);
423                 enqueb(UNDOREC, link, ptr, &yanked);
424                 q = pdup(bw->cursor);
425                 pbkwd(q, ptr->len);
426                 inyank = 1;
427                 bdel(q, bw->cursor);
428                 inyank = 0;
429                 prm(q);
430                 return uyank(bw);
431         } else
432                 return uyank(bw);
433 }
434
435 /* Clear changed-flag: make buffer look unmodified */
436
437 int unotmod(BW *bw)
438 {
439         bw->b->changed = 0;
440         msgnw(bw->parent, US "Modified flag cleared");
441         return 0;
442 }
443
444 int ucopy(BW *bw)
445 {
446         if (markv(1) && !square) {
447                 B *b = bcpy(markb, markk);
448
449                 yankdel(markb->byte, b);
450                 brm(b);
451                 if (lightoff)
452                         unmark(bw);
453                 return 0;
454         } else {
455                 msgnw(bw->parent, US "No block");
456                 return -1;
457         }
458 }