Merge from vendor branch DHCP:
[dragonfly.git] / contrib / nvi / vi / v_ch.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_ch.c        10.8 (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 #include <stdlib.h>
24
25 #include "../common/common.h"
26 #include "vi.h"
27
28 static void notfound __P((SCR *, ARG_CHAR_T));
29 static void noprev __P((SCR *));
30
31 /*
32  * v_chrepeat -- [count];
33  *      Repeat the last F, f, T or t search.
34  *
35  * PUBLIC: int v_chrepeat __P((SCR *, VICMD *));
36  */
37 int
38 v_chrepeat(sp, vp)
39         SCR *sp;
40         VICMD *vp;
41 {
42         vp->character = VIP(sp)->lastckey;
43
44         switch (VIP(sp)->csearchdir) {
45         case CNOTSET:
46                 noprev(sp);
47                 return (1);
48         case FSEARCH:
49                 return (v_chF(sp, vp));
50         case fSEARCH:
51                 return (v_chf(sp, vp));
52         case TSEARCH:
53                 return (v_chT(sp, vp));
54         case tSEARCH:
55                 return (v_cht(sp, vp));
56         default:
57                 abort();
58         }
59         /* NOTREACHED */
60 }
61
62 /*
63  * v_chrrepeat -- [count],
64  *      Repeat the last F, f, T or t search in the reverse direction.
65  *
66  * PUBLIC: int v_chrrepeat __P((SCR *, VICMD *));
67  */
68 int
69 v_chrrepeat(sp, vp)
70         SCR *sp;
71         VICMD *vp;
72 {
73         cdir_t savedir;
74         int rval;
75
76         vp->character = VIP(sp)->lastckey;
77         savedir = VIP(sp)->csearchdir;
78
79         switch (VIP(sp)->csearchdir) {
80         case CNOTSET:
81                 noprev(sp);
82                 return (1);
83         case FSEARCH:
84                 rval = v_chf(sp, vp);
85                 break;
86         case fSEARCH:
87                 rval = v_chF(sp, vp);
88                 break;
89         case TSEARCH:
90                 rval = v_cht(sp, vp);
91                 break;
92         case tSEARCH:
93                 rval = v_chT(sp, vp);
94                 break;
95         default:
96                 abort();
97         }
98         VIP(sp)->csearchdir = savedir;
99         return (rval);
100 }
101
102 /*
103  * v_cht -- [count]tc
104  *      Search forward in the line for the character before the next
105  *      occurrence of the specified character.
106  *
107  * PUBLIC: int v_cht __P((SCR *, VICMD *));
108  */
109 int
110 v_cht(sp, vp)
111         SCR *sp;
112         VICMD *vp;
113 {
114         if (v_chf(sp, vp))
115                 return (1);
116
117         /*
118          * v_chf places the cursor on the character, where the 't'
119          * command wants it to its left.  We know this is safe since
120          * we had to move right for v_chf() to have succeeded.
121          */
122         --vp->m_stop.cno;
123
124         /*
125          * Make any necessary correction to the motion decision made
126          * by the v_chf routine.
127          */
128         if (!ISMOTION(vp))
129                 vp->m_final = vp->m_stop;
130
131         VIP(sp)->csearchdir = tSEARCH;
132         return (0);
133 }
134
135 /*
136  * v_chf -- [count]fc
137  *      Search forward in the line for the next occurrence of the
138  *      specified character.
139  *
140  * PUBLIC: int v_chf __P((SCR *, VICMD *));
141  */
142 int
143 v_chf(sp, vp)
144         SCR *sp;
145         VICMD *vp;
146 {
147         size_t len;
148         u_long cnt;
149         int isempty, key;
150         char *endp, *p, *startp;
151
152         /*
153          * !!!
154          * If it's a dot command, it doesn't reset the key for which we're
155          * searching, e.g. in "df1|f2|.|;", the ';' searches for a '2'.
156          */
157         key = vp->character;
158         if (!F_ISSET(vp, VC_ISDOT))
159                 VIP(sp)->lastckey = key;
160         VIP(sp)->csearchdir = fSEARCH;
161
162         if (db_eget(sp, vp->m_start.lno, &p, &len, &isempty)) {
163                 if (isempty)
164                         goto empty;
165                 return (1);
166         }
167
168         if (len == 0) {
169 empty:          notfound(sp, key);
170                 return (1);
171         }
172
173         endp = (startp = p) + len;
174         p += vp->m_start.cno;
175         for (cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; cnt--;) {
176                 while (++p < endp && *p != key);
177                 if (p == endp) {
178                         notfound(sp, key);
179                         return (1);
180                 }
181         }
182
183         vp->m_stop.cno = p - startp;
184
185         /*
186          * Non-motion commands move to the end of the range.
187          * Delete and yank stay at the start, ignore others.
188          */
189         vp->m_final = ISMOTION(vp) ? vp->m_start : vp->m_stop;
190         return (0);
191 }
192
193 /*
194  * v_chT -- [count]Tc
195  *      Search backward in the line for the character after the next
196  *      occurrence of the specified character.
197  *
198  * PUBLIC: int v_chT __P((SCR *, VICMD *));
199  */
200 int
201 v_chT(sp, vp)
202         SCR *sp;
203         VICMD *vp;
204 {
205         if (v_chF(sp, vp))
206                 return (1);
207
208         /*
209          * v_chF places the cursor on the character, where the 'T'
210          * command wants it to its right.  We know this is safe since
211          * we had to move left for v_chF() to have succeeded.
212          */
213         ++vp->m_stop.cno;
214         vp->m_final = vp->m_stop;
215
216         VIP(sp)->csearchdir = TSEARCH;
217         return (0);
218 }
219
220 /*
221  * v_chF -- [count]Fc
222  *      Search backward in the line for the next occurrence of the
223  *      specified character.
224  *
225  * PUBLIC: int v_chF __P((SCR *, VICMD *));
226  */
227 int
228 v_chF(sp, vp)
229         SCR *sp;
230         VICMD *vp;
231 {
232         size_t len;
233         u_long cnt;
234         int isempty, key;
235         char *endp, *p;
236
237         /*
238          * !!!
239          * If it's a dot command, it doesn't reset the key for which
240          * we're searching, e.g. in "df1|f2|.|;", the ';' searches
241          * for a '2'.
242          */
243         key = vp->character;
244         if (!F_ISSET(vp, VC_ISDOT))
245                 VIP(sp)->lastckey = key;
246         VIP(sp)->csearchdir = FSEARCH;
247
248         if (db_eget(sp, vp->m_start.lno, &p, &len, &isempty)) {
249                 if (isempty)
250                         goto empty;
251                 return (1);
252         }
253
254         if (len == 0) {
255 empty:          notfound(sp, key);
256                 return (1);
257         }
258
259         endp = p - 1;
260         p += vp->m_start.cno;
261         for (cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; cnt--;) {
262                 while (--p > endp && *p != key);
263                 if (p == endp) {
264                         notfound(sp, key);
265                         return (1);
266                 }
267         }
268
269         vp->m_stop.cno = (p - endp) - 1;
270
271         /*
272          * All commands move to the end of the range.  Motion commands
273          * adjust the starting point to the character before the current
274          * one.
275          */
276         vp->m_final = vp->m_stop;
277         if (ISMOTION(vp))
278                 --vp->m_start.cno;
279         return (0);
280 }
281
282 static void
283 noprev(sp)
284         SCR *sp;
285 {
286         msgq(sp, M_BERR, "178|No previous F, f, T or t search");
287 }
288
289 static void
290 notfound(sp, ch)
291         SCR *sp;
292         ARG_CHAR_T ch;
293 {
294         msgq(sp, M_BERR, "179|%s not found", KEY_NAME(sp, ch));
295 }