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