#include <sys/queue.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "def.h"
#define KBLOCK 8192
static char *kbufp = NULL;
static RSIZE kused = 0;
static RSIZE ksize = 0;
static RSIZE kstart = 0;
static int kgrow(int);
void
kdelete(void)
{
if (kbufp != NULL) {
free(kbufp);
kbufp = NULL;
kstart = kused = ksize = 0;
}
}
int
kinsert(int c, int dir)
{
if (dir == KNONE)
return (TRUE);
if (kused == ksize && dir == KFORW && kgrow(dir) == FALSE)
return (FALSE);
if (kstart == 0 && dir == KBACK && kgrow(dir) == FALSE)
return (FALSE);
if (dir == KFORW)
kbufp[kused++] = c;
else if (dir == KBACK)
kbufp[--kstart] = c;
else
panic("broken kinsert call");
return (TRUE);
}
static int
kgrow(int dir)
{
int nstart;
char *nbufp;
if ((unsigned)(ksize + KBLOCK) <= (unsigned)ksize) {
dobeep();
ewprintf("Kill buffer size at maximum");
return (FALSE);
}
if ((nbufp = malloc((unsigned)(ksize + KBLOCK))) == NULL) {
dobeep();
ewprintf("Can't get %ld bytes", (long)(ksize + KBLOCK));
return (FALSE);
}
nstart = (dir == KBACK) ? (kstart + KBLOCK) : (KBLOCK / 4);
bcopy(&(kbufp[kstart]), &(nbufp[nstart]), (int)(kused - kstart));
free(kbufp);
kbufp = nbufp;
ksize += KBLOCK;
kused = kused - kstart + nstart;
kstart = nstart;
return (TRUE);
}
int
kremove(int n)
{
if (n < 0 || n + kstart >= kused)
return (-1);
return (CHARMASK(kbufp[n + kstart]));
}
int
kchunk(char *cp1, RSIZE chunk, int kflag)
{
if (kused == kstart)
kflag = KFORW;
if (kflag & KFORW) {
while (ksize - kused < chunk)
if (kgrow(kflag) == FALSE)
return (FALSE);
bcopy(cp1, &(kbufp[kused]), (int)chunk);
kused += chunk;
} else if (kflag & KBACK) {
while (kstart < chunk)
if (kgrow(kflag) == FALSE)
return (FALSE);
bcopy(cp1, &(kbufp[kstart - chunk]), (int)chunk);
kstart -= chunk;
}
return (TRUE);
}
int
killline(int f, int n)
{
struct line *nextp;
RSIZE chunk;
int i, c;
if ((lastflag & CFKILL) == 0)
kdelete();
thisflag |= CFKILL;
if (!(f & FFARG)) {
for (i = curwp->w_doto; i < llength(curwp->w_dotp); ++i)
if ((c = lgetc(curwp->w_dotp, i)) != ' ' && c != '\t')
break;
if (i == llength(curwp->w_dotp))
chunk = llength(curwp->w_dotp) - curwp->w_doto + 1;
else {
chunk = llength(curwp->w_dotp) - curwp->w_doto;
if (chunk == 0)
chunk = 1;
}
} else if (n > 0) {
chunk = llength(curwp->w_dotp) - curwp->w_doto;
nextp = lforw(curwp->w_dotp);
if (nextp != curbp->b_headp)
chunk++;
if (nextp == curbp->b_headp)
goto done;
i = n;
while (--i) {
chunk += llength(nextp);
nextp = lforw(nextp);
if (nextp != curbp->b_headp)
chunk++;
if (nextp == curbp->b_headp)
break;
}
} else {
chunk = curwp->w_doto;
curwp->w_doto = 0;
i = n;
while (i++) {
if (lforw(curwp->w_dotp))
chunk++;
curwp->w_dotp = lback(curwp->w_dotp);
curwp->w_rflag |= WFMOVE;
chunk += llength(curwp->w_dotp);
}
}
done:
if (chunk)
return (ldelete(chunk, KFORW));
return (TRUE);
}
int
yank(int f, int n)
{
struct line *lp;
int c, i, nline;
if (n < 0)
return (FALSE);
nline = 0;
undo_boundary_enable(FFRAND, 0);
while (n--) {
isetmark();
i = 0;
while ((c = kremove(i)) >= 0) {
if (c == *curbp->b_nlchr) {
if (enewline(FFRAND, 1) == FALSE)
return (FALSE);
++nline;
} else {
if (linsert(1, c) == FALSE)
return (FALSE);
}
++i;
}
}
lp = curwp->w_linep;
if (curwp->w_dotp == lp) {
while (nline-- && lback(lp) != curbp->b_headp)
lp = lback(lp);
curwp->w_linep = lp;
curwp->w_rflag |= WFFULL;
}
undo_boundary_enable(FFRAND, 1);
return (TRUE);
}