Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include "sam.h"
2
 
3
/*
4
 * Structure of Undo list:
5
 * 	The Undo structure follows any associated data, so the list
6
 *	can be read backwards: read the structure, then read whatever
7
 *	data is associated (insert string, file name) and precedes it.
8
 *	The structure includes the previous value of the modify bit
9
 *	and a sequence number; successive Undo structures with the
10
 *	same sequence number represent simultaneous changes.
11
 */
12
 
13
typedef struct Undo Undo;
14
typedef struct Merge Merge;
15
 
16
struct Undo
17
{
18
	short	type;		/* Delete, Insert, Filename, Dot, Mark */
19
	short	mod;		/* modify bit */
20
	uint	seq;		/* sequence number */
21
	uint	p0;		/* location of change (unused in f) */
22
	uint	n;		/* # runes in string or file name */
23
};
24
 
25
struct Merge
26
{
27
	File	*f;
28
	uint	seq;		/* of logged change */
29
	uint	p0;		/* location of change (unused in f) */
30
	uint	n;		/* # runes to delete */
31
	uint	nbuf;		/* # runes to insert */
32
	Rune	buf[RBUFSIZE];
33
};
34
 
35
enum
36
{
37
	Maxmerge = 50,
38
	Undosize = sizeof(Undo)/sizeof(Rune),
39
};
40
 
41
static Merge	merge;
42
 
43
File*
44
fileopen(void)
45
{
46
	File *f;
47
 
48
	f = emalloc(sizeof(File));
49
	f->dot.f = f;
50
	f->ndot.f = f;
51
	f->seq = 0;
52
	f->mod = FALSE;
53
	f->unread = TRUE;
54
	Strinit0(&f->name);
55
	return f;
56
}
57
 
58
int
59
fileisdirty(File *f)
60
{
61
	return f->seq != f->cleanseq;
62
}
63
 
64
static void
65
wrinsert(Buffer *delta, int seq, int mod, uint p0, Rune *s, uint ns)
66
{
67
	Undo u;
68
 
69
	u.type = Insert;
70
	u.mod = mod;
71
	u.seq = seq;
72
	u.p0 = p0;
73
	u.n = ns;
74
	bufinsert(delta, delta->nc, s, ns);
75
	bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
76
}
77
 
78
static void
79
wrdelete(Buffer *delta, int seq, int mod, uint p0, uint p1)
80
{
81
	Undo u;
82
 
83
	u.type = Delete;
84
	u.mod = mod;
85
	u.seq = seq;
86
	u.p0 = p0;
87
	u.n = p1 - p0;
88
	bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
89
}
90
 
91
void
92
flushmerge(void)
93
{
94
	File *f;
95
 
96
	f = merge.f;
97
	if(f == nil)
98
		return;
99
	if(merge.seq != f->seq)
100
		panic("flushmerge seq mismatch");
101
	if(merge.n != 0)
102
		wrdelete(&f->epsilon, f->seq, TRUE, merge.p0, merge.p0+merge.n);
103
	if(merge.nbuf != 0)
104
		wrinsert(&f->epsilon, f->seq, TRUE, merge.p0+merge.n, merge.buf, merge.nbuf);
105
	merge.f = nil;
106
	merge.n = 0;
107
	merge.nbuf = 0;
108
}
109
 
110
void
111
mergeextend(File *f, uint p0)
112
{
113
	uint mp0n;
114
 
115
	mp0n = merge.p0+merge.n;
116
	if(mp0n != p0){
117
		bufread(f, mp0n, merge.buf+merge.nbuf, p0-mp0n);
118
		merge.nbuf += p0-mp0n;
119
		merge.n = p0-merge.p0;
120
	}
121
}
122
 
123
/*
124
 * like fileundelete, but get the data from arguments
125
 */
126
void
127
loginsert(File *f, uint p0, Rune *s, uint ns)
128
{
129
	if(f->rescuing)
130
		return;
131
	if(ns == 0)
132
		return;
133
	if(ns>STRSIZE)
134
		panic("loginsert");
135
	if(f->seq < seq)
136
		filemark(f);
137
	if(p0 < f->hiposn)
138
		error(Esequence);
139
 
140
	if(merge.f != f
141
	|| p0-(merge.p0+merge.n)>Maxmerge			/* too far */
142
	|| merge.nbuf+((p0+ns)-(merge.p0+merge.n))>=RBUFSIZE)	/* too long */
143
		flushmerge();
144
 
145
	if(ns>=RBUFSIZE){
146
		if(!(merge.n == 0 && merge.nbuf == 0 && merge.f == nil))
147
			panic("loginsert bad merge state");
148
		wrinsert(&f->epsilon, f->seq, TRUE, p0, s, ns);
149
	}else{
150
		if(merge.f != f){
151
			merge.f = f;
152
			merge.p0 = p0;
153
			merge.seq = f->seq;
154
		}
155
		mergeextend(f, p0);
156
 
157
		/* append string to merge */
158
		runemove(merge.buf+merge.nbuf, s, ns);
159
		merge.nbuf += ns;
160
	}
161
 
162
	f->hiposn = p0;
163
	if(!f->unread && !f->mod)
164
		state(f, Dirty);
165
}
166
 
