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