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