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: ex_move.c,v 10.16 2012/02/11 15:52:33 zy Exp $";
1419304Speter#endif /* not lint */
1519304Speter
1619304Speter#include <sys/types.h>
1719304Speter#include <sys/queue.h>
18254225Speter#include <sys/time.h>
1919304Speter
2019304Speter#include <bitstring.h>
2119304Speter#include <limits.h>
2219304Speter#include <stdio.h>
2319304Speter#include <stdlib.h>
2419304Speter#include <string.h>
2519304Speter
2619304Speter#include "../common/common.h"
2719304Speter
2819304Speter/*
2919304Speter * ex_copy -- :[line [,line]] co[py] line [flags]
3019304Speter *	Copy selected lines.
3119304Speter *
32281373Sbapt * PUBLIC: int ex_copy(SCR *, EXCMD *);
3319304Speter */
3419304Speterint
35254225Speterex_copy(SCR *sp, EXCMD *cmdp)
3619304Speter{
37254225Speter	CB cb = {{ 0 }};
3819304Speter	MARK fm1, fm2, m, tm;
3919304Speter	recno_t cnt;
4019304Speter	int rval;
4119304Speter
4219304Speter	rval = 0;
4319304Speter
4419304Speter	NEEDFILE(sp, cmdp);
4519304Speter
4619304Speter	/*
4719304Speter	 * It's possible to copy things into the area that's being
4819304Speter	 * copied, e.g. "2,5copy3" is legitimate.  Save the text to
4919304Speter	 * a cut buffer.
5019304Speter	 */
5119304Speter	fm1 = cmdp->addr1;
5219304Speter	fm2 = cmdp->addr2;
53254225Speter	TAILQ_INIT(cb.textq);
5419304Speter	for (cnt = fm1.lno; cnt <= fm2.lno; ++cnt)
55254225Speter		if (cut_line(sp, cnt, 0, ENTIRE_LINE, &cb)) {
5619304Speter			rval = 1;
5719304Speter			goto err;
5819304Speter		}
5919304Speter	cb.flags |= CB_LMODE;
6019304Speter
6119304Speter	/* Put the text into place. */
6219304Speter	tm.lno = cmdp->lineno;
6319304Speter	tm.cno = 0;
6419304Speter	if (put(sp, &cb, NULL, &tm, &m, 1))
6519304Speter		rval = 1;
6619304Speter	else {
6719304Speter		/*
6819304Speter		 * Copy puts the cursor on the last line copied.  The cursor
6919304Speter		 * returned by the put routine is the first line put, not the
7019304Speter		 * last, because that's the historic semantic of vi.
7119304Speter		 */
7219304Speter		cnt = (fm2.lno - fm1.lno) + 1;
7319304Speter		sp->lno = m.lno + (cnt - 1);
7419304Speter		sp->cno = 0;
7519304Speter	}
76254225Spetererr:	text_lfree(cb.textq);
7719304Speter	return (rval);
7819304Speter}
7919304Speter
8019304Speter/*
8119304Speter * ex_move -- :[line [,line]] mo[ve] line
8219304Speter *	Move selected lines.
8319304Speter *
84281373Sbapt * PUBLIC: int ex_move(SCR *, EXCMD *);
8519304Speter */
8619304Speterint
87254225Speterex_move(SCR *sp, EXCMD *cmdp)
8819304Speter{
8919304Speter	LMARK *lmp;
9019304Speter	MARK fm1, fm2;
9119304Speter	recno_t cnt, diff, fl, tl, mfl, mtl;
9219304Speter	size_t blen, len;
9319304Speter	int mark_reset;
94254225Speter	CHAR_T *bp;
95254225Speter	CHAR_T *p;
9619304Speter
9719304Speter	NEEDFILE(sp, cmdp);
9819304Speter
9919304Speter	/*
10019304Speter	 * It's not possible to move things into the area that's being
10119304Speter	 * moved.
10219304Speter	 */
10319304Speter	fm1 = cmdp->addr1;
10419304Speter	fm2 = cmdp->addr2;
10519304Speter	if (cmdp->lineno >= fm1.lno && cmdp->lineno <= fm2.lno) {
10619304Speter		msgq(sp, M_ERR, "139|Destination line is inside move range");
10719304Speter		return (1);
10819304Speter	}
10919304Speter
11019304Speter	/*
11119304Speter	 * Log the positions of any marks in the to-be-deleted lines.  This
11219304Speter	 * has to work with the logging code.  What happens is that we log
11319304Speter	 * the old mark positions, make the changes, then log the new mark
11419304Speter	 * positions.  Then the marks end up in the right positions no matter
11519304Speter	 * which way the log is traversed.
11619304Speter	 *
11719304Speter	 * XXX
11819304Speter	 * Reset the MARK_USERSET flag so that the log can undo the mark.
11919304Speter	 * This isn't very clean, and should probably be fixed.
12019304Speter	 */
12119304Speter	fl = fm1.lno;
12219304Speter	tl = cmdp->lineno;
12319304Speter
12419304Speter	/* Log the old positions of the marks. */
12519304Speter	mark_reset = 0;
126254225Speter	SLIST_FOREACH(lmp, sp->ep->marks, q)
12719304Speter		if (lmp->name != ABSMARK1 &&
12819304Speter		    lmp->lno >= fl && lmp->lno <= tl) {
12919304Speter			mark_reset = 1;
13019304Speter			F_CLR(lmp, MARK_USERSET);
13119304Speter			(void)log_mark(sp, lmp);
13219304Speter		}
13319304Speter
13419304Speter	/* Get memory for the copy. */
135254225Speter	GET_SPACE_RETW(sp, bp, blen, 256);
13619304Speter
13719304Speter	/* Move the lines. */
13819304Speter	diff = (fm2.lno - fm1.lno) + 1;
13919304Speter	if (tl > fl) {				/* Destination > source. */
14019304Speter		mfl = tl - diff;
14119304Speter		mtl = tl;
14219304Speter		for (cnt = diff; cnt--;) {
14319304Speter			if (db_get(sp, fl, DBG_FATAL, &p, &len))
14419304Speter				return (1);
145254225Speter			BINC_RETW(sp, bp, blen, len);
146254225Speter			MEMCPY(bp, p, len);
14719304Speter			if (db_append(sp, 1, tl, bp, len))
14819304Speter				return (1);
14919304Speter			if (mark_reset)
150254225Speter				SLIST_FOREACH(lmp, sp->ep->marks, q)
15119304Speter					if (lmp->name != ABSMARK1 &&
15219304Speter					    lmp->lno == fl)
15319304Speter						lmp->lno = tl + 1;
15419304Speter			if (db_delete(sp, fl))
15519304Speter				return (1);
15619304Speter		}
15719304Speter	} else {				/* Destination < source. */
15819304Speter		mfl = tl;
15919304Speter		mtl = tl + diff;
16019304Speter		for (cnt = diff; cnt--;) {
16119304Speter			if (db_get(sp, fl, DBG_FATAL, &p, &len))
16219304Speter				return (1);
163254225Speter			BINC_RETW(sp, bp, blen, len);
164254225Speter			MEMCPY(bp, p, len);
16519304Speter			if (db_append(sp, 1, tl++, bp, len))
16619304Speter				return (1);
16719304Speter			if (mark_reset)
168254225Speter				SLIST_FOREACH(lmp, sp->ep->marks, q)
16919304Speter					if (lmp->name != ABSMARK1 &&
17019304Speter					    lmp->lno == fl)
17119304Speter						lmp->lno = tl;
17219304Speter			++fl;
17319304Speter			if (db_delete(sp, fl))
17419304Speter				return (1);
17519304Speter		}
17619304Speter	}
177254225Speter	FREE_SPACEW(sp, bp, blen);
17819304Speter
17919304Speter	sp->lno = tl;				/* Last line moved. */
18019304Speter	sp->cno = 0;
18119304Speter
18219304Speter	/* Log the new positions of the marks. */
18319304Speter	if (mark_reset)
184254225Speter		SLIST_FOREACH(lmp, sp->ep->marks, q)
18519304Speter			if (lmp->name != ABSMARK1 &&
18619304Speter			    lmp->lno >= mfl && lmp->lno <= mtl)
18719304Speter				(void)log_mark(sp, lmp);
18819304Speter
18919304Speter
19019304Speter	sp->rptlines[L_MOVED] += diff;
19119304Speter	return (0);
19219304Speter}
193