GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/less/less/../forwback.c Lines: 77 116 66.4 %
Date: 2017-11-13 Branches: 48 110 43.6 %

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
 * Primitives for displaying the file on the screen,
14
 * scrolling either forward or backward.
15
 */
16
17
#include "less.h"
18
#include "position.h"
19
20
int screen_trashed;
21
int squished;
22
int no_back_scroll = 0;
23
int forw_prompt;
24
25
extern volatile sig_atomic_t sigs;
26
extern int top_scroll;
27
extern int quiet;
28
extern int sc_width, sc_height;
29
extern int plusoption;
30
extern int forw_scroll;
31
extern int back_scroll;
32
extern int ignore_eoi;
33
extern int clear_bg;
34
extern int final_attr;
35
extern int oldbot;
36
extern char *tagoption;
37
38
/*
39
 * Sound the bell to indicate user is trying to move past end of file.
40
 */
41
static void
42
eof_bell(void)
43
{
44
32
	if (quiet == NOT_QUIET)
45
16
		ring_bell();
46
	else
47
		vbell();
48
16
}
49
50
/*
51
 * Check to see if the end of file is currently displayed.
52
 */
53
int
54
eof_displayed(void)
55
{
56
	off_t pos;
57
58
82
	if (ignore_eoi)
59
		return (0);
60
61
41
	if (ch_length() == -1)
62
		/*
63
		 * If the file length is not known,
64
		 * we can't possibly be displaying EOF.
65
		 */
66
		return (0);
67
68
	/*
69
	 * If the bottom line is empty, we are at EOF.
70
	 * If the bottom line ends at the file length,
71
	 * we must be just at EOF.
72
	 */
73
41
	pos = position(BOTTOM_PLUS_ONE);
74
108
	return (pos == -1 || pos == ch_length());
75
41
}
76
77
/*
78
 * Check to see if the entire file is currently displayed.
79
 */
80
int
81
entire_file_displayed(void)
82
{
83
	off_t pos;
84
85
	/* Make sure last line of file is displayed. */
86
	if (!eof_displayed())
87
		return (0);
88
89
	/* Make sure first line of file is displayed. */
90
	pos = position(0);
91
	return (pos == -1 || pos == 0);
92
}
93
94
/*
95
 * If the screen is "squished", repaint it.
96
 * "Squished" means the first displayed line is not at the top
97
 * of the screen; this can happen when we display a short file
98
 * for the first time.
99
 */
100
void
101
squish_check(void)
102
{
103
76
	if (!squished)
104
		return;
105
	squished = 0;
106
	repaint();
107
38
}
108
109
/*
110
 * Display n lines, scrolling forward,
111
 * starting at position pos in the input file.
112
 * "force" means display the n lines even if we hit end of file.
113
 * "only_last" means display only the last screenful if n > screen size.
114
 * "nblank" is the number of blank lines to draw before the first
115
 *   real line.  If nblank > 0, the pos must be -1.
116
 *   The first real line after the blanks will start at ch_zero().
117
 */
118
void
119
forw(int n, off_t pos, int force, int only_last, int nblank)
120
{
121
	int nlines = 0;
122
	int do_repaint;
123
	static int first_time = 1;
124
125
50
	squish_check();
126
127
	/*
128
	 * do_repaint tells us not to display anything till the end,
129
	 * then just repaint the entire screen.
130
	 * We repaint if we are supposed to display only the last
131
	 * screenful and the request is for more than a screenful.
132
	 * Also if the request exceeds the forward scroll limit
133
	 * (but not if the request is for exactly a screenful, since
134
	 * repainting itself involves scrolling forward a screenful).
135
	 */
136

59
	do_repaint = (only_last && n > sc_height-1) ||
137

25
	    (forw_scroll >= 0 && n > forw_scroll && n != sc_height-1);
138
139
25
	if (!do_repaint) {
140

74
		if (top_scroll && n >= sc_height - 1 && pos != ch_length()) {
141
			/*
142
			 * Start a new screen.
143
			 * {{ This is not really desirable if we happen
144
			 *    to hit eof in the middle of this screen,
145
			 *    but we don't yet know if that will happen. }}
146
			 */
147
24
			pos_clear();
148
24
			add_forw_pos(pos);
149
			force = 1;
150
24
			do_clear();
151
24
			home();
152
24
		}
153
154

50
		if (pos != position(BOTTOM_PLUS_ONE) || empty_screen()) {
155
			/*
156
			 * This is not contiguous with what is
157
			 * currently displayed.  Clear the screen image
158
			 * (position table) and start a new screen.
159
			 */
160
9
			pos_clear();
161
9
			add_forw_pos(pos);
162
			force = 1;
163
9
			if (top_scroll) {
164
9
				do_clear();
165
9
				home();
166
9
			} else if (!first_time) {
167
				putstr("...skipping...\n");
168
			}
169
		}
170
	}
171
172
1594
	while (--n >= 0) {
173
		/*
174
		 * Read the next line of input.
175
		 */
176
772
		if (nblank > 0) {
177
			/*
178
			 * Still drawing blanks; don't get a line
179
			 * from the file yet.
180
			 * If this is the last blank line, get ready to
181
			 * read a line starting at ch_zero() next time.
182
			 */
183
			if (--nblank == 0)
184
				pos = ch_zero();
185
		} else {
186
			/*
187
			 * Get the next line from the file.
188
			 */
189
772
			pos = forw_line(pos);
190
772
			if (pos == -1) {
191
				/*
192
				 * End of file: stop here unless the top line
193
				 * is still empty, or "force" is true.
194
				 * Even if force is true, stop when the last
195
				 * line in the file reaches the top of screen.
196
				 */
197

28
				if (!force && position(TOP) != -1)
198
					break;
199

28
				if (!empty_lines(0, 0) &&
200
				    !empty_lines(1, 1) &&
201
				    empty_lines(2, sc_height-1))
202
					break;
203
			}
204
		}
205
		/*
206
		 * Add the position of the next line to the position table.
207
		 * Display the current line on the screen.
208
		 */
209
772
		add_forw_pos(pos);
210
772
		nlines++;
211
772
		if (do_repaint)
212
			continue;
213
		/*
214
		 * If this is the first screen displayed and
215
		 * we hit an early EOF (i.e. before the requested
216
		 * number of lines), we "squish" the display down
217
		 * at the bottom of the screen.
218
		 * But don't do this if a + option or a -t option
219
		 * was given.  These options can cause us to
220
		 * start the display after the beginning of the file,
221
		 * and it is not appropriate to squish in that case.
222
		 */
223
2316
		if (first_time && pos == -1 && !top_scroll &&
224
1544
		    tagoption == NULL && !plusoption) {
225
			squished = 1;
226
			continue;
227
		}
228
772
		put_line();
229
772
		forw_prompt = 1;
230
	}
231
232
25
	if (nlines == 0)
233
		eof_bell();
234
25
	else if (do_repaint)
235
		repaint();
236
25
	first_time = 0;
237
25
	(void) currline(BOTTOM);
238
25
}
239
240
/*
241
 * Display n lines, scrolling backward.
242
 */
