xref: /freebsd/contrib/less/input.c (revision d713e0891ff9ab8246245c3206851d486ecfdd37)
1a5f0fb15SPaul Saab /*
2*d713e089SXin LI  * Copyright (C) 1984-2023  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  *
796e55cc7SXin LI  * For more information, see the README file.
8a5f0fb15SPaul Saab  */
9a5f0fb15SPaul Saab 
10a5f0fb15SPaul Saab /*
11a5f0fb15SPaul Saab  * High level routines dealing with getting lines of input
12a5f0fb15SPaul Saab  * from the file being viewed.
13a5f0fb15SPaul Saab  *
14a5f0fb15SPaul Saab  * When we speak of "lines" here, we mean PRINTABLE lines;
15a5f0fb15SPaul Saab  * lines processed with respect to the screen width.
16a5f0fb15SPaul Saab  * We use the term "raw line" to refer to lines simply
17a5f0fb15SPaul Saab  * delimited by newlines; not processed with respect to screen width.
18a5f0fb15SPaul Saab  */
19a5f0fb15SPaul Saab 
20a5f0fb15SPaul Saab #include "less.h"
21a5f0fb15SPaul Saab 
22a5f0fb15SPaul Saab extern int squeeze;
238ed69c6fSPaul Saab extern int hshift;
24a5f0fb15SPaul Saab extern int quit_if_one_screen;
25a5f0fb15SPaul Saab extern int sigs;
26a5f0fb15SPaul Saab extern int ignore_eoi;
276dcb072bSXin LI extern int status_col;
28*d713e089SXin LI extern int wordwrap;
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;
342235c7feSXin LI extern int show_attn;
35a5f0fb15SPaul Saab #endif
36a5f0fb15SPaul Saab 
37a5f0fb15SPaul Saab /*
38*d713e089SXin LI  * Set the status column.
39*d713e089SXin LI  *  base  Position of first char in line.
40*d713e089SXin LI  *  disp  First visible char.
41*d713e089SXin LI  *        Different than base_pos if line is shifted.
42*d713e089SXin LI  *  edisp Last visible char.
43*d713e089SXin LI  *  eol   End of line. Normally the newline.
44*d713e089SXin LI  *        Different than edisp if line is chopped.
45*d713e089SXin LI  */
46*d713e089SXin LI static void init_status_col(POSITION base_pos, POSITION disp_pos, POSITION edisp_pos, POSITION eol_pos)
47*d713e089SXin LI {
48*d713e089SXin LI 	int hl_before = (chop_line() && disp_pos != NULL_POSITION) ?
49*d713e089SXin LI 	    is_hilited_attr(base_pos, disp_pos, TRUE, NULL) : 0;
50*d713e089SXin LI 	int hl_after = (chop_line()) ?
51*d713e089SXin LI 	    is_hilited_attr(edisp_pos, eol_pos, TRUE, NULL) : 0;
52*d713e089SXin LI 	int attr;
53*d713e089SXin LI 	char ch;
54*d713e089SXin LI 
55*d713e089SXin LI 	if (hl_before && hl_after)
56*d713e089SXin LI 	{
57*d713e089SXin LI 		attr = hl_after;
58*d713e089SXin LI 		ch = '=';
59*d713e089SXin LI 	} else if (hl_before)
60*d713e089SXin LI 	{
61*d713e089SXin LI 		attr = hl_before;
62*d713e089SXin LI 		ch = '<';
63*d713e089SXin LI 	} else if (hl_after)
64*d713e089SXin LI 	{
65*d713e089SXin LI 		attr = hl_after;
66*d713e089SXin LI 		ch = '>';
67*d713e089SXin LI 	} else
68*d713e089SXin LI 	{
69*d713e089SXin LI 		attr = is_hilited_attr(base_pos, eol_pos, TRUE, NULL);
70*d713e089SXin LI 		ch = '*';
71*d713e089SXin LI 	}
72*d713e089SXin LI 	if (attr)
73*d713e089SXin LI 		set_status_col(ch, attr);
74*d713e089SXin LI }
75*d713e089SXin LI 
76*d713e089SXin LI /*
77a5f0fb15SPaul Saab  * Get the next line.
78a5f0fb15SPaul Saab  * A "current" position is passed and a "new" position is returned.
79a5f0fb15SPaul Saab  * The current position is the position of the first character of
80a5f0fb15SPaul Saab  * a line.  The new position is the position of the first character
81a5f0fb15SPaul Saab  * of the NEXT line.  The line obtained is the line starting at curr_pos.
82a5f0fb15SPaul Saab  */
83*d713e089SXin LI public POSITION forw_line_seg(POSITION curr_pos, int skipeol, int rscroll, int nochop)
84a5f0fb15SPaul Saab {
856dcb072bSXin LI 	POSITION base_pos;
86a5f0fb15SPaul Saab 	POSITION new_pos;
87*d713e089SXin LI 	POSITION edisp_pos;
881ea31627SRobert Watson 	int c;
89a5f0fb15SPaul Saab 	int blankline;
90a5f0fb15SPaul Saab 	int endline;
91b2ea2440SXin LI 	int chopped;
926dcb072bSXin LI 	int backchars;
93*d713e089SXin LI 	POSITION wrap_pos;
94*d713e089SXin LI 	int skipped_leading;
95a5f0fb15SPaul Saab 
967374caaaSXin LI get_forw_line:
97a5f0fb15SPaul Saab 	if (curr_pos == NULL_POSITION)
98a5f0fb15SPaul Saab 	{
99a5f0fb15SPaul Saab 		null_line();
100a5f0fb15SPaul Saab 		return (NULL_POSITION);
101a5f0fb15SPaul Saab 	}
102a5f0fb15SPaul Saab #if HILITE_SEARCH
1037374caaaSXin LI 	if (hilite_search == OPT_ONPLUS || is_filtering() || status_col)
104a15691bfSXin LI 	{
105a5f0fb15SPaul Saab 		/*
106a5f0fb15SPaul Saab 		 * If we are ignoring EOI (command F), only prepare
107a5f0fb15SPaul Saab 		 * one line ahead, to avoid getting stuck waiting for
108a5f0fb15SPaul Saab 		 * slow data without displaying the data we already have.
109a5f0fb15SPaul Saab 		 * If we're not ignoring EOI, we *could* do the same, but
110a5f0fb15SPaul Saab 		 * for efficiency we prepare several lines ahead at once.
111a5f0fb15SPaul Saab 		 */
112a5f0fb15SPaul Saab 		prep_hilite(curr_pos, curr_pos + 3*size_linebuf,
113a5f0fb15SPaul Saab 				ignore_eoi ? 1 : -1);
114a15691bfSXin LI 		curr_pos = next_unfiltered(curr_pos);
115a15691bfSXin LI 	}
116a5f0fb15SPaul Saab #endif
117a5f0fb15SPaul Saab 	if (ch_seek(curr_pos))
118a5f0fb15SPaul Saab 	{
119a5f0fb15SPaul Saab 		null_line();
120a5f0fb15SPaul Saab 		return (NULL_POSITION);
121a5f0fb15SPaul Saab 	}
122a5f0fb15SPaul Saab 
1237374caaaSXin LI 	/*
1247374caaaSXin LI 	 * Step back to the beginning of the line.
1257374caaaSXin LI 	 */
1266dcb072bSXin LI 	base_pos = curr_pos;
1276dcb072bSXin LI 	for (;;)
1286dcb072bSXin LI 	{
1296dcb072bSXin LI 		if (ABORT_SIGS())
1306dcb072bSXin LI 		{
1316dcb072bSXin LI 			null_line();
1326dcb072bSXin LI 			return (NULL_POSITION);
1336dcb072bSXin LI 		}
1346dcb072bSXin LI 		c = ch_back_get();
1356dcb072bSXin LI 		if (c == EOI)
1366dcb072bSXin LI 			break;
1376dcb072bSXin LI 		if (c == '\n')
1386dcb072bSXin LI 		{
1396dcb072bSXin LI 			(void) ch_forw_get();
1406dcb072bSXin LI 			break;
1416dcb072bSXin LI 		}
1426dcb072bSXin LI 		--base_pos;
1436dcb072bSXin LI 	}
1446dcb072bSXin LI 
1457374caaaSXin LI 	/*
1467374caaaSXin LI 	 * Read forward again to the position we should start at.
1477374caaaSXin LI 	 */
148a5f0fb15SPaul Saab 	prewind();
1492235c7feSXin LI 	plinestart(base_pos);
1506dcb072bSXin LI 	(void) ch_seek(base_pos);
1517374caaaSXin LI 	new_pos = base_pos;
1527374caaaSXin LI 	while (new_pos < curr_pos)
1536dcb072bSXin LI 	{
1546dcb072bSXin LI 		if (ABORT_SIGS())
1556dcb072bSXin LI 		{
1566dcb072bSXin LI 			null_line();
1576dcb072bSXin LI 			return (NULL_POSITION);
1586dcb072bSXin LI 		}
1596dcb072bSXin LI 		c = ch_forw_get();
1607374caaaSXin LI 		backchars = pappend(c, new_pos);
1617374caaaSXin LI 		new_pos++;
1626dcb072bSXin LI 		if (backchars > 0)
1636dcb072bSXin LI 		{
1646dcb072bSXin LI 			pshift_all();
165*d713e089SXin LI 			if (wordwrap && (c == ' ' || c == '\t'))
166*d713e089SXin LI 			{
167*d713e089SXin LI 				do
168*d713e089SXin LI 				{
169*d713e089SXin LI 					new_pos++;
170*d713e089SXin LI 					c = ch_forw_get();
171*d713e089SXin LI 				} while (c == ' ' || c == '\t');
172*d713e089SXin LI 				backchars = 1;
173*d713e089SXin LI 			}
1747374caaaSXin LI 			new_pos -= backchars;
1756dcb072bSXin LI 			while (--backchars >= 0)
1766dcb072bSXin LI 				(void) ch_back_get();
1776dcb072bSXin LI 		}
1786dcb072bSXin LI 	}
1796dcb072bSXin LI 	(void) pflushmbc();
1806dcb072bSXin LI 	pshift_all();
181a5f0fb15SPaul Saab 
1827374caaaSXin LI 	/*
1837374caaaSXin LI 	 * Read the first character to display.
1847374caaaSXin LI 	 */
185a5f0fb15SPaul Saab 	c = ch_forw_get();
186a5f0fb15SPaul Saab 	if (c == EOI)
187a5f0fb15SPaul Saab 	{
188a5f0fb15SPaul Saab 		null_line();
189a5f0fb15SPaul Saab 		return (NULL_POSITION);
190a5f0fb15SPaul Saab 	}
191a5f0fb15SPaul Saab 	blankline = (c == '\n' || c == '\r');
192*d713e089SXin LI 	wrap_pos = NULL_POSITION;
193*d713e089SXin LI 	skipped_leading = FALSE;
194a5f0fb15SPaul Saab 
1957374caaaSXin LI 	/*
1967374caaaSXin LI 	 * Read each character in the line and append to the line buffer.
1977374caaaSXin LI 	 */
198b2ea2440SXin LI 	chopped = FALSE;
199a5f0fb15SPaul Saab 	for (;;)
200a5f0fb15SPaul Saab 	{
201a5f0fb15SPaul Saab 		if (ABORT_SIGS())
202a5f0fb15SPaul Saab 		{
203a5f0fb15SPaul Saab 			null_line();
204a5f0fb15SPaul Saab 			return (NULL_POSITION);
205a5f0fb15SPaul Saab 		}
206a5f0fb15SPaul Saab 		if (c == '\n' || c == EOI)
207a5f0fb15SPaul Saab 		{
208a5f0fb15SPaul Saab 			/*
209a5f0fb15SPaul Saab 			 * End of the line.
210a5f0fb15SPaul Saab 			 */
2116dcb072bSXin LI 			backchars = pflushmbc();
212a5f0fb15SPaul Saab 			new_pos = ch_tell();
21395270f73SXin LI 			if (backchars > 0 && (nochop || !chop_line()) && hshift == 0)
2146dcb072bSXin LI 			{
2156dcb072bSXin LI 				new_pos -= backchars + 1;
2166dcb072bSXin LI 				endline = FALSE;
2176dcb072bSXin LI 			} else
218a5f0fb15SPaul Saab 				endline = TRUE;
219*d713e089SXin LI 			edisp_pos = new_pos;
220a5f0fb15SPaul Saab 			break;
221a5f0fb15SPaul Saab 		}
2226dcb072bSXin LI 		if (c != '\r')
2236dcb072bSXin LI 			blankline = 0;
224a5f0fb15SPaul Saab 
225a5f0fb15SPaul Saab 		/*
226a5f0fb15SPaul Saab 		 * Append the char to the line and get the next char.
227a5f0fb15SPaul Saab 		 */
2286dcb072bSXin LI 		backchars = pappend(c, ch_tell()-1);
2296dcb072bSXin LI 		if (backchars > 0)
230a5f0fb15SPaul Saab 		{
231a5f0fb15SPaul Saab 			/*
232a5f0fb15SPaul Saab 			 * The char won't fit in the line; the line
233a5f0fb15SPaul Saab 			 * is too long to print in the screen width.
234a5f0fb15SPaul Saab 			 * End the line here.
235a5f0fb15SPaul Saab 			 */
23695270f73SXin LI 			if (skipeol)
237a5f0fb15SPaul Saab 			{
2382235c7feSXin LI 				/* Read to end of line. */
239*d713e089SXin LI 				edisp_pos = ch_tell();
240a5f0fb15SPaul Saab 				do
241a5f0fb15SPaul Saab 				{
24233096f16SXin LI 					if (ABORT_SIGS())
24333096f16SXin LI 					{
24433096f16SXin LI 						null_line();
24533096f16SXin LI 						return (NULL_POSITION);
24633096f16SXin LI 					}
247a5f0fb15SPaul Saab 					c = ch_forw_get();
248a5f0fb15SPaul Saab 				} while (c != '\n' && c != EOI);
249a5f0fb15SPaul Saab 				new_pos = ch_tell();
250a5f0fb15SPaul Saab 				endline = TRUE;
251a5f0fb15SPaul Saab 				quit_if_one_screen = FALSE;
252b2ea2440SXin LI 				chopped = TRUE;
253a5f0fb15SPaul Saab 			} else
254a5f0fb15SPaul Saab 			{
255*d713e089SXin LI 				if (!wordwrap)
2566dcb072bSXin LI 					new_pos = ch_tell() - backchars;
257*d713e089SXin LI 				else
258*d713e089SXin LI 				{
259*d713e089SXin LI 					/*
260*d713e089SXin LI 					 * We're word-wrapping, so go back to the last space.
261*d713e089SXin LI 					 * However, if it's the space itself that couldn't fit,
262*d713e089SXin LI 					 * simply ignore it and any subsequent spaces.
263*d713e089SXin LI 					 */
264*d713e089SXin LI 					if (c == ' ' || c == '\t')
265*d713e089SXin LI 					{
266*d713e089SXin LI 						do
267*d713e089SXin LI 						{
268*d713e089SXin LI 							new_pos = ch_tell();
269*d713e089SXin LI 							c = ch_forw_get();
270*d713e089SXin LI 						} while (c == ' ' || c == '\t');
271*d713e089SXin LI 						if (c == '\r')
272*d713e089SXin LI 							c = ch_forw_get();
273*d713e089SXin LI 						if (c == '\n')
274*d713e089SXin LI 							new_pos = ch_tell();
275*d713e089SXin LI 					} else if (wrap_pos == NULL_POSITION)
276*d713e089SXin LI 						new_pos = ch_tell() - backchars;
277*d713e089SXin LI 					else
278*d713e089SXin LI 					{
279*d713e089SXin LI 						new_pos = wrap_pos;
280*d713e089SXin LI 						loadc();
281*d713e089SXin LI 					}
282*d713e089SXin LI 				}
283a5f0fb15SPaul Saab 				endline = FALSE;
284a5f0fb15SPaul Saab 			}
285a5f0fb15SPaul Saab 			break;
286a5f0fb15SPaul Saab 		}
287*d713e089SXin LI 		if (wordwrap)
288*d713e089SXin LI 		{
289*d713e089SXin LI 			if (c == ' ' || c == '\t')
290*d713e089SXin LI 			{
291*d713e089SXin LI 				if (skipped_leading)
292*d713e089SXin LI 				{
293*d713e089SXin LI 					wrap_pos = ch_tell();
294*d713e089SXin LI 					savec();
295*d713e089SXin LI 				}
296*d713e089SXin LI 			} else
297*d713e089SXin LI 				skipped_leading = TRUE;
298*d713e089SXin LI 		}
299a5f0fb15SPaul Saab 		c = ch_forw_get();
300a5f0fb15SPaul Saab 	}
3017374caaaSXin LI 
3022235c7feSXin LI #if HILITE_SEARCH
3032235c7feSXin LI 	if (blankline && show_attn)
3042235c7feSXin LI 	{
3052235c7feSXin LI 		/* Add spurious space to carry possible attn hilite. */
3062235c7feSXin LI 		pappend(' ', ch_tell()-1);
3072235c7feSXin LI 	}
3082235c7feSXin LI #endif
30995270f73SXin LI 	pdone(endline, rscroll && chopped, 1);
3107374caaaSXin LI 
3117374caaaSXin LI #if HILITE_SEARCH
3127374caaaSXin LI 	if (is_filtered(base_pos))
3137374caaaSXin LI 	{
3147374caaaSXin LI 		/*
3157374caaaSXin LI 		 * We don't want to display this line.
3167374caaaSXin LI 		 * Get the next line.
3177374caaaSXin LI 		 */
3187374caaaSXin LI 		curr_pos = new_pos;
3197374caaaSXin LI 		goto get_forw_line;
3207374caaaSXin LI 	}
3212235c7feSXin LI 	if (status_col)
322*d713e089SXin LI 		init_status_col(base_pos, line_position(), edisp_pos, new_pos);
3237374caaaSXin LI #endif
324a5f0fb15SPaul Saab 
325a5f0fb15SPaul Saab 	if (squeeze && blankline)
326a5f0fb15SPaul Saab 	{
327a5f0fb15SPaul Saab 		/*
328a5f0fb15SPaul Saab 		 * This line is blank.
329a5f0fb15SPaul Saab 		 * Skip down to the last contiguous blank line
330a5f0fb15SPaul Saab 		 * and pretend it is the one which we are returning.
331a5f0fb15SPaul Saab 		 */
332a5f0fb15SPaul Saab 		while ((c = ch_forw_get()) == '\n' || c == '\r')
333a5f0fb15SPaul Saab 			if (ABORT_SIGS())
334a5f0fb15SPaul Saab 			{
335a5f0fb15SPaul Saab 				null_line();
336a5f0fb15SPaul Saab 				return (NULL_POSITION);
337a5f0fb15SPaul Saab 			}
338a5f0fb15SPaul Saab 		if (c != EOI)
339a5f0fb15SPaul Saab 			(void) ch_back_get();
340a5f0fb15SPaul Saab 		new_pos = ch_tell();
341a5f0fb15SPaul Saab 	}
342a5f0fb15SPaul Saab 
343a5f0fb15SPaul Saab 	return (new_pos);
344a5f0fb15SPaul Saab }
345a5f0fb15SPaul Saab 
346*d713e089SXin LI public POSITION forw_line(POSITION curr_pos)
3472235c7feSXin LI {
34895270f73SXin LI 
34995270f73SXin LI 	return forw_line_seg(curr_pos, (chop_line() || hshift > 0), TRUE, FALSE);
3502235c7feSXin LI }
3512235c7feSXin LI 
352a5f0fb15SPaul Saab /*
353a5f0fb15SPaul Saab  * Get the previous line.
354a5f0fb15SPaul Saab  * A "current" position is passed and a "new" position is returned.
355a5f0fb15SPaul Saab  * The current position is the position of the first character of
356a5f0fb15SPaul Saab  * a line.  The new position is the position of the first character
357a5f0fb15SPaul Saab  * of the PREVIOUS line.  The line obtained is the one starting at new_pos.
358a5f0fb15SPaul Saab  */
359*d713e089SXin LI public POSITION back_line(POSITION curr_pos)
360a5f0fb15SPaul Saab {
361*d713e089SXin LI 	POSITION base_pos;
362*d713e089SXin LI 	POSITION new_pos;
363*d713e089SXin LI 	POSITION edisp_pos;
364*d713e089SXin LI 	POSITION begin_new_pos;
365a5f0fb15SPaul Saab 	int c;
366a5f0fb15SPaul Saab 	int endline;
367b2ea2440SXin LI 	int chopped;
3686dcb072bSXin LI 	int backchars;
369*d713e089SXin LI 	POSITION wrap_pos;
370*d713e089SXin LI 	int skipped_leading;
371a5f0fb15SPaul Saab 
3727374caaaSXin LI get_back_line:
373a5f0fb15SPaul Saab 	if (curr_pos == NULL_POSITION || curr_pos <= ch_zero())
374a5f0fb15SPaul Saab 	{
375a5f0fb15SPaul Saab 		null_line();
376a5f0fb15SPaul Saab 		return (NULL_POSITION);
377a5f0fb15SPaul Saab 	}
378a5f0fb15SPaul Saab #if HILITE_SEARCH
3797374caaaSXin LI 	if (hilite_search == OPT_ONPLUS || is_filtering() || status_col)
380a5f0fb15SPaul Saab 		prep_hilite((curr_pos < 3*size_linebuf) ?
381a5f0fb15SPaul Saab 				0 : curr_pos - 3*size_linebuf, curr_pos, -1);
382a5f0fb15SPaul Saab #endif
383a5f0fb15SPaul Saab 	if (ch_seek(curr_pos-1))
384a5f0fb15SPaul Saab 	{
385a5f0fb15SPaul Saab 		null_line();
386a5f0fb15SPaul Saab 		return (NULL_POSITION);
387a5f0fb15SPaul Saab 	}
388a5f0fb15SPaul Saab 
389a5f0fb15SPaul Saab 	if (squeeze)
390a5f0fb15SPaul Saab 	{
391a5f0fb15SPaul Saab 		/*
392a5f0fb15SPaul Saab 		 * Find out if the "current" line was blank.
393a5f0fb15SPaul Saab 		 */
394a5f0fb15SPaul Saab 		(void) ch_forw_get();    /* Skip the newline */
395a5f0fb15SPaul Saab 		c = ch_forw_get();       /* First char of "current" line */
396a5f0fb15SPaul Saab 		(void) ch_back_get();    /* Restore our position */
397a5f0fb15SPaul Saab 		(void) ch_back_get();
398a5f0fb15SPaul Saab 
399a5f0fb15SPaul Saab 		if (c == '\n' || c == '\r')
400a5f0fb15SPaul Saab 		{
401a5f0fb15SPaul Saab 			/*
402a5f0fb15SPaul Saab 			 * The "current" line was blank.
403a5f0fb15SPaul Saab 			 * Skip over any preceding blank lines,
404a5f0fb15SPaul Saab 			 * since we skipped them in forw_line().
405a5f0fb15SPaul Saab 			 */
406a5f0fb15SPaul Saab 			while ((c = ch_back_get()) == '\n' || c == '\r')
407a5f0fb15SPaul Saab 				if (ABORT_SIGS())
408a5f0fb15SPaul Saab 				{
409a5f0fb15SPaul Saab 					null_line();
410a5f0fb15SPaul Saab 					return (NULL_POSITION);
411a5f0fb15SPaul Saab 				}
412a5f0fb15SPaul Saab 			if (c == EOI)
413a5f0fb15SPaul Saab 			{
414a5f0fb15SPaul Saab 				null_line();
415a5f0fb15SPaul Saab 				return (NULL_POSITION);
416a5f0fb15SPaul Saab 			}
417a5f0fb15SPaul Saab 			(void) ch_forw_get();
418a5f0fb15SPaul Saab 		}
419a5f0fb15SPaul Saab 	}
420a5f0fb15SPaul Saab 
421a5f0fb15SPaul Saab 	/*
422a5f0fb15SPaul Saab 	 * Scan backwards until we hit the beginning of the line.
423a5f0fb15SPaul Saab 	 */
424a5f0fb15SPaul Saab 	for (;;)
425a5f0fb15SPaul Saab 	{
426a5f0fb15SPaul Saab 		if (ABORT_SIGS())
427a5f0fb15SPaul Saab 		{
428a5f0fb15SPaul Saab 			null_line();
429a5f0fb15SPaul Saab 			return (NULL_POSITION);
430a5f0fb15SPaul Saab 		}
431a5f0fb15SPaul Saab 		c = ch_back_get();
432a5f0fb15SPaul Saab 		if (c == '\n')
433a5f0fb15SPaul Saab 		{
434a5f0fb15SPaul Saab 			/*
435a5f0fb15SPaul Saab 			 * This is the newline ending the previous line.
436a5f0fb15SPaul Saab 			 * We have hit the beginning of the line.
437a5f0fb15SPaul Saab 			 */
4387374caaaSXin LI 			base_pos = ch_tell() + 1;
439a5f0fb15SPaul Saab 			break;
440a5f0fb15SPaul Saab 		}
441a5f0fb15SPaul Saab 		if (c == EOI)
442a5f0fb15SPaul Saab 		{
443a5f0fb15SPaul Saab 			/*
444a5f0fb15SPaul Saab 			 * We have hit the beginning of the file.
445a5f0fb15SPaul Saab 			 * This must be the first line in the file.
446a5f0fb15SPaul Saab 			 * This must, of course, be the beginning of the line.
447a5f0fb15SPaul Saab 			 */
4487374caaaSXin LI 			base_pos = ch_tell();
449a5f0fb15SPaul Saab 			break;
450a5f0fb15SPaul Saab 		}
451a5f0fb15SPaul Saab 	}
452a5f0fb15SPaul Saab 
453a5f0fb15SPaul Saab 	/*
454a5f0fb15SPaul Saab 	 * Now scan forwards from the beginning of this line.
455a5f0fb15SPaul Saab 	 * We keep discarding "printable lines" (based on screen width)
456a5f0fb15SPaul Saab 	 * until we reach the curr_pos.
457a5f0fb15SPaul Saab 	 *
458a5f0fb15SPaul Saab 	 * {{ This algorithm is pretty inefficient if the lines
459a5f0fb15SPaul Saab 	 *    are much longer than the screen width,
460a5f0fb15SPaul Saab 	 *    but I don't know of any better way. }}
461a5f0fb15SPaul Saab 	 */
4627374caaaSXin LI 	new_pos = base_pos;
463a5f0fb15SPaul Saab 	if (ch_seek(new_pos))
464a5f0fb15SPaul Saab 	{
465a5f0fb15SPaul Saab 		null_line();
466a5f0fb15SPaul Saab 		return (NULL_POSITION);
467a5f0fb15SPaul Saab 	}
468a5f0fb15SPaul Saab 	endline = FALSE;
469a5f0fb15SPaul Saab 	prewind();
4702235c7feSXin LI 	plinestart(new_pos);
4716dcb072bSXin LI     loop:
472*d713e089SXin LI 	wrap_pos = NULL_POSITION;
473*d713e089SXin LI 	skipped_leading = FALSE;
4746dcb072bSXin LI 	begin_new_pos = new_pos;
475a5f0fb15SPaul Saab 	(void) ch_seek(new_pos);
476b2ea2440SXin LI 	chopped = FALSE;
477a5f0fb15SPaul Saab 
478*d713e089SXin LI 	for (;;)
479a5f0fb15SPaul Saab 	{
480a5f0fb15SPaul Saab 		c = ch_forw_get();
481a5f0fb15SPaul Saab 		if (c == EOI || ABORT_SIGS())
482a5f0fb15SPaul Saab 		{
483a5f0fb15SPaul Saab 			null_line();
484a5f0fb15SPaul Saab 			return (NULL_POSITION);
485a5f0fb15SPaul Saab 		}
486a5f0fb15SPaul Saab 		new_pos++;
487a5f0fb15SPaul Saab 		if (c == '\n')
488a5f0fb15SPaul Saab 		{
4896dcb072bSXin LI 			backchars = pflushmbc();
49095270f73SXin LI 			if (backchars > 0 && !chop_line() && hshift == 0)
4916dcb072bSXin LI 			{
4926dcb072bSXin LI 				backchars++;
4936dcb072bSXin LI 				goto shift;
4946dcb072bSXin LI 			}
495a5f0fb15SPaul Saab 			endline = TRUE;
496*d713e089SXin LI 			edisp_pos = new_pos;
497a5f0fb15SPaul Saab 			break;
498a5f0fb15SPaul Saab 		}
4996dcb072bSXin LI 		backchars = pappend(c, ch_tell()-1);
5006dcb072bSXin LI 		if (backchars > 0)
501a5f0fb15SPaul Saab 		{
502a5f0fb15SPaul Saab 			/*
503a5f0fb15SPaul Saab 			 * Got a full printable line, but we haven't
504a5f0fb15SPaul Saab 			 * reached our curr_pos yet.  Discard the line
505a5f0fb15SPaul Saab 			 * and start a new one.
506a5f0fb15SPaul Saab 			 */
50795270f73SXin LI 			if (chop_line() || hshift > 0)
508a5f0fb15SPaul Saab 			{
509a5f0fb15SPaul Saab 				endline = TRUE;
510b2ea2440SXin LI 				chopped = TRUE;
511a5f0fb15SPaul Saab 				quit_if_one_screen = FALSE;
512*d713e089SXin LI 				edisp_pos = new_pos;
513a5f0fb15SPaul Saab 				break;
514a5f0fb15SPaul Saab 			}
5156dcb072bSXin LI 		shift:
516*d713e089SXin LI 			if (!wordwrap)
5176dcb072bSXin LI 			{
518*d713e089SXin LI 				pshift_all();
519*d713e089SXin LI 				new_pos -= backchars;
520*d713e089SXin LI 			} else
521*d713e089SXin LI 			{
522*d713e089SXin LI 				if (c == ' ' || c == '\t')
523*d713e089SXin LI 				{
524*d713e089SXin LI 					for (;;)
525*d713e089SXin LI 					{
526*d713e089SXin LI 						c = ch_forw_get();
527*d713e089SXin LI 						if (c == ' ' || c == '\t')
528*d713e089SXin LI 							new_pos++;
529*d713e089SXin LI 						else
530*d713e089SXin LI 						{
531*d713e089SXin LI 							if (c == '\r')
532*d713e089SXin LI 							{
533*d713e089SXin LI 								c = ch_forw_get();
534*d713e089SXin LI 								if (c == '\n')
535*d713e089SXin LI 									new_pos++;
536*d713e089SXin LI 							}
537*d713e089SXin LI 							if (c == '\n')
538*d713e089SXin LI 								new_pos++;
539*d713e089SXin LI 							break;
540*d713e089SXin LI 						}
541*d713e089SXin LI 					}
542*d713e089SXin LI 					if (new_pos >= curr_pos)
543*d713e089SXin LI 						break;
544*d713e089SXin LI 					pshift_all();
545*d713e089SXin LI 				} else
546*d713e089SXin LI 				{
547*d713e089SXin LI 					pshift_all();
548*d713e089SXin LI 					if (wrap_pos == NULL_POSITION)
549*d713e089SXin LI 						new_pos -= backchars;
550*d713e089SXin LI 					else
551*d713e089SXin LI 						new_pos = wrap_pos;
552*d713e089SXin LI 				}
5536dcb072bSXin LI 			}
554a5f0fb15SPaul Saab 			goto loop;
555a5f0fb15SPaul Saab 		}
556*d713e089SXin LI 		if (wordwrap)
557*d713e089SXin LI 		{
558*d713e089SXin LI 			if (c == ' ' || c == '\t')
559*d713e089SXin LI 			{
560*d713e089SXin LI 				if (skipped_leading)
561*d713e089SXin LI 					wrap_pos = new_pos;
562*d713e089SXin LI 			} else
563*d713e089SXin LI 				skipped_leading = TRUE;
564*d713e089SXin LI 		}
565*d713e089SXin LI 		if (new_pos >= curr_pos)
566*d713e089SXin LI 		{
567*d713e089SXin LI 			edisp_pos = new_pos;
568*d713e089SXin LI 			break;
569*d713e089SXin LI 		}
570*d713e089SXin LI 	}
571a5f0fb15SPaul Saab 
572b2ea2440SXin LI 	pdone(endline, chopped, 0);
5737374caaaSXin LI 
5747374caaaSXin LI #if HILITE_SEARCH
5757374caaaSXin LI 	if (is_filtered(base_pos))
5767374caaaSXin LI 	{
5777374caaaSXin LI 		/*
5787374caaaSXin LI 		 * We don't want to display this line.
5797374caaaSXin LI 		 * Get the previous line.
5807374caaaSXin LI 		 */
5817374caaaSXin LI 		curr_pos = begin_new_pos;
5827374caaaSXin LI 		goto get_back_line;
5837374caaaSXin LI 	}
584*d713e089SXin LI 	if (status_col)
585*d713e089SXin LI 		init_status_col(base_pos, line_position(), edisp_pos, new_pos);
5867374caaaSXin LI #endif
587a5f0fb15SPaul Saab 
588a5f0fb15SPaul Saab 	return (begin_new_pos);
589a5f0fb15SPaul Saab }
590a5f0fb15SPaul Saab 
591a5f0fb15SPaul Saab /*
592a5f0fb15SPaul Saab  * Set attnpos.
593a5f0fb15SPaul Saab  */
594*d713e089SXin LI public void set_attnpos(POSITION pos)
595a5f0fb15SPaul Saab {
596a5f0fb15SPaul Saab 	int c;
597a5f0fb15SPaul Saab 
598a5f0fb15SPaul Saab 	if (pos != NULL_POSITION)
599a5f0fb15SPaul Saab 	{
600a5f0fb15SPaul Saab 		if (ch_seek(pos))
601a5f0fb15SPaul Saab 			return;
602a5f0fb15SPaul Saab 		for (;;)
603a5f0fb15SPaul Saab 		{
604a5f0fb15SPaul Saab 			c = ch_forw_get();
605a5f0fb15SPaul Saab 			if (c == EOI)
606a5f0fb15SPaul Saab 				break;
607a15691bfSXin LI 			if (c == '\n' || c == '\r')
608a15691bfSXin LI 			{
609a15691bfSXin LI 				(void) ch_back_get();
610a15691bfSXin LI 				break;
611a15691bfSXin LI 			}
612a5f0fb15SPaul Saab 			pos++;
613a5f0fb15SPaul Saab 		}
614a15691bfSXin LI 		end_attnpos = pos;
615a15691bfSXin LI 		for (;;)
616a15691bfSXin LI 		{
617a15691bfSXin LI 			c = ch_back_get();
618a15691bfSXin LI 			if (c == EOI || c == '\n' || c == '\r')
619a15691bfSXin LI 				break;
620a15691bfSXin LI 			pos--;
621a15691bfSXin LI 		}
622a5f0fb15SPaul Saab 	}
623a5f0fb15SPaul Saab 	start_attnpos = pos;
624a5f0fb15SPaul Saab }
625