167
void
168
logdelete(File *f, uint p0, uint p1)
169
{
170
	if(f->rescuing)
171
		return;
172
	if(p0 == p1)
173
		return;
174
	if(f->seq < seq)
175
		filemark(f);
176
	if(p0 < f->hiposn)
177
		error(Esequence);
178
 
179
	if(merge.f != f
180
	|| p0-(merge.p0+merge.n)>Maxmerge			/* too far */
181
	|| merge.nbuf+(p0-(merge.p0+merge.n))>=RBUFSIZE){	/* too long */
182
		flushmerge();
183
		merge.f = f;
184
		merge.p0 = p0;
185
		merge.seq = f->seq;
186
	}
187
 
188
	mergeextend(f, p0);
189
 
190
	/* add to deletion */
191
	merge.n = p1-merge.p0;
192
 
193
	f->hiposn = p1;
194
	if(!f->unread && !f->mod)
195
		state(f, Dirty);
196
}
197
 
198
/*
199
 * like fileunsetname, but get the data from arguments
200
 */
201
void
202
logsetname(File *f, String *s)
203
{
204
	Undo u;
205
	Buffer *delta;
206
 
207
	if(f->rescuing)
208
		return;
209
 
210
	if(f->unread){	/* This is setting initial file name */
211
		filesetname(f, s);
212
		return;
213
	}
214
 
215
	if(f->seq < seq)
216
		filemark(f);
217
 
218
	/* undo a file name change by restoring old name */
219
	delta = &f->epsilon;
220
	u.type = Filename;
221
	u.mod = TRUE;
222
	u.seq = f->seq;
223
	u.p0 = 0;	/* unused */
224
	u.n = s->n;
225
	if(s->n)
226
		bufinsert(delta, delta->nc, s->s, s->n);
227
	bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
228
	if(!f->unread && !f->mod)
229
		state(f, Dirty);
230
}
231
 
232
#ifdef NOTEXT
233
File*
234
fileaddtext(File *f, Text *t)
235
{
236
	if(f == nil){
237
		f = emalloc(sizeof(File));
238
		f->unread = TRUE;
239
	}
240
	f->text = realloc(f->text, (f->ntext+1)*sizeof(Text*));
241
	f->text[f->ntext++] = t;
242
	f->curtext = t;
243
	return f;
244
}
245
 
246
void
247
filedeltext(File *f, Text *t)
248
{
249
	int i;
250
 
251
	for(i=0; i<f->ntext; i++)
252
		if(f->text[i] == t)
253
			goto Found;
254
	panic("can't find text in filedeltext");
255
 
256
    Found:
257
	f->ntext--;
258
	if(f->ntext == 0){
259
		fileclose(f);
260
		return;
261
	}
262
	memmove(f->text+i, f->text+i+1, (f->ntext-i)*sizeof(Text*));
263
	if(f->curtext == t)
264
		f->curtext = f->text[0];
265
}
266
#endif
267
 
268
void
269
fileuninsert(File *f, Buffer *delta, uint p0, uint ns)
270
{
271
	Undo u;
272
 
273
	/* undo an insertion by deleting */
274
	u.type = Delete;
275
	u.mod = f->mod;
276
	u.seq = f->seq;
277
	u.p0 = p0;
278
	u.n = ns;
279
	bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
280
}
281
 
282
void
283
fileundelete(File *f, Buffer *delta, uint p0, uint p1)
284
{
285
	Undo u;
286
	Rune *buf;
287
	uint i, n;
288
 
289
	/* undo a deletion by inserting */
290
	u.type = Insert;
291
	u.mod = f->mod;
292
	u.seq = f->seq;
293
	u.p0 = p0;
294
	u.n = p1-p0;
295
	buf = fbufalloc();
296
	for(i=p0; i<p1; i+=n){
297
		n = p1 - i;
298
		if(n > RBUFSIZE)
299
			n = RBUFSIZE;
300
		bufread(f, i, buf, n);
301
		bufinsert(delta, delta->nc, buf, n);
302
	}
303
	fbuffree(buf);
304
	bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
305
 
306
}
307
 