243
void
244
back(int n, off_t pos, int force, int only_last)
245
{
246
	int nlines = 0;
247
	int do_repaint;
248
249
20
	squish_check();
250

20
	do_repaint = (n > get_back_scroll() || (only_last && n > sc_height-1));
251
468
	while (--n >= 0) {
252
		/*
253
		 * Get the previous line of input.
254
		 */
255
227
		pos = back_line(pos);
256
454
		if (pos == -1) {
257
			/*
258
			 * Beginning of file: stop here unless "force" is true.
259
			 */
260
227
			if (!force)
261
				break;
262
		}
263
		/*
264
		 * Add the position of the previous line to the position table.
265
		 * Display the line on the screen.
266
		 */
267
224
		add_back_pos(pos);
268
224
		nlines++;
269
224
		if (!do_repaint) {
270
			home();
271
			add_line();
272
			put_line();
273
		}
274
	}
275
276
10
	if (nlines == 0)
277
3
		eof_bell();
278
7
	else if (do_repaint)
279
7
		repaint();
280
	else if (!oldbot)
281
		lower_left();
282
10
	(void) currline(BOTTOM);
283
10
}
284
285
/*
286
 * Display n more lines, forward.
287
 * Start just after the line currently displayed at the bottom of the screen.
288
 */
289
void
290
forward(int n, int force, int only_last)
291
{
292
	off_t pos;
293
294

44
	if (get_quit_at_eof() && eof_displayed() &&
295
	    !(ch_getflags() & CH_HELPFILE)) {
296
		/*
297
		 * If the -e flag is set and we're trying to go
298
		 * forward from end-of-file, go on to the next file.
299
		 */
300
		if (edit_next(1))
301
			quit(QUIT_OK);
302
		return;
303
	}
304
305
22
	pos = position(BOTTOM_PLUS_ONE);
306

35
	if (pos == -1 && (!force || empty_lines(2, sc_height-1))) {
307
13
		if (ignore_eoi) {
308
			/*
309
			 * ignore_eoi is to support A_F_FOREVER.
310
			 * Back up until there is a line at the bottom
311
			 * of the screen.
312
			 */
313
			if (empty_screen()) {
314
				pos = ch_zero();
315
			} else {
316
				do {
317
					back(1, position(TOP), 1, 0);
318
					pos = position(BOTTOM_PLUS_ONE);
319
				} while (pos == -1);
320
			}
321
		} else {
322
13
			eof_bell();
323
13
			return;
324
		}
325
	}
326
9
	forw(n, pos, force, only_last, 0);
327
31
}
328
329
/*
330
 * Display n more lines, backward.
331
 * Start just before the line currently displayed at the top of the screen.
332
 */
333
void
334
backward(int n, int force, int only_last)
335
{
336
	off_t pos;
337
338
20
	pos = position(TOP);
339

10
	if (pos == -1 && (!force || position(BOTTOM) == 0)) {
340
		eof_bell();
341
		return;
342
	}
343
10
	back(n, pos, force, only_last);
344
20
}
345
346
/*
347
 * Get the backwards scroll limit.
348
 * Must call this function instead of just using the value of
349
 * back_scroll, because the default case depends on sc_height and
350
 * top_scroll, as well as back_scroll.
351
 */
352
int
353
get_back_scroll(void)
354
{
355
20
	if (no_back_scroll)
356
		return (0);
357
10
	if (back_scroll >= 0)
358
		return (back_scroll);
359
10
	if (top_scroll)
360
10
		return (sc_height - 2);
361
	return (10000); /* infinity */
362
10
}