2003-09-30 17:47:42 +00:00
|
|
|
#include "sam.h"
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Structure of Undo list:
|
|
|
|
* The Undo structure follows any associated data, so the list
|
|
|
|
* can be read backwards: read the structure, then read whatever
|
|
|
|
* data is associated (insert string, file name) and precedes it.
|
|
|
|
* The structure includes the previous value of the modify bit
|
|
|
|
* and a sequence number; successive Undo structures with the
|
|
|
|
* same sequence number represent simultaneous changes.
|
|
|
|
*/
|
|
|
|
|
|
|
|
typedef struct Undo Undo;
|
|
|
|
typedef struct Merge Merge;
|
|
|
|
|
|
|
|
struct Undo
|
|
|
|
{
|
|
|
|
short type; /* Delete, Insert, Filename, Dot, Mark */
|
|
|
|
short mod; /* modify bit */
|
|
|
|
uint seq; /* sequence number */
|
|
|
|
uint p0; /* location of change (unused in f) */
|
|
|
|
uint n; /* # runes in string or file name */
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Merge
|
|
|
|
{
|
|
|
|
File *f;
|
|
|
|
uint seq; /* of logged change */
|
|
|
|
uint p0; /* location of change (unused in f) */
|
|
|
|
uint n; /* # runes to delete */
|
|
|
|
uint nbuf; /* # runes to insert */
|
|
|
|
Rune buf[RBUFSIZE];
|
|
|
|
};
|
|
|
|
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
Maxmerge = 50,
|
|
|
|
Undosize = sizeof(Undo)/sizeof(Rune),
|
|
|
|
};
|
|
|
|
|
|
|
|
static Merge merge;
|
|
|
|
|
|
|
|
File*
|
|
|
|
fileopen(void)
|
|
|
|
{
|
|
|
|
File *f;
|
|
|
|
|
|
|
|
f = emalloc(sizeof(File));
|
|
|
|
f->dot.f = f;
|
|
|
|
f->ndot.f = f;
|
|
|
|
f->seq = 0;
|
|
|
|
f->mod = FALSE;
|
|
|
|
f->unread = TRUE;
|
|
|
|
Strinit0(&f->name);
|
|
|
|
return f;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
fileisdirty(File *f)
|
|
|
|
{
|
|
|
|
return f->seq != f->cleanseq;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
wrinsert(Buffer *delta, int seq, int mod, uint p0, Rune *s, uint ns)
|
|
|
|
{
|
|
|
|
Undo u;
|
|
|
|
|
|
|
|
u.type = Insert;
|
|
|
|
u.mod = mod;
|
|
|
|
u.seq = seq;
|
|
|
|
u.p0 = p0;
|
|
|
|
u.n = ns;
|
|
|
|
bufinsert(delta, delta->nc, s, ns);
|
|
|
|
bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
wrdelete(Buffer *delta, int seq, int mod, uint p0, uint p1)
|
|
|
|
{
|
|
|
|
Undo u;
|
|
|
|
|
|
|
|
u.type = Delete;
|
|
|
|
u.mod = mod;
|
|
|
|
u.seq = seq;
|
|
|
|
u.p0 = p0;
|
|
|
|
u.n = p1 - p0;
|
|
|
|
bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
flushmerge(void)
|
|
|
|
{
|
|
|
|
File *f;
|
|
|
|
|
|
|
|
f = merge.f;
|
|
|
|
if(f == nil)
|
|
|
|
return;
|
|
|
|
if(merge.seq != f->seq)
|
|
|
|
panic("flushmerge seq mismatch");
|
|
|
|
if(merge.n != 0)
|
|
|
|
wrdelete(&f->epsilon, f->seq, TRUE, merge.p0, merge.p0+merge.n);
|
|
|
|
if(merge.nbuf != 0)
|
|
|
|
wrinsert(&f->epsilon, f->seq, TRUE, merge.p0+merge.n, merge.buf, merge.nbuf);
|
|
|
|
merge.f = nil;
|
|
|
|
merge.n = 0;
|
|
|
|
merge.nbuf = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
mergeextend(File *f, uint p0)
|
|
|
|
{
|
|
|
|
uint mp0n;
|
|
|
|
|
|
|
|
mp0n = merge.p0+merge.n;
|
|
|
|
if(mp0n != p0){
|
2003-09-30 19:05:50 +00:00
|
|
|
bufread(&f->b, mp0n, merge.buf+merge.nbuf, p0-mp0n);
|
2003-09-30 17:47:42 +00:00
|
|
|
merge.nbuf += p0-mp0n;
|
|
|
|
merge.n = p0-merge.p0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* like fileundelete, but get the data from arguments
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
loginsert(File *f, uint p0, Rune *s, uint ns)
|
|
|
|
{
|
|
|
|
if(f->rescuing)
|
|
|
|
return;
|
|
|
|
if(ns == 0)
|
|
|
|
return;
|
|
|
|
if(ns<0 || ns>STRSIZE)
|
|
|
|
panic("loginsert");
|
|
|
|
if(f->seq < seq)
|
|
|
|
filemark(f);
|
|
|
|
if(p0 < f->hiposn)
|
|
|
|
error(Esequence);
|
|
|
|
|
|
|
|
if(merge.f != f
|
|
|
|
|| p0-(merge.p0+merge.n)>Maxmerge /* too far */
|
|
|
|
|| merge.nbuf+((p0+ns)-(merge.p0+merge.n))>RBUFSIZE) /* too long */
|
|
|
|
flushmerge();
|
|
|
|
|
|
|
|
if(ns>=RBUFSIZE){
|
|
|
|
if(!(merge.n == 0 && merge.nbuf == 0 && merge.f == nil))
|
|
|
|
panic("loginsert bad merge state");
|
|
|
|
wrinsert(&f->epsilon, f->seq, TRUE, p0, s, ns);
|
|
|
|
}else{
|
|
|
|
if(merge.f != f){
|
|
|
|
merge.f = f;
|
|
|
|
merge.p0 = p0;
|
|
|
|
merge.seq = f->seq;
|
|
|
|
}
|
|
|
|
mergeextend(f, p0);
|
|
|
|
|
|
|
|
/* append string to merge */
|
|
|
|
runemove(merge.buf+merge.nbuf, s, ns);
|
|
|
|
merge.nbuf += ns;
|
|
|
|
}
|
|
|
|
|
|
|
|
f->hiposn = p0;
|
|
|
|
if(!f->unread && !f->mod)
|
|
|
|
state(f, Dirty);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
logdelete(File *f, uint p0, uint p1)
|
|
|
|
{
|
|
|
|
if(f->rescuing)
|
|
|
|
return;
|
|
|
|
if(p0 == p1)
|
|
|
|
return;
|
|
|
|
if(f->seq < seq)
|
|
|
|
filemark(f);
|
|
|
|
if(p0 < f->hiposn)
|
|
|
|
error(Esequence);
|
|
|
|
|
|
|
|
if(merge.f != f
|
|
|
|
|| p0-(merge.p0+merge.n)>Maxmerge /* too far */
|
|
|
|
|| merge.nbuf+(p0-(merge.p0+merge.n))>RBUFSIZE){ /* too long */
|
|
|
|
flushmerge();
|
|
|
|
merge.f = f;
|
|
|
|
merge.p0 = p0;
|
|
|
|
merge.seq = f->seq;
|
|
|
|
}
|
|
|
|
|
|
|
|
mergeextend(f, p0);
|
|
|
|
|
|
|
|
/* add to deletion */
|
|
|
|
merge.n = p1-merge.p0;
|
|
|
|
|
|
|
|
f->hiposn = p1;
|
|
|
|
if(!f->unread && !f->mod)
|
|
|
|
state(f, Dirty);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* like fileunsetname, but get the data from arguments
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
logsetname(File *f, String *s)
|
|
|
|
{
|
|
|
|
Undo u;
|
|
|
|
Buffer *delta;
|
|
|
|
|
|
|
|
if(f->rescuing)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if(f->unread){ /* This is setting initial file name */
|
|
|
|
filesetname(f, s);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(f->seq < seq)
|
|
|
|
filemark(f);
|
|
|
|
|
|
|
|
/* undo a file name change by restoring old name */
|
|
|
|
delta = &f->epsilon;
|
|
|
|
u.type = Filename;
|
|
|
|
u.mod = TRUE;
|
|
|
|
u.seq = f->seq;
|
|
|
|
u.p0 = 0; /* unused */
|
|
|
|
u.n = s->n;
|
|
|
|
if(s->n)
|
|
|
|
bufinsert(delta, delta->nc, s->s, s->n);
|
|
|
|
bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
|
|
|
|
if(!f->unread && !f->mod)
|
|
|
|
state(f, Dirty);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef NOTEXT
|
|
|
|
File*
|
|
|
|
fileaddtext(File *f, Text *t)
|
|
|
|
{
|
|
|
|
if(f == nil){
|
|
|
|
f = emalloc(sizeof(File));
|
|
|
|
f->unread = TRUE;
|
|
|
|
}
|
|
|
|
f->text = realloc(f->text, (f->ntext+1)*sizeof(Text*));
|
|
|
|
f->text[f->ntext++] = t;
|
|
|
|
f->curtext = t;
|
|
|
|
return f;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
filedeltext(File *f, Text *t)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for(i=0; i<f->ntext; i++)
|
|
|
|
if(f->text[i] == t)
|
|
|
|
goto Found;
|
|
|
|
panic("can't find text in filedeltext");
|
|
|
|
|
|
|
|
Found:
|
|
|
|
f->ntext--;
|
|
|
|
if(f->ntext == 0){
|
|
|
|
fileclose(f);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
memmove(f->text+i, f->text+i+1, (f->ntext-i)*sizeof(Text*));
|
|
|
|
if(f->curtext == t)
|
|
|
|
f->curtext = f->text[0];
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void
|
|
|
|
fileinsert(File *f, uint p0, Rune *s, uint ns)
|
|
|
|
{
|
2003-09-30 19:05:50 +00:00
|
|
|
if(p0 > f->b.nc)
|
2003-09-30 17:47:42 +00:00
|
|
|
panic("internal error: fileinsert");
|
|
|
|
if(f->seq > 0)
|
|
|
|
fileuninsert(f, &f->delta, p0, ns);
|
2003-09-30 19:05:50 +00:00
|
|
|
bufinsert(&f->b, p0, s, ns);
|
2003-09-30 17:47:42 +00:00
|
|
|
if(ns)
|
|
|
|
f->mod = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
fileuninsert(File *f, Buffer *delta, uint p0, uint ns)
|
|
|
|
{
|
|
|
|
Undo u;
|
|
|
|
|
|
|
|
/* undo an insertion by deleting */
|
|
|
|
u.type = Delete;
|
|
|
|
u.mod = f->mod;
|
|
|
|
u.seq = f->seq;
|
|
|
|
u.p0 = p0;
|
|
|
|
u.n = ns;
|
|
|
|
bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
filedelete(File *f, uint p0, uint p1)
|
|
|
|
{
|
2003-09-30 19:05:50 +00:00
|
|
|
if(!(p0<=p1 && p0<=f->b.nc && p1<=f->b.nc))
|
2003-09-30 17:47:42 +00:00
|
|
|
panic("internal error: filedelete");
|
|
|
|
if(f->seq > 0)
|
|
|
|
fileundelete(f, &f->delta, p0, p1);
|
2003-09-30 19:05:50 +00:00
|
|
|
bufdelete(&f->b, p0, p1);
|
2003-09-30 17:47:42 +00:00
|
|
|
if(p1 > p0)
|
|
|
|
f->mod = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
fileundelete(File *f, Buffer *delta, uint p0, uint p1)
|
|
|
|
{
|
|
|
|
Undo u;
|
|
|
|
Rune *buf;
|
|
|
|
uint i, n;
|
|
|
|
|
|
|
|
/* undo a deletion by inserting */
|
|
|
|
u.type = Insert;
|
|
|
|
u.mod = f->mod;
|
|
|
|
u.seq = f->seq;
|
|
|
|
u.p0 = p0;
|
|
|
|
u.n = p1-p0;
|
|
|
|
buf = fbufalloc();
|
|
|
|
for(i=p0; i<p1; i+=n){
|
|
|
|
n = p1 - i;
|
|
|
|
if(n > RBUFSIZE)
|
|
|
|
n = RBUFSIZE;
|
2003-09-30 19:05:50 +00:00
|
|
|
bufread(&f->b, i, buf, n);
|
2003-09-30 17:47:42 +00:00
|
|
|
bufinsert(delta, delta->nc, buf, n);
|
|
|
|
}
|
|
|
|
fbuffree(buf);
|
|
|
|
bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
filereadc(File *f, uint q)
|
|
|
|
{
|
|
|
|
Rune r;
|
|
|
|
|
2003-09-30 19:05:50 +00:00
|
|
|
if(q >= f->b.nc)
|
2003-09-30 17:47:42 +00:00
|
|
|
return -1;
|
2003-09-30 19:05:50 +00:00
|
|
|
bufread(&f->b, q, &r, 1);
|
2003-09-30 17:47:42 +00:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
filesetname(File *f, String *s)
|
|
|
|
{
|
|
|
|
if(!f->unread) /* This is setting initial file name */
|
|
|
|
fileunsetname(f, &f->delta);
|
|
|
|
Strduplstr(&f->name, s);
|
|
|
|
sortname(f);
|
|
|
|
f->unread = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
fileunsetname(File *f, Buffer *delta)
|
|
|
|
{
|
|
|
|
String s;
|
|
|
|
Undo u;
|
|
|
|
|
|
|
|
/* undo a file name change by restoring old name */
|
|
|
|
u.type = Filename;
|
|
|
|
u.mod = f->mod;
|
|
|
|
u.seq = f->seq;
|
|
|
|
u.p0 = 0; /* unused */
|
|
|
|
Strinit(&s);
|
|
|
|
Strduplstr(&s, &f->name);
|
|
|
|
fullname(&s);
|
|
|
|
u.n = s.n;
|
|
|
|
if(s.n)
|
|
|
|
bufinsert(delta, delta->nc, s.s, s.n);
|
|
|
|
bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
|
|
|
|
Strclose(&s);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
fileunsetdot(File *f, Buffer *delta, Range dot)
|
|
|
|
{
|
|
|
|
Undo u;
|
|
|
|
|
|
|
|
u.type = Dot;
|
|
|
|
u.mod = f->mod;
|
|
|
|
u.seq = f->seq;
|
|
|
|
u.p0 = dot.p1;
|
|
|
|
u.n = dot.p2 - dot.p1;
|
|
|
|
bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
fileunsetmark(File *f, Buffer *delta, Range mark)
|
|
|
|
{
|
|
|
|
Undo u;
|
|
|
|
|
|
|
|
u.type = Mark;
|
|
|
|
u.mod = f->mod;
|
|
|
|
u.seq = f->seq;
|
|
|
|
u.p0 = mark.p1;
|
|
|
|
u.n = mark.p2 - mark.p1;
|
|
|
|
bufinsert(delta, delta->nc, (Rune*)&u, Undosize);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint
|
|
|
|
fileload(File *f, uint p0, int fd, int *nulls)
|
|
|
|
{
|
|
|
|
if(f->seq > 0)
|
|
|
|
panic("undo in file.load unimplemented");
|
2003-09-30 19:05:50 +00:00
|
|
|
return bufload(&f->b, p0, fd, nulls);
|
2003-09-30 17:47:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
fileupdate(File *f, int notrans, int toterm)
|
|
|
|
{
|
|
|
|
uint p1, p2;
|
|
|
|
int mod;
|
|
|
|
|
|
|
|
if(f->rescuing)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
flushmerge();
|
|
|
|
|
|
|
|
/*
|
|
|
|
* fix the modification bit
|
|
|
|
* subtle point: don't save it away in the log.
|
|
|
|
*
|
|
|
|
* if another change is made, the correct f->mod
|
|
|
|
* state is saved in the undo log by filemark
|
|
|
|
* when setting the dot and mark.
|
|
|
|
*
|
|
|
|
* if the change is undone, the correct state is
|
|
|
|
* saved from f in the fileun... routines.
|
|
|
|
*/
|
|
|
|
mod = f->mod;
|
|
|
|
f->mod = f->prevmod;
|
|
|
|
if(f == cmd)
|
|
|
|
notrans = TRUE;
|
|
|
|
else{
|
|
|
|
fileunsetdot(f, &f->delta, f->prevdot);
|
|
|
|
fileunsetmark(f, &f->delta, f->prevmark);
|
|
|
|
}
|
|
|
|
f->dot = f->ndot;
|
|
|
|
fileundo(f, FALSE, !notrans, &p1, &p2, toterm);
|
|
|
|
f->mod = mod;
|
|
|
|
|
|
|
|
if(f->delta.nc == 0)
|
|
|
|
f->seq = 0;
|
|
|
|
|
|
|
|
if(f == cmd)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if(f->mod){
|
|
|
|
f->closeok = 0;
|
|
|
|
quitok = 0;
|
|
|
|
}else
|
|
|
|
f->closeok = 1;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
long
|
|
|
|
prevseq(Buffer *b)
|
|
|
|
{
|
|
|
|
Undo u;
|
|
|
|
uint up;
|
|
|
|
|
|
|
|
up = b->nc;
|
|
|
|
if(up == 0)
|
|
|
|
return 0;
|
|
|
|
up -= Undosize;
|
|
|
|
bufread(b, up, (Rune*)&u, Undosize);
|
|
|
|
return u.seq;
|
|
|
|
}
|
|
|
|
|
|
|
|
long
|
|
|
|
undoseq(File *f, int isundo)
|
|
|
|
{
|
|
|
|
if(isundo)
|
|
|
|
return f->seq;
|
|
|
|
|
|
|
|
return prevseq(&f->epsilon);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
fileundo(File *f, int isundo, int canredo, uint *q0p, uint *q1p, int flag)
|
|
|
|
{
|
|
|
|
Undo u;
|
|
|
|
Rune *buf;
|
|
|
|
uint i, n, up;
|
|
|
|
uint stop;
|
|
|
|
Buffer *delta, *epsilon;
|
|
|
|
|
|
|
|
if(isundo){
|
|
|
|
/* undo; reverse delta onto epsilon, seq decreases */
|
|
|
|
delta = &f->delta;
|
|
|
|
epsilon = &f->epsilon;
|
|
|
|
stop = f->seq;
|
|
|
|
}else{
|
|
|
|
/* redo; reverse epsilon onto delta, seq increases */
|
|
|
|
delta = &f->epsilon;
|
|
|
|
epsilon = &f->delta;
|
|
|
|
stop = 0; /* don't know yet */
|
|
|
|
}
|
|
|
|
|
|
|
|
raspstart(f);
|
|
|
|
while(delta->nc > 0){
|
|
|
|
up = delta->nc-Undosize;
|
|
|
|
bufread(delta, up, (Rune*)&u, Undosize);
|
|
|
|
if(isundo){
|
|
|
|
if(u.seq < stop){
|
|
|
|
f->seq = u.seq;
|
|
|
|
raspdone(f, flag);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}else{
|
|
|
|
if(stop == 0)
|
|
|
|
stop = u.seq;
|
|
|
|
if(u.seq > stop){
|
|
|
|
raspdone(f, flag);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
switch(u.type){
|
|
|
|
default:
|
|
|
|
panic("undo unknown u.type");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Delete:
|
|
|
|
f->seq = u.seq;
|
|
|
|
if(canredo)
|
|
|
|
fileundelete(f, epsilon, u.p0, u.p0+u.n);
|
|
|
|
f->mod = u.mod;
|
2003-09-30 19:05:50 +00:00
|
|
|
bufdelete(&f->b, u.p0, u.p0+u.n);
|
2003-09-30 17:47:42 +00:00
|
|
|
raspdelete(f, u.p0, u.p0+u.n, flag);
|
|
|
|
*q0p = u.p0;
|
|
|
|
*q1p = u.p0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Insert:
|
|
|
|
f->seq = u.seq;
|
|
|
|
if(canredo)
|
|
|
|
fileuninsert(f, epsilon, u.p0, u.n);
|
|
|
|
f->mod = u.mod;
|
|
|
|
up -= u.n;
|
|
|
|
buf = fbufalloc();
|
|
|
|
for(i=0; i<u.n; i+=n){
|
|
|
|
n = u.n - i;
|
|
|
|
if(n > RBUFSIZE)
|
|
|
|
n = RBUFSIZE;
|
|
|
|
bufread(delta, up+i, buf, n);
|
2003-09-30 19:05:50 +00:00
|
|
|
bufinsert(&f->b, u.p0+i, buf, n);
|
2003-09-30 17:47:42 +00:00
|
|
|
raspinsert(f, u.p0+i, buf, n, flag);
|
|
|
|
}
|
|
|
|
fbuffree(buf);
|
|
|
|
*q0p = u.p0;
|
|
|
|
*q1p = u.p0+u.n;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Filename:
|
|
|
|
f->seq = u.seq;
|
|
|
|
if(canredo)
|
|
|
|
fileunsetname(f, epsilon);
|
|
|
|
f->mod = u.mod;
|
|
|
|
up -= u.n;
|
|
|
|
|
|
|
|
Strinsure(&f->name, u.n+1);
|
|
|
|
bufread(delta, up, f->name.s, u.n);
|
|
|
|
f->name.s[u.n] = 0;
|
|
|
|
f->name.n = u.n;
|
|
|
|
fixname(&f->name);
|
|
|
|
sortname(f);
|
|
|
|
break;
|
|
|
|
case Dot:
|
|
|
|
f->seq = u.seq;
|
|
|
|
if(canredo)
|
|
|
|
fileunsetdot(f, epsilon, f->dot.r);
|
|
|
|
f->mod = u.mod;
|
|
|
|
f->dot.r.p1 = u.p0;
|
|
|
|
f->dot.r.p2 = u.p0 + u.n;
|
|
|
|
break;
|
|
|
|
case Mark:
|
|
|
|
f->seq = u.seq;
|
|
|
|
if(canredo)
|
|
|
|
fileunsetmark(f, epsilon, f->mark);
|
|
|
|
f->mod = u.mod;
|
|
|
|
f->mark.p1 = u.p0;
|
|
|
|
f->mark.p2 = u.p0 + u.n;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
bufdelete(delta, up, delta->nc);
|
|
|
|
}
|
|
|
|
if(isundo)
|
|
|
|
f->seq = 0;
|
|
|
|
raspdone(f, flag);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
filereset(File *f)
|
|
|
|
{
|
|
|
|
bufreset(&f->delta);
|
|
|
|
bufreset(&f->epsilon);
|
|
|
|
f->seq = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
fileclose(File *f)
|
|
|
|
{
|
|
|
|
Strclose(&f->name);
|
2003-09-30 19:05:50 +00:00
|
|
|
bufclose(&f->b);
|
2003-09-30 17:47:42 +00:00
|
|
|
bufclose(&f->delta);
|
|
|
|
bufclose(&f->epsilon);
|
|
|
|
if(f->rasp)
|
|
|
|
listfree(f->rasp);
|
|
|
|
free(f);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
filemark(File *f)
|
|
|
|
{
|
|
|
|
|
|
|
|
if(f->unread)
|
|
|
|
return;
|
|
|
|
if(f->epsilon.nc)
|
|
|
|
bufdelete(&f->epsilon, 0, f->epsilon.nc);
|
|
|
|
|
|
|
|
if(f != cmd){
|
|
|
|
f->prevdot = f->dot.r;
|
|
|
|
f->prevmark = f->mark;
|
|
|
|
f->prevseq = f->seq;
|
|
|
|
f->prevmod = f->mod;
|
|
|
|
}
|
|
|
|
|
|
|
|
f->ndot = f->dot;
|
|
|
|
f->seq = seq;
|
|
|
|
f->hiposn = 0;
|
|
|
|
}
|