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