GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/less/less/../input.c Lines: 95 170 55.9 %
Date: 2017-11-13 Branches: 53 114 46.5 %

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
 * High level routines dealing with getting lines of input
14
 * from the file being viewed.
15
 *
16
 * When we speak of "lines" here, we mean PRINTABLE lines;
17
 * lines processed with respect to the screen width.
18
 * We use the term "raw line" to refer to lines simply
19
 * delimited by newlines; not processed with respect to screen width.
20
 */
21
22
#include "less.h"
23
24
extern int squeeze;
25
extern int chopline;
26
extern int hshift;
27
extern int quit_if_one_screen;
28
extern volatile sig_atomic_t sigs;
29
extern int ignore_eoi;
30
extern int status_col;
31
extern off_t start_attnpos;
32
extern off_t end_attnpos;
33
extern int hilite_search;
34
extern int size_linebuf;
35
36
/*
37
 * Get the next line.
38
 * A "current" position is passed and a "new" position is returned.
39
 * The current position is the position of the first character of
40
 * a line.  The new position is the position of the first character
41
 * of the NEXT line.  The line obtained is the line starting at curr_pos.
42
 */
43
off_t
44
forw_line(off_t curr_pos)
45
{
46
	off_t base_pos;
47
	off_t new_pos;
48
	int c;
49
	int blankline;
50
	int endline;
51
1928
	int backchars;
52
53
get_forw_line:
54
964
	if (curr_pos == -1) {
55
26
		null_line();
56
26
		return (-1);
57
	}
58

938
	if (hilite_search == OPT_ONPLUS || is_filtering() || status_col)
59
		/*
60
		 * If we are ignoring EOI (command F), only prepare
61
		 * one line ahead, to avoid getting stuck waiting for
62
		 * slow data without displaying the data we already have.
63
		 * If we're not ignoring EOI, we *could* do the same, but
64
		 * for efficiency we prepare several lines ahead at once.
65
		 */
66
1876
		prep_hilite(curr_pos, curr_pos + 3*size_linebuf,
67
938
		    ignore_eoi ? 1 : -1);
68
938
	if (ch_seek(curr_pos)) {
69
		null_line();
70
		return (-1);
71
	}
72
73
	/*
74
	 * Step back to the beginning of the line.
75
	 */
76
	base_pos = curr_pos;
77
2706
	for (;;) {
78
2706
		if (ABORT_SIGS()) {
79
			null_line();
80
			return (-1);
81
		}
82
2706
		c = ch_back_get();
83
2706
		if (c == EOI)
84
			break;
85
2691
		if (c == '\n') {
86
923
			(void) ch_forw_get();
87
923
			break;
88
		}
89
1768
		--base_pos;
90
	}
91
92
	/*
93
	 * Read forward again to the position we should start at.
94
	 */
95
938
	prewind();
96
938
	plinenum(base_pos);
97
938
	(void) ch_seek(base_pos);
98
	new_pos = base_pos;
99
5412
	while (new_pos < curr_pos) {
100
1768
		if (ABORT_SIGS()) {
101
			null_line();
102
			return (-1);
103
		}
104
1768
		c = ch_forw_get();
105
1768
		backchars = pappend(c, new_pos);
106
1768
		new_pos++;
107
1768
		if (backchars > 0) {
108
			pshift_all();
109
			new_pos -= backchars;
110
			while (--backchars >= 0)
111
				(void) ch_back_get();
112
		}
113
	}
114
938
	(void) pflushmbc();
115
938
	pshift_all();
116
117
	/*
118
	 * Read the first character to display.
119
	 */
120
938
	c = ch_forw_get();
121
938
	if (c == EOI) {
122
2
		null_line();
123
2
		return (-1);
124
	}
125
936
	blankline = (c == '\n' || c == '\r');
126
127
	/*
128
	 * Read each character in the line and append to the line buffer.
129
	 */
130
30449
	for (;;) {
131
30449
		if (ABORT_SIGS()) {
132
			null_line();
133
			return (-1);
134
		}
135
30449
		if (c == '\n' || c == EOI) {
136
			/*
137
			 * End of the line.
138
			 */
139
923
			backchars = pflushmbc();
140
923
			new_pos = ch_tell();
141
923
			if (backchars > 0 && !chopline && hshift == 0) {
142
				new_pos -= backchars + 1;
143
				endline = FALSE;
144
			} else
145
				endline = TRUE;
146
			break;
147
		}
148
29526
		if (c != '\r')
149
29526
			blankline = 0;
150
151
		/*
152
		 * Append the char to the line and get the next char.
153
		 */
154
29526
		backchars = pappend(c, ch_tell()-1);
155
29526
		if (backchars > 0) {
156
			/*
157
			 * The char won't fit in the line; the line
158
			 * is too long to print in the screen width.
159
			 * End the line here.
160
			 */
161
13
			if (chopline || hshift > 0) {
162
				do {
163
					if (ABORT_SIGS()) {
164
						null_line();
165
						return (-1);
166
					}
167
					c = ch_forw_get();
168
				} while (c != '\n' && c != EOI);
169
				new_pos = ch_tell();
170
				endline = TRUE;
171
				quit_if_one_screen = FALSE;
172
			} else {
173
13
				new_pos = ch_tell() - backchars;
174
				endline = FALSE;
175
			}
176
			break;
177
		}
178
29513
		c = ch_forw_get();
179
	}
180
181
936
	pdone(endline, 1);
182
183
936
	if (is_filtered(base_pos)) {
184
		/*
185
		 * We don't want to display this line.
186
		 * Get the next line.
187
		 */
188
		curr_pos = new_pos;
189
		goto get_forw_line;
190
	}
191
192

936
	if (status_col && is_hilited(base_pos, ch_tell()-1, 1, NULL))
193
		set_status_col('*');
194
195
936
	if (squeeze && blankline) {
196
		/*
197
		 * This line is blank.
198
		 * Skip down to the last contiguous blank line
199
		 * and pretend it is the one which we are returning.
200
		 */
201
		while ((c = ch_forw_get()) == '\n' || c == '\r')
202
			if (ABORT_SIGS()) {
203
				null_line();
204
				return (-1);
205
			}
206
		if (c != EOI)
207
			(void) ch_back_get();
208
		new_pos = ch_tell();
209
	}
210
211
936
	return (new_pos);
212
964
}
213
214
/*
215
 * Get the previous line.
216
 * A "current" position is passed and a "new" position is returned.
217
 * The current position is the position of the first character of
218
 * a line.  The new position is the position of the first character
219
 * of the PREVIOUS line.  The line obtained is the one starting at new_pos.
220
 */
