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
13254225Speterstatic const char sccsid[] = "$Id: cut.c,v 10.12 2012/02/11 15:52:33 zy Exp $";
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
67254225Spetercut(
68254225Speter	SCR *sp,
69254225Speter	CHAR_T *namep,
70254225Speter	MARK *fm,
71254225Speter	MARK *tm,
72254225Speter	int flags)
7319304Speter{
7419304Speter	CB *cbp;
75254225Speter	CHAR_T name = '\0';
7619304Speter	recno_t lno;
7719304Speter	int append, copy_one, copy_def;
7819304Speter
7919304Speter	/*
8019304Speter	 * If the user specified a buffer, put it there.  (This may require
8119304Speter	 * a copy into the numeric buffers.  We do the copy so that we don't
8219304Speter	 * have to reference count and so we don't have to deal with things
8319304Speter	 * like appends to buffers that are used multiple times.)
8419304Speter	 *
8519304Speter	 * Otherwise, if it's supposed to be put in a numeric buffer (usually
8619304Speter	 * a delete) put it there.  The rules for putting things in numeric
8719304Speter	 * buffers were historically a little strange.  There were three cases.
8819304Speter	 *
8919304Speter	 *	1: Some motions are always line mode motions, which means
9019304Speter	 *	   that the cut always goes into the numeric buffers.
9119304Speter	 *	2: Some motions aren't line mode motions, e.g. d10w, but
9219304Speter	 *	   can cross line boundaries.  For these commands, if the
9319304Speter	 *	   cut crosses a line boundary, it goes into the numeric
9419304Speter	 *	   buffers.  This includes most of the commands.
9519304Speter	 *	3: Some motions aren't line mode motions, e.g. d`<char>,
9619304Speter	 *	   but always go into the numeric buffers, regardless.  This
9719304Speter	 *	   was the commands: % ` / ? ( ) N n { } -- and nvi adds ^A.
9819304Speter	 *
9919304Speter	 * Otherwise, put it in the unnamed buffer.
10019304Speter	 */
10119304Speter	append = copy_one = copy_def = 0;
10219304Speter	if (namep != NULL) {
10319304Speter		name = *namep;
104254225Speter		if (LF_ISSET(CUT_NUMREQ) || (LF_ISSET(CUT_NUMOPT) &&
105254225Speter		    (LF_ISSET(CUT_LINEMODE) || fm->lno != tm->lno))) {
10619304Speter			copy_one = 1;
10719304Speter			cb_rotate(sp);
10819304Speter		}
109254225Speter		if ((append = isupper(name))) {
11019304Speter			if (!copy_one)
11119304Speter				copy_def = 1;
11219304Speter			name = tolower(name);
11319304Speter		}
11419304Speternamecb:		CBNAME(sp, cbp, name);
115254225Speter	} else if (LF_ISSET(CUT_NUMREQ) || (LF_ISSET(CUT_NUMOPT) &&
116254225Speter	    (LF_ISSET(CUT_LINEMODE) || fm->lno != tm->lno))) {
11719304Speter		name = '1';
11819304Speter		cb_rotate(sp);
11919304Speter		goto namecb;
12019304Speter	} else
12119304Speter		cbp = &sp->gp->dcb_store;
12219304Speter
12319304Spetercopyloop:
12419304Speter	/*
12519304Speter	 * If this is a new buffer, create it and add it into the list.
12619304Speter	 * Otherwise, if it's not an append, free its current contents.
12719304Speter	 */
12819304Speter	if (cbp == NULL) {
12919304Speter		CALLOC_RET(sp, cbp, CB *, 1, sizeof(CB));
13019304Speter		cbp->name = name;
131254225Speter		TAILQ_INIT(cbp->textq);
132254225Speter		SLIST_INSERT_HEAD(sp->gp->cutq, cbp, q);
13319304Speter	} else if (!append) {
134254225Speter		text_lfree(cbp->textq);
13519304Speter		cbp->len = 0;
13619304Speter		cbp->flags = 0;
13719304Speter	}
13819304Speter
13919304Speter
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)
144254225Speter			if (cut_line(sp, lno, 0, ENTIRE_LINE, cbp))
14519304Speter				goto cut_line_err;
14619304Speter	} else {
14719304Speter		/*
148254225Speter		 * Get the first line.  A length of ENTIRE_LINE causes
149254225Speter		 * cut_line 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:
183254225Speter	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
194254225Spetercb_rotate(SCR *sp)
19519304Speter{
196254225Speter	CB *cbp, *del_cbp = NULL, *pre_cbp = NULL;
19719304Speter
198254225Speter	SLIST_FOREACH(cbp, sp->gp->cutq, q) {
19919304Speter		switch(cbp->name) {
200254225Speter		case '1': case '2': case '3':
201254225Speter		case '4': case '5': case '6':
202254225Speter		case '7': case '8':
203254225Speter			cbp->name += 1;
20419304Speter			break;
20519304Speter		case '9':
206254225Speter			if (cbp == SLIST_FIRST(sp->gp->cutq))
207254225Speter				SLIST_REMOVE_HEAD(sp->gp->cutq, q);
208254225Speter			else
209254225Speter				SLIST_REMOVE_AFTER(pre_cbp, q);
21019304Speter			del_cbp = cbp;
21119304Speter			break;
21219304Speter		}
213254225Speter		pre_cbp = cbp;
214254225Speter	}
21519304Speter	if (del_cbp != NULL) {
216254225Speter		text_lfree(del_cbp->textq);
21719304Speter		free(del_cbp);
21819304Speter	}
21919304Speter}
22019304Speter
22119304Speter/*
22219304Speter * cut_line --
22319304Speter *	Cut a portion of a single line.
22419304Speter *
22519304Speter * PUBLIC: int cut_line __P((SCR *, recno_t, size_t, size_t, CB *));
22619304Speter */
22719304Speterint
228254225Spetercut_line(
229254225Speter	SCR *sp,
230254225Speter	recno_t lno,
231254225Speter	size_t fcno,
232254225Speter	size_t clen,
233254225Speter	CB *cbp)
23419304Speter{
23519304Speter	TEXT *tp;
23619304Speter	size_t len;
237254225Speter	CHAR_T *p;
23819304Speter
23919304Speter	/* Get the line. */
24019304Speter	if (db_get(sp, lno, DBG_FATAL, &p, &len))
24119304Speter		return (1);
24219304Speter
24319304Speter	/* Create a TEXT structure that can hold the entire line. */
24419304Speter	if ((tp = text_init(sp, NULL, 0, len)) == NULL)
24519304Speter		return (1);
24619304Speter
24719304Speter	/*
24819304Speter	 * If the line isn't empty and it's not the entire line,
24919304Speter	 * copy the portion we want, and reset the TEXT length.
25019304Speter	 */
25119304Speter	if (len != 0) {
252254225Speter		if (clen == ENTIRE_LINE)
25319304Speter			clen = len - fcno;
254254225Speter		MEMCPY(tp->lb, p + fcno, clen);
25519304Speter		tp->len = clen;
25619304Speter	}
25719304Speter
25819304Speter	/* Append to the end of the cut buffer. */
259254225Speter	TAILQ_INSERT_TAIL(cbp->textq, tp, q);
26019304Speter	cbp->len += tp->len;
26119304Speter
26219304Speter	return (0);
26319304Speter}
26419304Speter
26519304Speter/*
26619304Speter * cut_close --
26719304Speter *	Discard all cut buffers.
26819304Speter *
26919304Speter * PUBLIC: void cut_close __P((GS *));
27019304Speter */
27119304Spetervoid
272254225Spetercut_close(GS *gp)
27319304Speter{
27419304Speter	CB *cbp;
27519304Speter
27619304Speter	/* Free cut buffer list. */
277254225Speter	while ((cbp = SLIST_FIRST(gp->cutq)) != NULL) {
278254225Speter		if (!TAILQ_EMPTY(cbp->textq))
279254225Speter			text_lfree(cbp->textq);
280254225Speter		SLIST_REMOVE_HEAD(gp->cutq, q);
28119304Speter		free(cbp);
28219304Speter	}
28319304Speter
28419304Speter	/* Free default cut storage. */
28519304Speter	cbp = &gp->dcb_store;
286254225Speter	if (!TAILQ_EMPTY(cbp->textq))
287254225Speter		text_lfree(cbp->textq);
28819304Speter}
28919304Speter
29019304Speter/*
29119304Speter * text_init --
29219304Speter *	Allocate a new TEXT structure.
29319304Speter *
294254225Speter * PUBLIC: TEXT *text_init __P((SCR *, const CHAR_T *, size_t, size_t));
29519304Speter */
29619304SpeterTEXT *
297254225Spetertext_init(
298254225Speter	SCR *sp,
299254225Speter	const CHAR_T *p,
300254225Speter	size_t len,
301254225Speter	size_t total_len)
30219304Speter{
30319304Speter	TEXT *tp;
30419304Speter
30519304Speter	CALLOC(sp, tp, TEXT *, 1, sizeof(TEXT));
30619304Speter	if (tp == NULL)
30719304Speter		return (NULL);
30819304Speter	/* ANSI C doesn't define a call to malloc(3) for 0 bytes. */
309254225Speter	if ((tp->lb_len = total_len * sizeof(CHAR_T)) != 0) {
31019304Speter		MALLOC(sp, tp->lb, CHAR_T *, tp->lb_len);
31119304Speter		if (tp->lb == NULL) {
31219304Speter			free(tp);
31319304Speter			return (NULL);
31419304Speter		}
31519304Speter		if (p != NULL && len != 0)
316254225Speter			MEMCPY(tp->lb, p, len);
31719304Speter	}
31819304Speter	tp->len = len;
31919304Speter	return (tp);
32019304Speter}
32119304Speter
32219304Speter/*
32319304Speter * text_lfree --
32419304Speter *	Free a chain of text structures.
32519304Speter *
32619304Speter * PUBLIC: void text_lfree __P((TEXTH *));
32719304Speter */
32819304Spetervoid
329254225Spetertext_lfree(TEXTH *headp)
33019304Speter{
33119304Speter	TEXT *tp;
33219304Speter
333254225Speter	while ((tp = TAILQ_FIRST(headp)) != NULL) {
334254225Speter		TAILQ_REMOVE(headp, tp, q);
33519304Speter		text_free(tp);
33619304Speter	}
33719304Speter}
33819304Speter
33919304Speter/*
34019304Speter * text_free --
34119304Speter *	Free a text structure.
34219304Speter *
34319304Speter * PUBLIC: void text_free __P((TEXT *));
34419304Speter */
34519304Spetervoid
346254225Spetertext_free(TEXT *tp)
34719304Speter{
34819304Speter	if (tp->lb != NULL)
34919304Speter		free(tp->lb);
35019304Speter	free(tp);
35119304Speter}
352