Introduction
Introduction Statistics Contact Development Disclaimer Help
file.c - sam - An updated version of the sam text editor.
git clone git://vernunftzentrum.de/sam.git
Log
Files
Refs
LICENSE
---
file.c (11350B)
---
1 /* Copyright (c) 1998 Lucent Technologies - All rights reserved. */
2 #include "sam.h"
3
4 /*
5 * Files are splayed out a factor of NDISC to reduce indirect block acce…
6 */
7 Buffer *undobuf;
8 static String *ftempstr(wchar_t*, int);
9 int fcount;
10 File *lastfile;
11
12 void puthdr_csl(Buffer*, char, int16_t, Posn);
13 void puthdr_cs(Buffer*, char, int16_t);
14 void puthdr_M(Buffer*, Posn, Range, Range, Mod, int16_t);
15 void puthdr_cll(Buffer*, char, Posn, Posn);
16 void Fflush(File*);
17
18 enum{
19 SKIP=50, /* max dist between file changes folded together */
20 MAXCACHE=STRSIZE /* max length of cache. must be < 32K-BLOCKSIZE …
21 };
22
23 void
24 freebufs(void)
25 {
26 Bterm(undobuf);
27 Bterm(snarfbuf);
28 Bterm(plan9buf);
29 }
30
31 void
32 Fstart(void)
33 {
34 undobuf = Bopen();
35 snarfbuf = Bopen();
36 plan9buf = Bopen();
37 }
38
39 void
40 Fmark(File *f, Mod m)
41 {
42 Buffer *t = f->transcript;
43 Posn p;
44
45 if(f->state == Readerr)
46 return;
47 if(f->state == Unread) /* this is implicit 'e' of a file */
48 return;
49 p = m==0? -1 : f->markp;
50 f->markp = t->nrunes;
51 puthdr_M(t, p, f->dot.r, f->mark, f->mod, f->state);
52 f->ndot = f->dot;
53 f->marked = true;
54 f->mod = m;
55 f->hiposn = -1;
56 /* Safety first */
57 f->cp1 = f->cp2 = 0;
58 }
59
60 File *
61 Fopen(void)
62 {
63 File *f;
64
65 f = emalloc(sizeof(File));
66 f->buf = Bopen();
67 f->transcript = Bopen();
68 if(++fcount == NDISC)
69 fcount = 0;
70 f->nrunes = 0;
71 f->markp = 0;
72 f->mod = 0;
73 f->dot.f = f;
74 f->ndot.f = f;
75 f->dev = ~0;
76 f->qid = ~0;
77 Strinit0(&f->name);
78 Strinit(&f->cache);
79 f->state = Unread;
80 Fmark(f, (Mod)0);
81 return f;
82 }
83
84 void
85 Fclose(File *f)
86 {
87 if (!f)
88 return;
89
90 if(f == lastfile)
91 lastfile = NULL;
92 Bterm(f->buf);
93 Bterm(f->transcript);
94 Strclose(&f->name);
95 Strclose(&f->cache);
96 if(f->rasp)
97 listfree(f->rasp);
98 free(f);
99 }
100
101 void
102 Finsert(File *f, String *str, Posn p1)
103 {
104 Buffer *t = f->transcript;
105
106 if(f->state == Readerr)
107 return;
108 if(str->n == 0)
109 return;
110 if(str->n<0 || str->n>STRSIZE)
111 panic("Finsert");
112 if(f->mod < modnum)
113 Fmark(f, modnum);
114 if(p1 < f->hiposn)
115 error(Esequence);
116 if(str->n >= BLOCKSIZE){ /* don't bother with the cache */
117 Fflush(f);
118 puthdr_csl(t, 'i', str->n, p1);
119 Binsert(t, str, t->nrunes);
120 }else{ /* insert into the cache instead of the transcript */
121 if(f->cp2==0 && f->cp1==0 && f->cache.n==0) /* empty cache */
122 f->cp1 = f->cp2 = p1;
123 if(p1-f->cp2>SKIP || f->cache.n+str->n>MAXCACHE-SKIP){
124 Fflush(f);
125 f->cp1 = f->cp2 = p1;
126 }
127 if(f->cp2 != p1){ /* grab the piece in between */
128 wchar_t buf[SKIP];
129 String s;
130 Fchars(f, buf, f->cp2, p1);
131 s.s = buf;
132 s.n = p1-f->cp2;
133 Strinsert(&f->cache, &s, f->cache.n);
134 f->cp2 = p1;
135 }
136 Strinsert(&f->cache, str, f->cache.n);
137 }
138 if(f != cmd)
139 quitok = false;
140 f->closeok = false;
141 if(f->state == Clean)
142 state(f, Dirty);
143 f->hiposn = p1;
144 }
145
146 void
147 Fdelete(File *f, Posn p1, Posn p2)
148 {
149 if(f->state == Readerr)
150 return;
151 if(p1==p2)
152 return;
153 if(f->mod<modnum)
154 Fmark(f, modnum);
155 if(p1<f->hiposn)
156 error(Esequence);
157 if(p1-f->cp2>SKIP)
158 Fflush(f);
159 if(f->cp2==0 && f->cp1==0 && f->cache.n==0) /* empty cache */
160 f->cp1 = f->cp2 = p1;
161 if(f->cp2 != p1){ /* grab the piece in between */
162 if(f->cache.n+(p1-f->cp2)>MAXCACHE){
163 Fflush(f);
164 f->cp1 = f->cp2 = p1;
165 }else{
166 wchar_t buf[SKIP];
167 String s;
168 Fchars(f, buf, f->cp2, p1);
169 s.s = buf;
170 s.n = p1-f->cp2;
171 Strinsert(&f->cache, &s, f->cache.n);
172 }
173 }
174 f->cp2 = p2;
175 if(f!=cmd)
176 quitok = false;
177 f->closeok = false;
178 if(f->state==Clean)
179 state(f, Dirty);
180 f->hiposn = p2;
181 }
182
183 void
184 Fflush(File *f)
185 {
186 Buffer *t = f->transcript;
187 Posn p1 = f->cp1, p2 = f->cp2;
188
189 if(f->state == Readerr)
190 return;
191 if(p1 != p2)
192 puthdr_cll(t, 'd', p1, p2);
193 if(f->cache.n){
194 puthdr_csl(t, 'i', f->cache.n, p2);
195 Binsert(t, &f->cache, t->nrunes);
196 Strzero(&f->cache);
197 }
198 f->cp1 = f->cp2 = 0;
199 }
200
201 void
202 Fsetname(File *f, String *s)
203 {
204 Buffer *t = f->transcript;
205
206 if(f->state == Readerr)
207 return;
208 if(f->state == Unread){ /* This is setting initial file name */
209 Strduplstr(&f->name, s);
210 sortname(f);
211 }else{
212 if(f->mod < modnum)
213 Fmark(f, modnum);
214 puthdr_cs(t, 'f', s->n);
215 Binsert(t, s, t->nrunes);
216 }
217 }
218
219 /*
220 * The heart of it all. Fupdate will run along the transcript list, exec…
221 * the commands and converting them into their inverses for a later undo…
222 * The pass runs top to bottom, so addresses in the transcript are track…
223 * (by the var. delta) so they stay valid during the operation. This ca…
224 * all operations to appear to happen simultaneously, which is why the a…
225 * passed to Fdelete and Finsert never take into account other changes o…
226 * in this command (and is why things are done this way).
227 */
228 int
229 Fupdate(File *f, int mktrans, int toterm)
230 {
231 Buffer *t = f->transcript;
232 Buffer *u = undobuf;
233 int n, ni;
234 Posn p0, p1, p2, p, deltadot = 0, deltamark = 0, delta = 0;
235 bool changes = false;
236 union Hdr buf;
237 wchar_t tmp[BLOCKSIZE+1]; /* +1 for NUL in 'f' case */
238
239 if(f->state == Readerr)
240 return false;
241 lastfile = f;
242 Fflush(f);
243 if(f->marked)
244 p0 = f->markp+sizeof(Mark)/RUNESIZE;
245 else
246 p0 = 0;
247 f->dot = f->ndot;
248 while((n=Bread(t, (wchar_t*)&buf, sizeof buf/RUNESIZE, p0)) > 0){
249 switch(buf.cs.c){
250 default:
251 panic("unknown in Fupdate");
252 case 'd':
253 p1 = buf.cll.l;
254 p2 = buf.cll.l1;
255 p0 += sizeof(struct _cll)/RUNESIZE;
256 if(p2 <= f->dot.r.p1)
257 deltadot -= p2-p1;
258 if(p2 <= f->mark.p1)
259 deltamark -= p2-p1;
260 p1 += delta, p2+=delta;
261 delta -= p2-p1;
262 if(!mktrans)
263 for(p = p1; p<p2; p+=ni){
264 if(p2-p>BLOCKSIZE)
265 ni = BLOCKSIZE;
266 else
267 ni = p2-p;
268 puthdr_csl(u, 'i', ni, p1);
269 Bread(f->buf, tmp, ni, p);
270 Binsert(u, ftempstr(tmp, ni), u->nrunes);
271 }
272 f->nrunes -= p2-p1;
273 Bdelete(f->buf, p1, p2);
274 changes = true;
275 break;
276
277 case 'f':
278 n = buf.cs.s;
279 p0 += sizeof(struct _cs)/RUNESIZE;
280 Strinsure(&genstr, n+1);
281 Bread(t, tmp, n, p0);
282 tmp[n] = 0;
283 p0 += n;
284 Strdupl(&genstr, tmp);
285 if(!mktrans){
286 puthdr_cs(u, 'f', f->name.n);
287 Binsert(u, &f->name, u->nrunes);
288 }
289 Strduplstr(&f->name, &genstr);
290 sortname(f);
291 changes = true;
292 break;
293
294 case 'i':
295 n = buf.csl.s;
296 p1 = buf.csl.l;
297 p0 += sizeof(struct _csl)/RUNESIZE;
298 if(p1 < f->dot.r.p1)
299 deltadot += n;
300 if(p1 < f->mark.p1)
301 deltamark += n;
302 p1 += delta;
303 delta += n;
304 if(!mktrans)
305 puthdr_cll(u, 'd', p1, p1+n);
306 changes = true;
307 f->nrunes += n;
308 while(n > 0){
309 if(n > BLOCKSIZE)
310 ni = BLOCKSIZE;
311 else
312 ni = n;
313 Bread(t, tmp, ni, p0);
314 Binsert(f->buf, ftempstr(tmp, ni), p1);
315 n -= ni;
316 p1 += ni;
317 p0 += ni;
318 }
319 break;
320 }
321 }
322 toterminal(f, toterm);
323 f->dot.r.p1 += deltadot;
324 f->dot.r.p2 += deltadot;
325 if(f->dot.r.p1 > f->nrunes)
326 f->dot.r.p1 = f->nrunes;
327 if(f->dot.r.p2 > f->nrunes)
328 f->dot.r.p2 = f->nrunes;
329 f->mark.p1 += deltamark;
330 f->mark.p2 += deltamark;
331 if(f->mark.p1 > f->nrunes)
332 f->mark.p1 = f->nrunes;
333 if(f->mark.p2 > f->nrunes)
334 f->mark.p2 = f->nrunes;
335 if(n < 0)
336 panic("Fupdate read");
337 if(f == cmd)
338 f->mod = 0; /* can't undo command file */
339 if(p0 > f->markp+sizeof(Posn)/RUNESIZE){ /* for undo, this throws…
340 if(f->mod > 0){ /* can't undo the dawn of time */
341 Bdelete(t, f->markp+sizeof(Mark)/RUNESIZE, t->nrunes);
342 /* copy the undo list back into the transcript */
343 for(p = 0; p<u->nrunes; p+=ni){
344 if(u->nrunes-p>BLOCKSIZE)
345 ni = BLOCKSIZE;
346 else
347 ni = u->nrunes-p;
348 Bread(u, tmp, ni, p);
349 Binsert(t, ftempstr(tmp, ni), t->nrunes);
350 }
351 }
352 Bdelete(u, (Posn)0, u->nrunes);
353 }
354 return f==cmd? false : changes;
355 }
356
357 void
358 puthdr_csl(Buffer *b, char c, int16_t s, Posn p)
359 {
360 struct _csl buf;
361
362 if(p < 0)
363 panic("puthdr_csP");
364 buf.c = c;
365 buf.s = s;
366 buf.l = p;
367 Binsert(b, ftempstr((wchar_t*)&buf, sizeof buf/RUNESIZE), b->nrunes);
368 }
369
370 void
371 puthdr_cs(Buffer *b, char c, int16_t s)
372 {
373 struct _cs buf;
374
375 buf.c = c;
376 buf.s = s;
377 Binsert(b, ftempstr((wchar_t*)&buf, sizeof buf/RUNESIZE), b->nrunes);
378 }
379
380 void
381 puthdr_M(Buffer *b, Posn p, Range dot, Range mk, Mod m, int16_t s1)
382 {
383 Mark mark;
384 static bool first = true;
385
386 if(!first && p<0)
387 panic("puthdr_M");
388 mark.p = p;
389 mark.dot = dot;
390 mark.mark = mk;
391 mark.m = m;
392 mark.s1 = s1;
393 Binsert(b, ftempstr((wchar_t *)&mark, sizeof mark/RUNESIZE), b->nrun…
394 }
395
396 void
397 puthdr_cll(Buffer *b, char c, Posn p1, Posn p2)
398 {
399 struct _cll buf;
400
401 if(p1<0 || p2<0)
402 panic("puthdr_cll");
403 buf.c = c;
404 buf.l = p1;
405 buf.l1 = p2;
406 Binsert(b, ftempstr((wchar_t*)&buf, sizeof buf/RUNESIZE), b->nrunes);
407 }
408
409 int64_t
410 Fchars(File *f, wchar_t *addr, Posn p1, Posn p2)
411 {
412 return Bread(f->buf, addr, p2-p1, p1);
413 }
414
415 int
416 Fgetcset(File *f, Posn p)
417 {
418 if(p<0 || p>f->nrunes)
419 panic("Fgetcset out of range");
420 if((f->ngetc = Fchars(f, f->getcbuf, p, p+NGETC))<0)
421 panic("Fgetcset Bread fail");
422 f->getcp = p;
423 f->getci = 0;
424 return f->ngetc;
425 }
426
427 int
428 Fbgetcset(File *f, Posn p)
429 {
430 if(p<0 || p>f->nrunes)
431 panic("Fbgetcset out of range");
432 if((f->ngetc = Fchars(f, f->getcbuf, p<NGETC? (Posn)0 : p-NGETC, p))…
433 panic("Fbgetcset Bread fail");
434 f->getcp = p;
435 f->getci = f->ngetc;
436 return f->ngetc;
437 }
438
439 int
440 Fgetcload(File *f, Posn p)
441 {
442 if(Fgetcset(f, p)){
443 --f->ngetc;
444 f->getcp++;
445 return f->getcbuf[f->getci++];
446 }
447 return -1;
448 }
449
450 int
451 Fbgetcload(File *f, Posn p)
452 {
453 if(Fbgetcset(f, p)){
454 --f->getcp;
455 return f->getcbuf[--f->getci];
456 }
457 return -1;
458 }
459
460 static String*
461 ftempstr(wchar_t *s, int n)
462 {
463 static String p;
464
465 p.s = s;
466 p.n = n;
467 p.size = n;
468 return &p;
469 }
You are viewing proxied material from vernunftzentrum.de. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.