plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

file.c (5789B)


      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*
     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
     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
     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
     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
    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
    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
    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
    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
    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
    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
    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
    282 filereset(File *f)
    283 {
    284 	bufreset(&f->delta);
    285 	bufreset(&f->epsilon);
    286 	f->seq = 0;
    287 }
    288 
    289 void
    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
    306 filemark(File *f)
    307 {
    308 	if(f->epsilon.nc)
    309 		bufdelete(&f->epsilon, 0, f->epsilon.nc);
    310 	f->seq = seq;
    311 }