GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/vi/build/../vi/v_ch.c Lines: 0 88 0.0 %
Date: 2017-11-07 Branches: 0 66 0.0 %

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