221
off_t
222
back_line(off_t curr_pos)
223
{
224
	off_t new_pos, begin_new_pos, base_pos;
225
	int c;
226
	int endline;
227
454
	int backchars;
228
229
get_back_line:
230
227
	if (curr_pos == -1 || curr_pos <= ch_zero()) {
231
3
		null_line();
232
3
		return (-1);
233
	}
234

224
	if (hilite_search == OPT_ONPLUS || is_filtering() || status_col)
235
551
		prep_hilite((curr_pos < 3*size_linebuf) ?
236
103
		    0 : curr_pos - 3*size_linebuf, curr_pos, -1);
237
224
	if (ch_seek(curr_pos-1)) {
238
		null_line();
239
		return (-1);
240
	}
241
242
224
	if (squeeze) {
243
		/*
244
		 * Find out if the "current" line was blank.
245
		 */
246
		(void) ch_forw_get();	/* Skip the newline */
247
		c = ch_forw_get();	/* First char of "current" line */
248
		(void) ch_back_get();	/* Restore our position */
249
		(void) ch_back_get();
250
251
		if (c == '\n' || c == '\r') {
252
			/*
253
			 * The "current" line was blank.
254
			 * Skip over any preceding blank lines,
255
			 * since we skipped them in forw_line().
256
			 */
257
			while ((c = ch_back_get()) == '\n' || c == '\r')
258
				if (ABORT_SIGS()) {
259
					null_line();
260
					return (-1);
261
				}
262
			if (c == EOI) {
263
				null_line();
264
				return (-1);
265
			}
266
			(void) ch_forw_get();
267
		}
268
	}
269
270
	/*
271
	 * Scan backwards until we hit the beginning of the line.
272
	 */
273
7553
	for (;;) {
274
7553
		if (ABORT_SIGS()) {
275
			null_line();
276
			return (-1);
277
		}
278
7553
		c = ch_back_get();
279
7553
		if (c == '\n') {
280
			/*
281
			 * This is the newline ending the previous line.
282
			 * We have hit the beginning of the line.
283
			 */
284
223
			base_pos = ch_tell() + 1;
285
223
			break;
286
		}
287
7330
		if (c == EOI) {
288
			/*
289
			 * We have hit the beginning of the file.
290
			 * This must be the first line in the file.
291
			 * This must, of course, be the beginning of the line.
292
			 */
293
1
			base_pos = ch_tell();
294
1
			break;
295
		}
296
	}
297
298
	/*
299
	 * Now scan forwards from the beginning of this line.
300
	 * We keep discarding "printable lines" (based on screen width)
301
	 * until we reach the curr_pos.
302
	 *
303
	 * {{ This algorithm is pretty inefficient if the lines
304
	 *    are much longer than the screen width,
305
	 *    but I don't know of any better way. }}
306
	 */
307
	new_pos = base_pos;
308
224
	if (ch_seek(new_pos)) {
309
		null_line();
310
		return (-1);
311
	}
312
	endline = FALSE;
313
224
	prewind();
314
224
	plinenum(new_pos);
315
loop:
316
	begin_new_pos = new_pos;
317
230
	(void) ch_seek(new_pos);
318
319
230
	do {
320
7559
		c = ch_forw_get();
321

15118
		if (c == EOI || ABORT_SIGS()) {
322
			null_line();
323
			return (-1);
324
		}
325
7559
		new_pos++;
326
7559
		if (c == '\n') {
327
218
			backchars = pflushmbc();
328
218
			if (backchars > 0 && !chopline && hshift == 0) {
329
				backchars++;
330
				goto shift;
331
			}
332
			endline = TRUE;
333
218
			break;
334
		}
335
7341
		backchars = pappend(c, ch_tell()-1);
336
7341
		if (backchars > 0) {
337
			/*
338
			 * Got a full printable line, but we haven't
339
			 * reached our curr_pos yet.  Discard the line
340
			 * and start a new one.
341
			 */
342
6
			if (chopline || hshift > 0) {
343
				endline = TRUE;
344
				quit_if_one_screen = FALSE;
345
				break;
346
			}
347
		shift:
348
6
			pshift_all();
349
24
			while (backchars-- > 0) {
350
6
				(void) ch_back_get();
351
6
				new_pos--;
352
			}
353
6
			goto loop;
354
		}
355
7335
	} while (new_pos < curr_pos);
356
357
224
	pdone(endline, 0);
358
359
224
	if (is_filtered(base_pos)) {
360
		/*
361
		 * We don't want to display this line.
362
		 * Get the previous line.
363
		 */
364
		curr_pos = begin_new_pos;
365
		goto get_back_line;
366
	}
367
368

224
	if (status_col && curr_pos > 0 &&
369
	    is_hilited(base_pos, curr_pos-1, 1, NULL))
370
		set_status_col('*');
371
372
224
	return (begin_new_pos);
373
227
}
374
375
/*
376
 * Set attnpos.
377
 */
378
void
379
set_attnpos(off_t pos)
380
{
381
	int c;
382
383
	if (pos != -1) {
384
		if (ch_seek(pos))
385
			return;
386
		for (;;) {
387
			c = ch_forw_get();
388
			if (c == EOI)
389
				return;
390
			if (c != '\n' && c != '\r')
391
				break;
392
			pos++;
393
		}
394
	}
395
	start_attnpos = pos;
396
	for (;;) {
397
		c = ch_forw_get();
398
		pos++;
399
		if (c == EOI || c == '\n' || c == '\r')
400
			break;
401
	}
402
	end_attnpos = pos;
403
}