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