GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/less/less/../jump.c Lines: 23 92 25.0 %
Date: 2017-11-13 Branches: 7 62 11.3 %

Line Branch Exec Source
1
/*
2
 * Copyright (C) 1984-2012  Mark Nudelman
3
 * Modified for use with illumos by Garrett D'Amore.
4
 * Copyright 2014 Garrett D'Amore <garrett@damore.org>
5
 *
6
 * You may distribute under the terms of either the GNU General Public
7
 * License or the Less License, as specified in the README file.
8
 *
9
 * For more information, see the README file.
10
 */
11
12
/*
13
 * Routines which jump to a new location in the file.
14
 */
15
16
#include "less.h"
17
#include "position.h"
18
19
extern int jump_sline;
20
extern int squished;
21
extern int screen_trashed;
22
extern int sc_width, sc_height;
23
extern int show_attn;
24
extern int top_scroll;
25
26
/*
27
 * Jump to the end of the file.
28
 */
29
void
30
jump_forw(void)
31
{
32
	off_t pos;
33
	off_t end_pos;
34
35
	if (ch_end_seek()) {
36
		error("Cannot seek to end of file", NULL);
37
		return;
38
	}
39
	/*
40
	 * Note; lastmark will be called later by jump_loc, but it fails
41
	 * because the position table has been cleared by pos_clear below.
42
	 * So call it here before calling pos_clear.
43
	 */
44
	lastmark();
45
	/*
46
	 * Position the last line in the file at the last screen line.
47
	 * Go back one line from the end of the file
48
	 * to get to the beginning of the last line.
49
	 */
50
	pos_clear();
51
	end_pos = ch_tell();
52
	pos = back_line(end_pos);
53
	if (pos == -1) {
54
		jump_loc(0, sc_height-1);
55
	} else {
56
		jump_loc(pos, sc_height-1);
57
		if (position(sc_height-1) != end_pos)
58
			repaint();
59
	}
60
}
61
62
/*
63
 * Jump to line n in the file.
64
 */
65
void
66
jump_back(off_t linenum)
67
{
68
	off_t pos;
69
	PARG parg;
70
71
	/*
72
	 * Find the position of the specified line.
73
	 * If we can seek there, just jump to it.
74
	 * If we can't seek, but we're trying to go to line number 1,
75
	 * use ch_beg_seek() to get as close as we can.
76
	 */
77
	pos = find_pos(linenum);
78
	if (pos != -1 && ch_seek(pos) == 0) {
79
		if (show_attn)
80
			set_attnpos(pos);
81
		jump_loc(pos, jump_sline);
82
	} else if (linenum <= 1 && ch_beg_seek() == 0) {
83
		jump_loc(ch_tell(), jump_sline);
84
		error("Cannot seek to beginning of file", NULL);
85
	} else {
86
		parg.p_linenum = linenum;
87
		error("Cannot seek to line number %n", &parg);
88
	}
89
}
90
91
/*
92
 * Repaint the screen.
93
 */
94
void
95
repaint(void)
96
{
97
14
	struct scrpos scrpos;
98
	/*
99
	 * Start at the line currently at the top of the screen
100
	 * and redisplay the screen.
101
	 */
102
7
	get_scrpos(&scrpos);
103
7
	pos_clear();
104
7
	jump_loc(scrpos.pos, scrpos.ln);
105
7
}
106
107
/*
108
 * Jump to a specified percentage into the file.
109
 */
110
void
111
jump_percent(int percent, long fraction)
112
{
113
	off_t pos, len;
114
115
	/*
116
	 * Determine the position in the file
117
	 * (the specified percentage of the file's length).
118
	 */
119
	if ((len = ch_length()) == -1) {
120
		ierror("Determining length of file", NULL);
121
		ch_end_seek();
122
	}
123
	if ((len = ch_length()) == -1) {
124
		error("Don't know length of file", NULL);
125
		return;
126
	}
127
	pos = percent_pos(len, percent, fraction);
128
	if (pos >= len)
129
		pos = len-1;
130
131
	jump_line_loc(pos, jump_sline);
132
}
133
134
/*
135
 * Jump to a specified position in the file.
136
 * Like jump_loc, but the position need not be
137
 * the first character in a line.
138
 */
