Merge branch 'vendor/EXPAT'
[dragonfly.git] / contrib / nvi / vi / v_left.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[] = "@(#)v_left.c      10.7 (Berkeley) 3/6/96";
14 #endif /* not lint */
15
16 #include <sys/types.h>
17 #include <sys/queue.h>
18 #include <sys/time.h>
19
20 #include <bitstring.h>
21 #include <limits.h>
22 #include <stdio.h>
23
24 #include "../common/common.h"
25 #include "vi.h"
26
27 /*
28  * v_left -- [count]^H, [count]h
29  *      Move left by columns.
30  *
31  * PUBLIC: int v_left __P((SCR *, VICMD *));
32  */
33 int
34 v_left(sp, vp)
35         SCR *sp;
36         VICMD *vp;
37 {
38         recno_t cnt;
39
40         /*
41          * !!!
42          * The ^H and h commands always failed in the first column.
43          */
44         if (vp->m_start.cno == 0) {
45                 v_sol(sp);
46                 return (1);
47         }
48
49         /* Find the end of the range. */
50         cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
51         if (vp->m_start.cno > cnt)
52                 vp->m_stop.cno = vp->m_start.cno - cnt;
53         else
54                 vp->m_stop.cno = 0;
55
56         /*
57          * All commands move to the end of the range.  Motion commands
58          * adjust the starting point to the character before the current
59          * one.
60          */
61         if (ISMOTION(vp))
62                 --vp->m_start.cno;
63         vp->m_final = vp->m_stop;
64         return (0);
65 }
66
67 /*
68  * v_cfirst -- [count]_
69  *      Move to the first non-blank character in a line.
70  *
71  * PUBLIC: int v_cfirst __P((SCR *, VICMD *));
72  */
73 int
74 v_cfirst(sp, vp)
75         SCR *sp;
76         VICMD *vp;
77 {
78         recno_t cnt, lno;
79
80         /*
81          * !!!
82          * If the _ is a motion component, it makes the command a line motion
83          * e.g. "d_" deletes the line.  It also means that the cursor doesn't
84          * move.
85          *
86          * The _ command never failed in the first column.
87          */
88         if (ISMOTION(vp))
89                 F_SET(vp, VM_LMODE);
90         /*
91          * !!!
92          * Historically a specified count makes _ move down count - 1
93          * rows, so, "3_" is the same as "2j_".
94          */
95         cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
96         if (cnt != 1) {
97                 --vp->count;
98                 return (v_down(sp, vp));
99         }
100
101         /*
102          * Move to the first non-blank.
103          *
104          * Can't just use RCM_SET_FNB, in case _ is used as the motion
105          * component of another command.
106          */
107         vp->m_stop.cno = 0;
108         if (nonblank(sp, vp->m_stop.lno, &vp->m_stop.cno))
109                 return (1);
110
111         /*
112          * !!!
113          * The _ command has to fail if the file is empty and we're doing
114          * a delete.  If deleting line 1, and 0 is the first nonblank,
115          * make the check.
116          */
117         if (vp->m_stop.lno == 1 &&
118             vp->m_stop.cno == 0 && ISCMD(vp->rkp, 'd')) {
119                 if (db_last(sp, &lno))
120                         return (1);
121                 if (lno == 0) {
122                         v_sol(sp);
123                         return (1);
124                 }
125         }
126
127         /*
128          * Delete and non-motion commands move to the end of the range,
129          * yank stays at the start.  Ignore others.
130          */
131         vp->m_final =
132             ISMOTION(vp) && ISCMD(vp->rkp, 'y') ? vp->m_start : vp->m_stop;
133         return (0);
134 }
135
136 /*
137  * v_first -- ^
138  *      Move to the first non-blank character in this line.
139  *
140  * PUBLIC: int v_first __P((SCR *, VICMD *));
141  */
142 int
143 v_first(sp, vp)
144         SCR *sp;
145         VICMD *vp;
146 {
147         /*
148          * !!!
149          * Yielding to none in our quest for compatibility with every
150          * historical blemish of vi, no matter how strange it might be,
151          * we permit the user to enter a count and then ignore it.
152          */
153
154         /*
155          * Move to the first non-blank.
156          *
157          * Can't just use RCM_SET_FNB, in case ^ is used as the motion
158          * component of another command.
159          */
160         vp->m_stop.cno = 0;
161         if (nonblank(sp, vp->m_stop.lno, &vp->m_stop.cno))
162                 return (1);
163
164         /*
165          * !!!
166          * The ^ command succeeded if used as a command when the cursor was
167          * on the first non-blank in the line, but failed if used as a motion
168          * component in the same situation.
169          */
170         if (ISMOTION(vp) && vp->m_start.cno == vp->m_stop.cno) {
171                 v_sol(sp);
172                 return (1);
173         }
174
175         /*
176          * If moving right, non-motion commands move to the end of the range.
177          * Delete and yank stay at the start.  Motion commands adjust the
178          * ending point to the character before the current ending charcter.
179          *
180          * If moving left, all commands move to the end of the range.  Motion
181          * commands adjust the starting point to the character before the
182          * current starting character.
183          */
184         if (vp->m_start.cno < vp->m_stop.cno)
185                 if (ISMOTION(vp)) {
186                         --vp->m_stop.cno;
187                         vp->m_final = vp->m_start;
188                 } else
189                         vp->m_final = vp->m_stop;
190         else {
191                 if (ISMOTION(vp))
192                         --vp->m_start.cno;
193                 vp->m_final = vp->m_stop;
194         }
195         return (0);
196 }
197
198 /*
199  * v_ncol -- [count]|
200  *      Move to column count or the first column on this line.  If the
201  *      requested column is past EOL, move to EOL.  The nasty part is
202  *      that we have to know character column widths to make this work.
203  *
204  * PUBLIC: int v_ncol __P((SCR *, VICMD *));
205  */
206 int
207 v_ncol(sp, vp)
208         SCR *sp;
209         VICMD *vp;
210 {
211         if (F_ISSET(vp, VC_C1SET) && vp->count > 1) {
212                 --vp->count;
213                 vp->m_stop.cno =
214                     vs_colpos(sp, vp->m_start.lno, (size_t)vp->count);
215                 /*
216                  * !!!
217                  * The | command succeeded if used as a command and the cursor
218                  * didn't move, but failed if used as a motion component in the
219                  * same situation.
220                  */
221                 if (ISMOTION(vp) && vp->m_stop.cno == vp->m_start.cno) {
222                         v_nomove(sp);
223                         return (1);
224                 }
225         } else {
226                 /*
227                  * !!!
228                  * The | command succeeded if used as a command in column 0
229                  * without a count, but failed if used as a motion component
230                  * in the same situation.
231                  */
232                 if (ISMOTION(vp) && vp->m_start.cno == 0) {
233                         v_sol(sp);
234                         return (1);
235                 }
236                 vp->m_stop.cno = 0;
237         }
238
239         /*
240          * If moving right, non-motion commands move to the end of the range.
241          * Delete and yank stay at the start.  Motion commands adjust the
242          * ending point to the character before the current ending charcter.
243          *
244          * If moving left, all commands move to the end of the range.  Motion
245          * commands adjust the starting point to the character before the
246          * current starting character.
247          */
248         if (vp->m_start.cno < vp->m_stop.cno)
249                 if (ISMOTION(vp)) {
250                         --vp->m_stop.cno;
251                         vp->m_final = vp->m_start;
252                 } else
253                         vp->m_final = vp->m_stop;
254         else {
255                 if (ISMOTION(vp))
256                         --vp->m_start.cno;
257                 vp->m_final = vp->m_stop;
258         }
259         return (0);
260 }
261
262 /*
263  * v_zero -- 0
264  *      Move to the first column on this line.
265  *
266  * PUBLIC: int v_zero __P((SCR *, VICMD *));
267  */
268 int
269 v_zero(sp, vp)
270         SCR *sp;
271         VICMD *vp;
272 {
273         /*
274          * !!!
275          * The 0 command succeeded if used as a command in the first column
276          * but failed if used as a motion component in the same situation.
277          */
278         if (ISMOTION(vp) && vp->m_start.cno == 0) {
279                 v_sol(sp);
280                 return (1);
281         }
282
283         /*
284          * All commands move to the end of the range.  Motion commands
285          * adjust the starting point to the character before the current
286          * one.
287          */
288         vp->m_stop.cno = 0;
289         if (ISMOTION(vp))
290                 --vp->m_start.cno;
291         vp->m_final = vp->m_stop;
292         return (0);
293 }