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

Line Branch Exec Source
1
/*	$OpenBSD: v_section.c,v 1.7 2014/11/12 04:28:41 bentley 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 <string.h>
22
23
#include "../common/common.h"
24
#include "vi.h"
25
26
/*
27
 * !!!
28
 * In historic vi, the section commands ignored empty lines, unlike the
29
 * paragraph commands, which was probably okay.  However, they also moved
30
 * to the start of the last line when there where no more sections instead
31
 * of the end of the last line like the paragraph commands.  I've changed
32
 * the latter behavior to match the paragraph commands.
33
 *
34
 * In historic vi, a section was defined as the first character(s) of the
35
 * line matching, which could be followed by anything.  This implementation
36
 * follows that historic practice.
37
 *
38
 * !!!
39
 * The historic vi documentation (USD:15-10) claimed:
40
 *	The section commands interpret a preceding count as a different
41
 *	window size in which to redraw the screen at the new location,
42
 *	and this window size is the base size for newly drawn windows
43
 *	until another size is specified.  This is very useful if you are
44
 *	on a slow terminal ...
45
 *
46
 * I can't get the 4BSD vi to do this, it just beeps at me.  For now, a
47
 * count to the section commands simply repeats the command.
48
 */
49
50
/*
51
 * v_sectionf -- [count]]]
52
 *	Move forward count sections/functions.
53
 *
54
 * !!!
55
 * Using ]] as a motion command was a bit special, historically.  It could
56
 * match } as well as the usual { and section values.  If it matched a { or
57
 * a section, it did NOT include the matched line.  If it matched a }, it
58
 * did include the line.  No clue why.
59
 *
60
 * PUBLIC: int v_sectionf(SCR *, VICMD *);
61
 */
62
int
63
v_sectionf(SCR *sp, VICMD *vp)
64
{
65
	recno_t cnt, lno;
66
	size_t len;
67
	char *p, *list, *lp;
68
69
	/* Get the macro list. */
70
	if ((list = O_STR(sp, O_SECTIONS)) == NULL)
71
		return (1);
72
73
	/*
74
	 * !!!
75
	 * If the starting cursor position is at or before any non-blank
76
	 * characters in the line, i.e. the movement is cutting all of the
77
	 * line's text, the buffer is in line mode.  It's a lot easier to
78
	 * check here, because we know that the end is going to be the start
79
	 * or end of a line.
80
	 */
81
	if (ISMOTION(vp)) {
82
		if (vp->m_start.cno == 0)
83
			F_SET(vp, VM_LMODE);
84
		else {
85
			vp->m_stop = vp->m_start;
86
			vp->m_stop.cno = 0;
87
			if (nonblank(sp, vp->m_stop.lno, &vp->m_stop.cno))
88
				return (1);
89
			if (vp->m_start.cno <= vp->m_stop.cno)
90
				F_SET(vp, VM_LMODE);
91
		}
92
	}
93
94
	cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
95
	for (lno = vp->m_start.lno; !db_get(sp, ++lno, 0, &p, &len);) {
96
		if (len == 0)
97
			continue;
98
		if (p[0] == '{' || (ISMOTION(vp) && p[0] == '}')) {
99
			if (!--cnt) {
100
				if (p[0] == '{')
101
					goto adjust1;
102
				goto adjust2;
103
			}
104
			continue;
105
		}
106
		/*
107
		 * !!!
108
		 * Historic documentation (USD:15-11, 4.2) said that formfeed
109
		 * characters (^L) in the first column delimited sections.
110
		 * The historic code mentions formfeed characters, but never
111
		 * implements them.  Seems reasonable, do it.
112
		 */
113
		if (p[0] == '\014') {
114
			if (!--cnt)
115
				goto adjust1;
116
			continue;
117
		}
118
		if (p[0] != '.' || len < 2)
119
			continue;
120
		for (lp = list; *lp != '\0'; lp += 2 * sizeof(*lp))
121
			if (lp[0] == p[1] &&
122
			    ((lp[1] == ' ' && len == 2) || lp[1] == p[2]) &&
123
			    !--cnt) {
124
				/*
125
				 * !!!
126
				 * If not cutting this line, adjust to the end
127
				 * of the previous one.  Otherwise, position to
128
				 * column 0.
129
				 */
130
adjust1:			if (ISMOTION(vp))
131
					goto ret1;
132
133
adjust2:			vp->m_stop.lno = lno;
134
				vp->m_stop.cno = 0;
135
				goto ret2;
136
			}
137
	}
138
139
	/* If moving forward, reached EOF, check to see if we started there. */
140
	if (vp->m_start.lno == lno - 1) {
141
		v_eof(sp, NULL);
142
		return (1);
143
	}
144
145
ret1:	if (db_get(sp, --lno, DBG_FATAL, NULL, &len))
146
		return (1);
147
	vp->m_stop.lno = lno;
148
	vp->m_stop.cno = len ? len - 1 : 0;
149
150
	/*
151
	 * Non-motion commands go to the end of the range.  Delete and
152
	 * yank stay at the start of the range.  Ignore others.
153
	 */
154
ret2:	if (ISMOTION(vp)) {
155
		vp->m_final = vp->m_start;
156
		if (F_ISSET(vp, VM_LMODE))
157
			vp->m_final.cno = 0;
158
	} else
159
		vp->m_final = vp->m_stop;
160
	return (0);
161
}
162
163
/*
164
 * v_sectionb -- [count][[
165
 *	Move backward count sections/functions.
166
 *
167
 * PUBLIC: int v_sectionb(SCR *, VICMD *);
168
 */
