GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/less/less/../input.c Lines: 111 169 65.7 %
Date: 2017-11-07 Branches: 69 114 60.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
50322
	int backchars;
52
53
get_forw_line:
54
25161
	if (curr_pos == -1) {
55
154
		null_line();
56
154
		return (-1);
57
	}
58

26090
	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
47848
		prep_hilite(curr_pos, curr_pos + 3*size_linebuf,
67
23924
		    ignore_eoi ? 1 : -1);
68
25007
	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
2390961
	for (;;) {
78
2390961
		if (ABORT_SIGS()) {
79
			null_line();
80
			return (-1);
81
		}
82
2390961
		c = ch_back_get();
83
2390961
		if (c == EOI)
84
			break;
85
2390917
		if (c == '\n') {
86
24963
			(void) ch_forw_get();
87
24963
			break;
88
		}
89
2365954
		--base_pos;
90
	}
91
92
	/*
93
	 * Read forward again to the position we should start at.
94
	 */
95
25007
	prewind();
96
25007
	plinenum(base_pos);
97
25007
	(void) ch_seek(base_pos);
98
	new_pos = base_pos;
99
2428255
	while (new_pos < curr_pos) {
100
2378241
		if (ABORT_SIGS()) {
101
			null_line();
102
			return (-1);
103
		}
104
2378241
		c = ch_forw_get();
105
2378241
		backchars = pappend(c, new_pos);
106
2378241
		new_pos++;
107
2378241
		if (backchars > 0) {
108
12287
			pshift_all();
109
12287
			new_pos -= backchars;
110
49148
			while (--backchars >= 0)
111
12287
				(void) ch_back_get();
112
		}
113
	}
114
25007
	(void) pflushmbc();
115
25007
	pshift_all();
116
117
	/*
118
	 * Read the first character to display.
119
	 */
120
25007
	c = ch_forw_get();
121
25007
	if (c == EOI) {
122
19
		null_line();
123
19
		return (-1);
124
	}
125
24988
	blankline = (c == '\n' || c == '\r');
126
127
	/*
128
	 * Read each character in the line and append to the line buffer.
129
	 */
130
1668041
	for (;;) {
131
1668041
		if (ABORT_SIGS()) {
132
			null_line();
133
			return (-1);
134
		}
135
1668041
		if (c == '\n' || c == EOI) {
136
			/*
137
			 * End of the line.
138
			 */
139
19877
			backchars = pflushmbc();
140
19877
			new_pos = ch_tell();
141
19877
			if (backchars > 0 && !chopline && hshift == 0) {
142
				new_pos -= backchars + 1;
143
				endline = FALSE;
144
			} else
145
				endline = TRUE;
146
			break;
147
		}
148
1648164
		if (c != '\r')
149
1648162
			blankline = 0;
150
151
		/*
152
		 * Append the char to the line and get the next char.
153
		 */
154
1648164
		backchars = pappend(c, ch_tell()-1);
155
1648164
		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
5111
			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
5111
				new_pos = ch_tell() - backchars;
174
				endline = FALSE;
175
			}
176
			break;
177
		}
178
1643053
		c = ch_forw_get();
179
	}
180
181
24988
	pdone(endline, 1);
182
183
24988
	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

24988
	if (status_col && is_hilited(base_pos, ch_tell()-1, 1, NULL))
193
		set_status_col('*');
194
195
24988
	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
235
		while ((c = ch_forw_get()) == '\n' || c == '\r')
202
			if (ABORT_SIGS()) {
203
				null_line();
204
				return (-1);
205
			}
206
235
		if (c != EOI)
207
235
			(void) ch_back_get();
208
235
		new_pos = ch_tell();
209
235
	}
210
211
24988
	return (new_pos);
212
25161
}
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
5602
	int backchars;
228
229
get_back_line:
230
2801
	if (curr_pos == -1 || curr_pos <= ch_zero()) {
231
26
		null_line();
232
26
		return (-1);
233
	}
234

2880
	if (hilite_search == OPT_ONPLUS || is_filtering() || status_col)
235
7751
		prep_hilite((curr_pos < 3*size_linebuf) ?
236
2411
		    0 : curr_pos - 3*size_linebuf, curr_pos, -1);
237
2775
	if (ch_seek(curr_pos-1)) {
238
		null_line();
239
		return (-1);
240
	}
241
242
2775
	if (squeeze) {
243
		/*
244
		 * Find out if the "current" line was blank.
245
		 */
246
105
		(void) ch_forw_get();	/* Skip the newline */
247
105
		c = ch_forw_get();	/* First char of "current" line */
248
105
		(void) ch_back_get();	/* Restore our position */
249
105
		(void) ch_back_get();
250
251
105
		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
33
			while ((c = ch_back_get()) == '\n' || c == '\r')
258
				if (ABORT_SIGS()) {
259
					null_line();
260
					return (-1);
261
				}
262
33
			if (c == EOI) {
263
				null_line();
264
				return (-1);
265
			}
266
33
			(void) ch_forw_get();
267
33
		}
268
	}
269
270
	/*
271
	 * Scan backwards until we hit the beginning of the line.
272
	 */
273
	for (;;) {
274
101155
		if (ABORT_SIGS()) {
275
			null_line();
276
			return (-1);
277
		}
278
101155
		c = ch_back_get();
279
101155
		if (c == '\n') {
280
			/*
281
			 * This is the newline ending the previous line.
282
			 * We have hit the beginning of the line.
283
			 */
284
2770
			base_pos = ch_tell() + 1;
285
2770
			break;
286
		}
287
98385
		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
5
			base_pos = ch_tell();
294
5
			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
2775
	if (ch_seek(new_pos)) {
309
		null_line();
310
		return (-1);
311
	}
312
	endline = FALSE;
313
2775
	prewind();
314
2775
	plinenum(new_pos);
315
loop:
316
	begin_new_pos = new_pos;
317
2798
	(void) ch_seek(new_pos);
318
319
2798
	do {
320
101178
		c = ch_forw_get();
321

202356
		if (c == EOI || ABORT_SIGS()) {
322
			null_line();
323
			return (-1);
324
		}
325
101178
		new_pos++;
326
101178
		if (c == '\n') {
327
2751
			backchars = pflushmbc();
328
2751
			if (backchars > 0 && !chopline && hshift == 0) {
329
				backchars++;
330
				goto shift;
331
			}
332
			endline = TRUE;
333
2751
			break;
334
		}
335
98427
		backchars = pappend(c, ch_tell()-1);
336
98427
		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
23
			if (chopline || hshift > 0) {
343
				endline = TRUE;
344
				quit_if_one_screen = FALSE;
345
				break;
346
			}
347
		shift:
348
23
			pshift_all();
349
92
			while (backchars-- > 0) {
350
23
				(void) ch_back_get();
351
23
				new_pos--;
352
			}
353
			goto loop;
354
		}
355
98404
	} while (new_pos < curr_pos);
356
357
2775
	pdone(endline, 0);
358
359
2775
	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

2775
	if (status_col && curr_pos > 0 &&
369
	    is_hilited(base_pos, curr_pos-1, 1, NULL))
370
		set_status_col('*');
371
372
2775
	return (begin_new_pos);
373
2801
}
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
}