xref: /plan9/sys/src/cmd/sam/file.c (revision 6b6b9ac8b0b103b1e30e4d019522a78c950fce74)
13e12c5d1SDavid du Colombier #include "sam.h"
27dd7cddfSDavid du Colombier 
33e12c5d1SDavid du Colombier /*
47dd7cddfSDavid du Colombier  * Structure of Undo list:
57dd7cddfSDavid du Colombier  * 	The Undo structure follows any associated data, so the list
67dd7cddfSDavid du Colombier  *	can be read backwards: read the structure, then read whatever
77dd7cddfSDavid du Colombier  *	data is associated (insert string, file name) and precedes it.
87dd7cddfSDavid du Colombier  *	The structure includes the previous value of the modify bit
97dd7cddfSDavid du Colombier  *	and a sequence number; successive Undo structures with the
107dd7cddfSDavid du Colombier  *	same sequence number represent simultaneous changes.
113e12c5d1SDavid du Colombier  */
123e12c5d1SDavid du Colombier 
137dd7cddfSDavid du Colombier typedef struct Undo Undo;
147dd7cddfSDavid du Colombier typedef struct Merge Merge;
153e12c5d1SDavid du Colombier 
167dd7cddfSDavid du Colombier struct Undo
177dd7cddfSDavid du Colombier {
187dd7cddfSDavid du Colombier 	short	type;		/* Delete, Insert, Filename, Dot, Mark */
197dd7cddfSDavid du Colombier 	short	mod;		/* modify bit */
207dd7cddfSDavid du Colombier 	uint	seq;		/* sequence number */
217dd7cddfSDavid du Colombier 	uint	p0;		/* location of change (unused in f) */
227dd7cddfSDavid du Colombier 	uint	n;		/* # runes in string or file name */
233e12c5d1SDavid du Colombier };
243e12c5d1SDavid du Colombier 
257dd7cddfSDavid du Colombier struct Merge
263e12c5d1SDavid du Colombier {
277dd7cddfSDavid du Colombier 	File	*f;
287dd7cddfSDavid du Colombier 	uint	seq;		/* of logged change */
297dd7cddfSDavid du Colombier 	uint	p0;		/* location of change (unused in f) */
307dd7cddfSDavid du Colombier 	uint	n;		/* # runes to delete */
317dd7cddfSDavid du Colombier 	uint	nbuf;		/* # runes to insert */
327dd7cddfSDavid du Colombier 	Rune	buf[RBUFSIZE];
337dd7cddfSDavid du Colombier };
343e12c5d1SDavid du Colombier 
357dd7cddfSDavid du Colombier enum
363e12c5d1SDavid du Colombier {
377dd7cddfSDavid du Colombier 	Maxmerge = 50,
387dd7cddfSDavid du Colombier 	Undosize = sizeof(Undo)/sizeof(Rune),
397dd7cddfSDavid du Colombier };
403e12c5d1SDavid du Colombier 
417dd7cddfSDavid du Colombier static Merge	merge;
423e12c5d1SDavid du Colombier 
433e12c5d1SDavid du Colombier File*
447dd7cddfSDavid 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;
517dd7cddfSDavid du Colombier 	f->seq = 0;
527dd7cddfSDavid du Colombier 	f->mod = FALSE;
537dd7cddfSDavid du Colombier 	f->unread = TRUE;
543e12c5d1SDavid du Colombier 	Strinit0(&f->name);
557dd7cddfSDavid du Colombier 	return f;
567dd7cddfSDavid du Colombier }
577dd7cddfSDavid du Colombier 
587dd7cddfSDavid du Colombier int
597dd7cddfSDavid du Colombier fileisdirty(File *f)
607dd7cddfSDavid du Colombier {
617dd7cddfSDavid du Colombier 	return f->seq != f->cleanseq;
627dd7cddfSDavid du Colombier }
637dd7cddfSDavid du Colombier 
647dd7cddfSDavid du Colombier static void
657dd7cddfSDavid du Colombier wrinsert(Buffer *delta, int seq, int mod, uint p0, Rune *s, uint ns)
667dd7cddfSDavid du Colombier {
677dd7cddfSDavid du Colombier 	Undo u;
687dd7cddfSDavid du Colombier 
697dd7cddfSDavid du Colombier 	u.type = Insert;
707dd7cddfSDavid du Colombier 	u.mod = mod;
717dd7cddfSDavid du Colombier 	u.seq = seq;
727dd7cddfSDavid du Colombier 	u.p0 = p0;
737dd7cddfSDavid du Colombier 	u.n = ns;
747dd7cddfSDavid du Colombier 	bufinsert(delta, delta->nc, s, ns);
757dd7cddfSDavid du Colombier 	bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
767dd7cddfSDavid du Colombier }
777dd7cddfSDavid du Colombier 
787dd7cddfSDavid du Colombier static void
797dd7cddfSDavid du Colombier wrdelete(Buffer *delta, int seq, int mod, uint p0, uint p1)
807dd7cddfSDavid du Colombier {
817dd7cddfSDavid du Colombier 	Undo u;
827dd7cddfSDavid du Colombier 
837dd7cddfSDavid du Colombier 	u.type = Delete;
847dd7cddfSDavid du Colombier 	u.mod = mod;
857dd7cddfSDavid du Colombier 	u.seq = seq;
867dd7cddfSDavid du Colombier 	u.p0 = p0;
877dd7cddfSDavid du Colombier 	u.n = p1 - p0;
887dd7cddfSDavid du Colombier 	bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
897dd7cddfSDavid du Colombier }
907dd7cddfSDavid du Colombier 
917dd7cddfSDavid du Colombier void
927dd7cddfSDavid du Colombier flushmerge(void)
937dd7cddfSDavid du Colombier {
947dd7cddfSDavid du Colombier 	File *f;
957dd7cddfSDavid du Colombier 
967dd7cddfSDavid du Colombier 	f = merge.f;
977dd7cddfSDavid du Colombier 	if(f == nil)
987dd7cddfSDavid du Colombier 		return;
997dd7cddfSDavid du Colombier 	if(merge.seq != f->seq)
1007dd7cddfSDavid du Colombier 		panic("flushmerge seq mismatch");
1017dd7cddfSDavid du Colombier 	if(merge.n != 0)
1027dd7cddfSDavid du Colombier 		wrdelete(&f->epsilon, f->seq, TRUE, merge.p0, merge.p0+merge.n);
1037dd7cddfSDavid du Colombier 	if(merge.nbuf != 0)
1047dd7cddfSDavid du Colombier 		wrinsert(&f->epsilon, f->seq, TRUE, merge.p0+merge.n, merge.buf, merge.nbuf);
1057dd7cddfSDavid du Colombier 	merge.f = nil;
1067dd7cddfSDavid du Colombier 	merge.n = 0;
1077dd7cddfSDavid du Colombier 	merge.nbuf = 0;
1087dd7cddfSDavid du Colombier }
1097dd7cddfSDavid du Colombier 
1107dd7cddfSDavid du Colombier void
1117dd7cddfSDavid du Colombier mergeextend(File *f, uint p0)
1127dd7cddfSDavid du Colombier {
1137dd7cddfSDavid du Colombier 	uint mp0n;
1147dd7cddfSDavid du Colombier 
1157dd7cddfSDavid du Colombier 	mp0n = merge.p0+merge.n;
1167dd7cddfSDavid du Colombier 	if(mp0n != p0){
1177dd7cddfSDavid du Colombier 		bufread(f, mp0n, merge.buf+merge.nbuf, p0-mp0n);
1187dd7cddfSDavid du Colombier 		merge.nbuf += p0-mp0n;
1197dd7cddfSDavid du Colombier 		merge.n = p0-merge.p0;
1207dd7cddfSDavid du Colombier 	}
1217dd7cddfSDavid du Colombier }
1227dd7cddfSDavid du Colombier 
1237dd7cddfSDavid du Colombier /*
1247dd7cddfSDavid du Colombier  * like fileundelete, but get the data from arguments
1257dd7cddfSDavid du Colombier  */
1267dd7cddfSDavid du Colombier void
1277dd7cddfSDavid du Colombier loginsert(File *f, uint p0, Rune *s, uint ns)
1287dd7cddfSDavid du Colombier {
1297dd7cddfSDavid du Colombier 	if(f->rescuing)
1307dd7cddfSDavid du Colombier 		return;
1317dd7cddfSDavid du Colombier 	if(ns == 0)
1327dd7cddfSDavid du Colombier 		return;
1337dd7cddfSDavid du Colombier 	if(ns<0 || ns>STRSIZE)
1347dd7cddfSDavid du Colombier 		panic("loginsert");
1357dd7cddfSDavid du Colombier 	if(f->seq < seq)
1367dd7cddfSDavid du Colombier 		filemark(f);
1377dd7cddfSDavid du Colombier 	if(p0 < f->hiposn)
1387dd7cddfSDavid du Colombier 		error(Esequence);
1397dd7cddfSDavid du Colombier 
1407dd7cddfSDavid du Colombier 	if(merge.f != f
1417dd7cddfSDavid du Colombier 	|| p0-(merge.p0+merge.n)>Maxmerge			/* too far */
1427dd7cddfSDavid du Colombier 	|| merge.nbuf+((p0+ns)-(merge.p0+merge.n))>RBUFSIZE)	/* too long */
1437dd7cddfSDavid du Colombier 		flushmerge();
1447dd7cddfSDavid du Colombier 
1457dd7cddfSDavid du Colombier 	if(ns>=RBUFSIZE){
1467dd7cddfSDavid du Colombier 		if(!(merge.n == 0 && merge.nbuf == 0 && merge.f == nil))
1477dd7cddfSDavid du Colombier 			panic("loginsert bad merge state");
1487dd7cddfSDavid du Colombier 		wrinsert(&f->epsilon, f->seq, TRUE, p0, s, ns);
1497dd7cddfSDavid du Colombier 	}else{
1507dd7cddfSDavid du Colombier 		if(merge.f != f){
1517dd7cddfSDavid du Colombier 			merge.f = f;
1527dd7cddfSDavid du Colombier 			merge.p0 = p0;
1537dd7cddfSDavid du Colombier 			merge.seq = f->seq;
1547dd7cddfSDavid du Colombier 		}
1557dd7cddfSDavid du Colombier 		mergeextend(f, p0);
1567dd7cddfSDavid du Colombier 
1577dd7cddfSDavid du Colombier 		/* append string to merge */
1587dd7cddfSDavid du Colombier 		runemove(merge.buf+merge.nbuf, s, ns);
1597dd7cddfSDavid du Colombier 		merge.nbuf += ns;
1607dd7cddfSDavid du Colombier 	}
1617dd7cddfSDavid du Colombier 
1627dd7cddfSDavid du Colombier 	f->hiposn = p0;
1637dd7cddfSDavid du Colombier 	if(!f->unread && !f->mod)
1647dd7cddfSDavid du Colombier 		state(f, Dirty);
1657dd7cddfSDavid du Colombier }
1667dd7cddfSDavid du Colombier 
1677dd7cddfSDavid du Colombier void
1687dd7cddfSDavid du Colombier logdelete(File *f, uint p0, uint p1)
1697dd7cddfSDavid du Colombier {
1707dd7cddfSDavid du Colombier 	if(f->rescuing)
1717dd7cddfSDavid du Colombier 		return;
1727dd7cddfSDavid du Colombier 	if(p0 == p1)
1737dd7cddfSDavid du Colombier 		return;
1747dd7cddfSDavid du Colombier 	if(f->seq < seq)
1757dd7cddfSDavid du Colombier 		filemark(f);
176*6b6b9ac8SDavid du Colombier 	if(p0 < f->hiposn)
1777dd7cddfSDavid du Colombier 		error(Esequence);
1787dd7cddfSDavid du Colombier 
1797dd7cddfSDavid du Colombier 	if(merge.f != f
1807dd7cddfSDavid du Colombier 	|| p0-(merge.p0+merge.n)>Maxmerge			/* too far */
1817dd7cddfSDavid du Colombier 	|| merge.nbuf+(p0-(merge.p0+merge.n))>RBUFSIZE){	/* too long */
1827dd7cddfSDavid du Colombier 		flushmerge();
1837dd7cddfSDavid du Colombier 		merge.f = f;
1847dd7cddfSDavid du Colombier 		merge.p0 = p0;
1857dd7cddfSDavid du Colombier 		merge.seq = f->seq;
1867dd7cddfSDavid du Colombier 	}
1877dd7cddfSDavid du Colombier 
1887dd7cddfSDavid du Colombier 	mergeextend(f, p0);
1897dd7cddfSDavid du Colombier 
1907dd7cddfSDavid du Colombier 	/* add to deletion */
1917dd7cddfSDavid du Colombier 	merge.n = p1-merge.p0;
1927dd7cddfSDavid du Colombier 
1937dd7cddfSDavid du Colombier 	f->hiposn = p1;
1947dd7cddfSDavid du Colombier 	if(!f->unread && !f->mod)
1957dd7cddfSDavid du Colombier 		state(f, Dirty);
1967dd7cddfSDavid du Colombier }
1977dd7cddfSDavid du Colombier 
1987dd7cddfSDavid du Colombier /*
1997dd7cddfSDavid du Colombier  * like fileunsetname, but get the data from arguments
2007dd7cddfSDavid du Colombier  */
2017dd7cddfSDavid du Colombier void
2027dd7cddfSDavid du Colombier logsetname(File *f, String *s)
2037dd7cddfSDavid du Colombier {
2047dd7cddfSDavid du Colombier 	Undo u;
2057dd7cddfSDavid du Colombier 	Buffer *delta;
2067dd7cddfSDavid du Colombier 
2077dd7cddfSDavid du Colombier 	if(f->rescuing)
2087dd7cddfSDavid du Colombier 		return;
2097dd7cddfSDavid du Colombier 
2107dd7cddfSDavid du Colombier 	if(f->unread){	/* This is setting initial file name */
2117dd7cddfSDavid du Colombier 		filesetname(f, s);
2127dd7cddfSDavid du Colombier 		return;
2137dd7cddfSDavid du Colombier 	}
2147dd7cddfSDavid du Colombier 
2157dd7cddfSDavid du Colombier 	if(f->seq < seq)
2167dd7cddfSDavid du Colombier 		filemark(f);
2177dd7cddfSDavid du Colombier 
2187dd7cddfSDavid du Colombier 	/* undo a file name change by restoring old name */
2197dd7cddfSDavid du Colombier 	delta = &f->epsilon;
2207dd7cddfSDavid du Colombier 	u.type = Filename;
2217dd7cddfSDavid du Colombier 	u.mod = TRUE;
2227dd7cddfSDavid du Colombier 	u.seq = f->seq;
2237dd7cddfSDavid du Colombier 	u.p0 = 0;	/* unused */
2247dd7cddfSDavid du Colombier 	u.n = s->n;
2257dd7cddfSDavid du Colombier 	if(s->n)
2267dd7cddfSDavid du Colombier 		bufinsert(delta, delta->nc, s->s, s->n);
2277dd7cddfSDavid du Colombier 	bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
2287dd7cddfSDavid du Colombier 	if(!f->unread && !f->mod)
2297dd7cddfSDavid du Colombier 		state(f, Dirty);
2307dd7cddfSDavid du Colombier }
2317dd7cddfSDavid du Colombier 
2327dd7cddfSDavid du Colombier #ifdef NOTEXT
2337dd7cddfSDavid du Colombier File*
2347dd7cddfSDavid du Colombier fileaddtext(File *f, Text *t)
2357dd7cddfSDavid du Colombier {
2367dd7cddfSDavid du Colombier 	if(f == nil){
2377dd7cddfSDavid du Colombier 		f = emalloc(sizeof(File));
2387dd7cddfSDavid du Colombier 		f->unread = TRUE;
2397dd7cddfSDavid du Colombier 	}
2407dd7cddfSDavid du Colombier 	f->text = realloc(f->text, (f->ntext+1)*sizeof(Text*));
2417dd7cddfSDavid du Colombier 	f->text[f->ntext++] = t;
2427dd7cddfSDavid du Colombier 	f->curtext = t;
2433e12c5d1SDavid du Colombier 	return f;
2443e12c5d1SDavid du Colombier }
2453e12c5d1SDavid du Colombier 
2463e12c5d1SDavid du Colombier void
2477dd7cddfSDavid du Colombier filedeltext(File *f, Text *t)
2483e12c5d1SDavid du Colombier {
2497dd7cddfSDavid du Colombier 	int i;
2507dd7cddfSDavid du Colombier 
2517dd7cddfSDavid du Colombier 	for(i=0; i<f->ntext; i++)
2527dd7cddfSDavid du Colombier 		if(f->text[i] == t)
2537dd7cddfSDavid du Colombier 			goto Found;
2547dd7cddfSDavid du Colombier 	panic("can't find text in filedeltext");
2557dd7cddfSDavid du Colombier 
2567dd7cddfSDavid du Colombier     Found:
2577dd7cddfSDavid du Colombier 	f->ntext--;
2587dd7cddfSDavid du Colombier 	if(f->ntext == 0){
2597dd7cddfSDavid du Colombier 		fileclose(f);
2607dd7cddfSDavid du Colombier 		return;
2617dd7cddfSDavid du Colombier 	}
2627dd7cddfSDavid du Colombier 	memmove(f->text+i, f->text+i+1, (f->ntext-i)*sizeof(Text*));
2637dd7cddfSDavid du Colombier 	if(f->curtext == t)
2647dd7cddfSDavid du Colombier 		f->curtext = f->text[0];
2657dd7cddfSDavid du Colombier }
2667dd7cddfSDavid du Colombier #endif
2677dd7cddfSDavid du Colombier 
2687dd7cddfSDavid du Colombier void
2697dd7cddfSDavid du Colombier fileinsert(File *f, uint p0, Rune *s, uint ns)
2707dd7cddfSDavid du Colombier {
2717dd7cddfSDavid du Colombier 	if(p0 > f->nc)
2727dd7cddfSDavid du Colombier 		panic("internal error: fileinsert");
2737dd7cddfSDavid du Colombier 	if(f->seq > 0)
2747dd7cddfSDavid du Colombier 		fileuninsert(f, &f->delta, p0, ns);
2757dd7cddfSDavid du Colombier 	bufinsert(f, p0, s, ns);
2767dd7cddfSDavid du Colombier 	if(ns)
2777dd7cddfSDavid du Colombier 		f->mod = TRUE;
2787dd7cddfSDavid du Colombier }
2797dd7cddfSDavid du Colombier 
2807dd7cddfSDavid du Colombier void
2817dd7cddfSDavid du Colombier fileuninsert(File *f, Buffer *delta, uint p0, uint ns)
2827dd7cddfSDavid du Colombier {
2837dd7cddfSDavid du Colombier 	Undo u;
2847dd7cddfSDavid du Colombier 
2857dd7cddfSDavid du Colombier 	/* undo an insertion by deleting */
2867dd7cddfSDavid du Colombier 	u.type = Delete;
2877dd7cddfSDavid du Colombier 	u.mod = f->mod;
2887dd7cddfSDavid du Colombier 	u.seq = f->seq;
2897dd7cddfSDavid du Colombier 	u.p0 = p0;
2907dd7cddfSDavid du Colombier 	u.n = ns;
2917dd7cddfSDavid du Colombier 	bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
2927dd7cddfSDavid du Colombier }
2937dd7cddfSDavid du Colombier 
2947dd7cddfSDavid du Colombier void
2957dd7cddfSDavid du Colombier filedelete(File *f, uint p0, uint p1)
2967dd7cddfSDavid du Colombier {
2977dd7cddfSDavid du Colombier 	if(!(p0<=p1 && p0<=f->nc && p1<=f->nc))
2987dd7cddfSDavid du Colombier 		panic("internal error: filedelete");
2997dd7cddfSDavid du Colombier 	if(f->seq > 0)
3007dd7cddfSDavid du Colombier 		fileundelete(f, &f->delta, p0, p1);
3017dd7cddfSDavid du Colombier 	bufdelete(f, p0, p1);
3027dd7cddfSDavid du Colombier 	if(p1 > p0)
3037dd7cddfSDavid du Colombier 		f->mod = TRUE;
3047dd7cddfSDavid du Colombier }
3057dd7cddfSDavid du Colombier 
3067dd7cddfSDavid du Colombier void
3077dd7cddfSDavid du Colombier fileundelete(File *f, Buffer *delta, uint p0, uint p1)
3087dd7cddfSDavid du Colombier {
3097dd7cddfSDavid du Colombier 	Undo u;
3107dd7cddfSDavid du Colombier 	Rune *buf;
3117dd7cddfSDavid du Colombier 	uint i, n;
3127dd7cddfSDavid du Colombier 
3137dd7cddfSDavid du Colombier 	/* undo a deletion by inserting */
3147dd7cddfSDavid du Colombier 	u.type = Insert;
3157dd7cddfSDavid du Colombier 	u.mod = f->mod;
3167dd7cddfSDavid du Colombier 	u.seq = f->seq;
3177dd7cddfSDavid du Colombier 	u.p0 = p0;
3187dd7cddfSDavid du Colombier 	u.n = p1-p0;
3197dd7cddfSDavid du Colombier 	buf = fbufalloc();
3207dd7cddfSDavid du Colombier 	for(i=p0; i<p1; i+=n){
3217dd7cddfSDavid du Colombier 		n = p1 - i;
3227dd7cddfSDavid du Colombier 		if(n > RBUFSIZE)
3237dd7cddfSDavid du Colombier 			n = RBUFSIZE;
3247dd7cddfSDavid du Colombier 		bufread(f, i, buf, n);
3257dd7cddfSDavid du Colombier 		bufinsert(delta, delta->nc, buf, n);
3267dd7cddfSDavid du Colombier 	}
3277dd7cddfSDavid du Colombier 	fbuffree(buf);
3287dd7cddfSDavid du Colombier 	bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
3297dd7cddfSDavid du Colombier 
3307dd7cddfSDavid du Colombier }
3317dd7cddfSDavid du Colombier 
3327dd7cddfSDavid du Colombier int
3337dd7cddfSDavid du Colombier filereadc(File *f, uint q)
3347dd7cddfSDavid du Colombier {
3357dd7cddfSDavid du Colombier 	Rune r;
3367dd7cddfSDavid du Colombier 
3377dd7cddfSDavid du Colombier 	if(q >= f->nc)
3387dd7cddfSDavid du Colombier 		return -1;
3397dd7cddfSDavid du Colombier 	bufread(f, q, &r, 1);
3407dd7cddfSDavid du Colombier 	return r;
3417dd7cddfSDavid du Colombier }
3427dd7cddfSDavid du Colombier 
3437dd7cddfSDavid du Colombier void
3447dd7cddfSDavid du Colombier filesetname(File *f, String *s)
3457dd7cddfSDavid du Colombier {
3467dd7cddfSDavid du Colombier 	if(!f->unread)	/* This is setting initial file name */
3477dd7cddfSDavid du Colombier 		fileunsetname(f, &f->delta);
3487dd7cddfSDavid du Colombier 	Strduplstr(&f->name, s);
3497dd7cddfSDavid du Colombier 	sortname(f);
3507dd7cddfSDavid du Colombier 	f->unread = TRUE;
3517dd7cddfSDavid du Colombier }
3527dd7cddfSDavid du Colombier 
3537dd7cddfSDavid du Colombier void
3547dd7cddfSDavid du Colombier fileunsetname(File *f, Buffer *delta)
3557dd7cddfSDavid du Colombier {
3567dd7cddfSDavid du Colombier 	String s;
3577dd7cddfSDavid du Colombier 	Undo u;
3587dd7cddfSDavid du Colombier 
3597dd7cddfSDavid du Colombier 	/* undo a file name change by restoring old name */
3607dd7cddfSDavid du Colombier 	u.type = Filename;
3617dd7cddfSDavid du Colombier 	u.mod = f->mod;
3627dd7cddfSDavid du Colombier 	u.seq = f->seq;
3637dd7cddfSDavid du Colombier 	u.p0 = 0;	/* unused */
3647dd7cddfSDavid du Colombier 	Strinit(&s);
3657dd7cddfSDavid du Colombier 	Strduplstr(&s, &f->name);
3667dd7cddfSDavid du Colombier 	fullname(&s);
3677dd7cddfSDavid du Colombier 	u.n = s.n;
3687dd7cddfSDavid du Colombier 	if(s.n)
3697dd7cddfSDavid du Colombier 		bufinsert(delta, delta->nc, s.s, s.n);
3707dd7cddfSDavid du Colombier 	bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
3717dd7cddfSDavid du Colombier 	Strclose(&s);
3727dd7cddfSDavid du Colombier }
3737dd7cddfSDavid du Colombier 
3747dd7cddfSDavid du Colombier void
3757dd7cddfSDavid du Colombier fileunsetdot(File *f, Buffer *delta, Range dot)
3767dd7cddfSDavid du Colombier {
3777dd7cddfSDavid du Colombier 	Undo u;
3787dd7cddfSDavid du Colombier 
3797dd7cddfSDavid du Colombier 	u.type = Dot;
3807dd7cddfSDavid du Colombier 	u.mod = f->mod;
3817dd7cddfSDavid du Colombier 	u.seq = f->seq;
3827dd7cddfSDavid du Colombier 	u.p0 = dot.p1;
3837dd7cddfSDavid du Colombier 	u.n = dot.p2 - dot.p1;
3847dd7cddfSDavid du Colombier 	bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
3857dd7cddfSDavid du Colombier }
3867dd7cddfSDavid du Colombier 
3877dd7cddfSDavid du Colombier void
3887dd7cddfSDavid du Colombier fileunsetmark(File *f, Buffer *delta, Range mark)
3897dd7cddfSDavid du Colombier {
3907dd7cddfSDavid du Colombier 	Undo u;
3917dd7cddfSDavid du Colombier 
3927dd7cddfSDavid du Colombier 	u.type = Mark;
3937dd7cddfSDavid du Colombier 	u.mod = f->mod;
3947dd7cddfSDavid du Colombier 	u.seq = f->seq;
3957dd7cddfSDavid du Colombier 	u.p0 = mark.p1;
3967dd7cddfSDavid du Colombier 	u.n = mark.p2 - mark.p1;
3977dd7cddfSDavid du Colombier 	bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
3987dd7cddfSDavid du Colombier }
3997dd7cddfSDavid du Colombier 
4007dd7cddfSDavid du Colombier uint
4017dd7cddfSDavid du Colombier fileload(File *f, uint p0, int fd, int *nulls)
4027dd7cddfSDavid du Colombier {
4037dd7cddfSDavid du Colombier 	if(f->seq > 0)
4047dd7cddfSDavid du Colombier 		panic("undo in file.load unimplemented");
4057dd7cddfSDavid du Colombier 	return bufload(f, p0, fd, nulls);
4067dd7cddfSDavid du Colombier }
4077dd7cddfSDavid du Colombier 
4087dd7cddfSDavid du Colombier int
4097dd7cddfSDavid du Colombier fileupdate(File *f, int notrans, int toterm)
4107dd7cddfSDavid du Colombier {
4117dd7cddfSDavid du Colombier 	uint p1, p2;
4127dd7cddfSDavid du Colombier 	int mod;
4137dd7cddfSDavid du Colombier 
4147dd7cddfSDavid du Colombier 	if(f->rescuing)
4157dd7cddfSDavid du Colombier 		return FALSE;
4167dd7cddfSDavid du Colombier 
4177dd7cddfSDavid du Colombier 	flushmerge();
4187dd7cddfSDavid du Colombier 
4197dd7cddfSDavid du Colombier 	/*
4207dd7cddfSDavid du Colombier 	 * fix the modification bit
4217dd7cddfSDavid du Colombier 	 * subtle point: don't save it away in the log.
4227dd7cddfSDavid du Colombier 	 *
4237dd7cddfSDavid du Colombier 	 * if another change is made, the correct f->mod
4247dd7cddfSDavid du Colombier 	 * state is saved  in the undo log by filemark
4257dd7cddfSDavid du Colombier 	 * when setting the dot and mark.
4267dd7cddfSDavid du Colombier 	 *
4277dd7cddfSDavid du Colombier 	 * if the change is undone, the correct state is
4287dd7cddfSDavid du Colombier 	 * saved from f in the fileun... routines.
4297dd7cddfSDavid du Colombier 	 */
4307dd7cddfSDavid du Colombier 	mod = f->mod;
4317dd7cddfSDavid du Colombier 	f->mod = f->prevmod;
4327dd7cddfSDavid du Colombier 	if(f == cmd)
4337dd7cddfSDavid du Colombier 		notrans = TRUE;
4347dd7cddfSDavid du Colombier 	else{
4357dd7cddfSDavid du Colombier 		fileunsetdot(f, &f->delta, f->prevdot);
4367dd7cddfSDavid du Colombier 		fileunsetmark(f, &f->delta, f->prevmark);
4377dd7cddfSDavid du Colombier 	}
4387dd7cddfSDavid du Colombier 	f->dot = f->ndot;
4397dd7cddfSDavid du Colombier 	fileundo(f, FALSE, !notrans, &p1, &p2, toterm);
4407dd7cddfSDavid du Colombier 	f->mod = mod;
4417dd7cddfSDavid du Colombier 
4427dd7cddfSDavid du Colombier 	if(f->delta.nc == 0)
4437dd7cddfSDavid du Colombier 		f->seq = 0;
4447dd7cddfSDavid du Colombier 
4457dd7cddfSDavid du Colombier 	if(f == cmd)
4467dd7cddfSDavid du Colombier 		return FALSE;
4477dd7cddfSDavid du Colombier 
4487dd7cddfSDavid du Colombier 	if(f->mod){
4497dd7cddfSDavid du Colombier 		f->closeok = 0;
4507dd7cddfSDavid du Colombier 		quitok = 0;
4517dd7cddfSDavid du Colombier 	}else
4527dd7cddfSDavid du Colombier 		f->closeok = 1;
4537dd7cddfSDavid du Colombier 	return TRUE;
4547dd7cddfSDavid du Colombier }
4557dd7cddfSDavid du Colombier 
4567dd7cddfSDavid du Colombier long
4577dd7cddfSDavid du Colombier prevseq(Buffer *b)
4587dd7cddfSDavid du Colombier {
4597dd7cddfSDavid du Colombier 	Undo u;
4607dd7cddfSDavid du Colombier 	uint up;
4617dd7cddfSDavid du Colombier 
4627dd7cddfSDavid du Colombier 	up = b->nc;
4637dd7cddfSDavid du Colombier 	if(up == 0)
4647dd7cddfSDavid du Colombier 		return 0;
4657dd7cddfSDavid du Colombier 	up -= Undosize;
4667dd7cddfSDavid du Colombier 	bufread(b, up, (Rune*)&u, Undosize);
4677dd7cddfSDavid du Colombier 	return u.seq;
4687dd7cddfSDavid du Colombier }
4697dd7cddfSDavid du Colombier 
4707dd7cddfSDavid du Colombier long
4717dd7cddfSDavid du Colombier undoseq(File *f, int isundo)
4727dd7cddfSDavid du Colombier {
4737dd7cddfSDavid du Colombier 	if(isundo)
4747dd7cddfSDavid du Colombier 		return f->seq;
4757dd7cddfSDavid du Colombier 
4767dd7cddfSDavid du Colombier 	return prevseq(&f->epsilon);
4777dd7cddfSDavid du Colombier }
4787dd7cddfSDavid du Colombier 
4797dd7cddfSDavid du Colombier void
4807dd7cddfSDavid du Colombier fileundo(File *f, int isundo, int canredo, uint *q0p, uint *q1p, int flag)
4817dd7cddfSDavid du Colombier {
4827dd7cddfSDavid du Colombier 	Undo u;
4837dd7cddfSDavid du Colombier 	Rune *buf;
4847dd7cddfSDavid du Colombier 	uint i, n, up;
4857dd7cddfSDavid du Colombier 	uint stop;
4867dd7cddfSDavid du Colombier 	Buffer *delta, *epsilon;
4877dd7cddfSDavid du Colombier 
4887dd7cddfSDavid du Colombier 	if(isundo){
4897dd7cddfSDavid du Colombier 		/* undo; reverse delta onto epsilon, seq decreases */
4907dd7cddfSDavid du Colombier 		delta = &f->delta;
4917dd7cddfSDavid du Colombier 		epsilon = &f->epsilon;
4927dd7cddfSDavid du Colombier 		stop = f->seq;
4937dd7cddfSDavid du Colombier 	}else{
4947dd7cddfSDavid du Colombier 		/* redo; reverse epsilon onto delta, seq increases */
4957dd7cddfSDavid du Colombier 		delta = &f->epsilon;
4967dd7cddfSDavid du Colombier 		epsilon = &f->delta;
4977dd7cddfSDavid du Colombier 		stop = 0;	/* don't know yet */
4987dd7cddfSDavid du Colombier 	}
4997dd7cddfSDavid du Colombier 
5007dd7cddfSDavid du Colombier 	raspstart(f);
5017dd7cddfSDavid du Colombier 	while(delta->nc > 0){
5027dd7cddfSDavid du Colombier 		up = delta->nc-Undosize;
5037dd7cddfSDavid du Colombier 		bufread(delta, up, (Rune*)&u, Undosize);
5047dd7cddfSDavid du Colombier 		if(isundo){
5057dd7cddfSDavid du Colombier 			if(u.seq < stop){
5067dd7cddfSDavid du Colombier 				f->seq = u.seq;
5077dd7cddfSDavid du Colombier 				raspdone(f, flag);
5087dd7cddfSDavid du Colombier 				return;
5097dd7cddfSDavid du Colombier 			}
5107dd7cddfSDavid du Colombier 		}else{
5117dd7cddfSDavid du Colombier 			if(stop == 0)
5127dd7cddfSDavid du Colombier 				stop = u.seq;
5137dd7cddfSDavid du Colombier 			if(u.seq > stop){
5147dd7cddfSDavid du Colombier 				raspdone(f, flag);
5157dd7cddfSDavid du Colombier 				return;
5167dd7cddfSDavid du Colombier 			}
5177dd7cddfSDavid du Colombier 		}
5187dd7cddfSDavid du Colombier 		switch(u.type){
5197dd7cddfSDavid du Colombier 		default:
5207dd7cddfSDavid du Colombier 			panic("undo unknown u.type");
5217dd7cddfSDavid du Colombier 			break;
5227dd7cddfSDavid du Colombier 
5237dd7cddfSDavid du Colombier 		case Delete:
5247dd7cddfSDavid du Colombier 			f->seq = u.seq;
5257dd7cddfSDavid du Colombier 			if(canredo)
5267dd7cddfSDavid du Colombier 				fileundelete(f, epsilon, u.p0, u.p0+u.n);
5277dd7cddfSDavid du Colombier 			f->mod = u.mod;
5287dd7cddfSDavid du Colombier 			bufdelete(f, u.p0, u.p0+u.n);
5297dd7cddfSDavid du Colombier 			raspdelete(f, u.p0, u.p0+u.n, flag);
5307dd7cddfSDavid du Colombier 			*q0p = u.p0;
5317dd7cddfSDavid du Colombier 			*q1p = u.p0;
5327dd7cddfSDavid du Colombier 			break;
5337dd7cddfSDavid du Colombier 
5347dd7cddfSDavid du Colombier 		case Insert:
5357dd7cddfSDavid du Colombier 			f->seq = u.seq;
5367dd7cddfSDavid du Colombier 			if(canredo)
5377dd7cddfSDavid du Colombier 				fileuninsert(f, epsilon, u.p0, u.n);
5387dd7cddfSDavid du Colombier 			f->mod = u.mod;
5397dd7cddfSDavid du Colombier 			up -= u.n;
5407dd7cddfSDavid du Colombier 			buf = fbufalloc();
5417dd7cddfSDavid du Colombier 			for(i=0; i<u.n; i+=n){
5427dd7cddfSDavid du Colombier 				n = u.n - i;
5437dd7cddfSDavid du Colombier 				if(n > RBUFSIZE)
5447dd7cddfSDavid du Colombier 					n = RBUFSIZE;
5457dd7cddfSDavid du Colombier 				bufread(delta, up+i, buf, n);
5467dd7cddfSDavid du Colombier 				bufinsert(f, u.p0+i, buf, n);
5477dd7cddfSDavid du Colombier 				raspinsert(f, u.p0+i, buf, n, flag);
5487dd7cddfSDavid du Colombier 			}
5497dd7cddfSDavid du Colombier 			fbuffree(buf);
5507dd7cddfSDavid du Colombier 			*q0p = u.p0;
5517dd7cddfSDavid du Colombier 			*q1p = u.p0+u.n;
5527dd7cddfSDavid du Colombier 			break;
5537dd7cddfSDavid du Colombier 
5547dd7cddfSDavid du Colombier 		case Filename:
5557dd7cddfSDavid du Colombier 			f->seq = u.seq;
5567dd7cddfSDavid du Colombier 			if(canredo)
5577dd7cddfSDavid du Colombier 				fileunsetname(f, epsilon);
5587dd7cddfSDavid du Colombier 			f->mod = u.mod;
5597dd7cddfSDavid du Colombier 			up -= u.n;
5607dd7cddfSDavid du Colombier 
5617dd7cddfSDavid du Colombier 			Strinsure(&f->name, u.n+1);
5627dd7cddfSDavid du Colombier 			bufread(delta, up, f->name.s, u.n);
5637dd7cddfSDavid du Colombier 			f->name.s[u.n] = 0;
5647dd7cddfSDavid du Colombier 			f->name.n = u.n;
5657dd7cddfSDavid du Colombier 			fixname(&f->name);
5667dd7cddfSDavid du Colombier 			sortname(f);
5677dd7cddfSDavid du Colombier 			break;
5687dd7cddfSDavid du Colombier 		case Dot:
5697dd7cddfSDavid du Colombier 			f->seq = u.seq;
5707dd7cddfSDavid du Colombier 			if(canredo)
5717dd7cddfSDavid du Colombier 				fileunsetdot(f, epsilon, f->dot.r);
5727dd7cddfSDavid du Colombier 			f->mod = u.mod;
5737dd7cddfSDavid du Colombier 			f->dot.r.p1 = u.p0;
5747dd7cddfSDavid du Colombier 			f->dot.r.p2 = u.p0 + u.n;
5757dd7cddfSDavid du Colombier 			break;
5767dd7cddfSDavid du Colombier 		case Mark:
5777dd7cddfSDavid du Colombier 			f->seq = u.seq;
5787dd7cddfSDavid du Colombier 			if(canredo)
5797dd7cddfSDavid du Colombier 				fileunsetmark(f, epsilon, f->mark);
5807dd7cddfSDavid du Colombier 			f->mod = u.mod;
5817dd7cddfSDavid du Colombier 			f->mark.p1 = u.p0;
5827dd7cddfSDavid du Colombier 			f->mark.p2 = u.p0 + u.n;
5837dd7cddfSDavid du Colombier 			break;
5847dd7cddfSDavid du Colombier 		}
5857dd7cddfSDavid du Colombier 		bufdelete(delta, up, delta->nc);
5867dd7cddfSDavid du Colombier 	}
5877dd7cddfSDavid du Colombier 	if(isundo)
5887dd7cddfSDavid du Colombier 		f->seq = 0;
5897dd7cddfSDavid du Colombier 	raspdone(f, flag);
5907dd7cddfSDavid du Colombier }
5917dd7cddfSDavid du Colombier 
5927dd7cddfSDavid du Colombier void
5937dd7cddfSDavid du Colombier filereset(File *f)
5947dd7cddfSDavid du Colombier {
5957dd7cddfSDavid du Colombier 	bufreset(&f->delta);
5967dd7cddfSDavid du Colombier 	bufreset(&f->epsilon);
5977dd7cddfSDavid du Colombier 	f->seq = 0;
5987dd7cddfSDavid du Colombier }
5997dd7cddfSDavid du Colombier 
6007dd7cddfSDavid du Colombier void
6017dd7cddfSDavid du Colombier fileclose(File *f)
6027dd7cddfSDavid du Colombier {
6033e12c5d1SDavid du Colombier 	Strclose(&f->name);
6047dd7cddfSDavid du Colombier 	bufclose(f);
6057dd7cddfSDavid du Colombier 	bufclose(&f->delta);
6067dd7cddfSDavid 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
6137dd7cddfSDavid du Colombier filemark(File *f)
6143e12c5d1SDavid du Colombier {
6153e12c5d1SDavid du Colombier 
6167dd7cddfSDavid du Colombier 	if(f->unread)
617bd389b36SDavid du Colombier 		return;
6187dd7cddfSDavid du Colombier 	if(f->epsilon.nc)
6197dd7cddfSDavid du Colombier 		bufdelete(&f->epsilon, 0, f->epsilon.nc);
6207dd7cddfSDavid du Colombier 
6217dd7cddfSDavid du Colombier 	if(f != cmd){
6227dd7cddfSDavid du Colombier 		f->prevdot = f->dot.r;
6237dd7cddfSDavid du Colombier 		f->prevmark = f->mark;
6247dd7cddfSDavid du Colombier 		f->prevseq = f->seq;
6257dd7cddfSDavid du Colombier 		f->prevmod = f->mod;
6263e12c5d1SDavid du Colombier 	}
6273e12c5d1SDavid du Colombier 
6287dd7cddfSDavid du Colombier 	f->ndot = f->dot;
6297dd7cddfSDavid du Colombier 	f->seq = seq;
6307dd7cddfSDavid du Colombier 	f->hiposn = 0;
6313e12c5d1SDavid du Colombier }
632