xref: /dflybsd-src/contrib/less/input.c (revision e0f238eda64c20d98364903e0c003825fd0b66dd)
11133e27eSPeter Avalos /*
2*e433da38SAaron LI  * Copyright (C) 1984-2024  Mark Nudelman
31133e27eSPeter Avalos  *
41133e27eSPeter Avalos  * You may distribute under the terms of either the GNU General Public
51133e27eSPeter Avalos  * License or the Less License, as specified in the README file.
61133e27eSPeter Avalos  *
7e639dc31SJohn Marino  * For more information, see the README file.
81133e27eSPeter Avalos  */
91133e27eSPeter Avalos 
101133e27eSPeter Avalos /*
111133e27eSPeter Avalos  * High level routines dealing with getting lines of input
121133e27eSPeter Avalos  * from the file being viewed.
131133e27eSPeter Avalos  *
141133e27eSPeter Avalos  * When we speak of "lines" here, we mean PRINTABLE lines;
151133e27eSPeter Avalos  * lines processed with respect to the screen width.
161133e27eSPeter Avalos  * We use the term "raw line" to refer to lines simply
171133e27eSPeter Avalos  * delimited by newlines; not processed with respect to screen width.
181133e27eSPeter Avalos  */
191133e27eSPeter Avalos 
201133e27eSPeter Avalos #include "less.h"
211133e27eSPeter Avalos 
221133e27eSPeter Avalos extern int squeeze;
231133e27eSPeter Avalos extern int hshift;
241133e27eSPeter Avalos extern int quit_if_one_screen;
251133e27eSPeter Avalos extern int ignore_eoi;
261133e27eSPeter Avalos extern int status_col;
27320d7c8aSAaron LI extern int wordwrap;
281133e27eSPeter Avalos extern POSITION start_attnpos;
291133e27eSPeter Avalos extern POSITION end_attnpos;
301133e27eSPeter Avalos #if HILITE_SEARCH
311133e27eSPeter Avalos extern int hilite_search;
32*e433da38SAaron LI extern size_t size_linebuf;
330c7ad07eSAntonio Huete Jimenez extern int show_attn;
341133e27eSPeter Avalos #endif
351133e27eSPeter Avalos 
361133e27eSPeter Avalos /*
37320d7c8aSAaron LI  * Set the status column.
38320d7c8aSAaron LI  *  base  Position of first char in line.
39320d7c8aSAaron LI  *  disp  First visible char.
40320d7c8aSAaron LI  *        Different than base_pos if line is shifted.
41320d7c8aSAaron LI  *  edisp Last visible char.
42320d7c8aSAaron LI  *  eol   End of line. Normally the newline.
43320d7c8aSAaron LI  *        Different than edisp if line is chopped.
44320d7c8aSAaron LI  */
init_status_col(POSITION base_pos,POSITION disp_pos,POSITION edisp_pos,POSITION eol_pos)45320d7c8aSAaron LI static void init_status_col(POSITION base_pos, POSITION disp_pos, POSITION edisp_pos, POSITION eol_pos)
46320d7c8aSAaron LI {
47320d7c8aSAaron LI 	int hl_before = (chop_line() && disp_pos != NULL_POSITION) ?
48320d7c8aSAaron LI 	    is_hilited_attr(base_pos, disp_pos, TRUE, NULL) : 0;
49*e433da38SAaron LI 	int hl_after = (chop_line() && edisp_pos != NULL_POSITION) ?
50320d7c8aSAaron LI 	    is_hilited_attr(edisp_pos, eol_pos, TRUE, NULL) : 0;
51320d7c8aSAaron LI 	int attr;
52320d7c8aSAaron LI 	char ch;
53320d7c8aSAaron LI 
54320d7c8aSAaron LI 	if (hl_before && hl_after)
55320d7c8aSAaron LI 	{
56320d7c8aSAaron LI 		attr = hl_after;
57320d7c8aSAaron LI 		ch = '=';
58320d7c8aSAaron LI 	} else if (hl_before)
59320d7c8aSAaron LI 	{
60320d7c8aSAaron LI 		attr = hl_before;
61320d7c8aSAaron LI 		ch = '<';
62320d7c8aSAaron LI 	} else if (hl_after)
63320d7c8aSAaron LI 	{
64320d7c8aSAaron LI 		attr = hl_after;
65320d7c8aSAaron LI 		ch = '>';
66*e433da38SAaron LI 	} else if (disp_pos != NULL_POSITION)
67*e433da38SAaron LI 	{
68*e433da38SAaron LI 		attr = is_hilited_attr(disp_pos, edisp_pos, TRUE, NULL);
69*e433da38SAaron LI 		ch = '*';
70320d7c8aSAaron LI 	} else
71320d7c8aSAaron LI     {
72*e433da38SAaron LI         attr = 0;
73320d7c8aSAaron LI     }
74320d7c8aSAaron LI 	if (attr)
75320d7c8aSAaron LI 		set_status_col(ch, attr);
76320d7c8aSAaron LI }
77320d7c8aSAaron LI 
78320d7c8aSAaron LI /*
791133e27eSPeter Avalos  * Get the next line.
801133e27eSPeter Avalos  * A "current" position is passed and a "new" position is returned.
811133e27eSPeter Avalos  * The current position is the position of the first character of
821133e27eSPeter Avalos  * a line.  The new position is the position of the first character
831133e27eSPeter Avalos  * of the NEXT line.  The line obtained is the line starting at curr_pos.
841133e27eSPeter Avalos  */
forw_line_seg(POSITION curr_pos,lbool skipeol,lbool rscroll,lbool nochop)85*e433da38SAaron LI public POSITION forw_line_seg(POSITION curr_pos, lbool skipeol, lbool rscroll, lbool nochop)
861133e27eSPeter Avalos {
871133e27eSPeter Avalos 	POSITION base_pos;
881133e27eSPeter Avalos 	POSITION new_pos;
89320d7c8aSAaron LI 	POSITION edisp_pos;
9002d62a0fSDaniel Fojt 	int c;
91*e433da38SAaron LI 	lbool blankline;
92*e433da38SAaron LI 	lbool endline;
93*e433da38SAaron LI 	lbool chopped;
941133e27eSPeter Avalos 	int backchars;
95320d7c8aSAaron LI 	POSITION wrap_pos;
96*e433da38SAaron LI 	lbool skipped_leading;
971133e27eSPeter Avalos 
988be36e5bSPeter Avalos get_forw_line:
991133e27eSPeter Avalos 	if (curr_pos == NULL_POSITION)
1001133e27eSPeter Avalos 	{
1011133e27eSPeter Avalos 		null_line();
1021133e27eSPeter Avalos 		return (NULL_POSITION);
1031133e27eSPeter Avalos 	}
1041133e27eSPeter Avalos #if HILITE_SEARCH
1058be36e5bSPeter Avalos 	if (hilite_search == OPT_ONPLUS || is_filtering() || status_col)
106fa0be7c5SJohn Marino 	{
1071133e27eSPeter Avalos 		/*
1081133e27eSPeter Avalos 		 * If we are ignoring EOI (command F), only prepare
1091133e27eSPeter Avalos 		 * one line ahead, to avoid getting stuck waiting for
1101133e27eSPeter Avalos 		 * slow data without displaying the data we already have.
1111133e27eSPeter Avalos 		 * If we're not ignoring EOI, we *could* do the same, but
1121133e27eSPeter Avalos 		 * for efficiency we prepare several lines ahead at once.
1131133e27eSPeter Avalos 		 */
114*e433da38SAaron LI 		prep_hilite(curr_pos, curr_pos + (POSITION) (3*size_linebuf), ignore_eoi ? 1 : -1);
115fa0be7c5SJohn Marino 		curr_pos = next_unfiltered(curr_pos);
116fa0be7c5SJohn Marino 	}
1171133e27eSPeter Avalos #endif
1181133e27eSPeter Avalos 	if (ch_seek(curr_pos))
1191133e27eSPeter Avalos 	{
1201133e27eSPeter Avalos 		null_line();
1211133e27eSPeter Avalos 		return (NULL_POSITION);
1221133e27eSPeter Avalos 	}
1231133e27eSPeter Avalos 
1248be36e5bSPeter Avalos 	/*
1258be36e5bSPeter Avalos 	 * Step back to the beginning of the line.
1268be36e5bSPeter Avalos 	 */
1271133e27eSPeter Avalos 	base_pos = curr_pos;
1281133e27eSPeter Avalos 	for (;;)
1291133e27eSPeter Avalos 	{
1301133e27eSPeter Avalos 		c = ch_back_get();
1311133e27eSPeter Avalos 		if (c == EOI)
1321133e27eSPeter Avalos 			break;
1331133e27eSPeter Avalos 		if (c == '\n')
1341133e27eSPeter Avalos 		{
1351133e27eSPeter Avalos 			(void) ch_forw_get();
1361133e27eSPeter Avalos 			break;
1371133e27eSPeter Avalos 		}
1381133e27eSPeter Avalos 		--base_pos;
1391133e27eSPeter Avalos 	}
1401133e27eSPeter Avalos 
1418be36e5bSPeter Avalos 	/*
1428be36e5bSPeter Avalos 	 * Read forward again to the position we should start at.
1438be36e5bSPeter Avalos 	 */
1441133e27eSPeter Avalos 	prewind();
1450c7ad07eSAntonio Huete Jimenez 	plinestart(base_pos);
1461133e27eSPeter Avalos 	(void) ch_seek(base_pos);
1478be36e5bSPeter Avalos 	new_pos = base_pos;
1488be36e5bSPeter Avalos 	while (new_pos < curr_pos)
1491133e27eSPeter Avalos 	{
150*e433da38SAaron LI 		c = ch_forw_get();
151*e433da38SAaron LI 		if (c == EOI)
1521133e27eSPeter Avalos 		{
1531133e27eSPeter Avalos 			null_line();
1541133e27eSPeter Avalos 			return (NULL_POSITION);
1551133e27eSPeter Avalos 		}
156*e433da38SAaron LI 		backchars = pappend((char) c, new_pos);
1578be36e5bSPeter Avalos 		new_pos++;
1581133e27eSPeter Avalos 		if (backchars > 0)
1591133e27eSPeter Avalos 		{
1601133e27eSPeter Avalos 			pshift_all();
161320d7c8aSAaron LI 			if (wordwrap && (c == ' ' || c == '\t'))
162320d7c8aSAaron LI 			{
163320d7c8aSAaron LI 				do
164320d7c8aSAaron LI 				{
165320d7c8aSAaron LI 					new_pos++;
166*e433da38SAaron LI 					c = ch_forw_get(); /* {{ what if c == EOI? }} */
167320d7c8aSAaron LI 				} while (c == ' ' || c == '\t');
168320d7c8aSAaron LI 				backchars = 1;
169320d7c8aSAaron LI 			}
1708be36e5bSPeter Avalos 			new_pos -= backchars;
1711133e27eSPeter Avalos 			while (--backchars >= 0)
1721133e27eSPeter Avalos 				(void) ch_back_get();
1731133e27eSPeter Avalos 		}
1741133e27eSPeter Avalos 	}
1751133e27eSPeter Avalos 	(void) pflushmbc();
1761133e27eSPeter Avalos 	pshift_all();
1771133e27eSPeter Avalos 
1788be36e5bSPeter Avalos 	/*
1798be36e5bSPeter Avalos 	 * Read the first character to display.
1808be36e5bSPeter Avalos 	 */
1811133e27eSPeter Avalos 	c = ch_forw_get();
1821133e27eSPeter Avalos 	if (c == EOI)
1831133e27eSPeter Avalos 	{
1841133e27eSPeter Avalos 		null_line();
1851133e27eSPeter Avalos 		return (NULL_POSITION);
1861133e27eSPeter Avalos 	}
1871133e27eSPeter Avalos 	blankline = (c == '\n' || c == '\r');
188320d7c8aSAaron LI 	wrap_pos = NULL_POSITION;
189320d7c8aSAaron LI 	skipped_leading = FALSE;
1901133e27eSPeter Avalos 
1918be36e5bSPeter Avalos 	/*
1928be36e5bSPeter Avalos 	 * Read each character in the line and append to the line buffer.
1938be36e5bSPeter Avalos 	 */
19402d62a0fSDaniel Fojt 	chopped = FALSE;
1951133e27eSPeter Avalos 	for (;;)
1961133e27eSPeter Avalos 	{
1971133e27eSPeter Avalos 		if (c == '\n' || c == EOI)
1981133e27eSPeter Avalos 		{
1991133e27eSPeter Avalos 			/*
2001133e27eSPeter Avalos 			 * End of the line.
2011133e27eSPeter Avalos 			 */
2021133e27eSPeter Avalos 			backchars = pflushmbc();
2031133e27eSPeter Avalos 			new_pos = ch_tell();
2040c7ad07eSAntonio Huete Jimenez 			if (backchars > 0 && (nochop || !chop_line()) && hshift == 0)
2051133e27eSPeter Avalos 			{
2061133e27eSPeter Avalos 				new_pos -= backchars + 1;
2071133e27eSPeter Avalos 				endline = FALSE;
2081133e27eSPeter Avalos 			} else
2091133e27eSPeter Avalos 				endline = TRUE;
210320d7c8aSAaron LI 			edisp_pos = new_pos;
2111133e27eSPeter Avalos 			break;
2121133e27eSPeter Avalos 		}
2131133e27eSPeter Avalos 		if (c != '\r')
214*e433da38SAaron LI 			blankline = FALSE;
2151133e27eSPeter Avalos 
2161133e27eSPeter Avalos 		/*
2171133e27eSPeter Avalos 		 * Append the char to the line and get the next char.
2181133e27eSPeter Avalos 		 */
219*e433da38SAaron LI 		backchars = pappend((char) c, ch_tell()-1);
2201133e27eSPeter Avalos 		if (backchars > 0)
2211133e27eSPeter Avalos 		{
2221133e27eSPeter Avalos 			/*
2231133e27eSPeter Avalos 			 * The char won't fit in the line; the line
2241133e27eSPeter Avalos 			 * is too long to print in the screen width.
2251133e27eSPeter Avalos 			 * End the line here.
2261133e27eSPeter Avalos 			 */
2270c7ad07eSAntonio Huete Jimenez 			if (skipeol)
2281133e27eSPeter Avalos 			{
2290c7ad07eSAntonio Huete Jimenez 				/* Read to end of line. */
230*e433da38SAaron LI 				edisp_pos = ch_tell() - backchars;
2311133e27eSPeter Avalos 				do
2321133e27eSPeter Avalos 				{
2331133e27eSPeter Avalos 					c = ch_forw_get();
2341133e27eSPeter Avalos 				} while (c != '\n' && c != EOI);
2351133e27eSPeter Avalos 				new_pos = ch_tell();
2361133e27eSPeter Avalos 				endline = TRUE;
2371133e27eSPeter Avalos 				quit_if_one_screen = FALSE;
23802d62a0fSDaniel Fojt 				chopped = TRUE;
2391133e27eSPeter Avalos 			} else
2401133e27eSPeter Avalos 			{
241320d7c8aSAaron LI 				if (!wordwrap)
2421133e27eSPeter Avalos 					new_pos = ch_tell() - backchars;
243320d7c8aSAaron LI 				else
244320d7c8aSAaron LI 				{
245320d7c8aSAaron LI 					/*
246320d7c8aSAaron LI 					 * We're word-wrapping, so go back to the last space.
247320d7c8aSAaron LI 					 * However, if it's the space itself that couldn't fit,
248320d7c8aSAaron LI 					 * simply ignore it and any subsequent spaces.
249320d7c8aSAaron LI 					 */
250320d7c8aSAaron LI 					if (c == ' ' || c == '\t')
251320d7c8aSAaron LI 					{
252320d7c8aSAaron LI 						do
253320d7c8aSAaron LI 						{
254320d7c8aSAaron LI 							new_pos = ch_tell();
255*e433da38SAaron LI 							c = ch_forw_get(); /* {{ what if c == EOI? }} */
256320d7c8aSAaron LI 						} while (c == ' ' || c == '\t');
257320d7c8aSAaron LI 						if (c == '\r')
258*e433da38SAaron LI 							c = ch_forw_get(); /* {{ what if c == EOI? }} */
259320d7c8aSAaron LI 						if (c == '\n')
260320d7c8aSAaron LI 							new_pos = ch_tell();
261320d7c8aSAaron LI 					} else if (wrap_pos == NULL_POSITION)
262320d7c8aSAaron LI 						new_pos = ch_tell() - backchars;
263320d7c8aSAaron LI 					else
264320d7c8aSAaron LI 					{
265320d7c8aSAaron LI 						new_pos = wrap_pos;
266320d7c8aSAaron LI 						loadc();
267320d7c8aSAaron LI 					}
268320d7c8aSAaron LI 				}
2691133e27eSPeter Avalos 				endline = FALSE;
270*e433da38SAaron LI 				edisp_pos = new_pos;
2711133e27eSPeter Avalos 			}
2721133e27eSPeter Avalos 			break;
2731133e27eSPeter Avalos 		}
274320d7c8aSAaron LI 		if (wordwrap)
275320d7c8aSAaron LI 		{
276320d7c8aSAaron LI 			if (c == ' ' || c == '\t')
277320d7c8aSAaron LI 			{
278320d7c8aSAaron LI 				if (skipped_leading)
279320d7c8aSAaron LI 				{
280320d7c8aSAaron LI 					wrap_pos = ch_tell();
281320d7c8aSAaron LI 					savec();
282320d7c8aSAaron LI 				}
283320d7c8aSAaron LI 			} else
284320d7c8aSAaron LI 				skipped_leading = TRUE;
285320d7c8aSAaron LI 		}
2861133e27eSPeter Avalos 		c = ch_forw_get();
2871133e27eSPeter Avalos 	}
2888be36e5bSPeter Avalos 
2890c7ad07eSAntonio Huete Jimenez #if HILITE_SEARCH
2900c7ad07eSAntonio Huete Jimenez 	if (blankline && show_attn)
2910c7ad07eSAntonio Huete Jimenez 	{
292*e433da38SAaron LI 		/* Add spurious space to carry possible attn hilite.
293*e433da38SAaron LI 		 * Use pappend_b so that if line ended with \r\n,
294*e433da38SAaron LI 		 * we insert the space before the \r. */
295*e433da38SAaron LI 		pappend_b(' ', ch_tell()-1, TRUE);
2960c7ad07eSAntonio Huete Jimenez 	}
2970c7ad07eSAntonio Huete Jimenez #endif
2980c7ad07eSAntonio Huete Jimenez 	pdone(endline, rscroll && chopped, 1);
2998be36e5bSPeter Avalos 
3008be36e5bSPeter Avalos #if HILITE_SEARCH
3018be36e5bSPeter Avalos 	if (is_filtered(base_pos))
3028be36e5bSPeter Avalos 	{
3038be36e5bSPeter Avalos 		/*
3048be36e5bSPeter Avalos 		 * We don't want to display this line.
3058be36e5bSPeter Avalos 		 * Get the next line.
3068be36e5bSPeter Avalos 		 */
3078be36e5bSPeter Avalos 		curr_pos = new_pos;
3088be36e5bSPeter Avalos 		goto get_forw_line;
3098be36e5bSPeter Avalos 	}
3100c7ad07eSAntonio Huete Jimenez 	if (status_col)
311320d7c8aSAaron LI 		init_status_col(base_pos, line_position(), edisp_pos, new_pos);
3128be36e5bSPeter Avalos #endif
3131133e27eSPeter Avalos 
3141133e27eSPeter Avalos 	if (squeeze && blankline)
3151133e27eSPeter Avalos 	{
3161133e27eSPeter Avalos 		/*
3171133e27eSPeter Avalos 		 * This line is blank.
3181133e27eSPeter Avalos 		 * Skip down to the last contiguous blank line
3191133e27eSPeter Avalos 		 * and pretend it is the one which we are returning.
3201133e27eSPeter Avalos 		 */
3211133e27eSPeter Avalos 		while ((c = ch_forw_get()) == '\n' || c == '\r')
322*e433da38SAaron LI 			continue;
3231133e27eSPeter Avalos 		if (c != EOI)
3241133e27eSPeter Avalos 			(void) ch_back_get();
3251133e27eSPeter Avalos 		new_pos = ch_tell();
3261133e27eSPeter Avalos 	}
3271133e27eSPeter Avalos 
3281133e27eSPeter Avalos 	return (new_pos);
3291133e27eSPeter Avalos }
3301133e27eSPeter Avalos 
forw_line(POSITION curr_pos)331320d7c8aSAaron LI public POSITION forw_line(POSITION curr_pos)
3320c7ad07eSAntonio Huete Jimenez {
3330c7ad07eSAntonio Huete Jimenez 
3340c7ad07eSAntonio Huete Jimenez 	return forw_line_seg(curr_pos, (chop_line() || hshift > 0), TRUE, FALSE);
3350c7ad07eSAntonio Huete Jimenez }
3360c7ad07eSAntonio Huete Jimenez 
3371133e27eSPeter Avalos /*
3381133e27eSPeter Avalos  * Get the previous line.
3391133e27eSPeter Avalos  * A "current" position is passed and a "new" position is returned.
3401133e27eSPeter Avalos  * The current position is the position of the first character of
3411133e27eSPeter Avalos  * a line.  The new position is the position of the first character
3421133e27eSPeter Avalos  * of the PREVIOUS line.  The line obtained is the one starting at new_pos.
3431133e27eSPeter Avalos  */
back_line(POSITION curr_pos)344320d7c8aSAaron LI public POSITION back_line(POSITION curr_pos)
3451133e27eSPeter Avalos {
346320d7c8aSAaron LI 	POSITION base_pos;
347320d7c8aSAaron LI 	POSITION new_pos;
348320d7c8aSAaron LI 	POSITION edisp_pos;
349320d7c8aSAaron LI 	POSITION begin_new_pos;
3501133e27eSPeter Avalos 	int c;
351*e433da38SAaron LI 	lbool endline;
352*e433da38SAaron LI 	lbool chopped;
3531133e27eSPeter Avalos 	int backchars;
354320d7c8aSAaron LI 	POSITION wrap_pos;
355*e433da38SAaron LI 	lbool skipped_leading;
3561133e27eSPeter Avalos 
3578be36e5bSPeter Avalos get_back_line:
3581133e27eSPeter Avalos 	if (curr_pos == NULL_POSITION || curr_pos <= ch_zero())
3591133e27eSPeter Avalos 	{
3601133e27eSPeter Avalos 		null_line();
3611133e27eSPeter Avalos 		return (NULL_POSITION);
3621133e27eSPeter Avalos 	}
3631133e27eSPeter Avalos #if HILITE_SEARCH
3648be36e5bSPeter Avalos 	if (hilite_search == OPT_ONPLUS || is_filtering() || status_col)
365*e433da38SAaron LI 		prep_hilite((curr_pos < (POSITION) (3*size_linebuf)) ? 0 :
366*e433da38SAaron LI 		    curr_pos - (POSITION) (3*size_linebuf), curr_pos, -1);
3671133e27eSPeter Avalos #endif
3681133e27eSPeter Avalos 	if (ch_seek(curr_pos-1))
3691133e27eSPeter Avalos 	{
3701133e27eSPeter Avalos 		null_line();
3711133e27eSPeter Avalos 		return (NULL_POSITION);
3721133e27eSPeter Avalos 	}
3731133e27eSPeter Avalos 
3741133e27eSPeter Avalos 	if (squeeze)
3751133e27eSPeter Avalos 	{
3761133e27eSPeter Avalos 		/*
3771133e27eSPeter Avalos 		 * Find out if the "current" line was blank.
3781133e27eSPeter Avalos 		 */
3791133e27eSPeter Avalos 		(void) ch_forw_get();    /* Skip the newline */
3801133e27eSPeter Avalos 		c = ch_forw_get();       /* First char of "current" line */
381*e433da38SAaron LI 		/* {{ what if c == EOI? }} */
3821133e27eSPeter Avalos 		(void) ch_back_get();    /* Restore our position */
3831133e27eSPeter Avalos 		(void) ch_back_get();
3841133e27eSPeter Avalos 
3851133e27eSPeter Avalos 		if (c == '\n' || c == '\r')
3861133e27eSPeter Avalos 		{
3871133e27eSPeter Avalos 			/*
3881133e27eSPeter Avalos 			 * The "current" line was blank.
3891133e27eSPeter Avalos 			 * Skip over any preceding blank lines,
3901133e27eSPeter Avalos 			 * since we skipped them in forw_line().
3911133e27eSPeter Avalos 			 */
3921133e27eSPeter Avalos 			while ((c = ch_back_get()) == '\n' || c == '\r')
393*e433da38SAaron LI 				continue;
3941133e27eSPeter Avalos 			if (c == EOI)
3951133e27eSPeter Avalos 			{
3961133e27eSPeter Avalos 				null_line();
3971133e27eSPeter Avalos 				return (NULL_POSITION);
3981133e27eSPeter Avalos 			}
3991133e27eSPeter Avalos 			(void) ch_forw_get();
4001133e27eSPeter Avalos 		}
4011133e27eSPeter Avalos 	}
4021133e27eSPeter Avalos 
4031133e27eSPeter Avalos 	/*
4041133e27eSPeter Avalos 	 * Scan backwards until we hit the beginning of the line.
4051133e27eSPeter Avalos 	 */
4061133e27eSPeter Avalos 	for (;;)
4071133e27eSPeter Avalos 	{
4081133e27eSPeter Avalos 		c = ch_back_get();
4091133e27eSPeter Avalos 		if (c == '\n')
4101133e27eSPeter Avalos 		{
4111133e27eSPeter Avalos 			/*
4121133e27eSPeter Avalos 			 * This is the newline ending the previous line.
4131133e27eSPeter Avalos 			 * We have hit the beginning of the line.
4141133e27eSPeter Avalos 			 */
4158be36e5bSPeter Avalos 			base_pos = ch_tell() + 1;
4161133e27eSPeter Avalos 			break;
4171133e27eSPeter Avalos 		}
4181133e27eSPeter Avalos 		if (c == EOI)
4191133e27eSPeter Avalos 		{
4201133e27eSPeter Avalos 			/*
4211133e27eSPeter Avalos 			 * We have hit the beginning of the file.
4221133e27eSPeter Avalos 			 * This must be the first line in the file.
4231133e27eSPeter Avalos 			 * This must, of course, be the beginning of the line.
4241133e27eSPeter Avalos 			 */
4258be36e5bSPeter Avalos 			base_pos = ch_tell();
4261133e27eSPeter Avalos 			break;
4271133e27eSPeter Avalos 		}
4281133e27eSPeter Avalos 	}
4291133e27eSPeter Avalos 
4301133e27eSPeter Avalos 	/*
4311133e27eSPeter Avalos 	 * Now scan forwards from the beginning of this line.
4321133e27eSPeter Avalos 	 * We keep discarding "printable lines" (based on screen width)
4331133e27eSPeter Avalos 	 * until we reach the curr_pos.
4341133e27eSPeter Avalos 	 *
4351133e27eSPeter Avalos 	 * {{ This algorithm is pretty inefficient if the lines
4361133e27eSPeter Avalos 	 *    are much longer than the screen width,
4371133e27eSPeter Avalos 	 *    but I don't know of any better way. }}
4381133e27eSPeter Avalos 	 */
4398be36e5bSPeter Avalos 	new_pos = base_pos;
4401133e27eSPeter Avalos 	if (ch_seek(new_pos))
4411133e27eSPeter Avalos 	{
4421133e27eSPeter Avalos 		null_line();
4431133e27eSPeter Avalos 		return (NULL_POSITION);
4441133e27eSPeter Avalos 	}
4451133e27eSPeter Avalos 	endline = FALSE;
4461133e27eSPeter Avalos 	prewind();
4470c7ad07eSAntonio Huete Jimenez 	plinestart(new_pos);
4481133e27eSPeter Avalos     loop:
449320d7c8aSAaron LI 	wrap_pos = NULL_POSITION;
450320d7c8aSAaron LI 	skipped_leading = FALSE;
4511133e27eSPeter Avalos 	begin_new_pos = new_pos;
4521133e27eSPeter Avalos 	(void) ch_seek(new_pos);
45302d62a0fSDaniel Fojt 	chopped = FALSE;
4541133e27eSPeter Avalos 
455320d7c8aSAaron LI 	for (;;)
4561133e27eSPeter Avalos 	{
4571133e27eSPeter Avalos 		c = ch_forw_get();
458*e433da38SAaron LI 		if (c == EOI)
4591133e27eSPeter Avalos 		{
4601133e27eSPeter Avalos 			null_line();
4611133e27eSPeter Avalos 			return (NULL_POSITION);
4621133e27eSPeter Avalos 		}
4631133e27eSPeter Avalos 		new_pos++;
4641133e27eSPeter Avalos 		if (c == '\n')
4651133e27eSPeter Avalos 		{
4661133e27eSPeter Avalos 			backchars = pflushmbc();
4670c7ad07eSAntonio Huete Jimenez 			if (backchars > 0 && !chop_line() && hshift == 0)
4681133e27eSPeter Avalos 			{
4691133e27eSPeter Avalos 				backchars++;
4701133e27eSPeter Avalos 				goto shift;
4711133e27eSPeter Avalos 			}
4721133e27eSPeter Avalos 			endline = TRUE;
473320d7c8aSAaron LI 			edisp_pos = new_pos;
4741133e27eSPeter Avalos 			break;
4751133e27eSPeter Avalos 		}
476*e433da38SAaron LI 		backchars = pappend((char) c, ch_tell()-1);
4771133e27eSPeter Avalos 		if (backchars > 0)
4781133e27eSPeter Avalos 		{
4791133e27eSPeter Avalos 			/*
4801133e27eSPeter Avalos 			 * Got a full printable line, but we haven't
4811133e27eSPeter Avalos 			 * reached our curr_pos yet.  Discard the line
4821133e27eSPeter Avalos 			 * and start a new one.
4831133e27eSPeter Avalos 			 */
4840c7ad07eSAntonio Huete Jimenez 			if (chop_line() || hshift > 0)
4851133e27eSPeter Avalos 			{
4861133e27eSPeter Avalos 				endline = TRUE;
48702d62a0fSDaniel Fojt 				chopped = TRUE;
4881133e27eSPeter Avalos 				quit_if_one_screen = FALSE;
489320d7c8aSAaron LI 				edisp_pos = new_pos;
4901133e27eSPeter Avalos 				break;
4911133e27eSPeter Avalos 			}
4921133e27eSPeter Avalos 		shift:
493320d7c8aSAaron LI 			if (!wordwrap)
4941133e27eSPeter Avalos 			{
495320d7c8aSAaron LI 				pshift_all();
496320d7c8aSAaron LI 				new_pos -= backchars;
497320d7c8aSAaron LI 			} else
498320d7c8aSAaron LI 			{
499320d7c8aSAaron LI 				if (c == ' ' || c == '\t')
500320d7c8aSAaron LI 				{
501320d7c8aSAaron LI 					for (;;)
502320d7c8aSAaron LI 					{
503*e433da38SAaron LI 						c = ch_forw_get(); /* {{ what if c == EOI? }} */
504320d7c8aSAaron LI 						if (c == ' ' || c == '\t')
505320d7c8aSAaron LI 							new_pos++;
506320d7c8aSAaron LI 						else
507320d7c8aSAaron LI 						{
508320d7c8aSAaron LI 							if (c == '\r')
509320d7c8aSAaron LI 							{
510*e433da38SAaron LI 								c = ch_forw_get(); /* {{ what if c == EOI? }} */
511320d7c8aSAaron LI 								if (c == '\n')
512320d7c8aSAaron LI 									new_pos++;
513320d7c8aSAaron LI 							}
514320d7c8aSAaron LI 							if (c == '\n')
515320d7c8aSAaron LI 								new_pos++;
516*e433da38SAaron LI 							edisp_pos = new_pos;
517320d7c8aSAaron LI 							break;
518320d7c8aSAaron LI 						}
519320d7c8aSAaron LI 					}
520320d7c8aSAaron LI 					if (new_pos >= curr_pos)
521*e433da38SAaron LI 					{
522*e433da38SAaron LI 						edisp_pos = new_pos;
523320d7c8aSAaron LI 						break;
524*e433da38SAaron LI 					}
525320d7c8aSAaron LI 					pshift_all();
526320d7c8aSAaron LI 				} else
527320d7c8aSAaron LI 				{
528320d7c8aSAaron LI 					pshift_all();
529320d7c8aSAaron LI 					if (wrap_pos == NULL_POSITION)
530320d7c8aSAaron LI 						new_pos -= backchars;
531320d7c8aSAaron LI 					else
532320d7c8aSAaron LI 						new_pos = wrap_pos;
533320d7c8aSAaron LI 				}
5341133e27eSPeter Avalos 			}
5351133e27eSPeter Avalos 			goto loop;
5361133e27eSPeter Avalos 		}
537320d7c8aSAaron LI 		if (wordwrap)
538320d7c8aSAaron LI 		{
539320d7c8aSAaron LI 			if (c == ' ' || c == '\t')
540320d7c8aSAaron LI 			{
541320d7c8aSAaron LI 				if (skipped_leading)
542320d7c8aSAaron LI 					wrap_pos = new_pos;
543320d7c8aSAaron LI 			} else
544320d7c8aSAaron LI 				skipped_leading = TRUE;
545320d7c8aSAaron LI 		}
546320d7c8aSAaron LI 		if (new_pos >= curr_pos)
547320d7c8aSAaron LI 		{
548320d7c8aSAaron LI 			edisp_pos = new_pos;
549320d7c8aSAaron LI 			break;
550320d7c8aSAaron LI 		}
551320d7c8aSAaron LI 	}
5521133e27eSPeter Avalos 
55302d62a0fSDaniel Fojt 	pdone(endline, chopped, 0);
5548be36e5bSPeter Avalos 
5558be36e5bSPeter Avalos #if HILITE_SEARCH
5568be36e5bSPeter Avalos 	if (is_filtered(base_pos))
5578be36e5bSPeter Avalos 	{
5588be36e5bSPeter Avalos 		/*
5598be36e5bSPeter Avalos 		 * We don't want to display this line.
5608be36e5bSPeter Avalos 		 * Get the previous line.
5618be36e5bSPeter Avalos 		 */
5628be36e5bSPeter Avalos 		curr_pos = begin_new_pos;
5638be36e5bSPeter Avalos 		goto get_back_line;
5648be36e5bSPeter Avalos 	}
565320d7c8aSAaron LI 	if (status_col)
566320d7c8aSAaron LI 		init_status_col(base_pos, line_position(), edisp_pos, new_pos);
5678be36e5bSPeter Avalos #endif
5681133e27eSPeter Avalos 
5691133e27eSPeter Avalos 	return (begin_new_pos);
5701133e27eSPeter Avalos }
5711133e27eSPeter Avalos 
5721133e27eSPeter Avalos /*
5731133e27eSPeter Avalos  * Set attnpos.
5741133e27eSPeter Avalos  */
set_attnpos(POSITION pos)575320d7c8aSAaron LI public void set_attnpos(POSITION pos)
5761133e27eSPeter Avalos {
5771133e27eSPeter Avalos 	int c;
5781133e27eSPeter Avalos 
5791133e27eSPeter Avalos 	if (pos != NULL_POSITION)
5801133e27eSPeter Avalos 	{
5811133e27eSPeter Avalos 		if (ch_seek(pos))
5821133e27eSPeter Avalos 			return;
5831133e27eSPeter Avalos 		for (;;)
5841133e27eSPeter Avalos 		{
5851133e27eSPeter Avalos 			c = ch_forw_get();
5861133e27eSPeter Avalos 			if (c == EOI)
5871133e27eSPeter Avalos 				break;
588fa0be7c5SJohn Marino 			if (c == '\n' || c == '\r')
589fa0be7c5SJohn Marino 			{
590fa0be7c5SJohn Marino 				(void) ch_back_get();
591fa0be7c5SJohn Marino 				break;
592fa0be7c5SJohn Marino 			}
5931133e27eSPeter Avalos 			pos++;
5941133e27eSPeter Avalos 		}
595fa0be7c5SJohn Marino 		end_attnpos = pos;
596fa0be7c5SJohn Marino 		for (;;)
597fa0be7c5SJohn Marino 		{
598fa0be7c5SJohn Marino 			c = ch_back_get();
599fa0be7c5SJohn Marino 			if (c == EOI || c == '\n' || c == '\r')
600fa0be7c5SJohn Marino 				break;
601fa0be7c5SJohn Marino 			pos--;
602fa0be7c5SJohn Marino 		}
6031133e27eSPeter Avalos 	}
6041133e27eSPeter Avalos 	start_attnpos = pos;
6051133e27eSPeter Avalos }
606