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 }