|
|
1.1 ! root 1: #include "sam.h" ! 2: ! 3: /* ! 4: * Files are splayed out a factor of NDISC to reduce indirect block access ! 5: */ ! 6: Discdesc *files[NDISC]; ! 7: Discdesc *transcripts[NDISC]; ! 8: Buffer *undobuf; ! 9: static String *ftempstr(); ! 10: int fcount; ! 11: ! 12: #ifdef SUN ! 13: #define SKIP 50 ! 14: #define MAXCACHE 25000 ! 15: #else ! 16: enum{ ! 17: SKIP=50, /* max dist between file changes folded together */ ! 18: MAXCACHE=25000, /* max length of cache. must be < 32K-BLOCKSIZE */ ! 19: }; ! 20: #endif ! 21: ! 22: Fstart() ! 23: { ! 24: undobuf=Bopen(Dstart()); ! 25: snarfbuf=Bopen(Dstart()); ! 26: } ! 27: File * ! 28: Fopen() ! 29: { ! 30: register File *f; ! 31: f=new(File, 1); ! 32: if(files[fcount]==0){ ! 33: files[fcount]=Dstart(); ! 34: transcripts[fcount]=Dstart(); ! 35: } ! 36: f->buf=Bopen(files[fcount]); ! 37: f->transcript=Bopen(transcripts[fcount]); ! 38: if(++fcount==NDISC) ! 39: fcount=0; ! 40: f->nbytes=0; ! 41: f->markp=0; ! 42: f->mod=0; ! 43: f->dot.f=f; ! 44: strinit(&f->name); ! 45: straddc(&f->name, '\0'); ! 46: strinit(&f->cache); ! 47: f->state=Unread; ! 48: Fmark(f, (Mod)0); ! 49: return f; ! 50: } ! 51: Fclose(f) ! 52: File *f; ! 53: { ! 54: Bclose(f->buf); ! 55: Bclose(f->transcript); ! 56: strclose(&f->name); ! 57: strclose(&f->cache); ! 58: if(f->rasp) ! 59: listfree(f->rasp); ! 60: free((uchar *)f); ! 61: } ! 62: Fmark(f, m) ! 63: register File *f; ! 64: Mod m; ! 65: { ! 66: register Buffer *t=f->transcript; ! 67: Posn p; ! 68: if(f->state==Unread) /* this is implicit 'e' of a file */ ! 69: return; ! 70: p=m==0? -1 : f->markp; ! 71: f->markp=t->nbytes; ! 72: puthdr_M(t, p, f->dot.r, f->mark, f->mod, f->state); ! 73: f->marked=TRUE; ! 74: f->mod=m; ! 75: f->hiposn= -1; ! 76: /* Safety first */ ! 77: f->cp1=f->cp2=0; ! 78: strzero(&f->cache); ! 79: } ! 80: Finsert(f, str, p1) ! 81: register File *f; ! 82: String *str; ! 83: Posn p1; ! 84: { ! 85: register Buffer *t=f->transcript; ! 86: if(str->n==0) ! 87: return; ! 88: if(str->n<0 || str->n>32767) ! 89: panic("Finsert"); ! 90: if(f->mod<modnum) ! 91: Fmark(f, modnum); ! 92: if(p1<f->hiposn) ! 93: error(Esequence); ! 94: if(str->n>=BLOCKSIZE){ /* don't bother with the cache */ ! 95: Fflush(f); ! 96: puthdr_csP(t, 'i', str->n, p1); ! 97: Binsert(t, str, t->nbytes); ! 98: }else{ /* insert into the cache instead of the transcript */ ! 99: if(f->cp2==0 && f->cp1==0 && f->cache.n==0) /* empty cache */ ! 100: f->cp1=f->cp2=p1; ! 101: if(p1-f->cp2>SKIP || (long)f->cache.n+(long)str->n>MAXCACHE){ ! 102: Fflush(f); ! 103: f->cp1=f->cp2=p1; ! 104: } ! 105: if(f->cp2!=p1){ /* grab the piece in between */ ! 106: unsigned char buf[SKIP]; ! 107: String s; ! 108: Fchars(f, buf, f->cp2, p1); ! 109: s.s=buf; ! 110: s.n=p1-f->cp2; ! 111: strinsert(&f->cache, &s, (long)f->cache.n); ! 112: f->cp2=p1; ! 113: } ! 114: strinsert(&f->cache, str, (long)f->cache.n); ! 115: } ! 116: if(f!=cmd) ! 117: quitok=FALSE; ! 118: f->closeok=FALSE; ! 119: if(f->state==Clean) ! 120: state(f, Dirty); ! 121: f->hiposn=p1; ! 122: } ! 123: Fdelete(f, p1, p2) ! 124: register File *f; ! 125: Posn p1, p2; ! 126: { ! 127: if(p1==p2) ! 128: return; ! 129: if(f->mod<modnum) ! 130: Fmark(f, modnum); ! 131: if(p1<f->hiposn) ! 132: error(Esequence); ! 133: if(p1-f->cp2>SKIP) ! 134: Fflush(f); ! 135: if(f->cp2==0 && f->cp1==0 && f->cache.n==0) /* empty cache */ ! 136: f->cp1=f->cp2=p1; ! 137: if(f->cp2!=p1){ /* grab the piece in between */ ! 138: if(f->cache.n+(p1-f->cp2)>MAXCACHE){ ! 139: Fflush(f); ! 140: f->cp1=f->cp2=p1; ! 141: }else{ ! 142: unsigned char buf[SKIP]; ! 143: String s; ! 144: Fchars(f, buf, f->cp2, p1); ! 145: s.s=buf; ! 146: s.n=p1-f->cp2; ! 147: strinsert(&f->cache, &s, (long)f->cache.n); ! 148: } ! 149: } ! 150: f->cp2=p2; ! 151: if(f!=cmd) ! 152: quitok=FALSE; ! 153: f->closeok=FALSE; ! 154: if(f->state==Clean) ! 155: state(f, Dirty); ! 156: f->hiposn=p2; ! 157: } ! 158: Fflush(f) ! 159: register File *f; ! 160: { ! 161: register Buffer *t=f->transcript; ! 162: register Posn p1=f->cp1, p2=f->cp2; ! 163: if(p1!=p2) ! 164: puthdr_cPP(t, 'd', p1, p2); ! 165: if(f->cache.n){ ! 166: puthdr_csP(t, 'i', f->cache.n, p2); ! 167: Binsert(t, &f->cache, t->nbytes); ! 168: strzero(&f->cache); ! 169: } ! 170: f->cp1=f->cp2=0; ! 171: } ! 172: Fsetname(f) ! 173: register File *f; ! 174: { ! 175: register Buffer *t=f->transcript; ! 176: if(f->state==Unread){ /* This is setting initial file name */ ! 177: strdupstr(&f->name, &genstr); ! 178: sortname(f); ! 179: }else{ ! 180: if(f->mod<modnum) ! 181: Fmark(f, modnum); ! 182: if(genstr.n>BLOCKSIZE) ! 183: error(Elong); ! 184: puthdr_cs(t, 'f', genstr.n); ! 185: Binsert(t, &genstr, t->nbytes); ! 186: } ! 187: } ! 188: /* ! 189: * The heart of it all. Fupdate will run along the transcript list, executing ! 190: * the commands and converting them into their inverses for a later undo pass. ! 191: * The pass runs top to bottom, so addresses in the transcript are tracked ! 192: * (by the var. delta) so they stay valid during the operation. This causes ! 193: * all operations to appear to happen simultaneously, which is why the addresses ! 194: * passed to Fdelete and Finsert never take into account other changes occurring ! 195: * in this command (and is why things are done this way). ! 196: */ ! 197: Fupdate(f, isundo, toterm) ! 198: register File *f; ! 199: { ! 200: register Buffer *t=f->transcript; ! 201: register Buffer *u=undobuf; ! 202: register n, ni; ! 203: register Posn p0, p1, p2, p, deltadot=0, deltamark=0, delta=0; ! 204: int changes=FALSE; ! 205: uchar buf[32]; ! 206: uchar tmp[BLOCKSIZE]; ! 207: Fflush(f); ! 208: if(f->marked) ! 209: p0=f->markp+sizeof(Mark); ! 210: else ! 211: p0=0; ! 212: while((n=Bread(t, buf, sizeof buf, p0))>0){ ! 213: switch(buf[0]){ ! 214: default: ! 215: panic("unknown in Fupdate"); ! 216: case 'd': ! 217: GETPOSN(p1, buf+1); ! 218: GETPOSN(p2, buf+1+sizeof(Posn)); ! 219: p0+=1+2*sizeof(Posn); ! 220: if(p2<=f->dot.r.p1) ! 221: deltadot-=p2-p1; ! 222: if(p2<=f->mark.p1) ! 223: deltamark-=p2-p1; ! 224: p1+=delta, p2+=delta; ! 225: delta-=p2-p1; ! 226: if(!isundo) ! 227: for(p=p1; p<p2; p+=ni){ ! 228: if(p2-p>BLOCKSIZE) ! 229: ni=BLOCKSIZE; ! 230: else ! 231: ni=p2-p; ! 232: puthdr_csP(u, 'i', ni, p1); ! 233: Bread(f->buf, tmp, ni, p); ! 234: Binsert(u, ftempstr(tmp, ni), u->nbytes); ! 235: } ! 236: f->nbytes-=p2-p1; ! 237: Bdelete(f->buf, p1, p2); ! 238: changes=TRUE; ! 239: break; ! 240: case 'f': ! 241: n=buf[1]&0xFF; ! 242: n|=buf[2]<<8; ! 243: p0+=1+SS; ! 244: strinsure(&genstr, (ulong)n); ! 245: Bread(t, tmp, n, p0); ! 246: p0+=n; ! 247: strdup(&genstr, tmp); ! 248: if(!isundo){ ! 249: puthdr_cs(u, 'f', f->name.n); ! 250: Binsert(u, &f->name, u->nbytes); ! 251: } ! 252: strdupstr(&f->name, &genstr); ! 253: sortname(f); ! 254: changes=TRUE; ! 255: break; ! 256: case 'i': ! 257: n=buf[1]&0xFF; ! 258: n|=buf[2]<<8; ! 259: GETPOSN(p1, (buf+1+SS)); ! 260: p0+=1+SS+sizeof(Posn); ! 261: if(p1<f->dot.r.p1) ! 262: deltadot+=n; ! 263: if(p1<f->mark.p1) ! 264: deltamark+=n; ! 265: p1+=delta; ! 266: delta+=n; ! 267: if(!isundo) ! 268: puthdr_cPP(u, 'd', p1, p1+n); ! 269: changes=TRUE; ! 270: f->nbytes+=n; ! 271: while(n>0){ ! 272: if(n>BLOCKSIZE) ! 273: ni=BLOCKSIZE; ! 274: else ! 275: ni=n; ! 276: Bread(t, tmp, ni, p0); ! 277: Binsert(f->buf, ftempstr(tmp, ni), p1); ! 278: n-=ni; ! 279: p1+=ni; ! 280: p0+=ni; ! 281: } ! 282: break; ! 283: } ! 284: } ! 285: toterminal(f, toterm); ! 286: f->dot.r.p1+=deltadot; ! 287: f->dot.r.p2+=deltadot; ! 288: if(f->dot.r.p1>f->nbytes) ! 289: f->dot.r.p1=f->nbytes; ! 290: if(f->dot.r.p2>f->nbytes) ! 291: f->dot.r.p2=f->nbytes; ! 292: f->mark.p1+=deltamark; ! 293: f->mark.p2+=deltamark; ! 294: if(f->mark.p1>f->nbytes) ! 295: f->mark.p1=f->nbytes; ! 296: if(f->mark.p2>f->nbytes) ! 297: f->mark.p2=f->nbytes; ! 298: if(n<0) ! 299: panic("Fupdate read"); ! 300: if(f==cmd) ! 301: f->mod=0; /* can't undo command file */ ! 302: if(p0>f->markp+sizeof(Posn)){ /* for undo, this throws away the undo transcript */ ! 303: if(f->mod>0){ /* can't undo the dawn of time */ ! 304: Bdelete(t, f->markp+sizeof(Mark), t->nbytes); ! 305: /* copy the undo list back into the transcript */ ! 306: for(p=0; p<u->nbytes; p+=ni){ ! 307: if(u->nbytes-p>BLOCKSIZE) ! 308: ni=BLOCKSIZE; ! 309: else ! 310: ni=u->nbytes-p; ! 311: Bread(u, tmp, ni, p); ! 312: Binsert(t, ftempstr(tmp, ni), t->nbytes); ! 313: } ! 314: } ! 315: Bdelete(u, (Posn)0, u->nbytes); ! 316: } ! 317: return f==cmd? FALSE : changes; ! 318: } ! 319: puthdr_csP(b, c, s, p) ! 320: Buffer *b; ! 321: char c; ! 322: short s; ! 323: Posn p; ! 324: { ! 325: uchar buf[1+2+sizeof p]; ! 326: register uchar *a=buf; ! 327: if(p<0) ! 328: panic("puthdr_csP"); ! 329: *a++=c; ! 330: *a++=s; ! 331: *a++=s>>8; ! 332: PUTPOSN(a, &p); ! 333: Binsert(b, ftempstr(buf, sizeof buf), b->nbytes); ! 334: } ! 335: puthdr_cs(b, c, s) ! 336: Buffer *b; ! 337: char c; ! 338: short s; ! 339: { ! 340: uchar buf[1+2]; ! 341: register uchar *a=buf; ! 342: *a++=c; ! 343: *a++=s; ! 344: *a=s>>8; ! 345: Binsert(b, ftempstr(buf, sizeof buf), b->nbytes); ! 346: } ! 347: puthdr_M(b, p, dot, mk, m, s1) ! 348: Buffer *b; ! 349: Posn p; ! 350: Range dot; ! 351: Range mk; ! 352: Mod m; ! 353: short s1; ! 354: { ! 355: Mark mark; ! 356: static first=1; ! 357: if(!first && p<0) ! 358: panic("puthdr_M"); ! 359: mark.p=p; ! 360: mark.dot=dot; ! 361: mark.mark=mk; ! 362: mark.m=m; ! 363: mark.s1=s1; ! 364: Binsert(b, ftempstr((uchar *)&mark, sizeof mark), b->nbytes); ! 365: } ! 366: puthdr_cPP(b, c, p1, p2) ! 367: Buffer *b; ! 368: char c; ! 369: Posn p1, p2; ! 370: { ! 371: uchar buf[1+2*sizeof p1]; ! 372: register uchar *a=buf; ! 373: if(p1<0 || p2<0) ! 374: panic("puthdr_cPP"); ! 375: *a++=c; ! 376: PUTPOSN(a, &p1); ! 377: PUTPOSN(a, &p2); ! 378: Binsert(b, ftempstr(buf, sizeof buf), b->nbytes); ! 379: } ! 380: Fchars(f, addr, p1, p2) ! 381: register File *f; ! 382: uchar *addr; ! 383: Posn p1, p2; ! 384: { ! 385: return Bread(f->buf, addr, (int)(p2-p1), p1); ! 386: } ! 387: Fgetcset(f, p) ! 388: File *f; ! 389: Posn p; ! 390: { ! 391: if(p<0 || p>f->nbytes) ! 392: panic("Fgetcset out of range"); ! 393: if((f->ngetc=Fchars(f, f->getcbuf, p, p+NGETC))<0) ! 394: panic("Fgetcset Bread fail"); ! 395: f->getcp=p; ! 396: f->getci=0; ! 397: return f->ngetc; ! 398: } ! 399: Fbgetcset(f, p) ! 400: File *f; ! 401: Posn p; ! 402: { ! 403: if(p<0 || p>f->nbytes) ! 404: panic("Fbgetcset out of range"); ! 405: if((f->ngetc=Fchars(f, f->getcbuf, p<NGETC? (Posn)0 : p-NGETC, p))<0) ! 406: panic("Fbgetcset Bread fail"); ! 407: f->getcp=p; ! 408: f->getci=f->ngetc; ! 409: return f->ngetc; ! 410: } ! 411: Fgetcload(f, p) ! 412: File *f; ! 413: Posn p; ! 414: { ! 415: if(Fgetcset(f, p)){ ! 416: --f->ngetc; ! 417: f->getcp++; ! 418: return f->getcbuf[f->getci++]; ! 419: } ! 420: return -1; ! 421: } ! 422: Fbgetcload(f, p) ! 423: File *f; ! 424: Posn p; ! 425: { ! 426: if(Fbgetcset(f, p)){ ! 427: --f->getcp; ! 428: return f->getcbuf[--f->getci]; ! 429: } ! 430: return -1; ! 431: } ! 432: static String * ! 433: ftempstr(s, n) ! 434: uchar *s; ! 435: { ! 436: static String p; ! 437: p.s=(uchar *)s; ! 438: p.n=n; ! 439: p.size=n; ! 440: return &p; ! 441: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.