kernel - Implement segment pmap optimizations for x86-64 (4)
[dragonfly.git] / contrib / nvi / vi / v_mark.c
blob447430efabe8879c750c2586a0f2b70d00ea2092
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.
7 * See the LICENSE file for redistribution information.
8 */
10 #include "config.h"
12 #ifndef lint
13 static const char sccsid[] = "@(#)v_mark.c 10.8 (Berkeley) 9/20/96";
14 #endif /* not lint */
16 #include <sys/types.h>
17 #include <sys/queue.h>
18 #include <sys/time.h>
20 #include <bitstring.h>
21 #include <limits.h>
22 #include <stdlib.h>
23 #include <stdio.h>
25 #include "../common/common.h"
26 #include "vi.h"
29 * v_mark -- m[a-z]
30 * Set a mark.
32 * PUBLIC: int v_mark __P((SCR *, VICMD *));
34 int
35 v_mark(sp, vp)
36 SCR *sp;
37 VICMD *vp;
39 return (mark_set(sp, vp->character, &vp->m_start, 1));
42 enum which {BQMARK, FQMARK};
43 static int mark __P((SCR *, VICMD *, enum which));
47 * v_bmark -- `['`a-z]
48 * Move to a mark.
50 * Moves to a mark, setting both row and column.
52 * !!!
53 * Although not commonly known, the "'`" and "'`" forms are historically
54 * valid. The behavior is determined by the first character, so "`'" is
55 * the same as "``". Remember this fact -- you'll be amazed at how many
56 * people don't know it and will be delighted that you are able to tell
57 * them.
59 * PUBLIC: int v_bmark __P((SCR *, VICMD *));
61 int
62 v_bmark(sp, vp)
63 SCR *sp;
64 VICMD *vp;
66 return (mark(sp, vp, BQMARK));
70 * v_fmark -- '['`a-z]
71 * Move to a mark.
73 * Move to the first nonblank character of the line containing the mark.
75 * PUBLIC: int v_fmark __P((SCR *, VICMD *));
77 int
78 v_fmark(sp, vp)
79 SCR *sp;
80 VICMD *vp;
82 return (mark(sp, vp, FQMARK));
86 * mark --
87 * Mark commands.
89 static int
90 mark(sp, vp, cmd)
91 SCR *sp;
92 VICMD *vp;
93 enum which cmd;
95 dir_t dir;
96 MARK m;
97 size_t len;
99 if (mark_get(sp, vp->character, &vp->m_stop, M_BERR))
100 return (1);
103 * !!!
104 * Historically, BQMARKS for character positions that no longer
105 * existed acted as FQMARKS.
107 * FQMARKS move to the first non-blank.
109 switch (cmd) {
110 case BQMARK:
111 if (db_get(sp, vp->m_stop.lno, DBG_FATAL, NULL, &len))
112 return (1);
113 if (vp->m_stop.cno < len ||
114 vp->m_stop.cno == len && len == 0)
115 break;
117 if (ISMOTION(vp))
118 F_SET(vp, VM_LMODE);
119 cmd = FQMARK;
120 /* FALLTHROUGH */
121 case FQMARK:
122 vp->m_stop.cno = 0;
123 if (nonblank(sp, vp->m_stop.lno, &vp->m_stop.cno))
124 return (1);
125 break;
126 default:
127 abort();
130 /* Non-motion commands move to the end of the range. */
131 if (!ISMOTION(vp)) {
132 vp->m_final = vp->m_stop;
133 return (0);
137 * !!!
138 * If a motion component to a BQMARK, the cursor has to move.
140 if (cmd == BQMARK &&
141 vp->m_stop.lno == vp->m_start.lno &&
142 vp->m_stop.cno == vp->m_start.cno) {
143 v_nomove(sp);
144 return (1);
148 * If the motion is in the reverse direction, switch the start and
149 * stop MARK's so that it's in a forward direction. (There's no
150 * reason for this other than to make the tests below easier. The
151 * code in vi.c:vi() would have done the switch.) Both forward
152 * and backward motions can happen for any kind of search command.
154 if (vp->m_start.lno > vp->m_stop.lno ||
155 vp->m_start.lno == vp->m_stop.lno &&
156 vp->m_start.cno > vp->m_stop.cno) {
157 m = vp->m_start;
158 vp->m_start = vp->m_stop;
159 vp->m_stop = m;
160 dir = BACKWARD;
161 } else
162 dir = FORWARD;
165 * Yank cursor motion, when associated with marks as motion commands,
166 * historically behaved as follows:
168 * ` motion ' motion
169 * Line change? Line change?
170 * Y N Y N
171 * -------------- ---------------
172 * FORWARD: | NM NM | NM NM
173 * | |
174 * BACKWARD: | M M | M NM(1)
176 * where NM means the cursor didn't move, and M means the cursor
177 * moved to the mark.
179 * As the cursor was usually moved for yank commands associated
180 * with backward motions, this implementation regularizes it by
181 * changing the NM at position (1) to be an M. This makes mark
182 * motions match search motions, which is probably A Good Thing.
184 * Delete cursor motion was always to the start of the text region,
185 * regardless. Ignore other motion commands.
187 #ifdef HISTORICAL_PRACTICE
188 if (ISCMD(vp->rkp, 'y')) {
189 if ((cmd == BQMARK ||
190 cmd == FQMARK && vp->m_start.lno != vp->m_stop.lno) &&
191 (vp->m_start.lno > vp->m_stop.lno ||
192 vp->m_start.lno == vp->m_stop.lno &&
193 vp->m_start.cno > vp->m_stop.cno))
194 vp->m_final = vp->m_stop;
195 } else if (ISCMD(vp->rkp, 'd'))
196 if (vp->m_start.lno > vp->m_stop.lno ||
197 vp->m_start.lno == vp->m_stop.lno &&
198 vp->m_start.cno > vp->m_stop.cno)
199 vp->m_final = vp->m_stop;
200 #else
201 vp->m_final = vp->m_start;
202 #endif
205 * Forward marks are always line oriented, and it's set in the
206 * vcmd.c table.
208 if (cmd == FQMARK)
209 return (0);
212 * BQMARK'S moving backward and starting at column 0, and ones moving
213 * forward and ending at column 0 are corrected to the last column of
214 * the previous line. Otherwise, adjust the starting/ending point to
215 * the character before the current one (this is safe because we know
216 * the search had to move to succeed).
218 * Mark motions become line mode opertions if they start at the first
219 * nonblank and end at column 0 of another line.
221 if (vp->m_start.lno < vp->m_stop.lno && vp->m_stop.cno == 0) {
222 if (db_get(sp, --vp->m_stop.lno, DBG_FATAL, NULL, &len))
223 return (1);
224 vp->m_stop.cno = len ? len - 1 : 0;
225 len = 0;
226 if (nonblank(sp, vp->m_start.lno, &len))
227 return (1);
228 if (vp->m_start.cno <= len)
229 F_SET(vp, VM_LMODE);
230 } else
231 --vp->m_stop.cno;
233 return (0);