169
int
170
v_sectionb(SCR *sp, VICMD *vp)
171
{
172
	size_t len;
173
	recno_t cnt, lno;
174
	char *p, *list, *lp;
175
176
	/* An empty file or starting from line 1 is always illegal. */
177
	if (vp->m_start.lno <= 1) {
178
		v_sof(sp, NULL);
179
		return (1);
180
	}
181
182
	/* Get the macro list. */
183
	if ((list = O_STR(sp, O_SECTIONS)) == NULL)
184
		return (1);
185
186
	cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
187
	for (lno = vp->m_start.lno; !db_get(sp, --lno, 0, &p, &len);) {
188
		if (len == 0)
189
			continue;
190
		if (p[0] == '{') {
191
			if (!--cnt)
192
				goto adjust1;
193
			continue;
194
		}
195
		/*
196
		 * !!!
197
		 * Historic documentation (USD:15-11, 4.2) said that formfeed
198
		 * characters (^L) in the first column delimited sections.
199
		 * The historic code mentions formfeed characters, but never
200
		 * implements them.  Seems reasonable, do it.
201
		 */
202
		if (p[0] == '\014') {
203
			if (!--cnt)
204
				goto adjust1;
205
			continue;
206
		}
207
		if (p[0] != '.' || len < 2)
208
			continue;
209
		for (lp = list; *lp != '\0'; lp += 2 * sizeof(*lp))
210
			if (lp[0] == p[1] &&
211
			    ((lp[1] == ' ' && len == 2) || lp[1] == p[2]) &&
212
			    !--cnt) {
213
adjust1:			vp->m_stop.lno = lno;
214
				vp->m_stop.cno = 0;
215
				goto ret1;
216
			}
217
	}
218
219
	/*
220
	 * If moving backward, reached SOF, which is a movement sink.
221
	 * We already checked for starting there.
222
	 */
223
	vp->m_stop.lno = 1;
224
	vp->m_stop.cno = 0;
225
226
	/*
227
	 * All commands move to the end of the range.
228
	 *
229
	 * !!!
230
	 * Historic practice is the section cut was in line mode if it started
231
	 * from column 0 and was in the backward direction.  Otherwise, left
232
	 * motion commands adjust the starting point to the character before
233
	 * the current one.  What makes this worse is that if it cut to line
234
	 * mode it also went to the first non-<blank>.
235
	 */
236
ret1:	if (vp->m_start.cno == 0) {
237
		F_CLR(vp, VM_RCM_MASK);
238
		F_SET(vp, VM_RCM_SETFNB);
239
240
		--vp->m_start.lno;
241
		F_SET(vp, VM_LMODE);
242
	} else
243
		--vp->m_start.cno;
244
245
	vp->m_final = vp->m_stop;
246
	return (0);
247
}