xref: /plan9/sys/src/cmd/acme/file.c (revision ef9eff0badb330e9dfd6ba476ea333c24db47db4)
17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <draw.h>
47dd7cddfSDavid du Colombier #include <thread.h>
59a747e4fSDavid du Colombier #include <cursor.h>
67dd7cddfSDavid du Colombier #include <mouse.h>
77dd7cddfSDavid du Colombier #include <keyboard.h>
87dd7cddfSDavid du Colombier #include <frame.h>
97dd7cddfSDavid du Colombier #include <fcall.h>
107dd7cddfSDavid du Colombier #include <plumb.h>
117dd7cddfSDavid du Colombier #include "dat.h"
127dd7cddfSDavid du Colombier #include "fns.h"
137dd7cddfSDavid du Colombier 
147dd7cddfSDavid du Colombier /*
157dd7cddfSDavid du Colombier  * Structure of Undo list:
167dd7cddfSDavid du Colombier  * 	The Undo structure follows any associated data, so the list
177dd7cddfSDavid du Colombier  *	can be read backwards: read the structure, then read whatever
187dd7cddfSDavid du Colombier  *	data is associated (insert string, file name) and precedes it.
197dd7cddfSDavid du Colombier  *	The structure includes the previous value of the modify bit
207dd7cddfSDavid du Colombier  *	and a sequence number; successive Undo structures with the
217dd7cddfSDavid du Colombier  *	same sequence number represent simultaneous changes.
227dd7cddfSDavid du Colombier  */
237dd7cddfSDavid du Colombier 
247dd7cddfSDavid du Colombier typedef struct Undo Undo;
257dd7cddfSDavid du Colombier struct Undo
267dd7cddfSDavid du Colombier {
277dd7cddfSDavid du Colombier 	short	type;		/* Delete, Insert, Filename */
287dd7cddfSDavid du Colombier 	short	mod;	/* modify bit */
297dd7cddfSDavid du Colombier 	uint		seq;		/* sequence number */
307dd7cddfSDavid du Colombier 	uint		p0;		/* location of change (unused in f) */
317dd7cddfSDavid du Colombier 	uint		n;		/* # runes in string or file name */
327dd7cddfSDavid du Colombier };
337dd7cddfSDavid du Colombier 
347dd7cddfSDavid du Colombier enum
357dd7cddfSDavid du Colombier {
367dd7cddfSDavid du Colombier 	Undosize = sizeof(Undo)/sizeof(Rune),
377dd7cddfSDavid du Colombier };
387dd7cddfSDavid du Colombier 
397dd7cddfSDavid du Colombier File*
fileaddtext(File * f,Text * t)407dd7cddfSDavid du Colombier fileaddtext(File *f, Text *t)
417dd7cddfSDavid du Colombier {
427dd7cddfSDavid du Colombier 	if(f == nil){
437dd7cddfSDavid du Colombier 		f = emalloc(sizeof(File));
447dd7cddfSDavid du Colombier 		f->unread = TRUE;
457dd7cddfSDavid du Colombier 	}
467dd7cddfSDavid du Colombier 	f->text = realloc(f->text, (f->ntext+1)*sizeof(Text*));
477dd7cddfSDavid du Colombier 	f->text[f->ntext++] = t;
487dd7cddfSDavid du Colombier 	f->curtext = t;
497dd7cddfSDavid du Colombier 	return f;
507dd7cddfSDavid du Colombier }
517dd7cddfSDavid du Colombier 
527dd7cddfSDavid du Colombier void
filedeltext(File * f,Text * t)537dd7cddfSDavid du Colombier filedeltext(File *f, Text *t)
547dd7cddfSDavid du Colombier {
557dd7cddfSDavid du Colombier 	int i;
567dd7cddfSDavid du Colombier 
577dd7cddfSDavid du Colombier 	for(i=0; i<f->ntext; i++)
587dd7cddfSDavid du Colombier 		if(f->text[i] == t)
597dd7cddfSDavid du Colombier 			goto Found;
607dd7cddfSDavid du Colombier 	error("can't find text in filedeltext");
617dd7cddfSDavid du Colombier 
627dd7cddfSDavid du Colombier     Found:
637dd7cddfSDavid du Colombier 	f->ntext--;
647dd7cddfSDavid du Colombier 	if(f->ntext == 0){
657dd7cddfSDavid du Colombier 		fileclose(f);
667dd7cddfSDavid du Colombier 		return;
677dd7cddfSDavid du Colombier 	}
687dd7cddfSDavid du Colombier 	memmove(f->text+i, f->text+i+1, (f->ntext-i)*sizeof(Text*));
697dd7cddfSDavid du Colombier 	if(f->curtext == t)
707dd7cddfSDavid du Colombier 		f->curtext = f->text[0];
717dd7cddfSDavid du Colombier }
727dd7cddfSDavid du Colombier 
737dd7cddfSDavid du Colombier void
fileinsert(File * f,uint p0,Rune * s,uint ns)747dd7cddfSDavid du Colombier fileinsert(File *f, uint p0, Rune *s, uint ns)
757dd7cddfSDavid du Colombier {
767dd7cddfSDavid du Colombier 	if(p0 > f->nc)
777dd7cddfSDavid du Colombier 		error("internal error: fileinsert");
787dd7cddfSDavid du Colombier 	if(f->seq > 0)
797dd7cddfSDavid du Colombier 		fileuninsert(f, &f->delta, p0, ns);
807dd7cddfSDavid du Colombier 	bufinsert(f, p0, s, ns);
817dd7cddfSDavid du Colombier 	if(ns)
827dd7cddfSDavid du Colombier 		f->mod = TRUE;
837dd7cddfSDavid du Colombier }
847dd7cddfSDavid du Colombier 
857dd7cddfSDavid du Colombier void
fileuninsert(File * f,Buffer * delta,uint p0,uint ns)867dd7cddfSDavid du Colombier fileuninsert(File *f, Buffer *delta, uint p0, uint ns)
877dd7cddfSDavid du Colombier {
887dd7cddfSDavid du Colombier 	Undo u;
897dd7cddfSDavid du Colombier 
907dd7cddfSDavid du Colombier 	/* undo an insertion by deleting */
917dd7cddfSDavid du Colombier 	u.type = Delete;
927dd7cddfSDavid du Colombier 	u.mod = f->mod;
937dd7cddfSDavid du Colombier 	u.seq = f->seq;
947dd7cddfSDavid du Colombier 	u.p0 = p0;
957dd7cddfSDavid du Colombier 	u.n = ns;
967dd7cddfSDavid du Colombier 	bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
977dd7cddfSDavid du Colombier }
987dd7cddfSDavid du Colombier 
997dd7cddfSDavid du Colombier void
filedelete(File * f,uint p0,uint p1)1007dd7cddfSDavid du Colombier filedelete(File *f, uint p0, uint p1)
1017dd7cddfSDavid du Colombier {
1027dd7cddfSDavid du Colombier 	if(!(p0<=p1 && p0<=f->nc && p1<=f->nc))
1037dd7cddfSDavid du Colombier 		error("internal error: filedelete");
1047dd7cddfSDavid du Colombier 	if(f->seq > 0)
1057dd7cddfSDavid du Colombier 		fileundelete(f, &f->delta, p0, p1);
1067dd7cddfSDavid du Colombier 	bufdelete(f, p0, p1);
1077dd7cddfSDavid du Colombier 	if(p1 > p0)
1087dd7cddfSDavid du Colombier 		f->mod = TRUE;
1097dd7cddfSDavid du Colombier }
1107dd7cddfSDavid du Colombier 
1117dd7cddfSDavid du Colombier void
fileundelete(File * f,Buffer * delta,uint p0,uint p1)1127dd7cddfSDavid du Colombier fileundelete(File *f, Buffer *delta, uint p0, uint p1)
1137dd7cddfSDavid du Colombier {
1147dd7cddfSDavid du Colombier 	Undo u;
1157dd7cddfSDavid du Colombier 	Rune *buf;
1167dd7cddfSDavid du Colombier 	uint i, n;
1177dd7cddfSDavid du Colombier 
1187dd7cddfSDavid du Colombier 	/* undo a deletion by inserting */
1197dd7cddfSDavid du Colombier 	u.type = Insert;
1207dd7cddfSDavid du Colombier 	u.mod = f->mod;
1217dd7cddfSDavid du Colombier 	u.seq = f->seq;
1227dd7cddfSDavid du Colombier 	u.p0 = p0;
1237dd7cddfSDavid du Colombier 	u.n = p1-p0;
1247dd7cddfSDavid du Colombier 	buf = fbufalloc();
1257dd7cddfSDavid du Colombier 	for(i=p0; i<p1; i+=n){
1267dd7cddfSDavid du Colombier 		n = p1 - i;
1277dd7cddfSDavid du Colombier 		if(n > RBUFSIZE)
1287dd7cddfSDavid du Colombier 			n = RBUFSIZE;
1297dd7cddfSDavid du Colombier 		bufread(f, i, buf, n);
1307dd7cddfSDavid du Colombier 		bufinsert(delta, delta->nc, buf, n);
1317dd7cddfSDavid du Colombier 	}
1327dd7cddfSDavid du Colombier 	fbuffree(buf);
1337dd7cddfSDavid du Colombier 	bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
1347dd7cddfSDavid du Colombier 
1357dd7cddfSDavid du Colombier }
1367dd7cddfSDavid du Colombier 
1377dd7cddfSDavid du Colombier void
filesetname(File * f,Rune * name,int n)1387dd7cddfSDavid du Colombier filesetname(File *f, Rune *name, int n)
1397dd7cddfSDavid du Colombier {
1407dd7cddfSDavid du Colombier 	if(f->seq > 0)
1417dd7cddfSDavid du Colombier 		fileunsetname(f, &f->delta);
1427dd7cddfSDavid du Colombier 	free(f->name);
1437dd7cddfSDavid du Colombier 	f->name = runemalloc(n);
1447dd7cddfSDavid du Colombier 	runemove(f->name, name, n);
1457dd7cddfSDavid du Colombier 	f->nname = n;
1467dd7cddfSDavid du Colombier 	f->unread = TRUE;
1477dd7cddfSDavid du Colombier }
1487dd7cddfSDavid du Colombier 
1497dd7cddfSDavid du Colombier void
fileunsetname(File * f,Buffer * delta)1507dd7cddfSDavid du Colombier fileunsetname(File *f, Buffer *delta)
1517dd7cddfSDavid du Colombier {
1527dd7cddfSDavid du Colombier 	Undo u;
1537dd7cddfSDavid du Colombier 
1547dd7cddfSDavid du Colombier 	/* undo a file name change by restoring old name */
1557dd7cddfSDavid du Colombier 	u.type = Filename;
1567dd7cddfSDavid du Colombier 	u.mod = f->mod;
1577dd7cddfSDavid du Colombier 	u.seq = f->seq;
1587dd7cddfSDavid du Colombier 	u.p0 = 0;	/* unused */
1597dd7cddfSDavid du Colombier 	u.n = f->nname;
1607dd7cddfSDavid du Colombier 	if(f->nname)
1617dd7cddfSDavid du Colombier 		bufinsert(delta, delta->nc, f->name, f->nname);
1627dd7cddfSDavid du Colombier 	bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
1637dd7cddfSDavid du Colombier }
1647dd7cddfSDavid du Colombier 
1657dd7cddfSDavid du Colombier uint
fileload(File * f,uint p0,int fd,int * nulls)1667dd7cddfSDavid du Colombier fileload(File *f, uint p0, int fd, int *nulls)
1677dd7cddfSDavid du Colombier {
1687dd7cddfSDavid du Colombier 	if(f->seq > 0)
1697dd7cddfSDavid du Colombier 		error("undo in file.load unimplemented");
1707dd7cddfSDavid du Colombier 	return bufload(f, p0, fd, nulls);
1717dd7cddfSDavid du Colombier }
1727dd7cddfSDavid du Colombier 
17359cc4ca5SDavid du Colombier /* return sequence number of pending redo */
17459cc4ca5SDavid du Colombier uint
fileredoseq(File * f)17559cc4ca5SDavid du Colombier fileredoseq(File *f)
17659cc4ca5SDavid du Colombier {
17759cc4ca5SDavid du Colombier 	Undo u;
17859cc4ca5SDavid du Colombier 	Buffer *delta;
17959cc4ca5SDavid du Colombier 
18059cc4ca5SDavid du Colombier 	delta = &f->epsilon;
18159cc4ca5SDavid du Colombier 	if(delta->nc == 0)
182*ef9eff0bSDavid du Colombier 		return 0;
18359cc4ca5SDavid du Colombier 	bufread(delta, delta->nc-Undosize, (Rune*)&u, Undosize);
18459cc4ca5SDavid du Colombier 	return u.seq;
18559cc4ca5SDavid du Colombier }
18659cc4ca5SDavid du Colombier 
1877dd7cddfSDavid du Colombier void
fileundo(File * f,int isundo,uint * q0p,uint * q1p)1887dd7cddfSDavid du Colombier fileundo(File *f, int isundo, uint *q0p, uint *q1p)
1897dd7cddfSDavid du Colombier {
1907dd7cddfSDavid du Colombier 	Undo u;
1917dd7cddfSDavid du Colombier 	Rune *buf;
1927dd7cddfSDavid du Colombier 	uint i, j, n, up;
1937dd7cddfSDavid du Colombier 	uint stop;
1947dd7cddfSDavid du Colombier 	Buffer *delta, *epsilon;
1957dd7cddfSDavid du Colombier 
1967dd7cddfSDavid du Colombier 	if(isundo){
1977dd7cddfSDavid du Colombier 		/* undo; reverse delta onto epsilon, seq decreases */
1987dd7cddfSDavid du Colombier 		delta = &f->delta;
1997dd7cddfSDavid du Colombier 		epsilon = &f->epsilon;
2007dd7cddfSDavid du Colombier 		stop = f->seq;
2017dd7cddfSDavid du Colombier 	}else{
2027dd7cddfSDavid du Colombier 		/* redo; reverse epsilon onto delta, seq increases */
2037dd7cddfSDavid du Colombier 		delta = &f->epsilon;
2047dd7cddfSDavid du Colombier 		epsilon = &f->delta;
2057dd7cddfSDavid du Colombier 		stop = 0;	/* don't know yet */
2067dd7cddfSDavid du Colombier 	}
2077dd7cddfSDavid du Colombier 
20859cc4ca5SDavid du Colombier 	buf = fbufalloc();
2097dd7cddfSDavid du Colombier 	while(delta->nc > 0){
2107dd7cddfSDavid du Colombier 		up = delta->nc-Undosize;
2117dd7cddfSDavid du Colombier 		bufread(delta, up, (Rune*)&u, Undosize);
2127dd7cddfSDavid du Colombier 		if(isundo){
2137dd7cddfSDavid du Colombier 			if(u.seq < stop){
2147dd7cddfSDavid du Colombier 				f->seq = u.seq;
21559cc4ca5SDavid du Colombier 				goto Return;
2167dd7cddfSDavid du Colombier 			}
2177dd7cddfSDavid du Colombier 		}else{
2187dd7cddfSDavid du Colombier 			if(stop == 0)
2197dd7cddfSDavid du Colombier 				stop = u.seq;
2207dd7cddfSDavid du Colombier 			if(u.seq > stop)
22159cc4ca5SDavid du Colombier 				goto Return;
2227dd7cddfSDavid du Colombier 		}
2237dd7cddfSDavid du Colombier 		switch(u.type){
2247dd7cddfSDavid du Colombier 		default:
2257dd7cddfSDavid du Colombier 			fprint(2, "undo: 0x%ux\n", u.type);
2267dd7cddfSDavid du Colombier 			abort();
2277dd7cddfSDavid du Colombier 			break;
2287dd7cddfSDavid du Colombier 
2297dd7cddfSDavid du Colombier 		case Delete:
2307dd7cddfSDavid du Colombier 			f->seq = u.seq;
2317dd7cddfSDavid du Colombier 			fileundelete(f, epsilon, u.p0, u.p0+u.n);
2327dd7cddfSDavid du Colombier 			f->mod = u.mod;
2337dd7cddfSDavid du Colombier 			bufdelete(f, u.p0, u.p0+u.n);
2347dd7cddfSDavid du Colombier 			for(j=0; j<f->ntext; j++)
2357dd7cddfSDavid du Colombier 				textdelete(f->text[j], u.p0, u.p0+u.n, FALSE);
2367dd7cddfSDavid du Colombier 			*q0p = u.p0;
2377dd7cddfSDavid du Colombier 			*q1p = u.p0;
2387dd7cddfSDavid du Colombier 			break;
2397dd7cddfSDavid du Colombier 
2407dd7cddfSDavid du Colombier 		case Insert:
2417dd7cddfSDavid du Colombier 			f->seq = u.seq;
2427dd7cddfSDavid du Colombier 			fileuninsert(f, epsilon, u.p0, u.n);
2437dd7cddfSDavid du Colombier 			f->mod = u.mod;
2447dd7cddfSDavid du Colombier 			up -= u.n;
2457dd7cddfSDavid du Colombier 			for(i=0; i<u.n; i+=n){
2467dd7cddfSDavid du Colombier 				n = u.n - i;
2477dd7cddfSDavid du Colombier 				if(n > RBUFSIZE)
2487dd7cddfSDavid du Colombier 					n = RBUFSIZE;
2497dd7cddfSDavid du Colombier 				bufread(delta, up+i, buf, n);
2507dd7cddfSDavid du Colombier 				bufinsert(f, u.p0+i, buf, n);
2517dd7cddfSDavid du Colombier 				for(j=0; j<f->ntext; j++)
2527dd7cddfSDavid du Colombier 					textinsert(f->text[j], u.p0+i, buf, n, FALSE);
2537dd7cddfSDavid du Colombier 			}
2547dd7cddfSDavid du Colombier 			*q0p = u.p0;
2557dd7cddfSDavid du Colombier 			*q1p = u.p0+u.n;
2567dd7cddfSDavid du Colombier 			break;
2577dd7cddfSDavid du Colombier 
2587dd7cddfSDavid du Colombier 		case Filename:
2597dd7cddfSDavid du Colombier 			f->seq = u.seq;
2607dd7cddfSDavid du Colombier 			fileunsetname(f, epsilon);
2617dd7cddfSDavid du Colombier 			f->mod = u.mod;
2627dd7cddfSDavid du Colombier 			up -= u.n;
2637dd7cddfSDavid du Colombier 			free(f->name);
2647dd7cddfSDavid du Colombier 			if(u.n == 0)
2657dd7cddfSDavid du Colombier 				f->name = nil;
2667dd7cddfSDavid du Colombier 			else
2677dd7cddfSDavid du Colombier 				f->name = runemalloc(u.n);
2687dd7cddfSDavid du Colombier 			bufread(delta, up, f->name, u.n);
2697dd7cddfSDavid du Colombier 			f->nname = u.n;
2707dd7cddfSDavid du Colombier 			break;
2717dd7cddfSDavid du Colombier 		}
2727dd7cddfSDavid du Colombier 		bufdelete(delta, up, delta->nc);
2737dd7cddfSDavid du Colombier 	}
2747dd7cddfSDavid du Colombier 	if(isundo)
2757dd7cddfSDavid du Colombier 		f->seq = 0;
27659cc4ca5SDavid du Colombier     Return:
27759cc4ca5SDavid du Colombier 	fbuffree(buf);
2787dd7cddfSDavid du Colombier }
2797dd7cddfSDavid du Colombier 
2807dd7cddfSDavid du Colombier void
filereset(File * f)2817dd7cddfSDavid du Colombier filereset(File *f)
2827dd7cddfSDavid du Colombier {
2837dd7cddfSDavid du Colombier 	bufreset(&f->delta);
2847dd7cddfSDavid du Colombier 	bufreset(&f->epsilon);
2857dd7cddfSDavid du Colombier 	f->seq = 0;
2867dd7cddfSDavid du Colombier }
2877dd7cddfSDavid du Colombier 
2887dd7cddfSDavid du Colombier void
fileclose(File * f)2897dd7cddfSDavid du Colombier fileclose(File *f)
2907dd7cddfSDavid du Colombier {
2917dd7cddfSDavid du Colombier 	free(f->name);
2927dd7cddfSDavid du Colombier 	f->nname = 0;
2937dd7cddfSDavid du Colombier 	f->name = nil;
2947dd7cddfSDavid du Colombier 	free(f->text);
2957dd7cddfSDavid du Colombier 	f->ntext = 0;
2967dd7cddfSDavid du Colombier 	f->text = nil;
2977dd7cddfSDavid du Colombier 	bufclose(f);
2987dd7cddfSDavid du Colombier 	bufclose(&f->delta);
2997dd7cddfSDavid du Colombier 	bufclose(&f->epsilon);
30059cc4ca5SDavid du Colombier 	elogclose(f);
3017dd7cddfSDavid du Colombier 	free(f);
3027dd7cddfSDavid du Colombier }
3037dd7cddfSDavid du Colombier 
3047dd7cddfSDavid du Colombier void
filemark(File * f)3057dd7cddfSDavid du Colombier filemark(File *f)
3067dd7cddfSDavid du Colombier {
3077dd7cddfSDavid du Colombier 	if(f->epsilon.nc)
3087dd7cddfSDavid du Colombier 		bufdelete(&f->epsilon, 0, f->epsilon.nc);
3097dd7cddfSDavid du Colombier 	f->seq = seq;
3107dd7cddfSDavid du Colombier }
311