[BACK]Return to yank.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / mg

File: [local] / src / usr.bin / mg / yank.c (download)

Revision 1.13, Thu Mar 19 21:22:15 2015 UTC (9 years, 2 months ago) by bcallah
Branch: MAIN
CVS Tags: OPENBSD_5_8_BASE, OPENBSD_5_8
Changes since 1.12: +8 -6 lines

Clean up the includes in mg.
This does the following:
Moves all POSIX headers from sysdef.h into the individual .c files so that
each file now only includes what it needs. All headers are properly sorted.
Moves the remainder of sysdef.h to other files (mostly def.h) and deletes
sysdef.h now that it's no longer contains anything.
Tweak a comment that references sysdef.h so that it no longer does that.
ok florian@

/*	$OpenBSD: yank.c,v 1.13 2015/03/19 21:22:15 bcallah Exp $	*/

/* This file is in the public domain. */

/*
 *	kill ring functions
 */

#include <sys/queue.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "def.h"

#define KBLOCK	 8192		/* Kill grow.                    */

static char	*kbufp = NULL;	/* Kill buffer data.		 */
static RSIZE	 kused = 0;	/* # of bytes used in KB.	 */
static RSIZE	 ksize = 0;	/* # of bytes allocated in KB.	 */
static RSIZE	 kstart = 0;	/* # of first used byte in KB.	 */

static int	 kgrow(int);

/*
 * Delete all of the text saved in the kill buffer.  Called by commands when
 * a new kill context is created. The kill buffer array is released, just in
 * case the buffer has grown to an immense size.  No errors.
 */
void
kdelete(void)
{
	if (kbufp != NULL) {
		free(kbufp);
		kbufp = NULL;
		kstart = kused = ksize = 0;
	}
}

/*
 * Insert a character to the kill buffer, enlarging the buffer if there
 * isn't any room. Always grow the buffer in chunks, on the assumption
 * that if you put something in the kill buffer you are going to put more
 * stuff there too later. Return TRUE if all is well, and FALSE on errors.
 * Print a message on errors.  Dir says whether to put it at back or front.
 * This call is ignored if  KNONE is set.
 */
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");	/* Oh shit! */
	return (TRUE);
}

/*
 * kgrow - just get more kill buffer for the callee. If dir = KBACK
 * we are trying to get space at the beginning of the kill buffer.
 */
static int
kgrow(int dir)
{
	int	 nstart;
	char	*nbufp;

	if ((unsigned)(ksize + KBLOCK) <= (unsigned)ksize) {
		/* probably 16 bit unsigned */
		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));
	if (kbufp != NULL)
		free(kbufp);
	kbufp = nbufp;
	ksize += KBLOCK;
	kused = kused - kstart + nstart;
	kstart = nstart;
	return (TRUE);
}

/*
 * This function gets characters from the kill buffer. If the character
 * index "n" is off the end, it returns "-1". This lets the caller just
 * scan along until it gets a "-1" back.
 */
int
kremove(int n)
{
	if (n < 0 || n + kstart >= kused)
		return (-1);
	return (CHARMASK(kbufp[n + kstart]));
}

/*
 * Copy a string into the kill buffer. kflag gives direction.
 * if KNONE, do nothing.
 */
int
kchunk(char *cp1, RSIZE chunk, int kflag)
{
	/*
	 * HACK - doesn't matter, and fixes back-over-nl bug for empty
	 *	kill buffers.
	 */
	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);
}

/*
 * Kill line.  If called without an argument, it kills from dot to the end
 * of the line, unless it is at the end of the line, when it kills the
 * newline.  If called with an argument of 0, it kills from the start of the
 * line to dot.  If called with a positive argument, it kills from dot
 * forward over that number of newlines.  If called with a negative argument
 * it kills any text before dot on the current line, then it kills back
 * abs(arg) lines.
 */
/* ARGSUSED */
int
killline(int f, int n)
{
	struct line	*nextp;
	RSIZE	 chunk;
	int	 i, c;

	/* clear kill buffer if last wasn't a kill */
	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++;		/* newline */
		if (nextp == curbp->b_headp)
			goto done;		/* EOL */
		i = n;
		while (--i) {
			chunk += llength(nextp);
			nextp = lforw(nextp);
			if (nextp != curbp->b_headp)
				chunk++;	/* newline */
			if (nextp == curbp->b_headp)
				break;		/* EOL */
		}
	} else {
		/* n <= 0 */
		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);
		}
	}
	/*
	 * KFORW here is a bug.  Should be KBACK/KFORW, but we need to
	 * rewrite the ldelete code (later)?
	 */
done:
	if (chunk)
		return (ldelete(chunk, KFORW));
	return (TRUE);
}

/*
 * Yank text back from the kill buffer.  This is really easy.  All of the work
 * is done by the standard insert routines.  All you do is run the loop, and
 * check for errors.  The blank lines are inserted with a call to "newline"
 * instead of a call to "lnewline" so that the magic stuff that happens when
 * you type a carriage return also happens when a carriage return is yanked
 * back from the kill buffer.  An attempt has been made to fix the cosmetic
 * bug associated with a yank when dot is on the top line of the window
 * (nothing moves, because all of the new text landed off screen).
 */
/* ARGSUSED */
int
yank(int f, int n)
{
	struct line	*lp;
	int	 c, i, nline;

	if (n < 0)
		return (FALSE);

	/* newline counting */
	nline = 0;

	undo_boundary_enable(FFRAND, 0);
	while (n--) {
		/* mark around last yank */
		isetmark();
		i = 0;
		while ((c = kremove(i)) >= 0) {
			if (c == '\n') {
				if (enewline(FFRAND, 1) == FALSE)
					return (FALSE);
				++nline;
			} else {
				if (linsert(1, c) == FALSE)
					return (FALSE);
			}
			++i;
		}
	}
	/* cosmetic adjustment */
	lp = curwp->w_linep;

	/* if offscreen insert */
	if (curwp->w_dotp == lp) {
		while (nline-- && lback(lp) != curbp->b_headp)
			lp = lback(lp);
		/* adjust framing */
		curwp->w_linep = lp;
		curwp->w_rflag |= WFFULL;
	}
	undo_boundary_enable(FFRAND, 1);
	return (TRUE);
}