Document the recently added WITHOUT_SRCS variable.
[dragonfly.git] / contrib / nvi / ex / ex_move.c
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 }