ex_move.c revision 19304
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[] = "@(#)ex_move.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 <limits.h>
2119304Speter#include <stdio.h>
2219304Speter#include <stdlib.h>
2319304Speter#include <string.h>
2419304Speter
2519304Speter#include "../common/common.h"
2619304Speter
2719304Speter/*
2819304Speter * ex_copy -- :[line [,line]] co[py] line [flags]
2919304Speter *	Copy selected lines.
3019304Speter *
3119304Speter * PUBLIC: int ex_copy __P((SCR *, EXCMD *));
3219304Speter */
3319304Speterint
3419304Speterex_copy(sp, cmdp)
3519304Speter	SCR *sp;
3619304Speter	EXCMD *cmdp;
3719304Speter{
3819304Speter	CB cb;
3919304Speter	MARK fm1, fm2, m, tm;
4019304Speter	recno_t cnt;
4119304Speter	int rval;
4219304Speter
4319304Speter	rval = 0;
4419304Speter
4519304Speter	NEEDFILE(sp, cmdp);
4619304Speter
4719304Speter	/*
4819304Speter	 * It's possible to copy things into the area that's being
4919304Speter	 * copied, e.g. "2,5copy3" is legitimate.  Save the text to
5019304Speter	 * a cut buffer.
5119304Speter	 */
5219304Speter	fm1 = cmdp->addr1;
5319304Speter	fm2 = cmdp->addr2;
5419304Speter	memset(&cb, 0, sizeof(cb));
5519304Speter	CIRCLEQ_INIT(&cb.textq);
5619304Speter	for (cnt = fm1.lno; cnt <= fm2.lno; ++cnt)
5719304Speter		if (cut_line(sp, cnt, 0, 0, &cb)) {
5819304Speter			rval = 1;
5919304Speter			goto err;
6019304Speter		}
6119304Speter	cb.flags |= CB_LMODE;
6219304Speter
6319304Speter	/* Put the text into place. */
6419304Speter	tm.lno = cmdp->lineno;
6519304Speter	tm.cno = 0;
6619304Speter	if (put(sp, &cb, NULL, &tm, &m, 1))
6719304Speter		rval = 1;
6819304Speter	else {
6919304Speter		/*
7019304Speter		 * Copy puts the cursor on the last line copied.  The cursor
7119304Speter		 * returned by the put routine is the first line put, not the
7219304Speter		 * last, because that's the historic semantic of vi.
7319304Speter		 */
7419304Speter		cnt = (fm2.lno - fm1.lno) + 1;
7519304Speter		sp->lno = m.lno + (cnt - 1);
7619304Speter		sp->cno = 0;
7719304Speter	}
7819304Spetererr:	text_lfree(&cb.textq);
7919304Speter	return (rval);
8019304Speter}
8119304Speter
8219304Speter/*
8319304Speter * ex_move -- :[line [,line]] mo[ve] line
8419304Speter *	Move selected lines.
8519304Speter *
8619304Speter * PUBLIC: int ex_move __P((SCR *, EXCMD *));
8719304Speter */
8819304Speterint
8919304Speterex_move(sp, cmdp)
9019304Speter	SCR *sp;
9119304Speter	EXCMD *cmdp;
9219304Speter{
9319304Speter	LMARK *lmp;
9419304Speter	MARK fm1, fm2;
9519304Speter	recno_t cnt, diff, fl, tl, mfl, mtl;
9619304Speter	size_t blen, len;
9719304Speter	int mark_reset;
9819304Speter	char *bp, *p;
9919304Speter
10019304Speter	NEEDFILE(sp, cmdp);
10119304Speter
10219304Speter	/*
10319304Speter	 * It's not possible to move things into the area that's being
10419304Speter	 * moved.
10519304Speter	 */
10619304Speter	fm1 = cmdp->addr1;
10719304Speter	fm2 = cmdp->addr2;
10819304Speter	if (cmdp->lineno >= fm1.lno && cmdp->lineno <= fm2.lno) {
10919304Speter		msgq(sp, M_ERR, "139|Destination line is inside move range");
11019304Speter		return (1);
11119304Speter	}
11219304Speter
11319304Speter	/*
11419304Speter	 * Log the positions of any marks in the to-be-deleted lines.  This
11519304Speter	 * has to work with the logging code.  What happens is that we log
11619304Speter	 * the old mark positions, make the changes, then log the new mark
11719304Speter	 * positions.  Then the marks end up in the right positions no matter
11819304Speter	 * which way the log is traversed.
11919304Speter	 *
12019304Speter	 * XXX
12119304Speter	 * Reset the MARK_USERSET flag so that the log can undo the mark.
12219304Speter	 * This isn't very clean, and should probably be fixed.
12319304Speter	 */
12419304Speter	fl = fm1.lno;
12519304Speter	tl = cmdp->lineno;
12619304Speter
12719304Speter	/* Log the old positions of the marks. */
12819304Speter	mark_reset = 0;
12919304Speter	for (lmp = sp->ep->marks.lh_first; lmp != NULL; lmp = lmp->q.le_next)
13019304Speter		if (lmp->name != ABSMARK1 &&
13119304Speter		    lmp->lno >= fl && lmp->lno <= tl) {
13219304Speter			mark_reset = 1;
13319304Speter			F_CLR(lmp, MARK_USERSET);
13419304Speter			(void)log_mark(sp, lmp);
13519304Speter		}
13619304Speter
13719304Speter	/* Get memory for the copy. */
13819304Speter	GET_SPACE_RET(sp, bp, blen, 256);
13919304Speter
14019304Speter	/* Move the lines. */
14119304Speter	diff = (fm2.lno - fm1.lno) + 1;
14219304Speter	if (tl > fl) {				/* Destination > source. */
14319304Speter		mfl = tl - diff;
14419304Speter		mtl = tl;
14519304Speter		for (cnt = diff; cnt--;) {
14619304Speter			if (db_get(sp, fl, DBG_FATAL, &p, &len))
14719304Speter				return (1);
14819304Speter			BINC_RET(sp, bp, blen, len);
14919304Speter			memcpy(bp, p, len);
15019304Speter			if (db_append(sp, 1, tl, bp, len))
15119304Speter				return (1);
15219304Speter			if (mark_reset)
15319304Speter				for (lmp = sp->ep->marks.lh_first;
15419304Speter				    lmp != NULL; lmp = lmp->q.le_next)
15519304Speter					if (lmp->name != ABSMARK1 &&
15619304Speter					    lmp->lno == fl)
15719304Speter						lmp->lno = tl + 1;
15819304Speter			if (db_delete(sp, fl))
15919304Speter				return (1);
16019304Speter		}
16119304Speter	} else {				/* Destination < source. */
16219304Speter		mfl = tl;
16319304Speter		mtl = tl + diff;
16419304Speter		for (cnt = diff; cnt--;) {
16519304Speter			if (db_get(sp, fl, DBG_FATAL, &p, &len))
16619304Speter				return (1);
16719304Speter			BINC_RET(sp, bp, blen, len);
16819304Speter			memcpy(bp, p, len);
16919304Speter			if (db_append(sp, 1, tl++, bp, len))
17019304Speter				return (1);
17119304Speter			if (mark_reset)
17219304Speter				for (lmp = sp->ep->marks.lh_first;
17319304Speter				    lmp != NULL; lmp = lmp->q.le_next)
17419304Speter					if (lmp->name != ABSMARK1 &&
17519304Speter					    lmp->lno == fl)
17619304Speter						lmp->lno = tl;
17719304Speter			++fl;
17819304Speter			if (db_delete(sp, fl))
17919304Speter				return (1);
18019304Speter		}
18119304Speter	}
18219304Speter	FREE_SPACE(sp, bp, blen);
18319304Speter
18419304Speter	sp->lno = tl;				/* Last line moved. */
18519304Speter	sp->cno = 0;
18619304Speter
18719304Speter	/* Log the new positions of the marks. */
18819304Speter	if (mark_reset)
18919304Speter		for (lmp = sp->ep->marks.lh_first;
19019304Speter		    lmp != NULL; lmp = lmp->q.le_next)
19119304Speter			if (lmp->name != ABSMARK1 &&
19219304Speter			    lmp->lno >= mfl && lmp->lno <= mtl)
19319304Speter				(void)log_mark(sp, lmp);
19419304Speter
19519304Speter
19619304Speter	sp->rptlines[L_MOVED] += diff;
19719304Speter	return (0);
19819304Speter}
199