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