xref: /freebsd/contrib/less/input.c (revision a5f0fb151d90effe79714de0fa059954725fe57f)
1a5f0fb15SPaul Saab /*
2a5f0fb15SPaul Saab  * Copyright (C) 1984-2000  Mark Nudelman
3a5f0fb15SPaul Saab  *
4a5f0fb15SPaul Saab  * You may distribute under the terms of either the GNU General Public
5a5f0fb15SPaul Saab  * License or the Less License, as specified in the README file.
6a5f0fb15SPaul Saab  *
7a5f0fb15SPaul Saab  * For more information about less, or for information on how to
8a5f0fb15SPaul Saab  * contact the author, see the README file.
9a5f0fb15SPaul Saab  */
10a5f0fb15SPaul Saab 
11a5f0fb15SPaul Saab 
12a5f0fb15SPaul Saab /*
13a5f0fb15SPaul Saab  * High level routines dealing with getting lines of input
14a5f0fb15SPaul Saab  * from the file being viewed.
15a5f0fb15SPaul Saab  *
16a5f0fb15SPaul Saab  * When we speak of "lines" here, we mean PRINTABLE lines;
17a5f0fb15SPaul Saab  * lines processed with respect to the screen width.
18a5f0fb15SPaul Saab  * We use the term "raw line" to refer to lines simply
19a5f0fb15SPaul Saab  * delimited by newlines; not processed with respect to screen width.
20a5f0fb15SPaul Saab  */
21a5f0fb15SPaul Saab 
22a5f0fb15SPaul Saab #include "less.h"
23a5f0fb15SPaul Saab 
24a5f0fb15SPaul Saab extern int squeeze;
25a5f0fb15SPaul Saab extern int chopline;
26a5f0fb15SPaul Saab extern int quit_if_one_screen;
27a5f0fb15SPaul Saab extern int sigs;
28a5f0fb15SPaul Saab extern int ignore_eoi;
29a5f0fb15SPaul Saab extern POSITION start_attnpos;
30a5f0fb15SPaul Saab extern POSITION end_attnpos;
31a5f0fb15SPaul Saab #if HILITE_SEARCH
32a5f0fb15SPaul Saab extern int hilite_search;
33a5f0fb15SPaul Saab extern int size_linebuf;
34a5f0fb15SPaul Saab #endif
35a5f0fb15SPaul Saab 
36a5f0fb15SPaul Saab /*
37a5f0fb15SPaul Saab  * Get the next line.
38a5f0fb15SPaul Saab  * A "current" position is passed and a "new" position is returned.
39a5f0fb15SPaul Saab  * The current position is the position of the first character of
40a5f0fb15SPaul Saab  * a line.  The new position is the position of the first character
41a5f0fb15SPaul Saab  * of the NEXT line.  The line obtained is the line starting at curr_pos.
42a5f0fb15SPaul Saab  */
43a5f0fb15SPaul Saab 	public POSITION
44a5f0fb15SPaul Saab forw_line(curr_pos)
45a5f0fb15SPaul Saab 	POSITION curr_pos;
46a5f0fb15SPaul Saab {
47a5f0fb15SPaul Saab 	POSITION new_pos;
48a5f0fb15SPaul Saab 	register int c;
49a5f0fb15SPaul Saab 	int blankline;
50a5f0fb15SPaul Saab 	int endline;
51a5f0fb15SPaul Saab 
52a5f0fb15SPaul Saab 	if (curr_pos == NULL_POSITION)
53a5f0fb15SPaul Saab 	{
54a5f0fb15SPaul Saab 		null_line();
55a5f0fb15SPaul Saab 		return (NULL_POSITION);
56a5f0fb15SPaul Saab 	}
57a5f0fb15SPaul Saab #if HILITE_SEARCH
58a5f0fb15SPaul Saab 	if (hilite_search == OPT_ONPLUS)
59a5f0fb15SPaul Saab 		/*
60a5f0fb15SPaul Saab 		 * If we are ignoring EOI (command F), only prepare
61a5f0fb15SPaul Saab 		 * one line ahead, to avoid getting stuck waiting for
62a5f0fb15SPaul Saab 		 * slow data without displaying the data we already have.
63a5f0fb15SPaul Saab 		 * If we're not ignoring EOI, we *could* do the same, but
64a5f0fb15SPaul Saab 		 * for efficiency we prepare several lines ahead at once.
65a5f0fb15SPaul Saab 		 */
66a5f0fb15SPaul Saab 		prep_hilite(curr_pos, curr_pos + 3*size_linebuf,
67a5f0fb15SPaul Saab 				ignore_eoi ? 1 : -1);
68a5f0fb15SPaul Saab #endif
69a5f0fb15SPaul Saab 	if (ch_seek(curr_pos))
70a5f0fb15SPaul Saab 	{
71a5f0fb15SPaul Saab 		null_line();
72a5f0fb15SPaul Saab 		return (NULL_POSITION);
73a5f0fb15SPaul Saab 	}
74a5f0fb15SPaul Saab 
75a5f0fb15SPaul Saab 	prewind();
76a5f0fb15SPaul Saab 	plinenum(curr_pos);
77a5f0fb15SPaul Saab 	(void) ch_seek(curr_pos);
78a5f0fb15SPaul Saab 
79a5f0fb15SPaul Saab 	c = ch_forw_get();
80a5f0fb15SPaul Saab 	if (c == EOI)
81a5f0fb15SPaul Saab 	{
82a5f0fb15SPaul Saab 		null_line();
83a5f0fb15SPaul Saab 		return (NULL_POSITION);
84a5f0fb15SPaul Saab 	}
85a5f0fb15SPaul Saab 	blankline = (c == '\n' || c == '\r');
86a5f0fb15SPaul Saab 
87a5f0fb15SPaul Saab 	for (;;)
88a5f0fb15SPaul Saab 	{
89a5f0fb15SPaul Saab 		if (ABORT_SIGS())
90a5f0fb15SPaul Saab 		{
91a5f0fb15SPaul Saab 			null_line();
92a5f0fb15SPaul Saab 			return (NULL_POSITION);
93a5f0fb15SPaul Saab 		}
94a5f0fb15SPaul Saab 		if (c == '\n' || c == EOI)
95a5f0fb15SPaul Saab 		{
96a5f0fb15SPaul Saab 			/*
97a5f0fb15SPaul Saab 			 * End of the line.
98a5f0fb15SPaul Saab 			 */
99a5f0fb15SPaul Saab 			new_pos = ch_tell();
100a5f0fb15SPaul Saab 			endline = TRUE;
101a5f0fb15SPaul Saab 			break;
102a5f0fb15SPaul Saab 		}
103a5f0fb15SPaul Saab 
104a5f0fb15SPaul Saab 		/*
105a5f0fb15SPaul Saab 		 * Append the char to the line and get the next char.
106a5f0fb15SPaul Saab 		 */
107a5f0fb15SPaul Saab 		if (pappend(c, ch_tell()-1))
108a5f0fb15SPaul Saab 		{
109a5f0fb15SPaul Saab 			/*
110a5f0fb15SPaul Saab 			 * The char won't fit in the line; the line
111a5f0fb15SPaul Saab 			 * is too long to print in the screen width.
112a5f0fb15SPaul Saab 			 * End the line here.
113a5f0fb15SPaul Saab 			 */
114a5f0fb15SPaul Saab 			if (chopline)
115a5f0fb15SPaul Saab 			{
116a5f0fb15SPaul Saab 				do
117a5f0fb15SPaul Saab 				{
118a5f0fb15SPaul Saab 					c = ch_forw_get();
119a5f0fb15SPaul Saab 				} while (c != '\n' && c != EOI);
120a5f0fb15SPaul Saab 				new_pos = ch_tell();
121a5f0fb15SPaul Saab 				endline = TRUE;
122a5f0fb15SPaul Saab 				quit_if_one_screen = FALSE;
123a5f0fb15SPaul Saab 			} else
124a5f0fb15SPaul Saab 			{
125a5f0fb15SPaul Saab 				new_pos = ch_tell() - 1;
126a5f0fb15SPaul Saab 				endline = FALSE;
127a5f0fb15SPaul Saab 			}
128a5f0fb15SPaul Saab 			break;
129a5f0fb15SPaul Saab 		}
130a5f0fb15SPaul Saab 		c = ch_forw_get();
131a5f0fb15SPaul Saab 	}
132a5f0fb15SPaul Saab 	pdone(endline);
133a5f0fb15SPaul Saab 
134a5f0fb15SPaul Saab 	if (squeeze && blankline)
135a5f0fb15SPaul Saab 	{
136a5f0fb15SPaul Saab 		/*
137a5f0fb15SPaul Saab 		 * This line is blank.
138a5f0fb15SPaul Saab 		 * Skip down to the last contiguous blank line
139a5f0fb15SPaul Saab 		 * and pretend it is the one which we are returning.
140a5f0fb15SPaul Saab 		 */
141a5f0fb15SPaul Saab 		while ((c = ch_forw_get()) == '\n' || c == '\r')
142a5f0fb15SPaul Saab 			if (ABORT_SIGS())
143a5f0fb15SPaul Saab 			{
144a5f0fb15SPaul Saab 				null_line();
145a5f0fb15SPaul Saab 				return (NULL_POSITION);
146a5f0fb15SPaul Saab 			}
147a5f0fb15SPaul Saab 		if (c != EOI)
148a5f0fb15SPaul Saab 			(void) ch_back_get();
149a5f0fb15SPaul Saab 		new_pos = ch_tell();
150a5f0fb15SPaul Saab 	}
151a5f0fb15SPaul Saab 
152a5f0fb15SPaul Saab 	return (new_pos);
153a5f0fb15SPaul Saab }
154a5f0fb15SPaul Saab 
155a5f0fb15SPaul Saab /*
156a5f0fb15SPaul Saab  * Get the previous line.
157a5f0fb15SPaul Saab  * A "current" position is passed and a "new" position is returned.
158a5f0fb15SPaul Saab  * The current position is the position of the first character of
159a5f0fb15SPaul Saab  * a line.  The new position is the position of the first character
160a5f0fb15SPaul Saab  * of the PREVIOUS line.  The line obtained is the one starting at new_pos.
161a5f0fb15SPaul Saab  */
162a5f0fb15SPaul Saab 	public POSITION
163a5f0fb15SPaul Saab back_line(curr_pos)
164a5f0fb15SPaul Saab 	POSITION curr_pos;
165a5f0fb15SPaul Saab {
166a5f0fb15SPaul Saab 	POSITION new_pos, begin_new_pos;
167a5f0fb15SPaul Saab 	int c;
168a5f0fb15SPaul Saab 	int endline;
169a5f0fb15SPaul Saab 
170a5f0fb15SPaul Saab 	if (curr_pos == NULL_POSITION || curr_pos <= ch_zero())
171a5f0fb15SPaul Saab 	{
172a5f0fb15SPaul Saab 		null_line();
173a5f0fb15SPaul Saab 		return (NULL_POSITION);
174a5f0fb15SPaul Saab 	}
175a5f0fb15SPaul Saab #if HILITE_SEARCH
176a5f0fb15SPaul Saab 	if (hilite_search == OPT_ONPLUS)
177a5f0fb15SPaul Saab 		prep_hilite((curr_pos < 3*size_linebuf) ?
178a5f0fb15SPaul Saab 				0 : curr_pos - 3*size_linebuf, curr_pos, -1);
179a5f0fb15SPaul Saab #endif
180a5f0fb15SPaul Saab 	if (ch_seek(curr_pos-1))
181a5f0fb15SPaul Saab 	{
182a5f0fb15SPaul Saab 		null_line();
183a5f0fb15SPaul Saab 		return (NULL_POSITION);
184a5f0fb15SPaul Saab 	}
185a5f0fb15SPaul Saab 
186a5f0fb15SPaul Saab 	if (squeeze)
187a5f0fb15SPaul Saab 	{
188a5f0fb15SPaul Saab 		/*
189a5f0fb15SPaul Saab 		 * Find out if the "current" line was blank.
190a5f0fb15SPaul Saab 		 */
191a5f0fb15SPaul Saab 		(void) ch_forw_get();	/* Skip the newline */
192a5f0fb15SPaul Saab 		c = ch_forw_get();	/* First char of "current" line */
193a5f0fb15SPaul Saab 		(void) ch_back_get();	/* Restore our position */
194a5f0fb15SPaul Saab 		(void) ch_back_get();
195a5f0fb15SPaul Saab 
196a5f0fb15SPaul Saab 		if (c == '\n' || c == '\r')
197a5f0fb15SPaul Saab 		{
198a5f0fb15SPaul Saab 			/*
199a5f0fb15SPaul Saab 			 * The "current" line was blank.
200a5f0fb15SPaul Saab 			 * Skip over any preceding blank lines,
201a5f0fb15SPaul Saab 			 * since we skipped them in forw_line().
202a5f0fb15SPaul Saab 			 */
203a5f0fb15SPaul Saab 			while ((c = ch_back_get()) == '\n' || c == '\r')
204a5f0fb15SPaul Saab 				if (ABORT_SIGS())
205a5f0fb15SPaul Saab 				{
206a5f0fb15SPaul Saab 					null_line();
207a5f0fb15SPaul Saab 					return (NULL_POSITION);
208a5f0fb15SPaul Saab 				}
209a5f0fb15SPaul Saab 			if (c == EOI)
210a5f0fb15SPaul Saab 			{
211a5f0fb15SPaul Saab 				null_line();
212a5f0fb15SPaul Saab 				return (NULL_POSITION);
213a5f0fb15SPaul Saab 			}
214a5f0fb15SPaul Saab 			(void) ch_forw_get();
215a5f0fb15SPaul Saab 		}
216a5f0fb15SPaul Saab 	}
217a5f0fb15SPaul Saab 
218a5f0fb15SPaul Saab 	/*
219a5f0fb15SPaul Saab 	 * Scan backwards until we hit the beginning of the line.
220a5f0fb15SPaul Saab 	 */
221a5f0fb15SPaul Saab 	for (;;)
222a5f0fb15SPaul Saab 	{
223a5f0fb15SPaul Saab 		if (ABORT_SIGS())
224a5f0fb15SPaul Saab 		{
225a5f0fb15SPaul Saab 			null_line();
226a5f0fb15SPaul Saab 			return (NULL_POSITION);
227a5f0fb15SPaul Saab 		}
228a5f0fb15SPaul Saab 		c = ch_back_get();
229a5f0fb15SPaul Saab 		if (c == '\n')
230a5f0fb15SPaul Saab 		{
231a5f0fb15SPaul Saab 			/*
232a5f0fb15SPaul Saab 			 * This is the newline ending the previous line.
233a5f0fb15SPaul Saab 			 * We have hit the beginning of the line.
234a5f0fb15SPaul Saab 			 */
235a5f0fb15SPaul Saab 			new_pos = ch_tell() + 1;
236a5f0fb15SPaul Saab 			break;
237a5f0fb15SPaul Saab 		}
238a5f0fb15SPaul Saab 		if (c == EOI)
239a5f0fb15SPaul Saab 		{
240a5f0fb15SPaul Saab 			/*
241a5f0fb15SPaul Saab 			 * We have hit the beginning of the file.
242a5f0fb15SPaul Saab 			 * This must be the first line in the file.
243a5f0fb15SPaul Saab 			 * This must, of course, be the beginning of the line.
244a5f0fb15SPaul Saab 			 */
245a5f0fb15SPaul Saab 			new_pos = ch_tell();
246a5f0fb15SPaul Saab 			break;
247a5f0fb15SPaul Saab 		}
248a5f0fb15SPaul Saab 	}
249a5f0fb15SPaul Saab 
250a5f0fb15SPaul Saab 	/*
251a5f0fb15SPaul Saab 	 * Now scan forwards from the beginning of this line.
252a5f0fb15SPaul Saab 	 * We keep discarding "printable lines" (based on screen width)
253a5f0fb15SPaul Saab 	 * until we reach the curr_pos.
254a5f0fb15SPaul Saab 	 *
255a5f0fb15SPaul Saab 	 * {{ This algorithm is pretty inefficient if the lines
256a5f0fb15SPaul Saab 	 *    are much longer than the screen width,
257a5f0fb15SPaul Saab 	 *    but I don't know of any better way. }}
258a5f0fb15SPaul Saab 	 */
259a5f0fb15SPaul Saab 	if (ch_seek(new_pos))
260a5f0fb15SPaul Saab 	{
261a5f0fb15SPaul Saab 		null_line();
262a5f0fb15SPaul Saab 		return (NULL_POSITION);
263a5f0fb15SPaul Saab 	}
264a5f0fb15SPaul Saab 	endline = FALSE;
265a5f0fb15SPaul Saab     loop:
266a5f0fb15SPaul Saab 	begin_new_pos = new_pos;
267a5f0fb15SPaul Saab 	prewind();
268a5f0fb15SPaul Saab 	plinenum(new_pos);
269a5f0fb15SPaul Saab 	(void) ch_seek(new_pos);
270a5f0fb15SPaul Saab 
271a5f0fb15SPaul Saab 	do
272a5f0fb15SPaul Saab 	{
273a5f0fb15SPaul Saab 		c = ch_forw_get();
274a5f0fb15SPaul Saab 		if (c == EOI || ABORT_SIGS())
275a5f0fb15SPaul Saab 		{
276a5f0fb15SPaul Saab 			null_line();
277a5f0fb15SPaul Saab 			return (NULL_POSITION);
278a5f0fb15SPaul Saab 		}
279a5f0fb15SPaul Saab 		new_pos++;
280a5f0fb15SPaul Saab 		if (c == '\n')
281a5f0fb15SPaul Saab 		{
282a5f0fb15SPaul Saab 			endline = TRUE;
283a5f0fb15SPaul Saab 			break;
284a5f0fb15SPaul Saab 		}
285a5f0fb15SPaul Saab 		if (pappend(c, ch_tell()-1))
286a5f0fb15SPaul Saab 		{
287a5f0fb15SPaul Saab 			/*
288a5f0fb15SPaul Saab 			 * Got a full printable line, but we haven't
289a5f0fb15SPaul Saab 			 * reached our curr_pos yet.  Discard the line
290a5f0fb15SPaul Saab 			 * and start a new one.
291a5f0fb15SPaul Saab 			 */
292a5f0fb15SPaul Saab 			if (chopline)
293a5f0fb15SPaul Saab 			{
294a5f0fb15SPaul Saab 				endline = TRUE;
295a5f0fb15SPaul Saab 				quit_if_one_screen = FALSE;
296a5f0fb15SPaul Saab 				break;
297a5f0fb15SPaul Saab 			}
298a5f0fb15SPaul Saab 			pdone(0);
299a5f0fb15SPaul Saab 			(void) ch_back_get();
300a5f0fb15SPaul Saab 			new_pos--;
301a5f0fb15SPaul Saab 			goto loop;
302a5f0fb15SPaul Saab 		}
303a5f0fb15SPaul Saab 	} while (new_pos < curr_pos);
304a5f0fb15SPaul Saab 
305a5f0fb15SPaul Saab 	pdone(endline);
306a5f0fb15SPaul Saab 
307a5f0fb15SPaul Saab 	return (begin_new_pos);
308a5f0fb15SPaul Saab }
309a5f0fb15SPaul Saab 
310a5f0fb15SPaul Saab /*
311a5f0fb15SPaul Saab  * Set attnpos.
312a5f0fb15SPaul Saab  */
313a5f0fb15SPaul Saab 	public void
314a5f0fb15SPaul Saab set_attnpos(pos)
315a5f0fb15SPaul Saab 	POSITION pos;
316a5f0fb15SPaul Saab {
317a5f0fb15SPaul Saab 	int c;
318a5f0fb15SPaul Saab 
319a5f0fb15SPaul Saab 	if (pos != NULL_POSITION)
320a5f0fb15SPaul Saab 	{
321a5f0fb15SPaul Saab 		if (ch_seek(pos))
322a5f0fb15SPaul Saab 			return;
323a5f0fb15SPaul Saab 		for (;;)
324a5f0fb15SPaul Saab 		{
325a5f0fb15SPaul Saab 			c = ch_forw_get();
326a5f0fb15SPaul Saab 			if (c == EOI)
327a5f0fb15SPaul Saab 				return;
328a5f0fb15SPaul Saab 			if (c != '\n' && c != '\r')
329a5f0fb15SPaul Saab 				break;
330a5f0fb15SPaul Saab 			pos++;
331a5f0fb15SPaul Saab 		}
332a5f0fb15SPaul Saab 	}
333a5f0fb15SPaul Saab 	start_attnpos = pos;
334a5f0fb15SPaul Saab 	for (;;)
335a5f0fb15SPaul Saab 	{
336a5f0fb15SPaul Saab 		c = ch_forw_get();
337a5f0fb15SPaul Saab 		pos++;
338a5f0fb15SPaul Saab 		if (c == EOI || c == '\n' || c == '\r')
339a5f0fb15SPaul Saab 			break;
340a5f0fb15SPaul Saab 	}
341a5f0fb15SPaul Saab 	end_attnpos = pos;
342a5f0fb15SPaul Saab }
343