xref: /freebsd/contrib/less/input.c (revision 6dcb072b3021f88118ab758d851d01be270f36b2)
1a5f0fb15SPaul Saab /*
26dcb072bSXin LI  * Copyright (C) 1984-2005  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;
268ed69c6fSPaul Saab extern int hshift;
27a5f0fb15SPaul Saab extern int quit_if_one_screen;
28a5f0fb15SPaul Saab extern int sigs;
29a5f0fb15SPaul Saab extern int ignore_eoi;
306dcb072bSXin LI extern int status_col;
31a5f0fb15SPaul Saab extern POSITION start_attnpos;
32a5f0fb15SPaul Saab extern POSITION end_attnpos;
33a5f0fb15SPaul Saab #if HILITE_SEARCH
34a5f0fb15SPaul Saab extern int hilite_search;
35a5f0fb15SPaul Saab extern int size_linebuf;
36a5f0fb15SPaul Saab #endif
37a5f0fb15SPaul Saab 
38a5f0fb15SPaul Saab /*
39a5f0fb15SPaul Saab  * Get the next line.
40a5f0fb15SPaul Saab  * A "current" position is passed and a "new" position is returned.
41a5f0fb15SPaul Saab  * The current position is the position of the first character of
42a5f0fb15SPaul Saab  * a line.  The new position is the position of the first character
43a5f0fb15SPaul Saab  * of the NEXT line.  The line obtained is the line starting at curr_pos.
44a5f0fb15SPaul Saab  */
45a5f0fb15SPaul Saab 	public POSITION
46a5f0fb15SPaul Saab forw_line(curr_pos)
47a5f0fb15SPaul Saab 	POSITION curr_pos;
48a5f0fb15SPaul Saab {
496dcb072bSXin LI 	POSITION base_pos;
50a5f0fb15SPaul Saab 	POSITION new_pos;
51a5f0fb15SPaul Saab 	register int c;
52a5f0fb15SPaul Saab 	int blankline;
53a5f0fb15SPaul Saab 	int endline;
546dcb072bSXin LI 	int backchars;
55a5f0fb15SPaul Saab 
56a5f0fb15SPaul Saab 	if (curr_pos == NULL_POSITION)
57a5f0fb15SPaul Saab 	{
58a5f0fb15SPaul Saab 		null_line();
59a5f0fb15SPaul Saab 		return (NULL_POSITION);
60a5f0fb15SPaul Saab 	}
61a5f0fb15SPaul Saab #if HILITE_SEARCH
626dcb072bSXin LI 	if (hilite_search == OPT_ONPLUS || status_col)
63a5f0fb15SPaul Saab 		/*
64a5f0fb15SPaul Saab 		 * If we are ignoring EOI (command F), only prepare
65a5f0fb15SPaul Saab 		 * one line ahead, to avoid getting stuck waiting for
66a5f0fb15SPaul Saab 		 * slow data without displaying the data we already have.
67a5f0fb15SPaul Saab 		 * If we're not ignoring EOI, we *could* do the same, but
68a5f0fb15SPaul Saab 		 * for efficiency we prepare several lines ahead at once.
69a5f0fb15SPaul Saab 		 */
70a5f0fb15SPaul Saab 		prep_hilite(curr_pos, curr_pos + 3*size_linebuf,
71a5f0fb15SPaul Saab 				ignore_eoi ? 1 : -1);
72a5f0fb15SPaul Saab #endif
73a5f0fb15SPaul Saab 	if (ch_seek(curr_pos))
74a5f0fb15SPaul Saab 	{
75a5f0fb15SPaul Saab 		null_line();
76a5f0fb15SPaul Saab 		return (NULL_POSITION);
77a5f0fb15SPaul Saab 	}
78a5f0fb15SPaul Saab 
796dcb072bSXin LI 	base_pos = curr_pos;
806dcb072bSXin LI 	for (;;)
816dcb072bSXin LI 	{
826dcb072bSXin LI 		if (ABORT_SIGS())
836dcb072bSXin LI 		{
846dcb072bSXin LI 			null_line();
856dcb072bSXin LI 			return (NULL_POSITION);
866dcb072bSXin LI 		}
876dcb072bSXin LI 		c = ch_back_get();
886dcb072bSXin LI 		if (c == EOI)
896dcb072bSXin LI 			break;
906dcb072bSXin LI 		if (c == '\n')
916dcb072bSXin LI 		{
926dcb072bSXin LI 			(void) ch_forw_get();
936dcb072bSXin LI 			break;
946dcb072bSXin LI 		}
956dcb072bSXin LI 		--base_pos;
966dcb072bSXin LI 	}
976dcb072bSXin LI 
98a5f0fb15SPaul Saab  	prewind();
996dcb072bSXin LI 	plinenum(base_pos);
1006dcb072bSXin LI 	(void) ch_seek(base_pos);
1016dcb072bSXin LI 	while (base_pos < curr_pos)
1026dcb072bSXin LI 	{
1036dcb072bSXin LI 		if (ABORT_SIGS())
1046dcb072bSXin LI 		{
1056dcb072bSXin LI 			null_line();
1066dcb072bSXin LI 			return (NULL_POSITION);
1076dcb072bSXin LI 		}
1086dcb072bSXin LI 		c = ch_forw_get();
1096dcb072bSXin LI 		backchars = pappend(c, base_pos);
1106dcb072bSXin LI 		base_pos++;
1116dcb072bSXin LI 		if (backchars > 0)
1126dcb072bSXin LI 		{
1136dcb072bSXin LI 			pshift_all();
1146dcb072bSXin LI 			base_pos -= backchars;
1156dcb072bSXin LI 			while (--backchars >= 0)
1166dcb072bSXin LI 				(void) ch_back_get();
1176dcb072bSXin LI 		}
1186dcb072bSXin LI 	}
1196dcb072bSXin LI 	(void) pflushmbc();
1206dcb072bSXin LI 	pshift_all();
121a5f0fb15SPaul Saab 
122a5f0fb15SPaul Saab 	c = ch_forw_get();
123a5f0fb15SPaul Saab 	if (c == EOI)
124a5f0fb15SPaul Saab 	{
125a5f0fb15SPaul Saab 		null_line();
126a5f0fb15SPaul Saab 		return (NULL_POSITION);
127a5f0fb15SPaul Saab 	}
128a5f0fb15SPaul Saab 	blankline = (c == '\n' || c == '\r');
129a5f0fb15SPaul Saab 
130a5f0fb15SPaul Saab 	for (;;)
131a5f0fb15SPaul Saab 	{
132a5f0fb15SPaul Saab 		if (ABORT_SIGS())
133a5f0fb15SPaul Saab 		{
134a5f0fb15SPaul Saab 			null_line();
135a5f0fb15SPaul Saab 			return (NULL_POSITION);
136a5f0fb15SPaul Saab 		}
137a5f0fb15SPaul Saab 		if (c == '\n' || c == EOI)
138a5f0fb15SPaul Saab 		{
139a5f0fb15SPaul Saab 			/*
140a5f0fb15SPaul Saab 			 * End of the line.
141a5f0fb15SPaul Saab 			 */
1426dcb072bSXin LI 			backchars = pflushmbc();
143a5f0fb15SPaul Saab 			new_pos = ch_tell();
1446dcb072bSXin LI 			if (backchars > 0 && !chopline && hshift == 0)
1456dcb072bSXin LI 			{
1466dcb072bSXin LI 				new_pos -= backchars + 1;
1476dcb072bSXin LI 				endline = FALSE;
1486dcb072bSXin LI 			} else
149a5f0fb15SPaul Saab 				endline = TRUE;
150a5f0fb15SPaul Saab 			break;
151a5f0fb15SPaul Saab 		}
1526dcb072bSXin LI 		if (c != '\r')
1536dcb072bSXin LI 			blankline = 0;
154a5f0fb15SPaul Saab 
155a5f0fb15SPaul Saab 		/*
156a5f0fb15SPaul Saab 		 * Append the char to the line and get the next char.
157a5f0fb15SPaul Saab 		 */
1586dcb072bSXin LI 		backchars = pappend(c, ch_tell()-1);
1596dcb072bSXin LI 		if (backchars > 0)
160a5f0fb15SPaul Saab 		{
161a5f0fb15SPaul Saab 			/*
162a5f0fb15SPaul Saab 			 * The char won't fit in the line; the line
163a5f0fb15SPaul Saab 			 * is too long to print in the screen width.
164a5f0fb15SPaul Saab 			 * End the line here.
165a5f0fb15SPaul Saab 			 */
1668ed69c6fSPaul Saab 			if (chopline || hshift > 0)
167a5f0fb15SPaul Saab 			{
168a5f0fb15SPaul Saab 				do
169a5f0fb15SPaul Saab 				{
170a5f0fb15SPaul Saab 					c = ch_forw_get();
171a5f0fb15SPaul Saab 				} while (c != '\n' && c != EOI);
172a5f0fb15SPaul Saab 				new_pos = ch_tell();
173a5f0fb15SPaul Saab 				endline = TRUE;
174a5f0fb15SPaul Saab 				quit_if_one_screen = FALSE;
175a5f0fb15SPaul Saab 			} else
176a5f0fb15SPaul Saab 			{
1776dcb072bSXin LI 				new_pos = ch_tell() - backchars;
178a5f0fb15SPaul Saab 				endline = FALSE;
179a5f0fb15SPaul Saab 			}
180a5f0fb15SPaul Saab 			break;
181a5f0fb15SPaul Saab 		}
182a5f0fb15SPaul Saab 		c = ch_forw_get();
183a5f0fb15SPaul Saab 	}
184a5f0fb15SPaul Saab 	pdone(endline);
185a5f0fb15SPaul Saab 
186a5f0fb15SPaul Saab 	if (squeeze && blankline)
187a5f0fb15SPaul Saab 	{
188a5f0fb15SPaul Saab 		/*
189a5f0fb15SPaul Saab 		 * This line is blank.
190a5f0fb15SPaul Saab 		 * Skip down to the last contiguous blank line
191a5f0fb15SPaul Saab 		 * and pretend it is the one which we are returning.
192a5f0fb15SPaul Saab 		 */
193a5f0fb15SPaul Saab 		while ((c = ch_forw_get()) == '\n' || c == '\r')
194a5f0fb15SPaul Saab 			if (ABORT_SIGS())
195a5f0fb15SPaul Saab 			{
196a5f0fb15SPaul Saab 				null_line();
197a5f0fb15SPaul Saab 				return (NULL_POSITION);
198a5f0fb15SPaul Saab 			}
199a5f0fb15SPaul Saab 		if (c != EOI)
200a5f0fb15SPaul Saab 			(void) ch_back_get();
201a5f0fb15SPaul Saab 		new_pos = ch_tell();
202a5f0fb15SPaul Saab 	}
203a5f0fb15SPaul Saab 
204a5f0fb15SPaul Saab 	return (new_pos);
205a5f0fb15SPaul Saab }
206a5f0fb15SPaul Saab 
207a5f0fb15SPaul Saab /*
208a5f0fb15SPaul Saab  * Get the previous line.
209a5f0fb15SPaul Saab  * A "current" position is passed and a "new" position is returned.
210a5f0fb15SPaul Saab  * The current position is the position of the first character of
211a5f0fb15SPaul Saab  * a line.  The new position is the position of the first character
212a5f0fb15SPaul Saab  * of the PREVIOUS line.  The line obtained is the one starting at new_pos.
213a5f0fb15SPaul Saab  */
214a5f0fb15SPaul Saab 	public POSITION
215a5f0fb15SPaul Saab back_line(curr_pos)
216a5f0fb15SPaul Saab 	POSITION curr_pos;
217a5f0fb15SPaul Saab {
218a5f0fb15SPaul Saab 	POSITION new_pos, begin_new_pos;
219a5f0fb15SPaul Saab 	int c;
220a5f0fb15SPaul Saab 	int endline;
2216dcb072bSXin LI 	int backchars;
222a5f0fb15SPaul Saab 
223a5f0fb15SPaul Saab 	if (curr_pos == NULL_POSITION || curr_pos <= ch_zero())
224a5f0fb15SPaul Saab 	{
225a5f0fb15SPaul Saab 		null_line();
226a5f0fb15SPaul Saab 		return (NULL_POSITION);
227a5f0fb15SPaul Saab 	}
228a5f0fb15SPaul Saab #if HILITE_SEARCH
2296dcb072bSXin LI 	if (hilite_search == OPT_ONPLUS || status_col)
230a5f0fb15SPaul Saab 		prep_hilite((curr_pos < 3*size_linebuf) ?
231a5f0fb15SPaul Saab 				0 : curr_pos - 3*size_linebuf, curr_pos, -1);
232a5f0fb15SPaul Saab #endif
233a5f0fb15SPaul Saab 	if (ch_seek(curr_pos-1))
234a5f0fb15SPaul Saab 	{
235a5f0fb15SPaul Saab 		null_line();
236a5f0fb15SPaul Saab 		return (NULL_POSITION);
237a5f0fb15SPaul Saab 	}
238a5f0fb15SPaul Saab 
239a5f0fb15SPaul Saab 	if (squeeze)
240a5f0fb15SPaul Saab 	{
241a5f0fb15SPaul Saab 		/*
242a5f0fb15SPaul Saab 		 * Find out if the "current" line was blank.
243a5f0fb15SPaul Saab 		 */
244a5f0fb15SPaul Saab 		(void) ch_forw_get();	/* Skip the newline */
245a5f0fb15SPaul Saab 		c = ch_forw_get();	/* First char of "current" line */
246a5f0fb15SPaul Saab 		(void) ch_back_get();	/* Restore our position */
247a5f0fb15SPaul Saab 		(void) ch_back_get();
248a5f0fb15SPaul Saab 
249a5f0fb15SPaul Saab 		if (c == '\n' || c == '\r')
250a5f0fb15SPaul Saab 		{
251a5f0fb15SPaul Saab 			/*
252a5f0fb15SPaul Saab 			 * The "current" line was blank.
253a5f0fb15SPaul Saab 			 * Skip over any preceding blank lines,
254a5f0fb15SPaul Saab 			 * since we skipped them in forw_line().
255a5f0fb15SPaul Saab 			 */
256a5f0fb15SPaul Saab 			while ((c = ch_back_get()) == '\n' || c == '\r')
257a5f0fb15SPaul Saab 				if (ABORT_SIGS())
258a5f0fb15SPaul Saab 				{
259a5f0fb15SPaul Saab 					null_line();
260a5f0fb15SPaul Saab 					return (NULL_POSITION);
261a5f0fb15SPaul Saab 				}
262a5f0fb15SPaul Saab 			if (c == EOI)
263a5f0fb15SPaul Saab 			{
264a5f0fb15SPaul Saab 				null_line();
265a5f0fb15SPaul Saab 				return (NULL_POSITION);
266a5f0fb15SPaul Saab 			}
267a5f0fb15SPaul Saab 			(void) ch_forw_get();
268a5f0fb15SPaul Saab 		}
269a5f0fb15SPaul Saab 	}
270a5f0fb15SPaul Saab 
271a5f0fb15SPaul Saab 	/*
272a5f0fb15SPaul Saab 	 * Scan backwards until we hit the beginning of the line.
273a5f0fb15SPaul Saab 	 */
274a5f0fb15SPaul Saab 	for (;;)
275a5f0fb15SPaul Saab 	{
276a5f0fb15SPaul Saab 		if (ABORT_SIGS())
277a5f0fb15SPaul Saab 		{
278a5f0fb15SPaul Saab 			null_line();
279a5f0fb15SPaul Saab 			return (NULL_POSITION);
280a5f0fb15SPaul Saab 		}
281a5f0fb15SPaul Saab 		c = ch_back_get();
282a5f0fb15SPaul Saab 		if (c == '\n')
283a5f0fb15SPaul Saab 		{
284a5f0fb15SPaul Saab 			/*
285a5f0fb15SPaul Saab 			 * This is the newline ending the previous line.
286a5f0fb15SPaul Saab 			 * We have hit the beginning of the line.
287a5f0fb15SPaul Saab 			 */
288a5f0fb15SPaul Saab 			new_pos = ch_tell() + 1;
289a5f0fb15SPaul Saab 			break;
290a5f0fb15SPaul Saab 		}
291a5f0fb15SPaul Saab 		if (c == EOI)
292a5f0fb15SPaul Saab 		{
293a5f0fb15SPaul Saab 			/*
294a5f0fb15SPaul Saab 			 * We have hit the beginning of the file.
295a5f0fb15SPaul Saab 			 * This must be the first line in the file.
296a5f0fb15SPaul Saab 			 * This must, of course, be the beginning of the line.
297a5f0fb15SPaul Saab 			 */
298a5f0fb15SPaul Saab 			new_pos = ch_tell();
299a5f0fb15SPaul Saab 			break;
300a5f0fb15SPaul Saab 		}
301a5f0fb15SPaul Saab 	}
302a5f0fb15SPaul Saab 
303a5f0fb15SPaul Saab 	/*
304a5f0fb15SPaul Saab 	 * Now scan forwards from the beginning of this line.
305a5f0fb15SPaul Saab 	 * We keep discarding "printable lines" (based on screen width)
306a5f0fb15SPaul Saab 	 * until we reach the curr_pos.
307a5f0fb15SPaul Saab 	 *
308a5f0fb15SPaul Saab 	 * {{ This algorithm is pretty inefficient if the lines
309a5f0fb15SPaul Saab 	 *    are much longer than the screen width,
310a5f0fb15SPaul Saab 	 *    but I don't know of any better way. }}
311a5f0fb15SPaul Saab 	 */
312a5f0fb15SPaul Saab 	if (ch_seek(new_pos))
313a5f0fb15SPaul Saab 	{
314a5f0fb15SPaul Saab 		null_line();
315a5f0fb15SPaul Saab 		return (NULL_POSITION);
316a5f0fb15SPaul Saab 	}
317a5f0fb15SPaul Saab 	endline = FALSE;
318a5f0fb15SPaul Saab 	prewind();
319a5f0fb15SPaul Saab 	plinenum(new_pos);
3206dcb072bSXin LI     loop:
3216dcb072bSXin LI 	begin_new_pos = new_pos;
322a5f0fb15SPaul Saab 	(void) ch_seek(new_pos);
323a5f0fb15SPaul Saab 
324a5f0fb15SPaul Saab 	do
325a5f0fb15SPaul Saab 	{
326a5f0fb15SPaul Saab 		c = ch_forw_get();
327a5f0fb15SPaul Saab 		if (c == EOI || ABORT_SIGS())
328a5f0fb15SPaul Saab 		{
329a5f0fb15SPaul Saab 			null_line();
330a5f0fb15SPaul Saab 			return (NULL_POSITION);
331a5f0fb15SPaul Saab 		}
332a5f0fb15SPaul Saab 		new_pos++;
333a5f0fb15SPaul Saab 		if (c == '\n')
334a5f0fb15SPaul Saab 		{
3356dcb072bSXin LI 			backchars = pflushmbc();
3366dcb072bSXin LI 			if (backchars > 0 && !chopline && hshift == 0)
3376dcb072bSXin LI 			{
3386dcb072bSXin LI 				backchars++;
3396dcb072bSXin LI 				goto shift;
3406dcb072bSXin LI 			}
341a5f0fb15SPaul Saab 			endline = TRUE;
342a5f0fb15SPaul Saab 			break;
343a5f0fb15SPaul Saab 		}
3446dcb072bSXin LI 		backchars = pappend(c, ch_tell()-1);
3456dcb072bSXin LI 		if (backchars > 0)
346a5f0fb15SPaul Saab 		{
347a5f0fb15SPaul Saab 			/*
348a5f0fb15SPaul Saab 			 * Got a full printable line, but we haven't
349a5f0fb15SPaul Saab 			 * reached our curr_pos yet.  Discard the line
350a5f0fb15SPaul Saab 			 * and start a new one.
351a5f0fb15SPaul Saab 			 */
3528ed69c6fSPaul Saab 			if (chopline || hshift > 0)
353a5f0fb15SPaul Saab 			{
354a5f0fb15SPaul Saab 				endline = TRUE;
355a5f0fb15SPaul Saab 				quit_if_one_screen = FALSE;
356a5f0fb15SPaul Saab 				break;
357a5f0fb15SPaul Saab 			}
3586dcb072bSXin LI 		shift:
3596dcb072bSXin LI 			pshift_all();
3606dcb072bSXin LI 			while (backchars-- > 0)
3616dcb072bSXin LI 			{
362a5f0fb15SPaul Saab 				(void) ch_back_get();
363a5f0fb15SPaul Saab 				new_pos--;
3646dcb072bSXin LI 			}
365a5f0fb15SPaul Saab 			goto loop;
366a5f0fb15SPaul Saab 		}
367a5f0fb15SPaul Saab 	} while (new_pos < curr_pos);
368a5f0fb15SPaul Saab 
369a5f0fb15SPaul Saab 	pdone(endline);
370a5f0fb15SPaul Saab 
371a5f0fb15SPaul Saab 	return (begin_new_pos);
372a5f0fb15SPaul Saab }
373a5f0fb15SPaul Saab 
374a5f0fb15SPaul Saab /*
375a5f0fb15SPaul Saab  * Set attnpos.
376a5f0fb15SPaul Saab  */
377a5f0fb15SPaul Saab 	public void
378a5f0fb15SPaul Saab set_attnpos(pos)
379a5f0fb15SPaul Saab 	POSITION pos;
380a5f0fb15SPaul Saab {
381a5f0fb15SPaul Saab 	int c;
382a5f0fb15SPaul Saab 
383a5f0fb15SPaul Saab 	if (pos != NULL_POSITION)
384a5f0fb15SPaul Saab 	{
385a5f0fb15SPaul Saab 		if (ch_seek(pos))
386a5f0fb15SPaul Saab 			return;
387a5f0fb15SPaul Saab 		for (;;)
388a5f0fb15SPaul Saab 		{
389a5f0fb15SPaul Saab 			c = ch_forw_get();
390a5f0fb15SPaul Saab 			if (c == EOI)
391a5f0fb15SPaul Saab 				return;
392a5f0fb15SPaul Saab 			if (c != '\n' && c != '\r')
393a5f0fb15SPaul Saab 				break;
394a5f0fb15SPaul Saab 			pos++;
395a5f0fb15SPaul Saab 		}
396a5f0fb15SPaul Saab 	}
397a5f0fb15SPaul Saab 	start_attnpos = pos;
398a5f0fb15SPaul Saab 	for (;;)
399a5f0fb15SPaul Saab 	{
400a5f0fb15SPaul Saab 		c = ch_forw_get();
401a5f0fb15SPaul Saab 		pos++;
402a5f0fb15SPaul Saab 		if (c == EOI || c == '\n' || c == '\r')
403a5f0fb15SPaul Saab 			break;
404a5f0fb15SPaul Saab 	}
405a5f0fb15SPaul Saab 	end_attnpos = pos;
406a5f0fb15SPaul Saab }
407