13e12c5d1SDavid du Colombier #include "sam.h" 27dd7cddfSDavid du Colombier 33e12c5d1SDavid du Colombier /* 47dd7cddfSDavid du Colombier * Structure of Undo list: 57dd7cddfSDavid du Colombier * The Undo structure follows any associated data, so the list 67dd7cddfSDavid du Colombier * can be read backwards: read the structure, then read whatever 77dd7cddfSDavid du Colombier * data is associated (insert string, file name) and precedes it. 87dd7cddfSDavid du Colombier * The structure includes the previous value of the modify bit 97dd7cddfSDavid du Colombier * and a sequence number; successive Undo structures with the 107dd7cddfSDavid du Colombier * same sequence number represent simultaneous changes. 113e12c5d1SDavid du Colombier */ 123e12c5d1SDavid du Colombier 137dd7cddfSDavid du Colombier typedef struct Undo Undo; 147dd7cddfSDavid du Colombier typedef struct Merge Merge; 153e12c5d1SDavid du Colombier 167dd7cddfSDavid du Colombier struct Undo 177dd7cddfSDavid du Colombier { 187dd7cddfSDavid du Colombier short type; /* Delete, Insert, Filename, Dot, Mark */ 197dd7cddfSDavid du Colombier short mod; /* modify bit */ 207dd7cddfSDavid du Colombier uint seq; /* sequence number */ 217dd7cddfSDavid du Colombier uint p0; /* location of change (unused in f) */ 227dd7cddfSDavid du Colombier uint n; /* # runes in string or file name */ 233e12c5d1SDavid du Colombier }; 243e12c5d1SDavid du Colombier 257dd7cddfSDavid du Colombier struct Merge 263e12c5d1SDavid du Colombier { 277dd7cddfSDavid du Colombier File *f; 287dd7cddfSDavid du Colombier uint seq; /* of logged change */ 297dd7cddfSDavid du Colombier uint p0; /* location of change (unused in f) */ 307dd7cddfSDavid du Colombier uint n; /* # runes to delete */ 317dd7cddfSDavid du Colombier uint nbuf; /* # runes to insert */ 327dd7cddfSDavid du Colombier Rune buf[RBUFSIZE]; 337dd7cddfSDavid du Colombier }; 343e12c5d1SDavid du Colombier 357dd7cddfSDavid du Colombier enum 363e12c5d1SDavid du Colombier { 377dd7cddfSDavid du Colombier Maxmerge = 50, 387dd7cddfSDavid du Colombier Undosize = sizeof(Undo)/sizeof(Rune), 397dd7cddfSDavid du Colombier }; 403e12c5d1SDavid du Colombier 417dd7cddfSDavid du Colombier static Merge merge; 423e12c5d1SDavid du Colombier 433e12c5d1SDavid du Colombier File* 447dd7cddfSDavid 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; 517dd7cddfSDavid du Colombier f->seq = 0; 527dd7cddfSDavid du Colombier f->mod = FALSE; 537dd7cddfSDavid du Colombier f->unread = TRUE; 543e12c5d1SDavid du Colombier Strinit0(&f->name); 557dd7cddfSDavid du Colombier return f; 567dd7cddfSDavid du Colombier } 577dd7cddfSDavid du Colombier 587dd7cddfSDavid du Colombier int 597dd7cddfSDavid du Colombier fileisdirty(File *f) 607dd7cddfSDavid du Colombier { 617dd7cddfSDavid du Colombier return f->seq != f->cleanseq; 627dd7cddfSDavid du Colombier } 637dd7cddfSDavid du Colombier 647dd7cddfSDavid du Colombier static void 657dd7cddfSDavid du Colombier wrinsert(Buffer *delta, int seq, int mod, uint p0, Rune *s, uint ns) 667dd7cddfSDavid du Colombier { 677dd7cddfSDavid du Colombier Undo u; 687dd7cddfSDavid du Colombier 697dd7cddfSDavid du Colombier u.type = Insert; 707dd7cddfSDavid du Colombier u.mod = mod; 717dd7cddfSDavid du Colombier u.seq = seq; 727dd7cddfSDavid du Colombier u.p0 = p0; 737dd7cddfSDavid du Colombier u.n = ns; 747dd7cddfSDavid du Colombier bufinsert(delta, delta->nc, s, ns); 757dd7cddfSDavid du Colombier bufinsert(delta, delta->nc, (Rune*)&u, Undosize); 767dd7cddfSDavid du Colombier } 777dd7cddfSDavid du Colombier 787dd7cddfSDavid du Colombier static void 797dd7cddfSDavid du Colombier wrdelete(Buffer *delta, int seq, int mod, uint p0, uint p1) 807dd7cddfSDavid du Colombier { 817dd7cddfSDavid du Colombier Undo u; 827dd7cddfSDavid du Colombier 837dd7cddfSDavid du Colombier u.type = Delete; 847dd7cddfSDavid du Colombier u.mod = mod; 857dd7cddfSDavid du Colombier u.seq = seq; 867dd7cddfSDavid du Colombier u.p0 = p0; 877dd7cddfSDavid du Colombier u.n = p1 - p0; 887dd7cddfSDavid du Colombier bufinsert(delta, delta->nc, (Rune*)&u, Undosize); 897dd7cddfSDavid du Colombier } 907dd7cddfSDavid du Colombier 917dd7cddfSDavid du Colombier void 927dd7cddfSDavid du Colombier flushmerge(void) 937dd7cddfSDavid du Colombier { 947dd7cddfSDavid du Colombier File *f; 957dd7cddfSDavid du Colombier 967dd7cddfSDavid du Colombier f = merge.f; 977dd7cddfSDavid du Colombier if(f == nil) 987dd7cddfSDavid du Colombier return; 997dd7cddfSDavid du Colombier if(merge.seq != f->seq) 1007dd7cddfSDavid du Colombier panic("flushmerge seq mismatch"); 1017dd7cddfSDavid du Colombier if(merge.n != 0) 1027dd7cddfSDavid du Colombier wrdelete(&f->epsilon, f->seq, TRUE, merge.p0, merge.p0+merge.n); 1037dd7cddfSDavid du Colombier if(merge.nbuf != 0) 1047dd7cddfSDavid du Colombier wrinsert(&f->epsilon, f->seq, TRUE, merge.p0+merge.n, merge.buf, merge.nbuf); 1057dd7cddfSDavid du Colombier merge.f = nil; 1067dd7cddfSDavid du Colombier merge.n = 0; 1077dd7cddfSDavid du Colombier merge.nbuf = 0; 1087dd7cddfSDavid du Colombier } 1097dd7cddfSDavid du Colombier 1107dd7cddfSDavid du Colombier void 1117dd7cddfSDavid du Colombier mergeextend(File *f, uint p0) 1127dd7cddfSDavid du Colombier { 1137dd7cddfSDavid du Colombier uint mp0n; 1147dd7cddfSDavid du Colombier 1157dd7cddfSDavid du Colombier mp0n = merge.p0+merge.n; 1167dd7cddfSDavid du Colombier if(mp0n != p0){ 1177dd7cddfSDavid du Colombier bufread(f, mp0n, merge.buf+merge.nbuf, p0-mp0n); 1187dd7cddfSDavid du Colombier merge.nbuf += p0-mp0n; 1197dd7cddfSDavid du Colombier merge.n = p0-merge.p0; 1207dd7cddfSDavid du Colombier } 1217dd7cddfSDavid du Colombier } 1227dd7cddfSDavid du Colombier 1237dd7cddfSDavid du Colombier /* 1247dd7cddfSDavid du Colombier * like fileundelete, but get the data from arguments 1257dd7cddfSDavid du Colombier */ 1267dd7cddfSDavid du Colombier void 1277dd7cddfSDavid du Colombier loginsert(File *f, uint p0, Rune *s, uint ns) 1287dd7cddfSDavid du Colombier { 1297dd7cddfSDavid du Colombier if(f->rescuing) 1307dd7cddfSDavid du Colombier return; 1317dd7cddfSDavid du Colombier if(ns == 0) 1327dd7cddfSDavid du Colombier return; 1337dd7cddfSDavid du Colombier if(ns<0 || ns>STRSIZE) 1347dd7cddfSDavid du Colombier panic("loginsert"); 1357dd7cddfSDavid du Colombier if(f->seq < seq) 1367dd7cddfSDavid du Colombier filemark(f); 1377dd7cddfSDavid du Colombier if(p0 < f->hiposn) 1387dd7cddfSDavid du Colombier error(Esequence); 1397dd7cddfSDavid du Colombier 1407dd7cddfSDavid du Colombier if(merge.f != f 1417dd7cddfSDavid du Colombier || p0-(merge.p0+merge.n)>Maxmerge /* too far */ 1427dd7cddfSDavid du Colombier || merge.nbuf+((p0+ns)-(merge.p0+merge.n))>RBUFSIZE) /* too long */ 1437dd7cddfSDavid du Colombier flushmerge(); 1447dd7cddfSDavid du Colombier 1457dd7cddfSDavid du Colombier if(ns>=RBUFSIZE){ 1467dd7cddfSDavid du Colombier if(!(merge.n == 0 && merge.nbuf == 0 && merge.f == nil)) 1477dd7cddfSDavid du Colombier panic("loginsert bad merge state"); 1487dd7cddfSDavid du Colombier wrinsert(&f->epsilon, f->seq, TRUE, p0, s, ns); 1497dd7cddfSDavid du Colombier }else{ 1507dd7cddfSDavid du Colombier if(merge.f != f){ 1517dd7cddfSDavid du Colombier merge.f = f; 1527dd7cddfSDavid du Colombier merge.p0 = p0; 1537dd7cddfSDavid du Colombier merge.seq = f->seq; 1547dd7cddfSDavid du Colombier } 1557dd7cddfSDavid du Colombier mergeextend(f, p0); 1567dd7cddfSDavid du Colombier 1577dd7cddfSDavid du Colombier /* append string to merge */ 1587dd7cddfSDavid du Colombier runemove(merge.buf+merge.nbuf, s, ns); 1597dd7cddfSDavid du Colombier merge.nbuf += ns; 1607dd7cddfSDavid du Colombier } 1617dd7cddfSDavid du Colombier 1627dd7cddfSDavid du Colombier f->hiposn = p0; 1637dd7cddfSDavid du Colombier if(!f->unread && !f->mod) 1647dd7cddfSDavid du Colombier state(f, Dirty); 1657dd7cddfSDavid du Colombier } 1667dd7cddfSDavid du Colombier 1677dd7cddfSDavid du Colombier void 1687dd7cddfSDavid du Colombier logdelete(File *f, uint p0, uint p1) 1697dd7cddfSDavid du Colombier { 1707dd7cddfSDavid du Colombier if(f->rescuing) 1717dd7cddfSDavid du Colombier return; 1727dd7cddfSDavid du Colombier if(p0 == p1) 1737dd7cddfSDavid du Colombier return; 1747dd7cddfSDavid du Colombier if(f->seq < seq) 1757dd7cddfSDavid du Colombier filemark(f); 176*6b6b9ac8SDavid du Colombier if(p0 < f->hiposn) 1777dd7cddfSDavid du Colombier error(Esequence); 1787dd7cddfSDavid du Colombier 1797dd7cddfSDavid du Colombier if(merge.f != f 1807dd7cddfSDavid du Colombier || p0-(merge.p0+merge.n)>Maxmerge /* too far */ 1817dd7cddfSDavid du Colombier || merge.nbuf+(p0-(merge.p0+merge.n))>RBUFSIZE){ /* too long */ 1827dd7cddfSDavid du Colombier flushmerge(); 1837dd7cddfSDavid du Colombier merge.f = f; 1847dd7cddfSDavid du Colombier merge.p0 = p0; 1857dd7cddfSDavid du Colombier merge.seq = f->seq; 1867dd7cddfSDavid du Colombier } 1877dd7cddfSDavid du Colombier 1887dd7cddfSDavid du Colombier mergeextend(f, p0); 1897dd7cddfSDavid du Colombier 1907dd7cddfSDavid du Colombier /* add to deletion */ 1917dd7cddfSDavid du Colombier merge.n = p1-merge.p0; 1927dd7cddfSDavid du Colombier 1937dd7cddfSDavid du Colombier f->hiposn = p1; 1947dd7cddfSDavid du Colombier if(!f->unread && !f->mod) 1957dd7cddfSDavid du Colombier state(f, Dirty); 1967dd7cddfSDavid du Colombier } 1977dd7cddfSDavid du Colombier 1987dd7cddfSDavid du Colombier /* 1997dd7cddfSDavid du Colombier * like fileunsetname, but get the data from arguments 2007dd7cddfSDavid du Colombier */ 2017dd7cddfSDavid du Colombier void 2027dd7cddfSDavid du Colombier logsetname(File *f, String *s) 2037dd7cddfSDavid du Colombier { 2047dd7cddfSDavid du Colombier Undo u; 2057dd7cddfSDavid du Colombier Buffer *delta; 2067dd7cddfSDavid du Colombier 2077dd7cddfSDavid du Colombier if(f->rescuing) 2087dd7cddfSDavid du Colombier return; 2097dd7cddfSDavid du Colombier 2107dd7cddfSDavid du Colombier if(f->unread){ /* This is setting initial file name */ 2117dd7cddfSDavid du Colombier filesetname(f, s); 2127dd7cddfSDavid du Colombier return; 2137dd7cddfSDavid du Colombier } 2147dd7cddfSDavid du Colombier 2157dd7cddfSDavid du Colombier if(f->seq < seq) 2167dd7cddfSDavid du Colombier filemark(f); 2177dd7cddfSDavid du Colombier 2187dd7cddfSDavid du Colombier /* undo a file name change by restoring old name */ 2197dd7cddfSDavid du Colombier delta = &f->epsilon; 2207dd7cddfSDavid du Colombier u.type = Filename; 2217dd7cddfSDavid du Colombier u.mod = TRUE; 2227dd7cddfSDavid du Colombier u.seq = f->seq; 2237dd7cddfSDavid du Colombier u.p0 = 0; /* unused */ 2247dd7cddfSDavid du Colombier u.n = s->n; 2257dd7cddfSDavid du Colombier if(s->n) 2267dd7cddfSDavid du Colombier bufinsert(delta, delta->nc, s->s, s->n); 2277dd7cddfSDavid du Colombier bufinsert(delta, delta->nc, (Rune*)&u, Undosize); 2287dd7cddfSDavid du Colombier if(!f->unread && !f->mod) 2297dd7cddfSDavid du Colombier state(f, Dirty); 2307dd7cddfSDavid du Colombier } 2317dd7cddfSDavid du Colombier 2327dd7cddfSDavid du Colombier #ifdef NOTEXT 2337dd7cddfSDavid du Colombier File* 2347dd7cddfSDavid du Colombier fileaddtext(File *f, Text *t) 2357dd7cddfSDavid du Colombier { 2367dd7cddfSDavid du Colombier if(f == nil){ 2377dd7cddfSDavid du Colombier f = emalloc(sizeof(File)); 2387dd7cddfSDavid du Colombier f->unread = TRUE; 2397dd7cddfSDavid du Colombier } 2407dd7cddfSDavid du Colombier f->text = realloc(f->text, (f->ntext+1)*sizeof(Text*)); 2417dd7cddfSDavid du Colombier f->text[f->ntext++] = t; 2427dd7cddfSDavid du Colombier f->curtext = t; 2433e12c5d1SDavid du Colombier return f; 2443e12c5d1SDavid du Colombier } 2453e12c5d1SDavid du Colombier 2463e12c5d1SDavid du Colombier void 2477dd7cddfSDavid du Colombier filedeltext(File *f, Text *t) 2483e12c5d1SDavid du Colombier { 2497dd7cddfSDavid du Colombier int i; 2507dd7cddfSDavid du Colombier 2517dd7cddfSDavid du Colombier for(i=0; i<f->ntext; i++) 2527dd7cddfSDavid du Colombier if(f->text[i] == t) 2537dd7cddfSDavid du Colombier goto Found; 2547dd7cddfSDavid du Colombier panic("can't find text in filedeltext"); 2557dd7cddfSDavid du Colombier 2567dd7cddfSDavid du Colombier Found: 2577dd7cddfSDavid du Colombier f->ntext--; 2587dd7cddfSDavid du Colombier if(f->ntext == 0){ 2597dd7cddfSDavid du Colombier fileclose(f); 2607dd7cddfSDavid du Colombier return; 2617dd7cddfSDavid du Colombier } 2627dd7cddfSDavid du Colombier memmove(f->text+i, f->text+i+1, (f->ntext-i)*sizeof(Text*)); 2637dd7cddfSDavid du Colombier if(f->curtext == t) 2647dd7cddfSDavid du Colombier f->curtext = f->text[0]; 2657dd7cddfSDavid du Colombier } 2667dd7cddfSDavid du Colombier #endif 2677dd7cddfSDavid du Colombier 2687dd7cddfSDavid du Colombier void 2697dd7cddfSDavid du Colombier fileinsert(File *f, uint p0, Rune *s, uint ns) 2707dd7cddfSDavid du Colombier { 2717dd7cddfSDavid du Colombier if(p0 > f->nc) 2727dd7cddfSDavid du Colombier panic("internal error: fileinsert"); 2737dd7cddfSDavid du Colombier if(f->seq > 0) 2747dd7cddfSDavid du Colombier fileuninsert(f, &f->delta, p0, ns); 2757dd7cddfSDavid du Colombier bufinsert(f, p0, s, ns); 2767dd7cddfSDavid du Colombier if(ns) 2777dd7cddfSDavid du Colombier f->mod = TRUE; 2787dd7cddfSDavid du Colombier } 2797dd7cddfSDavid du Colombier 2807dd7cddfSDavid du Colombier void 2817dd7cddfSDavid du Colombier fileuninsert(File *f, Buffer *delta, uint p0, uint ns) 2827dd7cddfSDavid du Colombier { 2837dd7cddfSDavid du Colombier Undo u; 2847dd7cddfSDavid du Colombier 2857dd7cddfSDavid du Colombier /* undo an insertion by deleting */ 2867dd7cddfSDavid du Colombier u.type = Delete; 2877dd7cddfSDavid du Colombier u.mod = f->mod; 2887dd7cddfSDavid du Colombier u.seq = f->seq; 2897dd7cddfSDavid du Colombier u.p0 = p0; 2907dd7cddfSDavid du Colombier u.n = ns; 2917dd7cddfSDavid du Colombier bufinsert(delta, delta->nc, (Rune*)&u, Undosize); 2927dd7cddfSDavid du Colombier } 2937dd7cddfSDavid du Colombier 2947dd7cddfSDavid du Colombier void 2957dd7cddfSDavid du Colombier filedelete(File *f, uint p0, uint p1) 2967dd7cddfSDavid du Colombier { 2977dd7cddfSDavid du Colombier if(!(p0<=p1 && p0<=f->nc && p1<=f->nc)) 2987dd7cddfSDavid du Colombier panic("internal error: filedelete"); 2997dd7cddfSDavid du Colombier if(f->seq > 0) 3007dd7cddfSDavid du Colombier fileundelete(f, &f->delta, p0, p1); 3017dd7cddfSDavid du Colombier bufdelete(f, p0, p1); 3027dd7cddfSDavid du Colombier if(p1 > p0) 3037dd7cddfSDavid du Colombier f->mod = TRUE; 3047dd7cddfSDavid du Colombier } 3057dd7cddfSDavid du Colombier 3067dd7cddfSDavid du Colombier void 3077dd7cddfSDavid du Colombier fileundelete(File *f, Buffer *delta, uint p0, uint p1) 3087dd7cddfSDavid du Colombier { 3097dd7cddfSDavid du Colombier Undo u; 3107dd7cddfSDavid du Colombier Rune *buf; 3117dd7cddfSDavid du Colombier uint i, n; 3127dd7cddfSDavid du Colombier 3137dd7cddfSDavid du Colombier /* undo a deletion by inserting */ 3147dd7cddfSDavid du Colombier u.type = Insert; 3157dd7cddfSDavid du Colombier u.mod = f->mod; 3167dd7cddfSDavid du Colombier u.seq = f->seq; 3177dd7cddfSDavid du Colombier u.p0 = p0; 3187dd7cddfSDavid du Colombier u.n = p1-p0; 3197dd7cddfSDavid du Colombier buf = fbufalloc(); 3207dd7cddfSDavid du Colombier for(i=p0; i<p1; i+=n){ 3217dd7cddfSDavid du Colombier n = p1 - i; 3227dd7cddfSDavid du Colombier if(n > RBUFSIZE) 3237dd7cddfSDavid du Colombier n = RBUFSIZE; 3247dd7cddfSDavid du Colombier bufread(f, i, buf, n); 3257dd7cddfSDavid du Colombier bufinsert(delta, delta->nc, buf, n); 3267dd7cddfSDavid du Colombier } 3277dd7cddfSDavid du Colombier fbuffree(buf); 3287dd7cddfSDavid du Colombier bufinsert(delta, delta->nc, (Rune*)&u, Undosize); 3297dd7cddfSDavid du Colombier 3307dd7cddfSDavid du Colombier } 3317dd7cddfSDavid du Colombier 3327dd7cddfSDavid du Colombier int 3337dd7cddfSDavid du Colombier filereadc(File *f, uint q) 3347dd7cddfSDavid du Colombier { 3357dd7cddfSDavid du Colombier Rune r; 3367dd7cddfSDavid du Colombier 3377dd7cddfSDavid du Colombier if(q >= f->nc) 3387dd7cddfSDavid du Colombier return -1; 3397dd7cddfSDavid du Colombier bufread(f, q, &r, 1); 3407dd7cddfSDavid du Colombier return r; 3417dd7cddfSDavid du Colombier } 3427dd7cddfSDavid du Colombier 3437dd7cddfSDavid du Colombier void 3447dd7cddfSDavid du Colombier filesetname(File *f, String *s) 3457dd7cddfSDavid du Colombier { 3467dd7cddfSDavid du Colombier if(!f->unread) /* This is setting initial file name */ 3477dd7cddfSDavid du Colombier fileunsetname(f, &f->delta); 3487dd7cddfSDavid du Colombier Strduplstr(&f->name, s); 3497dd7cddfSDavid du Colombier sortname(f); 3507dd7cddfSDavid du Colombier f->unread = TRUE; 3517dd7cddfSDavid du Colombier } 3527dd7cddfSDavid du Colombier 3537dd7cddfSDavid du Colombier void 3547dd7cddfSDavid du Colombier fileunsetname(File *f, Buffer *delta) 3557dd7cddfSDavid du Colombier { 3567dd7cddfSDavid du Colombier String s; 3577dd7cddfSDavid du Colombier Undo u; 3587dd7cddfSDavid du Colombier 3597dd7cddfSDavid du Colombier /* undo a file name change by restoring old name */ 3607dd7cddfSDavid du Colombier u.type = Filename; 3617dd7cddfSDavid du Colombier u.mod = f->mod; 3627dd7cddfSDavid du Colombier u.seq = f->seq; 3637dd7cddfSDavid du Colombier u.p0 = 0; /* unused */ 3647dd7cddfSDavid du Colombier Strinit(&s); 3657dd7cddfSDavid du Colombier Strduplstr(&s, &f->name); 3667dd7cddfSDavid du Colombier fullname(&s); 3677dd7cddfSDavid du Colombier u.n = s.n; 3687dd7cddfSDavid du Colombier if(s.n) 3697dd7cddfSDavid du Colombier bufinsert(delta, delta->nc, s.s, s.n); 3707dd7cddfSDavid du Colombier bufinsert(delta, delta->nc, (Rune*)&u, Undosize); 3717dd7cddfSDavid du Colombier Strclose(&s); 3727dd7cddfSDavid du Colombier } 3737dd7cddfSDavid du Colombier 3747dd7cddfSDavid du Colombier void 3757dd7cddfSDavid du Colombier fileunsetdot(File *f, Buffer *delta, Range dot) 3767dd7cddfSDavid du Colombier { 3777dd7cddfSDavid du Colombier Undo u; 3787dd7cddfSDavid du Colombier 3797dd7cddfSDavid du Colombier u.type = Dot; 3807dd7cddfSDavid du Colombier u.mod = f->mod; 3817dd7cddfSDavid du Colombier u.seq = f->seq; 3827dd7cddfSDavid du Colombier u.p0 = dot.p1; 3837dd7cddfSDavid du Colombier u.n = dot.p2 - dot.p1; 3847dd7cddfSDavid du Colombier bufinsert(delta, delta->nc, (Rune*)&u, Undosize); 3857dd7cddfSDavid du Colombier } 3867dd7cddfSDavid du Colombier 3877dd7cddfSDavid du Colombier void 3887dd7cddfSDavid du Colombier fileunsetmark(File *f, Buffer *delta, Range mark) 3897dd7cddfSDavid du Colombier { 3907dd7cddfSDavid du Colombier Undo u; 3917dd7cddfSDavid du Colombier 3927dd7cddfSDavid du Colombier u.type = Mark; 3937dd7cddfSDavid du Colombier u.mod = f->mod; 3947dd7cddfSDavid du Colombier u.seq = f->seq; 3957dd7cddfSDavid du Colombier u.p0 = mark.p1; 3967dd7cddfSDavid du Colombier u.n = mark.p2 - mark.p1; 3977dd7cddfSDavid du Colombier bufinsert(delta, delta->nc, (Rune*)&u, Undosize); 3987dd7cddfSDavid du Colombier } 3997dd7cddfSDavid du Colombier 4007dd7cddfSDavid du Colombier uint 4017dd7cddfSDavid du Colombier fileload(File *f, uint p0, int fd, int *nulls) 4027dd7cddfSDavid du Colombier { 4037dd7cddfSDavid du Colombier if(f->seq > 0) 4047dd7cddfSDavid du Colombier panic("undo in file.load unimplemented"); 4057dd7cddfSDavid du Colombier return bufload(f, p0, fd, nulls); 4067dd7cddfSDavid du Colombier } 4077dd7cddfSDavid du Colombier 4087dd7cddfSDavid du Colombier int 4097dd7cddfSDavid du Colombier fileupdate(File *f, int notrans, int toterm) 4107dd7cddfSDavid du Colombier { 4117dd7cddfSDavid du Colombier uint p1, p2; 4127dd7cddfSDavid du Colombier int mod; 4137dd7cddfSDavid du Colombier 4147dd7cddfSDavid du Colombier if(f->rescuing) 4157dd7cddfSDavid du Colombier return FALSE; 4167dd7cddfSDavid du Colombier 4177dd7cddfSDavid du Colombier flushmerge(); 4187dd7cddfSDavid du Colombier 4197dd7cddfSDavid du Colombier /* 4207dd7cddfSDavid du Colombier * fix the modification bit 4217dd7cddfSDavid du Colombier * subtle point: don't save it away in the log. 4227dd7cddfSDavid du Colombier * 4237dd7cddfSDavid du Colombier * if another change is made, the correct f->mod 4247dd7cddfSDavid du Colombier * state is saved in the undo log by filemark 4257dd7cddfSDavid du Colombier * when setting the dot and mark. 4267dd7cddfSDavid du Colombier * 4277dd7cddfSDavid du Colombier * if the change is undone, the correct state is 4287dd7cddfSDavid du Colombier * saved from f in the fileun... routines. 4297dd7cddfSDavid du Colombier */ 4307dd7cddfSDavid du Colombier mod = f->mod; 4317dd7cddfSDavid du Colombier f->mod = f->prevmod; 4327dd7cddfSDavid du Colombier if(f == cmd) 4337dd7cddfSDavid du Colombier notrans = TRUE; 4347dd7cddfSDavid du Colombier else{ 4357dd7cddfSDavid du Colombier fileunsetdot(f, &f->delta, f->prevdot); 4367dd7cddfSDavid du Colombier fileunsetmark(f, &f->delta, f->prevmark); 4377dd7cddfSDavid du Colombier } 4387dd7cddfSDavid du Colombier f->dot = f->ndot; 4397dd7cddfSDavid du Colombier fileundo(f, FALSE, !notrans, &p1, &p2, toterm); 4407dd7cddfSDavid du Colombier f->mod = mod; 4417dd7cddfSDavid du Colombier 4427dd7cddfSDavid du Colombier if(f->delta.nc == 0) 4437dd7cddfSDavid du Colombier f->seq = 0; 4447dd7cddfSDavid du Colombier 4457dd7cddfSDavid du Colombier if(f == cmd) 4467dd7cddfSDavid du Colombier return FALSE; 4477dd7cddfSDavid du Colombier 4487dd7cddfSDavid du Colombier if(f->mod){ 4497dd7cddfSDavid du Colombier f->closeok = 0; 4507dd7cddfSDavid du Colombier quitok = 0; 4517dd7cddfSDavid du Colombier }else 4527dd7cddfSDavid du Colombier f->closeok = 1; 4537dd7cddfSDavid du Colombier return TRUE; 4547dd7cddfSDavid du Colombier } 4557dd7cddfSDavid du Colombier 4567dd7cddfSDavid du Colombier long 4577dd7cddfSDavid du Colombier prevseq(Buffer *b) 4587dd7cddfSDavid du Colombier { 4597dd7cddfSDavid du Colombier Undo u; 4607dd7cddfSDavid du Colombier uint up; 4617dd7cddfSDavid du Colombier 4627dd7cddfSDavid du Colombier up = b->nc; 4637dd7cddfSDavid du Colombier if(up == 0) 4647dd7cddfSDavid du Colombier return 0; 4657dd7cddfSDavid du Colombier up -= Undosize; 4667dd7cddfSDavid du Colombier bufread(b, up, (Rune*)&u, Undosize); 4677dd7cddfSDavid du Colombier return u.seq; 4687dd7cddfSDavid du Colombier } 4697dd7cddfSDavid du Colombier 4707dd7cddfSDavid du Colombier long 4717dd7cddfSDavid du Colombier undoseq(File *f, int isundo) 4727dd7cddfSDavid du Colombier { 4737dd7cddfSDavid du Colombier if(isundo) 4747dd7cddfSDavid du Colombier return f->seq; 4757dd7cddfSDavid du Colombier 4767dd7cddfSDavid du Colombier return prevseq(&f->epsilon); 4777dd7cddfSDavid du Colombier } 4787dd7cddfSDavid du Colombier 4797dd7cddfSDavid du Colombier void 4807dd7cddfSDavid du Colombier fileundo(File *f, int isundo, int canredo, uint *q0p, uint *q1p, int flag) 4817dd7cddfSDavid du Colombier { 4827dd7cddfSDavid du Colombier Undo u; 4837dd7cddfSDavid du Colombier Rune *buf; 4847dd7cddfSDavid du Colombier uint i, n, up; 4857dd7cddfSDavid du Colombier uint stop; 4867dd7cddfSDavid du Colombier Buffer *delta, *epsilon; 4877dd7cddfSDavid du Colombier 4887dd7cddfSDavid du Colombier if(isundo){ 4897dd7cddfSDavid du Colombier /* undo; reverse delta onto epsilon, seq decreases */ 4907dd7cddfSDavid du Colombier delta = &f->delta; 4917dd7cddfSDavid du Colombier epsilon = &f->epsilon; 4927dd7cddfSDavid du Colombier stop = f->seq; 4937dd7cddfSDavid du Colombier }else{ 4947dd7cddfSDavid du Colombier /* redo; reverse epsilon onto delta, seq increases */ 4957dd7cddfSDavid du Colombier delta = &f->epsilon; 4967dd7cddfSDavid du Colombier epsilon = &f->delta; 4977dd7cddfSDavid du Colombier stop = 0; /* don't know yet */ 4987dd7cddfSDavid du Colombier } 4997dd7cddfSDavid du Colombier 5007dd7cddfSDavid du Colombier raspstart(f); 5017dd7cddfSDavid du Colombier while(delta->nc > 0){ 5027dd7cddfSDavid du Colombier up = delta->nc-Undosize; 5037dd7cddfSDavid du Colombier bufread(delta, up, (Rune*)&u, Undosize); 5047dd7cddfSDavid du Colombier if(isundo){ 5057dd7cddfSDavid du Colombier if(u.seq < stop){ 5067dd7cddfSDavid du Colombier f->seq = u.seq; 5077dd7cddfSDavid du Colombier raspdone(f, flag); 5087dd7cddfSDavid du Colombier return; 5097dd7cddfSDavid du Colombier } 5107dd7cddfSDavid du Colombier }else{ 5117dd7cddfSDavid du Colombier if(stop == 0) 5127dd7cddfSDavid du Colombier stop = u.seq; 5137dd7cddfSDavid du Colombier if(u.seq > stop){ 5147dd7cddfSDavid du Colombier raspdone(f, flag); 5157dd7cddfSDavid du Colombier return; 5167dd7cddfSDavid du Colombier } 5177dd7cddfSDavid du Colombier } 5187dd7cddfSDavid du Colombier switch(u.type){ 5197dd7cddfSDavid du Colombier default: 5207dd7cddfSDavid du Colombier panic("undo unknown u.type"); 5217dd7cddfSDavid du Colombier break; 5227dd7cddfSDavid du Colombier 5237dd7cddfSDavid du Colombier case Delete: 5247dd7cddfSDavid du Colombier f->seq = u.seq; 5257dd7cddfSDavid du Colombier if(canredo) 5267dd7cddfSDavid du Colombier fileundelete(f, epsilon, u.p0, u.p0+u.n); 5277dd7cddfSDavid du Colombier f->mod = u.mod; 5287dd7cddfSDavid du Colombier bufdelete(f, u.p0, u.p0+u.n); 5297dd7cddfSDavid du Colombier raspdelete(f, u.p0, u.p0+u.n, flag); 5307dd7cddfSDavid du Colombier *q0p = u.p0; 5317dd7cddfSDavid du Colombier *q1p = u.p0; 5327dd7cddfSDavid du Colombier break; 5337dd7cddfSDavid du Colombier 5347dd7cddfSDavid du Colombier case Insert: 5357dd7cddfSDavid du Colombier f->seq = u.seq; 5367dd7cddfSDavid du Colombier if(canredo) 5377dd7cddfSDavid du Colombier fileuninsert(f, epsilon, u.p0, u.n); 5387dd7cddfSDavid du Colombier f->mod = u.mod; 5397dd7cddfSDavid du Colombier up -= u.n; 5407dd7cddfSDavid du Colombier buf = fbufalloc(); 5417dd7cddfSDavid du Colombier for(i=0; i<u.n; i+=n){ 5427dd7cddfSDavid du Colombier n = u.n - i; 5437dd7cddfSDavid du Colombier if(n > RBUFSIZE) 5447dd7cddfSDavid du Colombier n = RBUFSIZE; 5457dd7cddfSDavid du Colombier bufread(delta, up+i, buf, n); 5467dd7cddfSDavid du Colombier bufinsert(f, u.p0+i, buf, n); 5477dd7cddfSDavid du Colombier raspinsert(f, u.p0+i, buf, n, flag); 5487dd7cddfSDavid du Colombier } 5497dd7cddfSDavid du Colombier fbuffree(buf); 5507dd7cddfSDavid du Colombier *q0p = u.p0; 5517dd7cddfSDavid du Colombier *q1p = u.p0+u.n; 5527dd7cddfSDavid du Colombier break; 5537dd7cddfSDavid du Colombier 5547dd7cddfSDavid du Colombier case Filename: 5557dd7cddfSDavid du Colombier f->seq = u.seq; 5567dd7cddfSDavid du Colombier if(canredo) 5577dd7cddfSDavid du Colombier fileunsetname(f, epsilon); 5587dd7cddfSDavid du Colombier f->mod = u.mod; 5597dd7cddfSDavid du Colombier up -= u.n; 5607dd7cddfSDavid du Colombier 5617dd7cddfSDavid du Colombier Strinsure(&f->name, u.n+1); 5627dd7cddfSDavid du Colombier bufread(delta, up, f->name.s, u.n); 5637dd7cddfSDavid du Colombier f->name.s[u.n] = 0; 5647dd7cddfSDavid du Colombier f->name.n = u.n; 5657dd7cddfSDavid du Colombier fixname(&f->name); 5667dd7cddfSDavid du Colombier sortname(f); 5677dd7cddfSDavid du Colombier break; 5687dd7cddfSDavid du Colombier case Dot: 5697dd7cddfSDavid du Colombier f->seq = u.seq; 5707dd7cddfSDavid du Colombier if(canredo) 5717dd7cddfSDavid du Colombier fileunsetdot(f, epsilon, f->dot.r); 5727dd7cddfSDavid du Colombier f->mod = u.mod; 5737dd7cddfSDavid du Colombier f->dot.r.p1 = u.p0; 5747dd7cddfSDavid du Colombier f->dot.r.p2 = u.p0 + u.n; 5757dd7cddfSDavid du Colombier break; 5767dd7cddfSDavid du Colombier case Mark: 5777dd7cddfSDavid du Colombier f->seq = u.seq; 5787dd7cddfSDavid du Colombier if(canredo) 5797dd7cddfSDavid du Colombier fileunsetmark(f, epsilon, f->mark); 5807dd7cddfSDavid du Colombier f->mod = u.mod; 5817dd7cddfSDavid du Colombier f->mark.p1 = u.p0; 5827dd7cddfSDavid du Colombier f->mark.p2 = u.p0 + u.n; 5837dd7cddfSDavid du Colombier break; 5847dd7cddfSDavid du Colombier } 5857dd7cddfSDavid du Colombier bufdelete(delta, up, delta->nc); 5867dd7cddfSDavid du Colombier } 5877dd7cddfSDavid du Colombier if(isundo) 5887dd7cddfSDavid du Colombier f->seq = 0; 5897dd7cddfSDavid du Colombier raspdone(f, flag); 5907dd7cddfSDavid du Colombier } 5917dd7cddfSDavid du Colombier 5927dd7cddfSDavid du Colombier void 5937dd7cddfSDavid du Colombier filereset(File *f) 5947dd7cddfSDavid du Colombier { 5957dd7cddfSDavid du Colombier bufreset(&f->delta); 5967dd7cddfSDavid du Colombier bufreset(&f->epsilon); 5977dd7cddfSDavid du Colombier f->seq = 0; 5987dd7cddfSDavid du Colombier } 5997dd7cddfSDavid du Colombier 6007dd7cddfSDavid du Colombier void 6017dd7cddfSDavid du Colombier fileclose(File *f) 6027dd7cddfSDavid du Colombier { 6033e12c5d1SDavid du Colombier Strclose(&f->name); 6047dd7cddfSDavid du Colombier bufclose(f); 6057dd7cddfSDavid du Colombier bufclose(&f->delta); 6067dd7cddfSDavid 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 6137dd7cddfSDavid du Colombier filemark(File *f) 6143e12c5d1SDavid du Colombier { 6153e12c5d1SDavid du Colombier 6167dd7cddfSDavid du Colombier if(f->unread) 617bd389b36SDavid du Colombier return; 6187dd7cddfSDavid du Colombier if(f->epsilon.nc) 6197dd7cddfSDavid du Colombier bufdelete(&f->epsilon, 0, f->epsilon.nc); 6207dd7cddfSDavid du Colombier 6217dd7cddfSDavid du Colombier if(f != cmd){ 6227dd7cddfSDavid du Colombier f->prevdot = f->dot.r; 6237dd7cddfSDavid du Colombier f->prevmark = f->mark; 6247dd7cddfSDavid du Colombier f->prevseq = f->seq; 6257dd7cddfSDavid du Colombier f->prevmod = f->mod; 6263e12c5d1SDavid du Colombier } 6273e12c5d1SDavid du Colombier 6287dd7cddfSDavid du Colombier f->ndot = f->dot; 6297dd7cddfSDavid du Colombier f->seq = seq; 6307dd7cddfSDavid du Colombier f->hiposn = 0; 6313e12c5d1SDavid du Colombier } 632