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