308
int
309
filereadc(File *f, uint q)
310
{
311
	Rune r;
312
 
313
	if(q >= f->nc)
314
		return -1;
315
	bufread(f, q, &r, 1);
316
	return r;
317
}
318
 
319
void
320
filesetname(File *f, String *s)
321
{
322
	if(!f->unread)	/* This is setting initial file name */
323
		fileunsetname(f, &f->delta);
324
	Strduplstr(&f->name, s);
325
	sortname(f);
326
	f->unread = TRUE;
327
}
328
 
329
void
330
fileunsetname(File *f, Buffer *delta)
331
{
332
	String s;
333
	Undo u;
334
 
335
	/* undo a file name change by restoring old name */
336
	u.type = Filename;
337
	u.mod = f->mod;
338
	u.seq = f->seq;
339
	u.p0 = 0;	/* unused */
340
	Strinit(&s);
341
	Strduplstr(&s, &f->name);
342
	fullname(&s);
343
	u.n = s.n;
344
	if(s.n)
345
		bufinsert(delta, delta->nc, s.s, s.n);
346
	bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
347
	Strclose(&s);
348
}
349
 
350
void
351
fileunsetdot(File *f, Buffer *delta, Range dot)
352
{
353
	Undo u;
354
 
355
	u.type = Dot;
356
	u.mod = f->mod;
357
	u.seq = f->seq;
358
	u.p0 = dot.p1;
359
	u.n = dot.p2 - dot.p1;
360
	bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
361
}
362
 
363
void
364
fileunsetmark(File *f, Buffer *delta, Range mark)
365
{
366
	Undo u;
367
 
368
	u.type = Mark;
369
	u.mod = f->mod;
370
	u.seq = f->seq;
371
	u.p0 = mark.p1;
372
	u.n = mark.p2 - mark.p1;
373
	bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
374
}
375
 
376
uint
377
fileload(File *f, uint p0, int fd, int *nulls)
378
{
379
	if(f->seq > 0)
380
		panic("undo in file.load unimplemented");
381
	return bufload(f, p0, fd, nulls);
382
}
383
 
384
int
385
fileupdate(File *f, int notrans, int toterm)
386
{
387
	uint p1, p2;
388
	int mod;
389
 
390
	if(f->rescuing)
391
		return FALSE;
392
 
393
	flushmerge();
394
 
395
	/*
396
	 * fix the modification bit
397
	 * subtle point: don't save it away in the log.
398
	 *
399
	 * if another change is made, the correct f->mod
400
	 * state is saved  in the undo log by filemark
401
	 * when setting the dot and mark.
402
	 *
403
	 * if the change is undone, the correct state is
404
	 * saved from f in the fileun... routines.
405
	 */
406
	mod = f->mod;
407
	f->mod = f->prevmod;
408
	if(f == cmd)
409
		notrans = TRUE;
410
	else{
411
		fileunsetdot(f, &f->delta, f->prevdot);
412
		fileunsetmark(f, &f->delta, f->prevmark);
413
	}
414
	f->dot = f->ndot;
415
	fileundo(f, FALSE, !notrans, &p1, &p2, toterm);
416
	f->mod = mod;
417
 
418
	if(f->delta.nc == 0)
419
		f->seq = 0;
420
 
421
	if(f == cmd)
422
		return FALSE;
423
 
424
	if(f->mod){
425
		f->closeok = 0;
426
		quitok = 0;
427
	}else
428
		f->closeok = 1;
429
	return TRUE;
430
}
431
 
432
long
433
prevseq(Buffer *b)
434
{
435
	Undo u;
436
	uint up;
437
 
438
	up = b->nc;
439
	if(up == 0)
440
		return 0;
441
	up -= Undosize;
442
	bufread(b, up, (Rune*)&u, Undosize);
443
	return u.seq;
444
}
445
 
446
long
447
undoseq(File *f, int isundo)
448
{
449
	if(isundo)
450
		return f->seq;
451
 
452
	return prevseq(&f->epsilon);
453
}
454
 
