1/* $NetBSD: ex_move.c,v 1.3 2013/11/25 22:43:46 christos Exp $ */ 2/*- 3 * Copyright (c) 1992, 1993, 1994 4 * The Regents of the University of California. All rights reserved. 5 * Copyright (c) 1992, 1993, 1994, 1995, 1996 6 * Keith Bostic. All rights reserved. 7 * 8 * See the LICENSE file for redistribution information. 9 */ 10 11#include "config.h" 12 13#include <sys/cdefs.h> 14#if 0 15#ifndef lint 16static const char sccsid[] = "Id: ex_move.c,v 10.15 2001/06/25 15:19:17 skimo Exp (Berkeley) Date: 2001/06/25 15:19:17 "; 17#endif /* not lint */ 18#else 19__RCSID("$NetBSD$"); 20#endif 21 22#include <sys/types.h> 23#include <sys/queue.h> 24 25#include <bitstring.h> 26#include <limits.h> 27#include <stdio.h> 28#include <stdlib.h> 29#include <string.h> 30 31#include "../common/common.h" 32 33/* 34 * ex_copy -- :[line [,line]] co[py] line [flags] 35 * Copy selected lines. 36 * 37 * PUBLIC: int ex_copy __P((SCR *, EXCMD *)); 38 */ 39int 40ex_copy(SCR *sp, EXCMD *cmdp) 41{ 42 CB cb; 43 MARK fm1, fm2, m, tm; 44 db_recno_t cnt; 45 int rval; 46 47 rval = 0; 48 49 NEEDFILE(sp, cmdp); 50 51 /* 52 * It's possible to copy things into the area that's being 53 * copied, e.g. "2,5copy3" is legitimate. Save the text to 54 * a cut buffer. 55 */ 56 fm1 = cmdp->addr1; 57 fm2 = cmdp->addr2; 58 memset(&cb, 0, sizeof(cb)); 59 TAILQ_INIT(&cb.textq); 60 for (cnt = fm1.lno; cnt <= fm2.lno; ++cnt) 61 if (cut_line(sp, cnt, 0, ENTIRE_LINE, &cb)) { 62 rval = 1; 63 goto err; 64 } 65 cb.flags |= CB_LMODE; 66 67 /* Put the text into place. */ 68 tm.lno = cmdp->lineno; 69 tm.cno = 0; 70 if (put(sp, &cb, NULL, &tm, &m, 1)) 71 rval = 1; 72 else { 73 /* 74 * Copy puts the cursor on the last line copied. The cursor 75 * returned by the put routine is the first line put, not the 76 * last, because that's the historic semantic of vi. 77 */ 78 cnt = (fm2.lno - fm1.lno) + 1; 79 sp->lno = m.lno + (cnt - 1); 80 sp->cno = 0; 81 } 82err: text_lfree(&cb.textq); 83 return (rval); 84} 85 86/* 87 * ex_move -- :[line [,line]] mo[ve] line 88 * Move selected lines. 89 * 90 * PUBLIC: int ex_move __P((SCR *, EXCMD *)); 91 */ 92int 93ex_move(SCR *sp, EXCMD *cmdp) 94{ 95 LMARK *lmp; 96 MARK fm1, fm2; 97 db_recno_t cnt, diff, fl, tl, mfl, mtl; 98 size_t blen, len; 99 int mark_reset; 100 CHAR_T *bp; 101 CHAR_T *p; 102 103 NEEDFILE(sp, cmdp); 104 105 /* 106 * It's not possible to move things into the area that's being 107 * moved. 108 */ 109 fm1 = cmdp->addr1; 110 fm2 = cmdp->addr2; 111 if (cmdp->lineno >= fm1.lno && cmdp->lineno <= fm2.lno) { 112 msgq(sp, M_ERR, "139|Destination line is inside move range"); 113 return (1); 114 } 115 116 /* 117 * Log the positions of any marks in the to-be-deleted lines. This 118 * has to work with the logging code. What happens is that we log 119 * the old mark positions, make the changes, then log the new mark 120 * positions. Then the marks end up in the right positions no matter 121 * which way the log is traversed. 122 * 123 * XXX 124 * Reset the MARK_USERSET flag so that the log can undo the mark. 125 * This isn't very clean, and should probably be fixed. 126 */ 127 fl = fm1.lno; 128 tl = cmdp->lineno; 129 130 /* Log the old positions of the marks. */ 131 mark_reset = 0; 132 LIST_FOREACH(lmp, &sp->ep->marks, q) 133 if (lmp->name != ABSMARK1 && 134 lmp->lno >= fl && lmp->lno <= tl) { 135 mark_reset = 1; 136 F_CLR(lmp, MARK_USERSET); 137 (void)log_mark(sp, lmp); 138 } 139 140 /* Get memory for the copy. */ 141 GET_SPACE_RETW(sp, bp, blen, 256); 142 143 /* Move the lines. */ 144 diff = (fm2.lno - fm1.lno) + 1; 145 if (tl > fl) { /* Destination > source. */ 146 mfl = tl - diff; 147 mtl = tl; 148 for (cnt = diff; cnt--;) { 149 if (db_get(sp, fl, DBG_FATAL, &p, &len)) 150 return (1); 151 BINC_RETW(sp, bp, blen, len); 152 MEMCPYW(bp, p, len); 153 if (db_append(sp, 1, tl, bp, len)) 154 return (1); 155 if (mark_reset) 156 LIST_FOREACH(lmp, &sp->ep->marks, q) 157 if (lmp->name != ABSMARK1 && 158 lmp->lno == fl) 159 lmp->lno = tl + 1; 160 if (db_delete(sp, fl)) 161 return (1); 162 } 163 } else { /* Destination < source. */ 164 mfl = tl; 165 mtl = tl + diff; 166 for (cnt = diff; cnt--;) { 167 if (db_get(sp, fl, DBG_FATAL, &p, &len)) 168 return (1); 169 BINC_RETW(sp, bp, blen, len); 170 MEMCPYW(bp, p, len); 171 if (db_append(sp, 1, tl++, bp, len)) 172 return (1); 173 if (mark_reset) 174 LIST_FOREACH(lmp, &sp->ep->marks, q) 175 if (lmp->name != ABSMARK1 && 176 lmp->lno == fl) 177 lmp->lno = tl; 178 ++fl; 179 if (db_delete(sp, fl)) 180 return (1); 181 } 182 } 183 FREE_SPACEW(sp, bp, blen); 184 185 sp->lno = tl; /* Last line moved. */ 186 sp->cno = 0; 187 188 /* Log the new positions of the marks. */ 189 if (mark_reset) 190 LIST_FOREACH(lmp, &sp->ep->marks, q) 191 if (lmp->name != ABSMARK1 && 192 lmp->lno >= mfl && lmp->lno <= mtl) 193 (void)log_mark(sp, lmp); 194 195 196 sp->rptlines[L_MOVED] += diff; 197 return (0); 198} 199