119304Speter/*-
219304Speter * Copyright (c) 1992, 1993, 1994
319304Speter *	The Regents of the University of California.  All rights reserved.
419304Speter * Copyright (c) 1992, 1993, 1994, 1995, 1996
519304Speter *	Keith Bostic.  All rights reserved.
619304Speter *
719304Speter * See the LICENSE file for redistribution information.
819304Speter */
919304Speter
1019304Speter#include "config.h"
1119304Speter
1219304Speter#ifndef lint
1319304Speterstatic const char sccsid[] = "@(#)cut.c	10.10 (Berkeley) 9/15/96";
1419304Speter#endif /* not lint */
1519304Speter
1619304Speter#include <sys/types.h>
1719304Speter#include <sys/queue.h>
1819304Speter
1919304Speter#include <bitstring.h>
2019304Speter#include <ctype.h>
2119304Speter#include <errno.h>
2219304Speter#include <fcntl.h>
2319304Speter#include <limits.h>
2419304Speter#include <stdio.h>
2519304Speter#include <stdlib.h>
2619304Speter#include <string.h>
2719304Speter
2819304Speter#include "common.h"
2919304Speter
3019304Speterstatic void	cb_rotate __P((SCR *));
3119304Speter
3219304Speter/*
3319304Speter * cut --
3419304Speter *	Put a range of lines/columns into a TEXT buffer.
3519304Speter *
3619304Speter * There are two buffer areas, both found in the global structure.  The first
3719304Speter * is the linked list of all the buffers the user has named, the second is the
3819304Speter * unnamed buffer storage.  There is a pointer, too, which is the current
3919304Speter * default buffer, i.e. it may point to the unnamed buffer or a named buffer
4019304Speter * depending on into what buffer the last text was cut.  Logically, in both
4119304Speter * delete and yank operations, if the user names a buffer, the text is cut
4219304Speter * into it.  If it's a delete of information on more than a single line, the
4319304Speter * contents of the numbered buffers are rotated up one, the contents of the
4419304Speter * buffer named '9' are discarded, and the text is cut into the buffer named
4519304Speter * '1'.  The text is always cut into the unnamed buffer.
4619304Speter *
4719304Speter * In all cases, upper-case buffer names are the same as lower-case names,
4819304Speter * with the exception that they cause the buffer to be appended to instead
4919304Speter * of replaced.  Note, however, that if text is appended to a buffer, the
5019304Speter * default buffer only contains the appended text, not the entire contents
5119304Speter * of the buffer.
5219304Speter *
5319304Speter * !!!
5419304Speter * The contents of the default buffer would disappear after most operations
5519304Speter * in historic vi.  It's unclear that this is useful, so we don't bother.
5619304Speter *
5719304Speter * When users explicitly cut text into the numeric buffers, historic vi became
5819304Speter * genuinely strange.  I've never been able to figure out what was supposed to
5919304Speter * happen.  It behaved differently if you deleted text than if you yanked text,
6019304Speter * and, in the latter case, the text was appended to the buffer instead of
6119304Speter * replacing the contents.  Hopefully it's not worth getting right, and here
6219304Speter * we just treat the numeric buffers like any other named buffer.
6319304Speter *
6419304Speter * PUBLIC: int cut __P((SCR *, CHAR_T *, MARK *, MARK *, int));
6519304Speter */
6619304Speterint
6719304Spetercut(sp, namep, fm, tm, flags)
6819304Speter	SCR *sp;
6919304Speter	CHAR_T *namep;
7019304Speter	MARK *fm, *tm;
7119304Speter	int flags;
7219304Speter{
7319304Speter	CB *cbp;
7419304Speter	CHAR_T name;
7519304Speter	recno_t lno;
7619304Speter	int append, copy_one, copy_def;
7719304Speter
7819304Speter	/*
7919304Speter	 * If the user specified a buffer, put it there.  (This may require
8019304Speter	 * a copy into the numeric buffers.  We do the copy so that we don't
8119304Speter	 * have to reference count and so we don't have to deal with things
8219304Speter	 * like appends to buffers that are used multiple times.)
8319304Speter	 *
8419304Speter	 * Otherwise, if it's supposed to be put in a numeric buffer (usually
8519304Speter	 * a delete) put it there.  The rules for putting things in numeric
8619304Speter	 * buffers were historically a little strange.  There were three cases.
8719304Speter	 *
8819304Speter	 *	1: Some motions are always line mode motions, which means
8919304Speter	 *	   that the cut always goes into the numeric buffers.
9019304Speter	 *	2: Some motions aren't line mode motions, e.g. d10w, but
9119304Speter	 *	   can cross line boundaries.  For these commands, if the
9219304Speter	 *	   cut crosses a line boundary, it goes into the numeric
9319304Speter	 *	   buffers.  This includes most of the commands.
9419304Speter	 *	3: Some motions aren't line mode motions, e.g. d`<char>,
9519304Speter	 *	   but always go into the numeric buffers, regardless.  This
9619304Speter	 *	   was the commands: % ` / ? ( ) N n { } -- and nvi adds ^A.
9719304Speter	 *
9819304Speter	 * Otherwise, put it in the unnamed buffer.
9919304Speter	 */
10019304Speter	append = copy_one = copy_def = 0;
10119304Speter	if (namep != NULL) {
10219304Speter		name = *namep;
10319304Speter		if (LF_ISSET(CUT_NUMREQ) || LF_ISSET(CUT_NUMOPT) &&
10419304Speter		    (LF_ISSET(CUT_LINEMODE) || fm->lno != tm->lno)) {
10519304Speter			copy_one = 1;
10619304Speter			cb_rotate(sp);
10719304Speter		}
10819304Speter		if ((append = isupper(name)) == 1) {
10919304Speter			if (!copy_one)
11019304Speter				copy_def = 1;
11119304Speter			name = tolower(name);
11219304Speter		}
11319304Speternamecb:		CBNAME(sp, cbp, name);
11419304Speter	} else if (LF_ISSET(CUT_NUMREQ) || LF_ISSET(CUT_NUMOPT) &&
11519304Speter	    (LF_ISSET(CUT_LINEMODE) || fm->lno != tm->lno)) {
11619304Speter		name = '1';
11719304Speter		cb_rotate(sp);
11819304Speter		goto namecb;
11919304Speter	} else
12019304Speter		cbp = &sp->gp->dcb_store;
12119304Speter
12219304Spetercopyloop:
12319304Speter	/*
12419304Speter	 * If this is a new buffer, create it and add it into the list.
12519304Speter	 * Otherwise, if it's not an append, free its current contents.
12619304Speter	 */
12719304Speter	if (cbp == NULL) {
12819304Speter		CALLOC_RET(sp, cbp, CB *, 1, sizeof(CB));
12919304Speter		cbp->name = name;
13019304Speter		CIRCLEQ_INIT(&cbp->textq);
13119304Speter		LIST_INSERT_HEAD(&sp->gp->cutq, cbp, q);
13219304Speter	} else if (!append) {
13319304Speter		text_lfree(&cbp->textq);
13419304Speter		cbp->len = 0;
13519304Speter		cbp->flags = 0;
13619304Speter	}
13719304Speter
13819304Speter
13919304Speter#define	ENTIRE_LINE	0
14019304Speter	/* In line mode, it's pretty easy, just cut the lines. */
14119304Speter	if (LF_ISSET(CUT_LINEMODE)) {
14219304Speter		cbp->flags |= CB_LMODE;
14319304Speter		for (lno = fm->lno; lno <= tm->lno; ++lno)
14419304Speter			if (cut_line(sp, lno, 0, 0, cbp))
14519304Speter				goto cut_line_err;
14619304Speter	} else {
14719304Speter		/*
14819304Speter		 * Get the first line.  A length of 0 causes cut_line
14919304Speter		 * to cut from the MARK to the end of the line.
15019304Speter		 */
15119304Speter		if (cut_line(sp, fm->lno, fm->cno, fm->lno != tm->lno ?
15219304Speter		    ENTIRE_LINE : (tm->cno - fm->cno) + 1, cbp))
15319304Speter			goto cut_line_err;
15419304Speter
15519304Speter		/* Get the intermediate lines. */
15619304Speter		for (lno = fm->lno; ++lno < tm->lno;)
15719304Speter			if (cut_line(sp, lno, 0, ENTIRE_LINE, cbp))
15819304Speter				goto cut_line_err;
15919304Speter
16019304Speter		/* Get the last line. */
16119304Speter		if (tm->lno != fm->lno &&
16219304Speter		    cut_line(sp, lno, 0, tm->cno + 1, cbp))
16319304Speter			goto cut_line_err;
16419304Speter	}
16519304Speter
16619304Speter	append = 0;		/* Only append to the named buffer. */
16719304Speter	sp->gp->dcbp = cbp;	/* Repoint the default buffer on each pass. */
16819304Speter
16919304Speter	if (copy_one) {		/* Copy into numeric buffer 1. */
17019304Speter		name = '1';
17119304Speter		CBNAME(sp, cbp, name);
17219304Speter		copy_one = 0;
17319304Speter		goto copyloop;
17419304Speter	}
17519304Speter	if (copy_def) {		/* Copy into the default buffer. */
17619304Speter		cbp = &sp->gp->dcb_store;
17719304Speter		copy_def = 0;
17819304Speter		goto copyloop;
17919304Speter	}
18019304Speter	return (0);
18119304Speter
18219304Spetercut_line_err:
18319304Speter	text_lfree(&cbp->textq);
18419304Speter	cbp->len = 0;
18519304Speter	cbp->flags = 0;
18619304Speter	return (1);
18719304Speter}
18819304Speter
18919304Speter/*
19019304Speter * cb_rotate --
19119304Speter *	Rotate the numbered buffers up one.
19219304Speter */
19319304Speterstatic void
19419304Spetercb_rotate(sp)
19519304Speter	SCR *sp;
19619304Speter{
19719304Speter	CB *cbp, *del_cbp;
19819304Speter
19919304Speter	del_cbp = NULL;
20019304Speter	for (cbp = sp->gp->cutq.lh_first; cbp != NULL; cbp = cbp->q.le_next)
20119304Speter		switch(cbp->name) {
20219304Speter		case '1':
20319304Speter			cbp->name = '2';
20419304Speter			break;
20519304Speter		case '2':
20619304Speter			cbp->name = '3';
20719304Speter			break;
20819304Speter		case '3':
20919304Speter			cbp->name = '4';
21019304Speter			break;
21119304Speter		case '4':
21219304Speter			cbp->name = '5';
21319304Speter			break;
21419304Speter		case '5':
21519304Speter			cbp->name = '6';
21619304Speter			break;
21719304Speter		case '6':
21819304Speter			cbp->name = '7';
21919304Speter			break;
22019304Speter		case '7':
22119304Speter			cbp->name = '8';
22219304Speter			break;
22319304Speter		case '8':
22419304Speter			cbp->name = '9';
22519304Speter			break;
22619304Speter		case '9':
22719304Speter			del_cbp = cbp;
22819304Speter			break;
22919304Speter		}
23019304Speter	if (del_cbp != NULL) {
23119304Speter		LIST_REMOVE(del_cbp, q);
23219304Speter		text_lfree(&del_cbp->textq);
23319304Speter		free(del_cbp);
23419304Speter	}
23519304Speter}
23619304Speter
23719304Speter/*
23819304Speter * cut_line --
23919304Speter *	Cut a portion of a single line.
24019304Speter *
24119304Speter * PUBLIC: int cut_line __P((SCR *, recno_t, size_t, size_t, CB *));
24219304Speter */
24319304Speterint
24419304Spetercut_line(sp, lno, fcno, clen, cbp)
24519304Speter	SCR *sp;
24619304Speter	recno_t lno;
24719304Speter	size_t fcno, clen;
24819304Speter	CB *cbp;
24919304Speter{
25019304Speter	TEXT *tp;
25119304Speter	size_t len;
25219304Speter	char *p;
25319304Speter
25419304Speter	/* Get the line. */
25519304Speter	if (db_get(sp, lno, DBG_FATAL, &p, &len))
25619304Speter		return (1);
25719304Speter
25819304Speter	/* Create a TEXT structure that can hold the entire line. */
25919304Speter	if ((tp = text_init(sp, NULL, 0, len)) == NULL)
26019304Speter		return (1);
26119304Speter
26219304Speter	/*
26319304Speter	 * If the line isn't empty and it's not the entire line,
26419304Speter	 * copy the portion we want, and reset the TEXT length.
26519304Speter	 */
26619304Speter	if (len != 0) {
26719304Speter		if (clen == 0)
26819304Speter			clen = len - fcno;
26919304Speter		memcpy(tp->lb, p + fcno, clen);
27019304Speter		tp->len = clen;
27119304Speter	}
27219304Speter
27319304Speter	/* Append to the end of the cut buffer. */
27419304Speter	CIRCLEQ_INSERT_TAIL(&cbp->textq, tp, q);
27519304Speter	cbp->len += tp->len;
27619304Speter
27719304Speter	return (0);
27819304Speter}
27919304Speter
28019304Speter/*
28119304Speter * cut_close --
28219304Speter *	Discard all cut buffers.
28319304Speter *
28419304Speter * PUBLIC: void cut_close __P((GS *));
28519304Speter */
28619304Spetervoid
28719304Spetercut_close(gp)
28819304Speter	GS *gp;
28919304Speter{
29019304Speter	CB *cbp;
29119304Speter
29219304Speter	/* Free cut buffer list. */
29319304Speter	while ((cbp = gp->cutq.lh_first) != NULL) {
29419304Speter		if (cbp->textq.cqh_first != (void *)&cbp->textq)
29519304Speter			text_lfree(&cbp->textq);
29619304Speter		LIST_REMOVE(cbp, q);
29719304Speter		free(cbp);
29819304Speter	}
29919304Speter
30019304Speter	/* Free default cut storage. */
30119304Speter	cbp = &gp->dcb_store;
30219304Speter	if (cbp->textq.cqh_first != (void *)&cbp->textq)
30319304Speter		text_lfree(&cbp->textq);
30419304Speter}
30519304Speter
30619304Speter/*
30719304Speter * text_init --
30819304Speter *	Allocate a new TEXT structure.
30919304Speter *
31019304Speter * PUBLIC: TEXT *text_init __P((SCR *, const char *, size_t, size_t));
31119304Speter */
31219304SpeterTEXT *
31319304Spetertext_init(sp, p, len, total_len)
31419304Speter	SCR *sp;
31519304Speter	const char *p;
31619304Speter	size_t len, total_len;
31719304Speter{
31819304Speter	TEXT *tp;
31919304Speter
32019304Speter	CALLOC(sp, tp, TEXT *, 1, sizeof(TEXT));
32119304Speter	if (tp == NULL)
32219304Speter		return (NULL);
32319304Speter	/* ANSI C doesn't define a call to malloc(3) for 0 bytes. */
32419304Speter	if ((tp->lb_len = total_len) != 0) {
32519304Speter		MALLOC(sp, tp->lb, CHAR_T *, tp->lb_len);
32619304Speter		if (tp->lb == NULL) {
32719304Speter			free(tp);
32819304Speter			return (NULL);
32919304Speter		}
33019304Speter		if (p != NULL && len != 0)
33119304Speter			memcpy(tp->lb, p, len);
33219304Speter	}
33319304Speter	tp->len = len;
33419304Speter	return (tp);
33519304Speter}
33619304Speter
33719304Speter/*
33819304Speter * text_lfree --
33919304Speter *	Free a chain of text structures.
34019304Speter *
34119304Speter * PUBLIC: void text_lfree __P((TEXTH *));
34219304Speter */
34319304Spetervoid
34419304Spetertext_lfree(headp)
34519304Speter	TEXTH *headp;
34619304Speter{
34719304Speter	TEXT *tp;
34819304Speter
34919304Speter	while ((tp = headp->cqh_first) != (void *)headp) {
35019304Speter		CIRCLEQ_REMOVE(headp, tp, q);
35119304Speter		text_free(tp);
35219304Speter	}
35319304Speter}
35419304Speter
35519304Speter/*
35619304Speter * text_free --
35719304Speter *	Free a text structure.
35819304Speter *
35919304Speter * PUBLIC: void text_free __P((TEXT *));
36019304Speter */
36119304Spetervoid
36219304Spetertext_free(tp)
36319304Speter	TEXT *tp;
36419304Speter{
36519304Speter	if (tp->lb != NULL)
36619304Speter		free(tp->lb);
36719304Speter	free(tp);
36819304Speter}
369