139
void
140
jump_line_loc(off_t pos, int sline)
141
{
142
	int c;
143
144
	if (ch_seek(pos) == 0) {
145
		/*
146
		 * Back up to the beginning of the line.
147
		 */
148
		while ((c = ch_back_get()) != '\n' && c != EOI)
149
			;
150
		if (c == '\n')
151
			(void) ch_forw_get();
152
		pos = ch_tell();
153
	}
154
	if (show_attn)
155
		set_attnpos(pos);
156
	jump_loc(pos, sline);
157
}
158
159
/*
160
 * Jump to a specified position in the file.
161
 * The position must be the first character in a line.
162
 * Place the target line on a specified line on the screen.
163
 */
164
void
165
jump_loc(off_t pos, int sline)
166
{
167
	int nline;
168
	off_t tpos;
169
	off_t bpos;
170
171
	/*
172
	 * Normalize sline.
173
	 */
174
32
	sline = adjsline(sline);
175
176
16
	if ((nline = onscreen(pos)) >= 0) {
177
		/*
178
		 * The line is currently displayed.
179
		 * Just scroll there.
180
		 */
181
1
		nline -= sline;
182
1
		if (nline > 0)
183
1
			forw(nline, position(BOTTOM_PLUS_ONE), 1, 0, 0);
184
		else
185
			back(-nline, position(TOP), 1, 0);
186
1
		if (show_attn)
187
			repaint_hilite(1);
188
1
		return;
189
	}
190
191
	/*
192
	 * Line is not on screen.
193
	 * Seek to the desired location.
194
	 */
195
15
	if (ch_seek(pos)) {
196
		error("Cannot seek to that file position", NULL);
197
		return;
198
	}
199
200
	/*
201
	 * See if the desired line is before or after
202
	 * the currently displayed screen.
203
	 */
204
15
	tpos = position(TOP);
205
15
	bpos = position(BOTTOM_PLUS_ONE);
206

15
	if (tpos == -1 || pos >= tpos) {
207
		/*
208
		 * The desired line is after the current screen.
209
		 * Move back in the file far enough so that we can
210
		 * call forw() and put the desired line at the
211
		 * sline-th line on the screen.
212
		 */
213
30
		for (nline = 0; nline < sline; nline++) {
214
			if (bpos != -1 && pos <= bpos) {
215
				/*
216
				 * Surprise!  The desired line is
217
				 * close enough to the current screen
218
				 * that we can just scroll there after all.
219
				 */
220
				forw(sc_height-sline+nline-1, bpos, 1, 0, 0);
221
				if (show_attn)
222
					repaint_hilite(1);
223
				return;
224
			}
225
			pos = back_line(pos);
226
			if (pos == -1) {
227
				/*
228
				 * Oops.  Ran into the beginning of the file.
229
				 * Exit the loop here and rely on forw()
230
				 * below to draw the required number of
231
				 * blank lines at the top of the screen.
232
				 */
233
				break;
234
			}
235
		}
236
15
		lastmark();
237
15
		squished = 0;
238
15
		screen_trashed = 0;
239
15
		forw(sc_height-1, pos, 1, 0, sline-nline);
240
15
	} else {
241
		/*
242
		 * The desired line is before the current screen.
243
		 * Move forward in the file far enough so that we
244
		 * can call back() and put the desired line at the
245
		 * sline-th line on the screen.
246
		 */
247
		for (nline = sline; nline < sc_height - 1; nline++) {
248
			pos = forw_line(pos);
249
			if (pos == -1) {
250
				/*
251
				 * Ran into end of file.
252
				 * This shouldn't normally happen,
253
				 * but may if there is some kind of read error.
254
				 */
255
				break;
256
			}
257
			if (pos >= tpos) {
258
				/*
259
				 * Surprise!  The desired line is
260
				 * close enough to the current screen
261
				 * that we can just scroll there after all.
262
				 */
263
				back(nline + 1, tpos, 1, 0);
264
				if (show_attn)
265
					repaint_hilite(1);
266
				return;
267
			}
268
		}
269
		lastmark();
270
		if (!top_scroll)
271
			do_clear();
272
		else
273
			home();
274
		screen_trashed = 0;
275
		add_back_pos(pos);
276
		back(sc_height-1, pos, 1, 0);
277
	}
278
31
}