xref: /freebsd/contrib/less/input.c (revision c77c488926555ca344ae3a417544cf7a720e1de1)
1a5f0fb15SPaul Saab /*
2*c77c4889SXin LI  * Copyright (C) 1984-2024  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 ignore_eoi;
266dcb072bSXin LI extern int status_col;
27d713e089SXin LI extern int wordwrap;
28a5f0fb15SPaul Saab extern POSITION start_attnpos;
29a5f0fb15SPaul Saab extern POSITION end_attnpos;
30a5f0fb15SPaul Saab #if HILITE_SEARCH
31a5f0fb15SPaul Saab extern int hilite_search;
32*c77c4889SXin LI extern size_t size_linebuf;
332235c7feSXin LI extern int show_attn;
34a5f0fb15SPaul Saab #endif
35a5f0fb15SPaul Saab 
36a5f0fb15SPaul Saab /*
37d713e089SXin LI  * Set the status column.
38d713e089SXin LI  *  base  Position of first char in line.
39d713e089SXin LI  *  disp  First visible char.
40d713e089SXin LI  *        Different than base_pos if line is shifted.
41d713e089SXin LI  *  edisp Last visible char.
42d713e089SXin LI  *  eol   End of line. Normally the newline.
43d713e089SXin LI  *        Different than edisp if line is chopped.
44d713e089SXin LI  */
45d713e089SXin LI static void init_status_col(POSITION base_pos, POSITION disp_pos, POSITION edisp_pos, POSITION eol_pos)
46d713e089SXin LI {
47d713e089SXin LI 	int hl_before = (chop_line() && disp_pos != NULL_POSITION) ?
48d713e089SXin LI 	    is_hilited_attr(base_pos, disp_pos, TRUE, NULL) : 0;
49*c77c4889SXin LI 	int hl_after = (chop_line() && edisp_pos != NULL_POSITION) ?
50d713e089SXin LI 	    is_hilited_attr(edisp_pos, eol_pos, TRUE, NULL) : 0;
51d713e089SXin LI 	int attr;
52d713e089SXin LI 	char ch;
53d713e089SXin LI 
54d713e089SXin LI 	if (hl_before && hl_after)
55d713e089SXin LI 	{
56d713e089SXin LI 		attr = hl_after;
57d713e089SXin LI 		ch = '=';
58d713e089SXin LI 	} else if (hl_before)
59d713e089SXin LI 	{
60d713e089SXin LI 		attr = hl_before;
61d713e089SXin LI 		ch = '<';
62d713e089SXin LI 	} else if (hl_after)
63d713e089SXin LI 	{
64d713e089SXin LI 		attr = hl_after;
65d713e089SXin LI 		ch = '>';
66*c77c4889SXin LI 	} else if (disp_pos != NULL_POSITION)
67*c77c4889SXin LI 	{
68*c77c4889SXin LI 		attr = is_hilited_attr(disp_pos, edisp_pos, TRUE, NULL);
69*c77c4889SXin LI 		ch = '*';
70d713e089SXin LI 	} else
71d713e089SXin LI     {
72*c77c4889SXin LI         attr = 0;
73d713e089SXin LI     }
74d713e089SXin LI 	if (attr)
75d713e089SXin LI 		set_status_col(ch, attr);
76d713e089SXin LI }
77d713e089SXin LI 
78d713e089SXin LI /*
79a5f0fb15SPaul Saab  * Get the next line.
80a5f0fb15SPaul Saab  * A "current" position is passed and a "new" position is returned.
81a5f0fb15SPaul Saab  * The current position is the position of the first character of
82a5f0fb15SPaul Saab  * a line.  The new position is the position of the first character
83a5f0fb15SPaul Saab  * of the NEXT line.  The line obtained is the line starting at curr_pos.
84a5f0fb15SPaul Saab  */
85*c77c4889SXin LI public POSITION forw_line_seg(POSITION curr_pos, lbool skipeol, lbool rscroll, lbool nochop)
86a5f0fb15SPaul Saab {
876dcb072bSXin LI 	POSITION base_pos;
88a5f0fb15SPaul Saab 	POSITION new_pos;
89d713e089SXin LI 	POSITION edisp_pos;
901ea31627SRobert Watson 	int c;
91*c77c4889SXin LI 	lbool blankline;
92*c77c4889SXin LI 	lbool endline;
93*c77c4889SXin LI 	lbool chopped;
946dcb072bSXin LI 	int backchars;
95d713e089SXin LI 	POSITION wrap_pos;
96*c77c4889SXin LI 	lbool skipped_leading;
97a5f0fb15SPaul Saab 
987374caaaSXin LI get_forw_line:
99a5f0fb15SPaul Saab 	if (curr_pos == NULL_POSITION)
100a5f0fb15SPaul Saab 	{
101a5f0fb15SPaul Saab 		null_line();
102a5f0fb15SPaul Saab 		return (NULL_POSITION);
103a5f0fb15SPaul Saab 	}
104a5f0fb15SPaul Saab #if HILITE_SEARCH
1057374caaaSXin LI 	if (hilite_search == OPT_ONPLUS || is_filtering() || status_col)
106a15691bfSXin LI 	{
107a5f0fb15SPaul Saab 		/*
108a5f0fb15SPaul Saab 		 * If we are ignoring EOI (command F), only prepare
109a5f0fb15SPaul Saab 		 * one line ahead, to avoid getting stuck waiting for
110a5f0fb15SPaul Saab 		 * slow data without displaying the data we already have.
111a5f0fb15SPaul Saab 		 * If we're not ignoring EOI, we *could* do the same, but
112a5f0fb15SPaul Saab 		 * for efficiency we prepare several lines ahead at once.
113a5f0fb15SPaul Saab 		 */
114*c77c4889SXin LI 		prep_hilite(curr_pos, curr_pos + (POSITION) (3*size_linebuf), ignore_eoi ? 1 : -1);
115a15691bfSXin LI 		curr_pos = next_unfiltered(curr_pos);
116a15691bfSXin LI 	}
117a5f0fb15SPaul Saab #endif
118a5f0fb15SPaul Saab 	if (ch_seek(curr_pos))
119a5f0fb15SPaul Saab 	{
120a5f0fb15SPaul Saab 		null_line();
121a5f0fb15SPaul Saab 		return (NULL_POSITION);
122a5f0fb15SPaul Saab 	}
123a5f0fb15SPaul Saab 
1247374caaaSXin LI 	/*
1257374caaaSXin LI 	 * Step back to the beginning of the line.
1267374caaaSXin LI 	 */
1276dcb072bSXin LI 	base_pos = curr_pos;
1286dcb072bSXin LI 	for (;;)
1296dcb072bSXin LI 	{
1306dcb072bSXin LI 		c = ch_back_get();
1316dcb072bSXin LI 		if (c == EOI)
1326dcb072bSXin LI 			break;
1336dcb072bSXin LI 		if (c == '\n')
1346dcb072bSXin LI 		{
1356dcb072bSXin LI 			(void) ch_forw_get();
1366dcb072bSXin LI 			break;
1376dcb072bSXin LI 		}
1386dcb072bSXin LI 		--base_pos;
1396dcb072bSXin LI 	}
1406dcb072bSXin LI 
1417374caaaSXin LI 	/*
1427374caaaSXin LI 	 * Read forward again to the position we should start at.
1437374caaaSXin LI 	 */
144a5f0fb15SPaul Saab 	prewind();
1452235c7feSXin LI 	plinestart(base_pos);
1466dcb072bSXin LI 	(void) ch_seek(base_pos);
1477374caaaSXin LI 	new_pos = base_pos;
1487374caaaSXin LI 	while (new_pos < curr_pos)
1496dcb072bSXin LI 	{
150*c77c4889SXin LI 		c = ch_forw_get();
151*c77c4889SXin LI 		if (c == EOI)
1526dcb072bSXin LI 		{
1536dcb072bSXin LI 			null_line();
1546dcb072bSXin LI 			return (NULL_POSITION);
1556dcb072bSXin LI 		}
156*c77c4889SXin LI 		backchars = pappend((char) c, new_pos);
1577374caaaSXin LI 		new_pos++;
1586dcb072bSXin LI 		if (backchars > 0)
1596dcb072bSXin LI 		{
1606dcb072bSXin LI 			pshift_all();
161d713e089SXin LI 			if (wordwrap && (c == ' ' || c == '\t'))
162d713e089SXin LI 			{
163d713e089SXin LI 				do
164d713e089SXin LI 				{
165d713e089SXin LI 					new_pos++;
166*c77c4889SXin LI 					c = ch_forw_get(); /* {{ what if c == EOI? }} */
167d713e089SXin LI 				} while (c == ' ' || c == '\t');
168d713e089SXin LI 				backchars = 1;
169d713e089SXin LI 			}
1707374caaaSXin LI 			new_pos -= backchars;
1716dcb072bSXin LI 			while (--backchars >= 0)
1726dcb072bSXin LI 				(void) ch_back_get();
1736dcb072bSXin LI 		}
1746dcb072bSXin LI 	}
1756dcb072bSXin LI 	(void) pflushmbc();
1766dcb072bSXin LI 	pshift_all();
177a5f0fb15SPaul Saab 
1787374caaaSXin LI 	/*
1797374caaaSXin LI 	 * Read the first character to display.
1807374caaaSXin LI 	 */
181a5f0fb15SPaul Saab 	c = ch_forw_get();
182a5f0fb15SPaul Saab 	if (c == EOI)
183a5f0fb15SPaul Saab 	{
184a5f0fb15SPaul Saab 		null_line();
185a5f0fb15SPaul Saab 		return (NULL_POSITION);
186a5f0fb15SPaul Saab 	}
187a5f0fb15SPaul Saab 	blankline = (c == '\n' || c == '\r');
188d713e089SXin LI 	wrap_pos = NULL_POSITION;
189d713e089SXin LI 	skipped_leading = FALSE;
190a5f0fb15SPaul Saab 
1917374caaaSXin LI 	/*
1927374caaaSXin LI 	 * Read each character in the line and append to the line buffer.
1937374caaaSXin LI 	 */
194b2ea2440SXin LI 	chopped = FALSE;
195a5f0fb15SPaul Saab 	for (;;)
196a5f0fb15SPaul Saab 	{
197a5f0fb15SPaul Saab 		if (c == '\n' || c == EOI)
198a5f0fb15SPaul Saab 		{
199a5f0fb15SPaul Saab 			/*
200a5f0fb15SPaul Saab 			 * End of the line.
201a5f0fb15SPaul Saab 			 */
2026dcb072bSXin LI 			backchars = pflushmbc();
203a5f0fb15SPaul Saab 			new_pos = ch_tell();
20495270f73SXin LI 			if (backchars > 0 && (nochop || !chop_line()) && hshift == 0)
2056dcb072bSXin LI 			{
2066dcb072bSXin LI 				new_pos -= backchars + 1;
2076dcb072bSXin LI 				endline = FALSE;
2086dcb072bSXin LI 			} else
209a5f0fb15SPaul Saab 				endline = TRUE;
210d713e089SXin LI 			edisp_pos = new_pos;
211a5f0fb15SPaul Saab 			break;
212a5f0fb15SPaul Saab 		}
2136dcb072bSXin LI 		if (c != '\r')
214*c77c4889SXin LI 			blankline = FALSE;
215a5f0fb15SPaul Saab 
216a5f0fb15SPaul Saab 		/*
217a5f0fb15SPaul Saab 		 * Append the char to the line and get the next char.
218a5f0fb15SPaul Saab 		 */
219*c77c4889SXin LI 		backchars = pappend((char) c, ch_tell()-1);
2206dcb072bSXin LI 		if (backchars > 0)
221a5f0fb15SPaul Saab 		{
222a5f0fb15SPaul Saab 			/*
223a5f0fb15SPaul Saab 			 * The char won't fit in the line; the line
224a5f0fb15SPaul Saab 			 * is too long to print in the screen width.
225a5f0fb15SPaul Saab 			 * End the line here.
226a5f0fb15SPaul Saab 			 */
22795270f73SXin LI 			if (skipeol)
228a5f0fb15SPaul Saab 			{
2292235c7feSXin LI 				/* Read to end of line. */
230*c77c4889SXin LI 				edisp_pos = ch_tell() - backchars;
231a5f0fb15SPaul Saab 				do
232a5f0fb15SPaul Saab 				{
233a5f0fb15SPaul Saab 					c = ch_forw_get();
234a5f0fb15SPaul Saab 				} while (c != '\n' && c != EOI);
235a5f0fb15SPaul Saab 				new_pos = ch_tell();
236a5f0fb15SPaul Saab 				endline = TRUE;
237a5f0fb15SPaul Saab 				quit_if_one_screen = FALSE;
238b2ea2440SXin LI 				chopped = TRUE;
239a5f0fb15SPaul Saab 			} else
240a5f0fb15SPaul Saab 			{
241d713e089SXin LI 				if (!wordwrap)
2426dcb072bSXin LI 					new_pos = ch_tell() - backchars;
243d713e089SXin LI 				else
244d713e089SXin LI 				{
245d713e089SXin LI 					/*
246d713e089SXin LI 					 * We're word-wrapping, so go back to the last space.
247d713e089SXin LI 					 * However, if it's the space itself that couldn't fit,
248d713e089SXin LI 					 * simply ignore it and any subsequent spaces.
249d713e089SXin LI 					 */
250d713e089SXin LI 					if (c == ' ' || c == '\t')
251d713e089SXin LI 					{
252d713e089SXin LI 						do
253d713e089SXin LI 						{
254d713e089SXin LI 							new_pos = ch_tell();
255*c77c4889SXin LI 							c = ch_forw_get(); /* {{ what if c == EOI? }} */
256d713e089SXin LI 						} while (c == ' ' || c == '\t');
257d713e089SXin LI 						if (c == '\r')
258*c77c4889SXin LI 							c = ch_forw_get(); /* {{ what if c == EOI? }} */
259d713e089SXin LI 						if (c == '\n')
260d713e089SXin LI 							new_pos = ch_tell();
261d713e089SXin LI 					} else if (wrap_pos == NULL_POSITION)
262d713e089SXin LI 						new_pos = ch_tell() - backchars;
263d713e089SXin LI 					else
264d713e089SXin LI 					{
265d713e089SXin LI 						new_pos = wrap_pos;
266d713e089SXin LI 						loadc();
267d713e089SXin LI 					}
268d713e089SXin LI 				}
269a5f0fb15SPaul Saab 				endline = FALSE;
270*c77c4889SXin LI 				edisp_pos = new_pos;
271a5f0fb15SPaul Saab 			}
272a5f0fb15SPaul Saab 			break;
273a5f0fb15SPaul Saab 		}
274d713e089SXin LI 		if (wordwrap)
275d713e089SXin LI 		{
276d713e089SXin LI 			if (c == ' ' || c == '\t')
277d713e089SXin LI 			{
278d713e089SXin LI 				if (skipped_leading)
279d713e089SXin LI 				{
280d713e089SXin LI 					wrap_pos = ch_tell();
281d713e089SXin LI 					savec();
282d713e089SXin LI 				}
283d713e089SXin LI 			} else
284d713e089SXin LI 				skipped_leading = TRUE;
285d713e089SXin LI 		}
286a5f0fb15SPaul Saab 		c = ch_forw_get();
287a5f0fb15SPaul Saab 	}
2887374caaaSXin LI 
2892235c7feSXin LI #if HILITE_SEARCH
2902235c7feSXin LI 	if (blankline && show_attn)
2912235c7feSXin LI 	{
292*c77c4889SXin LI 		/* Add spurious space to carry possible attn hilite.
293*c77c4889SXin LI 		 * Use pappend_b so that if line ended with \r\n,
294*c77c4889SXin LI 		 * we insert the space before the \r. */
295*c77c4889SXin LI 		pappend_b(' ', ch_tell()-1, TRUE);
2962235c7feSXin LI 	}
2972235c7feSXin LI #endif
29895270f73SXin LI 	pdone(endline, rscroll && chopped, 1);
2997374caaaSXin LI 
3007374caaaSXin LI #if HILITE_SEARCH
3017374caaaSXin LI 	if (is_filtered(base_pos))
3027374caaaSXin LI 	{
3037374caaaSXin LI 		/*
3047374caaaSXin LI 		 * We don't want to display this line.
3057374caaaSXin LI 		 * Get the next line.
3067374caaaSXin LI 		 */
3077374caaaSXin LI 		curr_pos = new_pos;
3087374caaaSXin LI 		goto get_forw_line;
3097374caaaSXin LI 	}
3102235c7feSXin LI 	if (status_col)
311d713e089SXin LI 		init_status_col(base_pos, line_position(), edisp_pos, new_pos);
3127374caaaSXin LI #endif
313a5f0fb15SPaul Saab 
314a5f0fb15SPaul Saab 	if (squeeze && blankline)
315a5f0fb15SPaul Saab 	{
316a5f0fb15SPaul Saab 		/*
317a5f0fb15SPaul Saab 		 * This line is blank.
318a5f0fb15SPaul Saab 		 * Skip down to the last contiguous blank line
319a5f0fb15SPaul Saab 		 * and pretend it is the one which we are returning.
320a5f0fb15SPaul Saab 		 */
321a5f0fb15SPaul Saab 		while ((c = ch_forw_get()) == '\n' || c == '\r')
322*c77c4889SXin LI 			continue;
323a5f0fb15SPaul Saab 		if (c != EOI)
324a5f0fb15SPaul Saab 			(void) ch_back_get();
325a5f0fb15SPaul Saab 		new_pos = ch_tell();
326a5f0fb15SPaul Saab 	}
327a5f0fb15SPaul Saab 
328a5f0fb15SPaul Saab 	return (new_pos);
329a5f0fb15SPaul Saab }
330a5f0fb15SPaul Saab 
331d713e089SXin LI public POSITION forw_line(POSITION curr_pos)
3322235c7feSXin LI {
33395270f73SXin LI 
33495270f73SXin LI 	return forw_line_seg(curr_pos, (chop_line() || hshift > 0), TRUE, FALSE);
3352235c7feSXin LI }
3362235c7feSXin LI 
337a5f0fb15SPaul Saab /*
338a5f0fb15SPaul Saab  * Get the previous line.
339a5f0fb15SPaul Saab  * A "current" position is passed and a "new" position is returned.
340a5f0fb15SPaul Saab  * The current position is the position of the first character of
341a5f0fb15SPaul Saab  * a line.  The new position is the position of the first character
342a5f0fb15SPaul Saab  * of the PREVIOUS line.  The line obtained is the one starting at new_pos.
343a5f0fb15SPaul Saab  */
344d713e089SXin LI public POSITION back_line(POSITION curr_pos)
345a5f0fb15SPaul Saab {
346d713e089SXin LI 	POSITION base_pos;
347d713e089SXin LI 	POSITION new_pos;
348d713e089SXin LI 	POSITION edisp_pos;
349d713e089SXin LI 	POSITION begin_new_pos;
350a5f0fb15SPaul Saab 	int c;
351*c77c4889SXin LI 	lbool endline;
352*c77c4889SXin LI 	lbool chopped;
3536dcb072bSXin LI 	int backchars;
354d713e089SXin LI 	POSITION wrap_pos;
355*c77c4889SXin LI 	lbool skipped_leading;
356a5f0fb15SPaul Saab 
3577374caaaSXin LI get_back_line:
358a5f0fb15SPaul Saab 	if (curr_pos == NULL_POSITION || curr_pos <= ch_zero())
359a5f0fb15SPaul Saab 	{
360a5f0fb15SPaul Saab 		null_line();
361a5f0fb15SPaul Saab 		return (NULL_POSITION);
362a5f0fb15SPaul Saab 	}
363a5f0fb15SPaul Saab #if HILITE_SEARCH
3647374caaaSXin LI 	if (hilite_search == OPT_ONPLUS || is_filtering() || status_col)
365*c77c4889SXin LI 		prep_hilite((curr_pos < (POSITION) (3*size_linebuf)) ? 0 :
366*c77c4889SXin LI 		    curr_pos - (POSITION) (3*size_linebuf), curr_pos, -1);
367a5f0fb15SPaul Saab #endif
368a5f0fb15SPaul Saab 	if (ch_seek(curr_pos-1))
369a5f0fb15SPaul Saab 	{
370a5f0fb15SPaul Saab 		null_line();
371a5f0fb15SPaul Saab 		return (NULL_POSITION);
372a5f0fb15SPaul Saab 	}
373a5f0fb15SPaul Saab 
374a5f0fb15SPaul Saab 	if (squeeze)
375a5f0fb15SPaul Saab 	{
376a5f0fb15SPaul Saab 		/*
377a5f0fb15SPaul Saab 		 * Find out if the "current" line was blank.
378a5f0fb15SPaul Saab 		 */
379a5f0fb15SPaul Saab 		(void) ch_forw_get();    /* Skip the newline */
380a5f0fb15SPaul Saab 		c = ch_forw_get();       /* First char of "current" line */
381*c77c4889SXin LI 		/* {{ what if c == EOI? }} */
382a5f0fb15SPaul Saab 		(void) ch_back_get();    /* Restore our position */
383a5f0fb15SPaul Saab 		(void) ch_back_get();
384a5f0fb15SPaul Saab 
385a5f0fb15SPaul Saab 		if (c == '\n' || c == '\r')
386a5f0fb15SPaul Saab 		{
387a5f0fb15SPaul Saab 			/*
388a5f0fb15SPaul Saab 			 * The "current" line was blank.
389a5f0fb15SPaul Saab 			 * Skip over any preceding blank lines,
390a5f0fb15SPaul Saab 			 * since we skipped them in forw_line().
391a5f0fb15SPaul Saab 			 */
392a5f0fb15SPaul Saab 			while ((c = ch_back_get()) == '\n' || c == '\r')
393*c77c4889SXin LI 				continue;
394a5f0fb15SPaul Saab 			if (c == EOI)
395a5f0fb15SPaul Saab 			{
396a5f0fb15SPaul Saab 				null_line();
397a5f0fb15SPaul Saab 				return (NULL_POSITION);
398a5f0fb15SPaul Saab 			}
399a5f0fb15SPaul Saab 			(void) ch_forw_get();
400a5f0fb15SPaul Saab 		}
401a5f0fb15SPaul Saab 	}
402a5f0fb15SPaul Saab 
403a5f0fb15SPaul Saab 	/*
404a5f0fb15SPaul Saab 	 * Scan backwards until we hit the beginning of the line.
405a5f0fb15SPaul Saab 	 */
406a5f0fb15SPaul Saab 	for (;;)
407a5f0fb15SPaul Saab 	{
408a5f0fb15SPaul Saab 		c = ch_back_get();
409a5f0fb15SPaul Saab 		if (c == '\n')
410a5f0fb15SPaul Saab 		{
411a5f0fb15SPaul Saab 			/*
412a5f0fb15SPaul Saab 			 * This is the newline ending the previous line.
413a5f0fb15SPaul Saab 			 * We have hit the beginning of the line.
414a5f0fb15SPaul Saab 			 */
4157374caaaSXin LI 			base_pos = ch_tell() + 1;
416a5f0fb15SPaul Saab 			break;
417a5f0fb15SPaul Saab 		}
418a5f0fb15SPaul Saab 		if (c == EOI)
419a5f0fb15SPaul Saab 		{
420a5f0fb15SPaul Saab 			/*
421a5f0fb15SPaul Saab 			 * We have hit the beginning of the file.
422a5f0fb15SPaul Saab 			 * This must be the first line in the file.
423a5f0fb15SPaul Saab 			 * This must, of course, be the beginning of the line.
424a5f0fb15SPaul Saab 			 */
4257374caaaSXin LI 			base_pos = ch_tell();
426a5f0fb15SPaul Saab 			break;
427a5f0fb15SPaul Saab 		}
428a5f0fb15SPaul Saab 	}
429a5f0fb15SPaul Saab 
430a5f0fb15SPaul Saab 	/*
431a5f0fb15SPaul Saab 	 * Now scan forwards from the beginning of this line.
432a5f0fb15SPaul Saab 	 * We keep discarding "printable lines" (based on screen width)
433a5f0fb15SPaul Saab 	 * until we reach the curr_pos.
434a5f0fb15SPaul Saab 	 *
435a5f0fb15SPaul Saab 	 * {{ This algorithm is pretty inefficient if the lines
436a5f0fb15SPaul Saab 	 *    are much longer than the screen width,
437a5f0fb15SPaul Saab 	 *    but I don't know of any better way. }}
438a5f0fb15SPaul Saab 	 */
4397374caaaSXin LI 	new_pos = base_pos;
440a5f0fb15SPaul Saab 	if (ch_seek(new_pos))
441a5f0fb15SPaul Saab 	{
442a5f0fb15SPaul Saab 		null_line();
443a5f0fb15SPaul Saab 		return (NULL_POSITION);
444a5f0fb15SPaul Saab 	}
445a5f0fb15SPaul Saab 	endline = FALSE;
446a5f0fb15SPaul Saab 	prewind();
4472235c7feSXin LI 	plinestart(new_pos);
4486dcb072bSXin LI     loop:
449d713e089SXin LI 	wrap_pos = NULL_POSITION;
450d713e089SXin LI 	skipped_leading = FALSE;
4516dcb072bSXin LI 	begin_new_pos = new_pos;
452a5f0fb15SPaul Saab 	(void) ch_seek(new_pos);
453b2ea2440SXin LI 	chopped = FALSE;
454a5f0fb15SPaul Saab 
455d713e089SXin LI 	for (;;)
456a5f0fb15SPaul Saab 	{
457a5f0fb15SPaul Saab 		c = ch_forw_get();
458*c77c4889SXin LI 		if (c == EOI)
459a5f0fb15SPaul Saab 		{
460a5f0fb15SPaul Saab 			null_line();
461a5f0fb15SPaul Saab 			return (NULL_POSITION);
462a5f0fb15SPaul Saab 		}
463a5f0fb15SPaul Saab 		new_pos++;
464a5f0fb15SPaul Saab 		if (c == '\n')
465a5f0fb15SPaul Saab 		{
4666dcb072bSXin LI 			backchars = pflushmbc();
46795270f73SXin LI 			if (backchars > 0 && !chop_line() && hshift == 0)
4686dcb072bSXin LI 			{
4696dcb072bSXin LI 				backchars++;
4706dcb072bSXin LI 				goto shift;
4716dcb072bSXin LI 			}
472a5f0fb15SPaul Saab 			endline = TRUE;
473d713e089SXin LI 			edisp_pos = new_pos;
474a5f0fb15SPaul Saab 			break;
475a5f0fb15SPaul Saab 		}
476*c77c4889SXin LI 		backchars = pappend((char) c, ch_tell()-1);
4776dcb072bSXin LI 		if (backchars > 0)
478a5f0fb15SPaul Saab 		{
479a5f0fb15SPaul Saab 			/*
480a5f0fb15SPaul Saab 			 * Got a full printable line, but we haven't
481a5f0fb15SPaul Saab 			 * reached our curr_pos yet.  Discard the line
482a5f0fb15SPaul Saab 			 * and start a new one.
483a5f0fb15SPaul Saab 			 */
48495270f73SXin LI 			if (chop_line() || hshift > 0)
485a5f0fb15SPaul Saab 			{
486a5f0fb15SPaul Saab 				endline = TRUE;
487b2ea2440SXin LI 				chopped = TRUE;
488a5f0fb15SPaul Saab 				quit_if_one_screen = FALSE;
489d713e089SXin LI 				edisp_pos = new_pos;
490a5f0fb15SPaul Saab 				break;
491a5f0fb15SPaul Saab 			}
4926dcb072bSXin LI 		shift:
493d713e089SXin LI 			if (!wordwrap)
4946dcb072bSXin LI 			{
495d713e089SXin LI 				pshift_all();
496d713e089SXin LI 				new_pos -= backchars;
497d713e089SXin LI 			} else
498d713e089SXin LI 			{
499d713e089SXin LI 				if (c == ' ' || c == '\t')
500d713e089SXin LI 				{
501d713e089SXin LI 					for (;;)
502d713e089SXin LI 					{
503*c77c4889SXin LI 						c = ch_forw_get(); /* {{ what if c == EOI? }} */
504d713e089SXin LI 						if (c == ' ' || c == '\t')
505d713e089SXin LI 							new_pos++;
506d713e089SXin LI 						else
507d713e089SXin LI 						{
508d713e089SXin LI 							if (c == '\r')
509d713e089SXin LI 							{
510*c77c4889SXin LI 								c = ch_forw_get(); /* {{ what if c == EOI? }} */
511d713e089SXin LI 								if (c == '\n')
512d713e089SXin LI 									new_pos++;
513d713e089SXin LI 							}
514d713e089SXin LI 							if (c == '\n')
515d713e089SXin LI 								new_pos++;
516*c77c4889SXin LI 							edisp_pos = new_pos;
517d713e089SXin LI 							break;
518d713e089SXin LI 						}
519d713e089SXin LI 					}
520d713e089SXin LI 					if (new_pos >= curr_pos)
521*c77c4889SXin LI 					{
522*c77c4889SXin LI 						edisp_pos = new_pos;
523d713e089SXin LI 						break;
524*c77c4889SXin LI 					}
525d713e089SXin LI 					pshift_all();
526d713e089SXin LI 				} else
527d713e089SXin LI 				{
528d713e089SXin LI 					pshift_all();
529d713e089SXin LI 					if (wrap_pos == NULL_POSITION)
530d713e089SXin LI 						new_pos -= backchars;
531d713e089SXin LI 					else
532d713e089SXin LI 						new_pos = wrap_pos;
533d713e089SXin LI 				}
5346dcb072bSXin LI 			}
535a5f0fb15SPaul Saab 			goto loop;
536a5f0fb15SPaul Saab 		}
537d713e089SXin LI 		if (wordwrap)
538d713e089SXin LI 		{
539d713e089SXin LI 			if (c == ' ' || c == '\t')
540d713e089SXin LI 			{
541d713e089SXin LI 				if (skipped_leading)
542d713e089SXin LI 					wrap_pos = new_pos;
543d713e089SXin LI 			} else
544d713e089SXin LI 				skipped_leading = TRUE;
545d713e089SXin LI 		}
546d713e089SXin LI 		if (new_pos >= curr_pos)
547d713e089SXin LI 		{
548d713e089SXin LI 			edisp_pos = new_pos;
549d713e089SXin LI 			break;
550d713e089SXin LI 		}
551d713e089SXin LI 	}
552a5f0fb15SPaul Saab 
553b2ea2440SXin LI 	pdone(endline, chopped, 0);
5547374caaaSXin LI 
5557374caaaSXin LI #if HILITE_SEARCH
5567374caaaSXin LI 	if (is_filtered(base_pos))
5577374caaaSXin LI 	{
5587374caaaSXin LI 		/*
5597374caaaSXin LI 		 * We don't want to display this line.
5607374caaaSXin LI 		 * Get the previous line.
5617374caaaSXin LI 		 */
5627374caaaSXin LI 		curr_pos = begin_new_pos;
5637374caaaSXin LI 		goto get_back_line;
5647374caaaSXin LI 	}
565d713e089SXin LI 	if (status_col)
566d713e089SXin LI 		init_status_col(base_pos, line_position(), edisp_pos, new_pos);
5677374caaaSXin LI #endif
568a5f0fb15SPaul Saab 
569a5f0fb15SPaul Saab 	return (begin_new_pos);
570a5f0fb15SPaul Saab }
571a5f0fb15SPaul Saab 
572a5f0fb15SPaul Saab /*
573a5f0fb15SPaul Saab  * Set attnpos.
574a5f0fb15SPaul Saab  */
575d713e089SXin LI public void set_attnpos(POSITION pos)
576a5f0fb15SPaul Saab {
577a5f0fb15SPaul Saab 	int c;
578a5f0fb15SPaul Saab 
579a5f0fb15SPaul Saab 	if (pos != NULL_POSITION)
580a5f0fb15SPaul Saab 	{
581a5f0fb15SPaul Saab 		if (ch_seek(pos))
582a5f0fb15SPaul Saab 			return;
583a5f0fb15SPaul Saab 		for (;;)
584a5f0fb15SPaul Saab 		{
585a5f0fb15SPaul Saab 			c = ch_forw_get();
586a5f0fb15SPaul Saab 			if (c == EOI)
587a5f0fb15SPaul Saab 				break;
588a15691bfSXin LI 			if (c == '\n' || c == '\r')
589a15691bfSXin LI 			{
590a15691bfSXin LI 				(void) ch_back_get();
591a15691bfSXin LI 				break;
592a15691bfSXin LI 			}
593a5f0fb15SPaul Saab 			pos++;
594a5f0fb15SPaul Saab 		}
595a15691bfSXin LI 		end_attnpos = pos;
596a15691bfSXin LI 		for (;;)
597a15691bfSXin LI 		{
598a15691bfSXin LI 			c = ch_back_get();
599a15691bfSXin LI 			if (c == EOI || c == '\n' || c == '\r')
600a15691bfSXin LI 				break;
601a15691bfSXin LI 			pos--;
602a15691bfSXin LI 		}
603a5f0fb15SPaul Saab 	}
604a5f0fb15SPaul Saab 	start_attnpos = pos;
605a5f0fb15SPaul Saab }
606