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