1 #include <u.h>
2 #include <libc.h>
3 #include <draw.h>
4 #include <thread.h>
5 #include <cursor.h>
6 #include <mouse.h>
7 #include <keyboard.h>
8 #include <frame.h>
9 #include <fcall.h>
10 #include <plumb.h>
11 #include <libsec.h>
12 #include "dat.h"
13 #include "fns.h"
14 
15 /*
16  * Structure of Undo list:
17  * 	The Undo structure follows any associated data, so the list
18  *	can be read backwards: read the structure, then read whatever
19  *	data is associated (insert string, file name) and precedes it.
20  *	The structure includes the previous value of the modify bit
21  *	and a sequence number; successive Undo structures with the
22  *	same sequence number represent simultaneous changes.
23  */
24 
25 typedef struct Undo Undo;
26 struct Undo
27 {
28 	short	type;		/* Delete, Insert, Filename */
29 	short	mod;	/* modify bit */
30 	uint		seq;		/* sequence number */
31 	uint		p0;		/* location of change (unused in f) */
32 	uint		n;		/* # runes in string or file name */
33 };
34 
35 enum
36 {
37 	Undosize = sizeof(Undo)/sizeof(Rune)
38 };
39 
40 File*
fileaddtext(File * f,Text * t)41 fileaddtext(File *f, Text *t)
42 {
43 	if(f == nil){
44 		f = emalloc(sizeof(File));
45 		f->unread = TRUE;
46 	}
47 	f->text = realloc(f->text, (f->ntext+1)*sizeof(Text*));
48 	f->text[f->ntext++] = t;
49 	f->curtext = t;
50 	return f;
51 }
52 
53 void
filedeltext(File * f,Text * t)54 filedeltext(File *f, Text *t)
55 {
56 	int i;
57 
58 	for(i=0; i<f->ntext; i++)
59 		if(f->text[i] == t)
60 			goto Found;
61 	error("can't find text in filedeltext");
62 
63     Found:
64 	f->ntext--;
65 	if(f->ntext == 0){
66 		fileclose(f);
67 		return;
68 	}
69 	memmove(f->text+i, f->text+i+1, (f->ntext-i)*sizeof(Text*));
70 	if(f->curtext == t)
71 		f->curtext = f->text[0];
72 }
73 
74 void
fileinsert(File * f,uint p0,Rune * s,uint ns)75 fileinsert(File *f, uint p0, Rune *s, uint ns)
76 {
77 	if(p0 > f->b.nc)
78 		error("internal error: fileinsert");
79 	if(f->seq > 0)
80 		fileuninsert(f, &f->delta, p0, ns);
81 	bufinsert(&f->b, p0, s, ns);
82 	if(ns)
83 		f->mod = TRUE;
84 }
85 
86 void
fileuninsert(File * f,Buffer * delta,uint p0,uint ns)87 fileuninsert(File *f, Buffer *delta, uint p0, uint ns)
88 {
89 	Undo u;
90 
91 	/* undo an insertion by deleting */
92 	u.type = Delete;
93 	u.mod = f->mod;
94 	u.seq = f->seq;
95 	u.p0 = p0;
96 	u.n = ns;
97 	bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
98 }
99 
100 void
filedelete(File * f,uint p0,uint p1)101 filedelete(File *f, uint p0, uint p1)
102 {
103 	if(!(p0<=p1 && p0<=f->b.nc && p1<=f->b.nc))
104 		error("internal error: filedelete");
105 	if(f->seq > 0)
106 		fileundelete(f, &f->delta, p0, p1);
107 	bufdelete(&f->b, p0, p1);
108 	if(p1 > p0)
109 		f->mod = TRUE;
110 }
111 
112 void
fileundelete(File * f,Buffer * delta,uint p0,uint p1)113 fileundelete(File *f, Buffer *delta, uint p0, uint p1)
114 {
115 	Undo u;
116 	Rune *buf;
117 	uint i, n;
118 
119 	/* undo a deletion by inserting */
120 	u.type = Insert;
121 	u.mod = f->mod;
122 	u.seq = f->seq;
123 	u.p0 = p0;
124 	u.n = p1-p0;
125 	buf = fbufalloc();
126 	for(i=p0; i<p1; i+=n){
127 		n = p1 - i;
128 		if(n > RBUFSIZE)
129 			n = RBUFSIZE;
130 		bufread(&f->b, i, buf, n);
131 		bufinsert(delta, delta->nc, buf, n);
132 	}
133 	fbuffree(buf);
134 	bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
135 
136 }
137 
138 void
filesetname(File * f,Rune * name,int n)139 filesetname(File *f, Rune *name, int n)
140 {
141 	if(f->seq > 0)
142 		fileunsetname(f, &f->delta);
143 	free(f->name);
144 	f->name = runemalloc(n);
145 	runemove(f->name, name, n);
146 	f->nname = n;
147 	f->unread = TRUE;
148 }
149 
150 void
fileunsetname(File * f,Buffer * delta)151 fileunsetname(File *f, Buffer *delta)
152 {
153 	Undo u;
154 
155 	/* undo a file name change by restoring old name */
156 	u.type = Filename;
157 	u.mod = f->mod;
158 	u.seq = f->seq;
159 	u.p0 = 0;	/* unused */
160 	u.n = f->nname;
161 	if(f->nname)
162 		bufinsert(delta, delta->nc, f->name, f->nname);
163 	bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
164 }
165 
166 uint
fileload(File * f,uint p0,int fd,int * nulls,DigestState * h)167 fileload(File *f, uint p0, int fd, int *nulls, DigestState *h)
168 {
169 	if(f->seq > 0)
170 		error("undo in file.load unimplemented");
171 	return bufload(&f->b, p0, fd, nulls, h);
172 }
173 
174 /* return sequence number of pending redo */
175 uint
fileredoseq(File * f)176 fileredoseq(File *f)
177 {
178 	Undo u;
179 	Buffer *delta;
180 
181 	delta = &f->epsilon;
182 	if(delta->nc == 0)
183 		return 0;
184 	bufread(delta, delta->nc-Undosize, (Rune*)&u, Undosize);
185 	return u.seq;
186 }
187 
188 void
fileundo(File * f,int isundo,uint * q0p,uint * q1p)189 fileundo(File *f, int isundo, uint *q0p, uint *q1p)
190 {
191 	Undo u;
192 	Rune *buf;
193 	uint i, j, n, up;
194 	uint stop;
195 	Buffer *delta, *epsilon;
196 
197 	if(isundo){
198 		/* undo; reverse delta onto epsilon, seq decreases */
199 		delta = &f->delta;
200 		epsilon = &f->epsilon;
201 		stop = f->seq;
202 	}else{
203 		/* redo; reverse epsilon onto delta, seq increases */
204 		delta = &f->epsilon;
205 		epsilon = &f->delta;
206 		stop = 0;	/* don't know yet */
207 	}
208 
209 	buf = fbufalloc();
210 	while(delta->nc > 0){
211 		up = delta->nc-Undosize;
212 		bufread(delta, up, (Rune*)&u, Undosize);
213 		if(isundo){
214 			if(u.seq < stop){
215 				f->seq = u.seq;
216 				goto Return;
217 			}
218 		}else{
219 			if(stop == 0)
220 				stop = u.seq;
221 			if(u.seq > stop)
222 				goto Return;
223 		}
224 		switch(u.type){
225 		default:
226 			fprint(2, "undo: 0x%ux\n", u.type);
227 			abort();
228 			break;
229 
230 		case Delete:
231 			f->seq = u.seq;
232 			fileundelete(f, epsilon, u.p0, u.p0+u.n);
233 			f->mod = u.mod;
234 			bufdelete(&f->b, u.p0, u.p0+u.n);
235 			for(j=0; j<f->ntext; j++)
236 				textdelete(f->text[j], u.p0, u.p0+u.n, FALSE);
237 			*q0p = u.p0;
238 			*q1p = u.p0;
239 			break;
240 
241 		case Insert:
242 			f->seq = u.seq;
243 			fileuninsert(f, epsilon, u.p0, u.n);
244 			f->mod = u.mod;
245 			up -= u.n;
246 			for(i=0; i<u.n; i+=n){
247 				n = u.n - i;
248 				if(n > RBUFSIZE)
249 					n = RBUFSIZE;
250 				bufread(delta, up+i, buf, n);
251 				bufinsert(&f->b, u.p0+i, buf, n);
252 				for(j=0; j<f->ntext; j++)
253 					textinsert(f->text[j], u.p0+i, buf, n, FALSE);
254 			}
255 			*q0p = u.p0;
256 			*q1p = u.p0+u.n;
257 			break;
258 
259 		case Filename:
260 			f->seq = u.seq;
261 			fileunsetname(f, epsilon);
262 			f->mod = u.mod;
263 			up -= u.n;
264 			free(f->name);
265 			if(u.n == 0)
266 				f->name = nil;
267 			else
268 				f->name = runemalloc(u.n);
269 			bufread(delta, up, f->name, u.n);
270 			f->nname = u.n;
271 			break;
272 		}
273 		bufdelete(delta, up, delta->nc);
274 	}
275 	if(isundo)
276 		f->seq = 0;
277     Return:
278 	fbuffree(buf);
279 }
280 
281 void
filereset(File * f)282 filereset(File *f)
283 {
284 	bufreset(&f->delta);
285 	bufreset(&f->epsilon);
286 	f->seq = 0;
287 }
288 
289 void
fileclose(File * f)290 fileclose(File *f)
291 {
292 	free(f->name);
293 	f->nname = 0;
294 	f->name = nil;
295 	free(f->text);
296 	f->ntext = 0;
297 	f->text = nil;
298 	bufclose(&f->b);
299 	bufclose(&f->delta);
300 	bufclose(&f->epsilon);
301 	elogclose(f);
302 	free(f);
303 }
304 
305 void
filemark(File * f)306 filemark(File *f)
307 {
308 	if(f->epsilon.nc)
309 		bufdelete(&f->epsilon, 0, f->epsilon.nc);
310 	f->seq = seq;
311 }
312