/*
* LEVEE, or Captain Video; A vi clone
*
* Copyright (c) 1982-2007 David L Parsons
* All rights reserved.
*
* Redistribution and use in source and binary forms, without or
* without modification, are permitted provided that the above
* copyright notice and this paragraph are duplicated in all such
* forms and that any documentation, advertising materials, and
* other materials related to such distribution and use acknowledge
* that the software was developed by David L Parsons (orc@pell.chi.il.us).
* My name may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
* PURPOSE.
*/
#include "levee.h"
#include "extern.h"
#define BUFSZ sizeof(undo.coreblock)
#define AVAIL(x) ((x)<<1)
#define INDEX(x) ((1+x)>>1)
bool PROC
pushblock(u)
struct undostack *u;
{
if (u->blockp == 0)
if ((uwrite = OPEN_NEW(undobuf)) < 0)
return FALSE;
if (BUFSZ == WRITE_TEXT(uwrite, u->coreblock, BUFSZ)) {
u->blockp++;
u->ptr = 0;
return TRUE;
}
return FALSE;
}
bool PROC
pushw(u, i)
struct undostack *u;
int i;
{
if (u->ptr >= PAGESIZE && !pushblock(u))
return FALSE;
u->coreblock[u->ptr++] = i;
return TRUE;
}
bool PROC
pushmem(u, start, size)
struct undostack *u;
int start,size;
{
int chunk;
bool ok;
ok = TRUE;
while (ok && size > 0) {
chunk = min(size, AVAIL(PAGESIZE-u->ptr));
moveleft(&core[start], (char*)&u->coreblock[u->ptr], chunk);
size -= chunk;
start += chunk;
if (size > 0)
ok = pushblock(u);
else
u->ptr += INDEX(chunk);
}
return ok;
}
VOID PROC
zerostack(u)
struct undostack *u;
{
if (u->blockp > 0)
CLOSE_FILE(uwrite);
u->blockp = 0; /* initialize the stack */
u->ptr = 0;
}
bool PROC
uputcmd(u, size, start, cmd)
struct undostack *u;
int size,start;
char cmd;
{
return(pushw(u, size) && pushw(u, start) && pushw(u, cmd));
}
VOID PROC
insert_to_undo(u, start, size)
struct undostack *u;
int start,size;
{
if (uputcmd(u, size, start, U_DELC)) {
fixmarkers(start, size);
bufmax += size;
}
else
error();
}
/* delete stuff from the buffer && put it into the undo stack */
bool PROC
delete_to_undo(u, start, lump)
struct undostack *u;
int start, lump;
{
if (lump <= 0)
return TRUE;
else if (pushmem(u,start,lump) && uputcmd(u,lump,start,U_ADDC)) {
moveleft(&core[start+lump], &core[start], bufmax-(start+lump));
bufmax -= lump;
fixmarkers(start,-lump);
return TRUE;
}
else
return FALSE;
}
/* copy stuff into the undo buffer */
bool PROC
move_to_undo(u, start, lump)
struct undostack *u;
int start,lump;
{
return pushmem(u, start, lump) && uputcmd(u,lump,start,U_MOVEC);
}
bool PROC
popblock(u)
struct undostack *u;
{
if (u->blockp > 0) {
if (SEEK_POSITION(uread, (long)((--u->blockp)*BUFSZ), 0) < 0)
return FALSE;
if (BUFSZ == READ_TEXT(uread, u->coreblock, BUFSZ)) {
u->ptr = PAGESIZE;
return TRUE;
}
}
return FALSE;
}
bool PROC
popw(u, i)
struct undostack *u;
int *i;
{
if (u->ptr < 1 && !popblock(u))
return FALSE;
*i = u->coreblock[--u->ptr];
return TRUE;
}
bool PROC
popmem(u, start, size)
struct undostack *u;
int start, size;
{
int chunk, loc;
bool ok;
loc = start+size; /* running backwards */
ok = TRUE;
while (ok && size > 0) {
chunk = min(size, AVAIL(u->ptr));
size -= chunk;
loc -= chunk;
moveleft((char*)&u->coreblock[u->ptr-INDEX(chunk)], &core[loc], chunk);
if (size > 0)
ok = popblock(u);
else
u->ptr -= INDEX(chunk);
}
return(ok);
}
/* delete (I)nserted text */
bool PROC
takeout(save_undo,curp)
struct undostack *save_undo;
int *curp;
{
int lump;
return popw(&undo,curp) && popw(&undo,&lump)
&& delete_to_undo(save_undo,*curp,lump);
}
bool PROC
copyover(save_undo,curp)
struct undostack *save_undo;
int *curp;
{
int lump;
return popw(&undo, curp) && popw(&undo, &lump)
&& move_to_undo(save_undo, *curp, lump)
&& popmem(&undo, *curp, lump);
}
bool PROC
putin(save_undo,curp)
struct undostack *save_undo;
int *curp;
{
int lump;
if (popw(&undo,curp) && popw(&undo,&lump) && (bufmax+lump < SIZE)) {
insert_to_undo(save_undo, *curp, lump);
moveright(&core[*curp], &core[*curp+lump], bufmax-*curp);
if (popmem(&undo, *curp, lump))
return TRUE;
else
moveleft(&core[*curp+lump], &core[*curp], bufmax-*curp);
}
return FALSE;
}
/* driver for undo -- returns last address modified || -1 if error */
int PROC
fixcore(topp)
int *topp;
{
int curp;
static struct undostack save_undo;
bool closeio, ok;
int cch;
if (undo.blockp > 0 || undo.ptr > 0) {
closeio = (undo.blockp > 0);
if (closeio) { /* save diskfile */
CLOSE_FILE(uwrite); /* close current undo file */
rename(undobuf,undotmp);
uread = OPEN_OLD(undotmp); /* reopen it for reading */
if (uread < 0)
return -1;
}
*topp = SIZE+1;
curp = -MAGICNUMBER;
save_undo.blockp = save_undo.ptr = 0;
ok = TRUE;
while (ok && popw(&undo,&cch)) {
switch (cch) {
case U_ADDC : ok = putin(&save_undo, &curp); break;
case U_MOVEC: ok = copyover(&save_undo, &curp); break;
case U_DELC : ok = takeout(&save_undo, &curp); break;
}
if (curp < *topp)
*topp = curp;
}
if (curp >= 0)
undo = save_undo;
if (closeio) {
CLOSE_FILE(uread); /* Zap old buffer */
unlink(undotmp);
}
if (!ok)
error();
return(curp);
}
return ERR;
}