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