455
void
456
fileundo(File *f, int isundo, int canredo, uint *q0p, uint *q1p, int flag)
457
{
458
	Undo u;
459
	Rune *buf;
460
	uint i, n, up;
461
	uint stop;
462
	Buffer *delta, *epsilon;
463
 
464
	if(isundo){
465
		/* undo; reverse delta onto epsilon, seq decreases */
466
		delta = &f->delta;
467
		epsilon = &f->epsilon;
468
		stop = f->seq;
469
	}else{
470
		/* redo; reverse epsilon onto delta, seq increases */
471
		delta = &f->epsilon;
472
		epsilon = &f->delta;
473
		stop = 0;	/* don't know yet */
474
	}
475
 
476
	raspstart(f);
477
	while(delta->nc > 0){
478
		/* rasp and buffer are in sync; sync with wire if needed */
479
		if(needoutflush())
480
			raspflush(f);
481
		up = delta->nc-Undosize;
482
		bufread(delta, up, (Rune*)&u, Undosize);
483
		if(isundo){
484
			if(u.seq < stop){
485
				f->seq = u.seq;
486
				raspdone(f, flag);
487
				return;
488
			}
489
		}else{
490
			if(stop == 0)
491
				stop = u.seq;
492
			if(u.seq > stop){
493
				raspdone(f, flag);
494
				return;
495
			}
496
		}
497
		switch(u.type){
498
		default:
499
			panic("undo unknown u.type");
500
			break;
501
 
502
		case Delete:
503
			f->seq = u.seq;
504
			if(canredo)
505
				fileundelete(f, epsilon, u.p0, u.p0+u.n);
506
			f->mod = u.mod;
507
			bufdelete(f, u.p0, u.p0+u.n);
508
			raspdelete(f, u.p0, u.p0+u.n, flag);
509
			*q0p = u.p0;
510
			*q1p = u.p0;
511
			break;
512
 
513
		case Insert:
514
			f->seq = u.seq;
515
			if(canredo)
516
				fileuninsert(f, epsilon, u.p0, u.n);
517
			f->mod = u.mod;
518
			up -= u.n;
519
			buf = fbufalloc();
520
			for(i=0; i<u.n; i+=n){
521
				n = u.n - i;
522
				if(n > RBUFSIZE)
523
					n = RBUFSIZE;
524
				bufread(delta, up+i, buf, n);
525
				bufinsert(f, u.p0+i, buf, n);
526
				raspinsert(f, u.p0+i, buf, n, flag);
527
			}
528
			fbuffree(buf);
529
			*q0p = u.p0;
530
			*q1p = u.p0+u.n;
531
			break;
532
 
533
		case Filename:
534
			f->seq = u.seq;
535
			if(canredo)
536
				fileunsetname(f, epsilon);
537
			f->mod = u.mod;
538
			up -= u.n;
539
 
540
			Strinsure(&f->name, u.n+1);
541
			bufread(delta, up, f->name.s, u.n);
542
			f->name.s[u.n] = 0;
543
			f->name.n = u.n;
544
			fixname(&f->name);
545
			sortname(f);
546
			break;
547
		case Dot:
548
			f->seq = u.seq;
549
			if(canredo)
550
				fileunsetdot(f, epsilon, f->dot.r);
551
			f->mod = u.mod;
552
			f->dot.r.p1 = u.p0;
553
			f->dot.r.p2 = u.p0 + u.n;
554
			break;
555
		case Mark:
556
			f->seq = u.seq;
557
			if(canredo)
558
				fileunsetmark(f, epsilon, f->mark);
559
			f->mod = u.mod;
560
			f->mark.p1 = u.p0;
561
			f->mark.p2 = u.p0 + u.n;
562
			break;
563
		}
564
		bufdelete(delta, up, delta->nc);
565
	}
566
	if(isundo)
567
		f->seq = 0;
568
	raspdone(f, flag);
569
}
570
 
571
void
572
filereset(File *f)
573
{
574
	bufreset(&f->delta);
575
	bufreset(&f->epsilon);
576
	f->seq = 0;
577
}
578
 
579
void
580
fileclose(File *f)
581
{
582
	Strclose(&f->name);
583
	bufclose(f);
584
	bufclose(&f->delta);
585
	bufclose(&f->epsilon);
586
	if(f->rasp)
587
		listfree(f->rasp);
588
	free(f);
589
}
590
 
591
void
592
filemark(File *f)
593
{
594
 
595
	if(f->unread)
596
		return;
597
	if(f->epsilon.nc)
598
		bufdelete(&f->epsilon, 0, f->epsilon.nc);
599
 
600
	if(f != cmd){
601
		f->prevdot = f->dot.r;
602
		f->prevmark = f->mark;
603
		f->prevseq = f->seq;
604
		f->prevmod = f->mod;
605
	}
606
 
607
	f->ndot = f->dot;
608
	f->seq = seq;
609
	f->hiposn = 0;
610
}