This is undo.c in view mode; [Download] [Up]
/* UNDO system
Copyright (C) 1992 Joseph H. Allen
This file is part of JOE (Joe's Own Editor)
JOE is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 1, or (at your option) any later version.
JOE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along with
JOE; see the file COPYING. If not, write to the Free Software Foundation,
675 Mass Ave, Cambridge, MA 02139, USA. */
#include "b.h"
#include "bw.h"
#include "blocks.h"
#include "ublock.h"
#include "undo.h"
extern int lightoff;
#define SMALL 1024
static UNDO undos={{&undos,&undos}};
static UNDO frdos={{&frdos,&frdos}};
int inundo=0;
int inredo=0;
UNDOREC frrecs={{&frrecs,&frrecs}};
UNDOREC *alrec()
{
UNDOREC *rec=(UNDOREC *)alitem(&frrecs,sizeof(UNDOREC));
return rec;
}
void frrec(rec)
UNDOREC *rec;
{
if(rec->del)
if(rec->len<SMALL) free(rec->small);
else
{
B *b=rec->big;
bonline(b);
brm(b);
}
enquef(UNDOREC,link,&frrecs,rec);
}
UNDO *undomk(b)
B *b;
{
UNDO *undo=(UNDO *)alitem(&frdos,sizeof(UNDO));
undo->nrecs=0;
undo->ptr=0;
undo->last=0;
undo->first=0;
undo->b=b;
izque(UNDOREC,link,&undo->recs);
enquef(UNDO,link,&undos,undo);
return undo;
}
void undorm(undo)
UNDO *undo;
{
frchn(&frrecs,&undo->recs);
demote(UNDO,link,&frdos,undo);
}
extern int dostaupd;
void doundo(bw,ptr)
BW *bw;
UNDOREC *ptr;
{
dostaupd=1;
if(ptr->del)
{
if(ptr->len<SMALL)
binsm(bw->cursor,ptr->small,(int)ptr->len);
else
{
B *b=ptr->big;
bonline(b);
binsb(bw->cursor,bcpy(b->bof,b->eof));
boffline(b);
}
}
else
{
P *q=pdup(bw->cursor);
pfwrd(q,ptr->len);
bdel(bw->cursor,q);
prm(q);
}
bw->b->changed=ptr->changed;
}
int uundo(bw)
BW *bw;
{
UNDOREC *upto;
UNDO *undo=bw->b->undo;
if(!undo) return -1;
if(!undo->nrecs) return -1;
if(!undo->ptr)
{
pgoto(bw->cursor,undo->recs.link.prev->where);
undo->ptr= &undo->recs;
/* If this return is uncommented, then uundo will jump to where the undo
is about to occur before actually undoing anything
return 0; */
}
if(undo->ptr->link.prev==&undo->recs) return -1;
upto=undo->ptr->link.prev->unit;
loop:
undo->ptr=undo->ptr->link.prev;
pgoto(bw->cursor,undo->ptr->where);
inundo=1;
doundo(bw,undo->ptr);
inundo=0;
if(upto && upto!=undo->ptr) goto loop;
return 0;
}
int uredo(bw)
BW *bw;
{
UNDOREC *upto;
UNDOREC *ptr;
UNDO *undo=bw->b->undo;
if(!undo) return -1;
if(!undo->ptr) return -1;
if(undo->ptr==&undo->recs) return -1;
upto=undo->recs.link.prev->unit;
do
{
ptr=undo->recs.link.prev;
pgoto(bw->cursor,ptr->where);
inredo=1;
doundo(bw,ptr);
inredo=0;
frrec(deque(UNDOREC,link,ptr));
undo->ptr=undo->ptr->link.next;
}
while(upto && upto!=ptr);
return 0;
}
void umclear()
{
UNDO *undo;
for(undo=undos.link.next;undo!=&undos;undo=undo->link.next)
{
UNDOREC *rec;
for(rec=undo->recs.link.next;rec!=&undo->recs;rec=rec->link.next) rec->min=0;
}
}
/* Eliminate excess undo records */
static void undogc(undo)
UNDO *undo;
{
UNDOREC *unit=undo->recs.link.next->unit;
int flg=0;
if(undo->ptr && undo->ptr->link.prev==&undo->recs) flg=1;
if(unit)
while(unit!=undo->recs.link.next)
frrec(deque(UNDOREC,link,undo->recs.link.next));
frrec(deque(UNDOREC,link,undo->recs.link.next));
--undo->nrecs;
if(flg) undo->ptr=undo->recs.link.next;
}
void undomark()
{
UNDO *undo;
for(undo=undos.link.next;undo!=&undos;undo=undo->link.next)
if(undo->first)
{
undo->first->unit=undo->last;
undo->last->unit=undo->first;
undo->first=undo->last=0;
if(++undo->nrecs==UNDOKEEP) undogc(undo);
}
}
/* Delete the alternate time-line after the user has resumed editing after
* undoing some number of changes
*/
static void undoover(undo)
UNDO *undo;
{
undo->ptr=0;
}
void undoins(undo,p,size)
UNDO *undo;
P *p;
long size;
{
UNDOREC *rec;
if(inredo) return;
if(!inundo) if(undo->ptr && undo->ptr!=&undo->recs) undoover(undo);
rec=undo->recs.link.prev;
if(rec!=&undo->recs && rec->min && !rec->del &&
(p->byte==rec->where+rec->len || p->byte==rec->where)) rec->len+=size;
else
{
rec=alrec();
rec->del=0;
if(!undo->first) undo->first=rec;
undo->last=rec;
rec->where=p->byte;
rec->min=1;
rec->unit=0;
rec->len=size;
rec->changed=undo->b->changed;
enqueb(UNDOREC,link,&undo->recs,rec);
}
}
UNDOREC yanked={{&yanked,&yanked}};
int nyanked=0;
int inyank=0;
int justkilled=0;
int uyapp(bw)
BW *bw;
{
UNDOREC *rec=yanked.link.prev;
if(rec!=&yanked) rec->where=bw->cursor->byte;
return 0;
}
void yankdel(where,b)
long where;
B *b;
{
UNDOREC *rec;
long size=b->eof->byte;
/* Store in yank buffer */
rec=yanked.link.prev;
if(!inyank)
if(rec!=&yanked && where==rec->where && justkilled)
{
if(rec->len+size>=SMALL)
{
if(rec->len<SMALL)
{
rec->big=bmk(NULL);
binsm(rec->big->bof,rec->small,(int)rec->len);
boffline(rec->big);
free(rec->small);
}
bonline(rec->big);
binsb(rec->big->eof,bcpy(b->bof,b->eof));
boffline(rec->big);
}
else
{
rec->small=(char *)realloc(rec->small,rec->len+size);
brmem(b->bof,rec->small+rec->len,(int)size);
}
rec->len+=size;
}
else if(rec!=&yanked && where+size==rec->where && justkilled)
{
if(rec->len+size>=SMALL)
{
if(rec->len<SMALL)
{
rec->big=bmk(NULL);
binsm(rec->big->bof,rec->small,(int)rec->len);
boffline(rec->big);
free(rec->small);
}
bonline(rec->big);
binsb(rec->big->bof,bcpy(b->bof,b->eof));
boffline(rec->big);
}
else
{
rec->small=(char *)realloc(rec->small,rec->len+size);
mbkwd(rec->small+size,rec->small,(int)rec->len);
brmem(b->bof,rec->small,(int)size);
}
rec->len+=size;
rec->where=where;
}
else
{
if(++nyanked==100)
frrec(deque(UNDOREC,link,yanked.link.next)), --nyanked;
rec=alrec();
if(size<SMALL)
{
rec->small=(char *)malloc(size);
brmem(b->bof,rec->small,(int)b->eof->byte);
}
else
{
rec->big=bcpy(b->bof,b->eof);
boffline(rec->big);
}
rec->where=where;
rec->len=size;
rec->del=1;
enqueb(UNDOREC,link,&yanked,rec);
}
}
void undodel(undo,where,b)
UNDO *undo;
long where;
B *b;
{
UNDOREC *rec;
long size=b->eof->byte;
if(inredo)
{
brm(b);
return;
}
if(!inundo) if(undo->ptr && undo->ptr!=&undo->recs) undoover(undo);
yankdel(where,b);
/* Store in undo buffer */
rec=undo->recs.link.prev;
if(rec!=&undo->recs && rec->min && rec->del && where==rec->where)
{
if(rec->len+size>=SMALL)
{
if(rec->len<SMALL)
{
rec->big=bmk(NULL);
binsm(rec->big->bof,rec->small,(int)rec->len);
boffline(rec->big);
free(rec->small);
}
bonline(rec->big);
binsb(rec->big->eof,b);
boffline(rec->big);
}
else
{
rec->small=(char *)realloc(rec->small,rec->len+size);
brmem(b->bof,rec->small+rec->len,(int)size);
brm(b);
}
rec->len+=size;
}
else if(rec!=&undo->recs && rec->min && rec->del && where+size==rec->where)
{
if(rec->len+size>=SMALL)
{
if(rec->len<SMALL)
{
rec->big=bmk(NULL);
binsm(rec->big->bof,rec->small,(int)rec->len);
boffline(rec->big);
free(rec->small);
}
bonline(rec->big);
binsb(rec->big->bof,b);
boffline(rec->big);
}
else
{
rec->small=(char *)realloc(rec->small,rec->len+size);
mbkwd(rec->small+size,rec->small,(int)rec->len);
brmem(b->bof,rec->small,(int)size);
brm(b);
}
rec->len+=size;
rec->where=where;
}
else
{
rec=alrec();
if(size<SMALL)
{
rec->small=(char *)malloc(size);
brmem(b->bof,rec->small,(int)b->eof->byte);
brm(b);
}
else
{
rec->big=b;
boffline(b);
}
if(!undo->first) undo->first=rec;
undo->last=rec;
rec->where=where;
rec->min=1;
rec->unit=0;
rec->len=size;
rec->del=1;
rec->changed=undo->b->changed;
enqueb(UNDOREC,link,&undo->recs,rec);
}
}
B *yankbuf=0;
long yankwhere= -1;
int uyank(bw)
BW *bw;
{
UNDOREC *ptr=yanked.link.prev;
if(ptr!=&yanked)
{
if(ptr->len<SMALL)
binsm(bw->cursor,ptr->small,(int)ptr->len);
else
{
B *b=ptr->big;
bonline(b);
binsb(bw->cursor,bcpy(b->bof,b->eof));
boffline(b);
}
pfwrd(bw->cursor,ptr->len);
yankbuf=bw->b;
yankwhere=bw->cursor->byte;
return 0;
}
else return -1;
}
int uyankpop(bw)
BW *bw;
{
if(bw->b==yankbuf && bw->cursor->byte==yankwhere)
{
P *q;
UNDOREC *ptr=yanked.link.prev;
deque(UNDOREC,link,&yanked);
enqueb(UNDOREC,link,ptr,&yanked);
q=pdup(bw->cursor);
pbkwd(q,ptr->len);
inyank=1;
bdel(q,bw->cursor);
inyank=0;
prm(q);
return uyank(bw);
}
else return uyank(bw);
}
/* Clear changed-flag: make buffer look unmodified */
int unotmod(bw)
BW *bw;
{
bw->b->changed=0;
msgnw(bw,"Modified flag cleared");
return 0;
}
int ucopy(bw)
BW *bw;
{
if(markv(1) && !square)
{
B *b=bcpy(markb,markk);
yankdel(markb->byte,b);
brm(b);
if(lightoff) unmark(bw);
return 0;
}
else
{
msgnw(bw,"No block");
return -1;
}
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.