xref: /dragonfly/contrib/less/input.c (revision 320d7c8a)
11133e27eSPeter Avalos /*
2*320d7c8aSAaron LI  * Copyright (C) 1984-2023  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 sigs;
261133e27eSPeter Avalos extern int ignore_eoi;
271133e27eSPeter Avalos extern int status_col;
28*320d7c8aSAaron LI extern int wordwrap;
291133e27eSPeter Avalos extern POSITION start_attnpos;
301133e27eSPeter Avalos extern POSITION end_attnpos;
311133e27eSPeter Avalos #if HILITE_SEARCH
321133e27eSPeter Avalos extern int hilite_search;
331133e27eSPeter Avalos extern int size_linebuf;
340c7ad07eSAntonio Huete Jimenez extern int show_attn;
351133e27eSPeter Avalos #endif
361133e27eSPeter Avalos 
371133e27eSPeter Avalos /*
38*320d7c8aSAaron LI  * Set the status column.
39*320d7c8aSAaron LI  *  base  Position of first char in line.
40*320d7c8aSAaron LI  *  disp  First visible char.
41*320d7c8aSAaron LI  *        Different than base_pos if line is shifted.
42*320d7c8aSAaron LI  *  edisp Last visible char.
43*320d7c8aSAaron LI  *  eol   End of line. Normally the newline.
44*320d7c8aSAaron LI  *        Different than edisp if line is chopped.
45*320d7c8aSAaron LI  */
init_status_col(POSITION base_pos,POSITION disp_pos,POSITION edisp_pos,POSITION eol_pos)46*320d7c8aSAaron LI static void init_status_col(POSITION base_pos, POSITION disp_pos, POSITION edisp_pos, POSITION eol_pos)
47*320d7c8aSAaron LI {
48*320d7c8aSAaron LI 	int hl_before = (chop_line() && disp_pos != NULL_POSITION) ?
49*320d7c8aSAaron LI 	    is_hilited_attr(base_pos, disp_pos, TRUE, NULL) : 0;
50*320d7c8aSAaron LI 	int hl_after = (chop_line()) ?
51*320d7c8aSAaron LI 	    is_hilited_attr(edisp_pos, eol_pos, TRUE, NULL) : 0;
52*320d7c8aSAaron LI 	int attr;
53*320d7c8aSAaron LI 	char ch;
54*320d7c8aSAaron LI 
55*320d7c8aSAaron LI 	if (hl_before && hl_after)
56*320d7c8aSAaron LI 	{
57*320d7c8aSAaron LI 		attr = hl_after;
58*320d7c8aSAaron LI 		ch = '=';
59*320d7c8aSAaron LI 	} else if (hl_before)
60*320d7c8aSAaron LI 	{
61*320d7c8aSAaron LI 		attr = hl_before;
62*320d7c8aSAaron LI 		ch = '<';
63*320d7c8aSAaron LI 	} else if (hl_after)
64*320d7c8aSAaron LI 	{
65*320d7c8aSAaron LI 		attr = hl_after;
66*320d7c8aSAaron LI 		ch = '>';
67*320d7c8aSAaron LI 	} else
68*320d7c8aSAaron LI 	{
69*320d7c8aSAaron LI 		attr = is_hilited_attr(base_pos, eol_pos, TRUE, NULL);
70*320d7c8aSAaron LI 		ch = '*';
71*320d7c8aSAaron LI 	}
72*320d7c8aSAaron LI 	if (attr)
73*320d7c8aSAaron LI 		set_status_col(ch, attr);
74*320d7c8aSAaron LI }
75*320d7c8aSAaron LI 
76*320d7c8aSAaron LI /*
771133e27eSPeter Avalos  * Get the next line.
781133e27eSPeter Avalos  * A "current" position is passed and a "new" position is returned.
791133e27eSPeter Avalos  * The current position is the position of the first character of
801133e27eSPeter Avalos  * a line.  The new position is the position of the first character
811133e27eSPeter Avalos  * of the NEXT line.  The line obtained is the line starting at curr_pos.
821133e27eSPeter Avalos  */
forw_line_seg(POSITION curr_pos,int skipeol,int rscroll,int nochop)83*320d7c8aSAaron LI public POSITION forw_line_seg(POSITION curr_pos, int skipeol, int rscroll, int nochop)
841133e27eSPeter Avalos {
851133e27eSPeter Avalos 	POSITION base_pos;
861133e27eSPeter Avalos 	POSITION new_pos;
87*320d7c8aSAaron LI 	POSITION edisp_pos;
8802d62a0fSDaniel Fojt 	int c;
891133e27eSPeter Avalos 	int blankline;
901133e27eSPeter Avalos 	int endline;
9102d62a0fSDaniel Fojt 	int chopped;
921133e27eSPeter Avalos 	int backchars;
93*320d7c8aSAaron LI 	POSITION wrap_pos;
94*320d7c8aSAaron LI 	int skipped_leading;
951133e27eSPeter Avalos 
968be36e5bSPeter Avalos get_forw_line:
971133e27eSPeter Avalos 	if (curr_pos == NULL_POSITION)
981133e27eSPeter Avalos 	{
991133e27eSPeter Avalos 		null_line();
1001133e27eSPeter Avalos 		return (NULL_POSITION);
1011133e27eSPeter Avalos 	}
1021133e27eSPeter Avalos #if HILITE_SEARCH
1038be36e5bSPeter Avalos 	if (hilite_search == OPT_ONPLUS || is_filtering() || status_col)
104fa0be7c5SJohn Marino 	{
1051133e27eSPeter Avalos 		/*
1061133e27eSPeter Avalos 		 * If we are ignoring EOI (command F), only prepare
1071133e27eSPeter Avalos 		 * one line ahead, to avoid getting stuck waiting for
1081133e27eSPeter Avalos 		 * slow data without displaying the data we already have.
1091133e27eSPeter Avalos 		 * If we're not ignoring EOI, we *could* do the same, but
1101133e27eSPeter Avalos 		 * for efficiency we prepare several lines ahead at once.
1111133e27eSPeter Avalos 		 */
1121133e27eSPeter Avalos 		prep_hilite(curr_pos, curr_pos + 3*size_linebuf,
1131133e27eSPeter Avalos 				ignore_eoi ? 1 : -1);
114fa0be7c5SJohn Marino 		curr_pos = next_unfiltered(curr_pos);
115fa0be7c5SJohn Marino 	}
1161133e27eSPeter Avalos #endif
1171133e27eSPeter Avalos 	if (ch_seek(curr_pos))
1181133e27eSPeter Avalos 	{
1191133e27eSPeter Avalos 		null_line();
1201133e27eSPeter Avalos 		return (NULL_POSITION);
1211133e27eSPeter Avalos 	}
1221133e27eSPeter Avalos 
1238be36e5bSPeter Avalos 	/*
1248be36e5bSPeter Avalos 	 * Step back to the beginning of the line.
1258be36e5bSPeter Avalos 	 */
1261133e27eSPeter Avalos 	base_pos = curr_pos;
1271133e27eSPeter Avalos 	for (;;)
1281133e27eSPeter Avalos 	{
1291133e27eSPeter Avalos 		if (ABORT_SIGS())
1301133e27eSPeter Avalos 		{
1311133e27eSPeter Avalos 			null_line();
1321133e27eSPeter Avalos 			return (NULL_POSITION);
1331133e27eSPeter Avalos 		}
1341133e27eSPeter Avalos 		c = ch_back_get();
1351133e27eSPeter Avalos 		if (c == EOI)
1361133e27eSPeter Avalos 			break;
1371133e27eSPeter Avalos 		if (c == '\n')
1381133e27eSPeter Avalos 		{
1391133e27eSPeter Avalos 			(void) ch_forw_get();
1401133e27eSPeter Avalos 			break;
1411133e27eSPeter Avalos 		}
1421133e27eSPeter Avalos 		--base_pos;
1431133e27eSPeter Avalos 	}
1441133e27eSPeter Avalos 
1458be36e5bSPeter Avalos 	/*
1468be36e5bSPeter Avalos 	 * Read forward again to the position we should start at.
1478be36e5bSPeter Avalos 	 */
1481133e27eSPeter Avalos 	prewind();
1490c7ad07eSAntonio Huete Jimenez 	plinestart(base_pos);
1501133e27eSPeter Avalos 	(void) ch_seek(base_pos);
1518be36e5bSPeter Avalos 	new_pos = base_pos;
1528be36e5bSPeter Avalos 	while (new_pos < curr_pos)
1531133e27eSPeter Avalos 	{
1541133e27eSPeter Avalos 		if (ABORT_SIGS())
1551133e27eSPeter Avalos 		{
1561133e27eSPeter Avalos 			null_line();
1571133e27eSPeter Avalos 			return (NULL_POSITION);
1581133e27eSPeter Avalos 		}
1591133e27eSPeter Avalos 		c = ch_forw_get();
1608be36e5bSPeter Avalos 		backchars = pappend(c, new_pos);
1618be36e5bSPeter Avalos 		new_pos++;
1621133e27eSPeter Avalos 		if (backchars > 0)
1631133e27eSPeter Avalos 		{
1641133e27eSPeter Avalos 			pshift_all();
165*320d7c8aSAaron LI 			if (wordwrap && (c == ' ' || c == '\t'))
166*320d7c8aSAaron LI 			{
167*320d7c8aSAaron LI 				do
168*320d7c8aSAaron LI 				{
169*320d7c8aSAaron LI 					new_pos++;
170*320d7c8aSAaron LI 					c = ch_forw_get();
171*320d7c8aSAaron LI 				} while (c == ' ' || c == '\t');
172*320d7c8aSAaron LI 				backchars = 1;
173*320d7c8aSAaron LI 			}
1748be36e5bSPeter Avalos 			new_pos -= backchars;
1751133e27eSPeter Avalos 			while (--backchars >= 0)
1761133e27eSPeter Avalos 				(void) ch_back_get();
1771133e27eSPeter Avalos 		}
1781133e27eSPeter Avalos 	}
1791133e27eSPeter Avalos 	(void) pflushmbc();
1801133e27eSPeter Avalos 	pshift_all();
1811133e27eSPeter Avalos 
1828be36e5bSPeter Avalos 	/*
1838be36e5bSPeter Avalos 	 * Read the first character to display.
1848be36e5bSPeter Avalos 	 */
1851133e27eSPeter Avalos 	c = ch_forw_get();
1861133e27eSPeter Avalos 	if (c == EOI)
1871133e27eSPeter Avalos 	{
1881133e27eSPeter Avalos 		null_line();
1891133e27eSPeter Avalos 		return (NULL_POSITION);
1901133e27eSPeter Avalos 	}
1911133e27eSPeter Avalos 	blankline = (c == '\n' || c == '\r');
192*320d7c8aSAaron LI 	wrap_pos = NULL_POSITION;
193*320d7c8aSAaron LI 	skipped_leading = FALSE;
1941133e27eSPeter Avalos 
1958be36e5bSPeter Avalos 	/*
1968be36e5bSPeter Avalos 	 * Read each character in the line and append to the line buffer.
1978be36e5bSPeter Avalos 	 */
19802d62a0fSDaniel Fojt 	chopped = FALSE;
1991133e27eSPeter Avalos 	for (;;)
2001133e27eSPeter Avalos 	{
2011133e27eSPeter Avalos 		if (ABORT_SIGS())
2021133e27eSPeter Avalos 		{
2031133e27eSPeter Avalos 			null_line();
2041133e27eSPeter Avalos 			return (NULL_POSITION);
2051133e27eSPeter Avalos 		}
2061133e27eSPeter Avalos 		if (c == '\n' || c == EOI)
2071133e27eSPeter Avalos 		{
2081133e27eSPeter Avalos 			/*
2091133e27eSPeter Avalos 			 * End of the line.
2101133e27eSPeter Avalos 			 */
2111133e27eSPeter Avalos 			backchars = pflushmbc();
2121133e27eSPeter Avalos 			new_pos = ch_tell();
2130c7ad07eSAntonio Huete Jimenez 			if (backchars > 0 && (nochop || !chop_line()) && hshift == 0)
2141133e27eSPeter Avalos 			{
2151133e27eSPeter Avalos 				new_pos -= backchars + 1;
2161133e27eSPeter Avalos 				endline = FALSE;
2171133e27eSPeter Avalos 			} else
2181133e27eSPeter Avalos 				endline = TRUE;
219*320d7c8aSAaron LI 			edisp_pos = new_pos;
2201133e27eSPeter Avalos 			break;
2211133e27eSPeter Avalos 		}
2221133e27eSPeter Avalos 		if (c != '\r')
2231133e27eSPeter Avalos 			blankline = 0;
2241133e27eSPeter Avalos 
2251133e27eSPeter Avalos 		/*
2261133e27eSPeter Avalos 		 * Append the char to the line and get the next char.
2271133e27eSPeter Avalos 		 */
2281133e27eSPeter Avalos 		backchars = pappend(c, ch_tell()-1);
2291133e27eSPeter Avalos 		if (backchars > 0)
2301133e27eSPeter Avalos 		{
2311133e27eSPeter Avalos 			/*
2321133e27eSPeter Avalos 			 * The char won't fit in the line; the line
2331133e27eSPeter Avalos 			 * is too long to print in the screen width.
2341133e27eSPeter Avalos 			 * End the line here.
2351133e27eSPeter Avalos 			 */
2360c7ad07eSAntonio Huete Jimenez 			if (skipeol)
2371133e27eSPeter Avalos 			{
2380c7ad07eSAntonio Huete Jimenez 				/* Read to end of line. */
239*320d7c8aSAaron LI 				edisp_pos = ch_tell();
2401133e27eSPeter Avalos 				do
2411133e27eSPeter Avalos 				{
24225ce721eSPeter Avalos 					if (ABORT_SIGS())
24325ce721eSPeter Avalos 					{
24425ce721eSPeter Avalos 						null_line();
24525ce721eSPeter Avalos 						return (NULL_POSITION);
24625ce721eSPeter Avalos 					}
2471133e27eSPeter Avalos 					c = ch_forw_get();
2481133e27eSPeter Avalos 				} while (c != '\n' && c != EOI);
2491133e27eSPeter Avalos 				new_pos = ch_tell();
2501133e27eSPeter Avalos 				endline = TRUE;
2511133e27eSPeter Avalos 				quit_if_one_screen = FALSE;
25202d62a0fSDaniel Fojt 				chopped = TRUE;
2531133e27eSPeter Avalos 			} else
2541133e27eSPeter Avalos 			{
255*320d7c8aSAaron LI 				if (!wordwrap)
2561133e27eSPeter Avalos 					new_pos = ch_tell() - backchars;
257*320d7c8aSAaron LI 				else
258*320d7c8aSAaron LI 				{
259*320d7c8aSAaron LI 					/*
260*320d7c8aSAaron LI 					 * We're word-wrapping, so go back to the last space.
261*320d7c8aSAaron LI 					 * However, if it's the space itself that couldn't fit,
262*320d7c8aSAaron LI 					 * simply ignore it and any subsequent spaces.
263*320d7c8aSAaron LI 					 */
264*320d7c8aSAaron LI 					if (c == ' ' || c == '\t')
265*320d7c8aSAaron LI 					{
266*320d7c8aSAaron LI 						do
267*320d7c8aSAaron LI 						{
268*320d7c8aSAaron LI 							new_pos = ch_tell();
269*320d7c8aSAaron LI 							c = ch_forw_get();
270*320d7c8aSAaron LI 						} while (c == ' ' || c == '\t');
271*320d7c8aSAaron LI 						if (c == '\r')
272*320d7c8aSAaron LI 							c = ch_forw_get();
273*320d7c8aSAaron LI 						if (c == '\n')
274*320d7c8aSAaron LI 							new_pos = ch_tell();
275*320d7c8aSAaron LI 					} else if (wrap_pos == NULL_POSITION)
276*320d7c8aSAaron LI 						new_pos = ch_tell() - backchars;
277*320d7c8aSAaron LI 					else
278*320d7c8aSAaron LI 					{
279*320d7c8aSAaron LI 						new_pos = wrap_pos;
280*320d7c8aSAaron LI 						loadc();
281*320d7c8aSAaron LI 					}
282*320d7c8aSAaron LI 				}
2831133e27eSPeter Avalos 				endline = FALSE;
2841133e27eSPeter Avalos 			}
2851133e27eSPeter Avalos 			break;
2861133e27eSPeter Avalos 		}
287*320d7c8aSAaron LI 		if (wordwrap)
288*320d7c8aSAaron LI 		{
289*320d7c8aSAaron LI 			if (c == ' ' || c == '\t')
290*320d7c8aSAaron LI 			{
291*320d7c8aSAaron LI 				if (skipped_leading)
292*320d7c8aSAaron LI 				{
293*320d7c8aSAaron LI 					wrap_pos = ch_tell();
294*320d7c8aSAaron LI 					savec();
295*320d7c8aSAaron LI 				}
296*320d7c8aSAaron LI 			} else
297*320d7c8aSAaron LI 				skipped_leading = TRUE;
298*320d7c8aSAaron LI 		}
2991133e27eSPeter Avalos 		c = ch_forw_get();
3001133e27eSPeter Avalos 	}
3018be36e5bSPeter Avalos 
3020c7ad07eSAntonio Huete Jimenez #if HILITE_SEARCH
3030c7ad07eSAntonio Huete Jimenez 	if (blankline && show_attn)
3040c7ad07eSAntonio Huete Jimenez 	{
3050c7ad07eSAntonio Huete Jimenez 		/* Add spurious space to carry possible attn hilite. */
3060c7ad07eSAntonio Huete Jimenez 		pappend(' ', ch_tell()-1);
3070c7ad07eSAntonio Huete Jimenez 	}
3080c7ad07eSAntonio Huete Jimenez #endif
3090c7ad07eSAntonio Huete Jimenez 	pdone(endline, rscroll && chopped, 1);
3108be36e5bSPeter Avalos 
3118be36e5bSPeter Avalos #if HILITE_SEARCH
3128be36e5bSPeter Avalos 	if (is_filtered(base_pos))
3138be36e5bSPeter Avalos 	{
3148be36e5bSPeter Avalos 		/*
3158be36e5bSPeter Avalos 		 * We don't want to display this line.
3168be36e5bSPeter Avalos 		 * Get the next line.
3178be36e5bSPeter Avalos 		 */
3188be36e5bSPeter Avalos 		curr_pos = new_pos;
3198be36e5bSPeter Avalos 		goto get_forw_line;
3208be36e5bSPeter Avalos 	}
3210c7ad07eSAntonio Huete Jimenez 	if (status_col)
322*320d7c8aSAaron LI 		init_status_col(base_pos, line_position(), edisp_pos, new_pos);
3238be36e5bSPeter Avalos #endif
3241133e27eSPeter Avalos 
3251133e27eSPeter Avalos 	if (squeeze && blankline)
3261133e27eSPeter Avalos 	{
3271133e27eSPeter Avalos 		/*
3281133e27eSPeter Avalos 		 * This line is blank.
3291133e27eSPeter Avalos 		 * Skip down to the last contiguous blank line
3301133e27eSPeter Avalos 		 * and pretend it is the one which we are returning.
3311133e27eSPeter Avalos 		 */
3321133e27eSPeter Avalos 		while ((c = ch_forw_get()) == '\n' || c == '\r')
3331133e27eSPeter Avalos 			if (ABORT_SIGS())
3341133e27eSPeter Avalos 			{
3351133e27eSPeter Avalos 				null_line();
3361133e27eSPeter Avalos 				return (NULL_POSITION);
3371133e27eSPeter Avalos 			}
3381133e27eSPeter Avalos 		if (c != EOI)
3391133e27eSPeter Avalos 			(void) ch_back_get();
3401133e27eSPeter Avalos 		new_pos = ch_tell();
3411133e27eSPeter Avalos 	}
3421133e27eSPeter Avalos 
3431133e27eSPeter Avalos 	return (new_pos);
3441133e27eSPeter Avalos }
3451133e27eSPeter Avalos 
forw_line(POSITION curr_pos)346*320d7c8aSAaron LI public POSITION forw_line(POSITION curr_pos)
3470c7ad07eSAntonio Huete Jimenez {
3480c7ad07eSAntonio Huete Jimenez 
3490c7ad07eSAntonio Huete Jimenez 	return forw_line_seg(curr_pos, (chop_line() || hshift > 0), TRUE, FALSE);
3500c7ad07eSAntonio Huete Jimenez }
3510c7ad07eSAntonio Huete Jimenez 
3521133e27eSPeter Avalos /*
3531133e27eSPeter Avalos  * Get the previous line.
3541133e27eSPeter Avalos  * A "current" position is passed and a "new" position is returned.
3551133e27eSPeter Avalos  * The current position is the position of the first character of
3561133e27eSPeter Avalos  * a line.  The new position is the position of the first character
3571133e27eSPeter Avalos  * of the PREVIOUS line.  The line obtained is the one starting at new_pos.
3581133e27eSPeter Avalos  */
back_line(POSITION curr_pos)359*320d7c8aSAaron LI public POSITION back_line(POSITION curr_pos)
3601133e27eSPeter Avalos {
361*320d7c8aSAaron LI 	POSITION base_pos;
362*320d7c8aSAaron LI 	POSITION new_pos;
363*320d7c8aSAaron LI 	POSITION edisp_pos;
364*320d7c8aSAaron LI 	POSITION begin_new_pos;
3651133e27eSPeter Avalos 	int c;
3661133e27eSPeter Avalos 	int endline;
36702d62a0fSDaniel Fojt 	int chopped;
3681133e27eSPeter Avalos 	int backchars;
369*320d7c8aSAaron LI 	POSITION wrap_pos;
370*320d7c8aSAaron LI 	int skipped_leading;
3711133e27eSPeter Avalos 
3728be36e5bSPeter Avalos get_back_line:
3731133e27eSPeter Avalos 	if (curr_pos == NULL_POSITION || curr_pos <= ch_zero())
3741133e27eSPeter Avalos 	{
3751133e27eSPeter Avalos 		null_line();
3761133e27eSPeter Avalos 		return (NULL_POSITION);
3771133e27eSPeter Avalos 	}
3781133e27eSPeter Avalos #if HILITE_SEARCH
3798be36e5bSPeter Avalos 	if (hilite_search == OPT_ONPLUS || is_filtering() || status_col)
3801133e27eSPeter Avalos 		prep_hilite((curr_pos < 3*size_linebuf) ?
3811133e27eSPeter Avalos 				0 : curr_pos - 3*size_linebuf, curr_pos, -1);
3821133e27eSPeter Avalos #endif
3831133e27eSPeter Avalos 	if (ch_seek(curr_pos-1))
3841133e27eSPeter Avalos 	{
3851133e27eSPeter Avalos 		null_line();
3861133e27eSPeter Avalos 		return (NULL_POSITION);
3871133e27eSPeter Avalos 	}
3881133e27eSPeter Avalos 
3891133e27eSPeter Avalos 	if (squeeze)
3901133e27eSPeter Avalos 	{
3911133e27eSPeter Avalos 		/*
3921133e27eSPeter Avalos 		 * Find out if the "current" line was blank.
3931133e27eSPeter Avalos 		 */
3941133e27eSPeter Avalos 		(void) ch_forw_get();    /* Skip the newline */
3951133e27eSPeter Avalos 		c = ch_forw_get();       /* First char of "current" line */
3961133e27eSPeter Avalos 		(void) ch_back_get();    /* Restore our position */
3971133e27eSPeter Avalos 		(void) ch_back_get();
3981133e27eSPeter Avalos 
3991133e27eSPeter Avalos 		if (c == '\n' || c == '\r')
4001133e27eSPeter Avalos 		{
4011133e27eSPeter Avalos 			/*
4021133e27eSPeter Avalos 			 * The "current" line was blank.
4031133e27eSPeter Avalos 			 * Skip over any preceding blank lines,
4041133e27eSPeter Avalos 			 * since we skipped them in forw_line().
4051133e27eSPeter Avalos 			 */
4061133e27eSPeter Avalos 			while ((c = ch_back_get()) == '\n' || c == '\r')
4071133e27eSPeter Avalos 				if (ABORT_SIGS())
4081133e27eSPeter Avalos 				{
4091133e27eSPeter Avalos 					null_line();
4101133e27eSPeter Avalos 					return (NULL_POSITION);
4111133e27eSPeter Avalos 				}
4121133e27eSPeter Avalos 			if (c == EOI)
4131133e27eSPeter Avalos 			{
4141133e27eSPeter Avalos 				null_line();
4151133e27eSPeter Avalos 				return (NULL_POSITION);
4161133e27eSPeter Avalos 			}
4171133e27eSPeter Avalos 			(void) ch_forw_get();
4181133e27eSPeter Avalos 		}
4191133e27eSPeter Avalos 	}
4201133e27eSPeter Avalos 
4211133e27eSPeter Avalos 	/*
4221133e27eSPeter Avalos 	 * Scan backwards until we hit the beginning of the line.
4231133e27eSPeter Avalos 	 */
4241133e27eSPeter Avalos 	for (;;)
4251133e27eSPeter Avalos 	{
4261133e27eSPeter Avalos 		if (ABORT_SIGS())
4271133e27eSPeter Avalos 		{
4281133e27eSPeter Avalos 			null_line();
4291133e27eSPeter Avalos 			return (NULL_POSITION);
4301133e27eSPeter Avalos 		}
4311133e27eSPeter Avalos 		c = ch_back_get();
4321133e27eSPeter Avalos 		if (c == '\n')
4331133e27eSPeter Avalos 		{
4341133e27eSPeter Avalos 			/*
4351133e27eSPeter Avalos 			 * This is the newline ending the previous line.
4361133e27eSPeter Avalos 			 * We have hit the beginning of the line.
4371133e27eSPeter Avalos 			 */
4388be36e5bSPeter Avalos 			base_pos = ch_tell() + 1;
4391133e27eSPeter Avalos 			break;
4401133e27eSPeter Avalos 		}
4411133e27eSPeter Avalos 		if (c == EOI)
4421133e27eSPeter Avalos 		{
4431133e27eSPeter Avalos 			/*
4441133e27eSPeter Avalos 			 * We have hit the beginning of the file.
4451133e27eSPeter Avalos 			 * This must be the first line in the file.
4461133e27eSPeter Avalos 			 * This must, of course, be the beginning of the line.
4471133e27eSPeter Avalos 			 */
4488be36e5bSPeter Avalos 			base_pos = ch_tell();
4491133e27eSPeter Avalos 			break;
4501133e27eSPeter Avalos 		}
4511133e27eSPeter Avalos 	}
4521133e27eSPeter Avalos 
4531133e27eSPeter Avalos 	/*
4541133e27eSPeter Avalos 	 * Now scan forwards from the beginning of this line.
4551133e27eSPeter Avalos 	 * We keep discarding "printable lines" (based on screen width)
4561133e27eSPeter Avalos 	 * until we reach the curr_pos.
4571133e27eSPeter Avalos 	 *
4581133e27eSPeter Avalos 	 * {{ This algorithm is pretty inefficient if the lines
4591133e27eSPeter Avalos 	 *    are much longer than the screen width,
4601133e27eSPeter Avalos 	 *    but I don't know of any better way. }}
4611133e27eSPeter Avalos 	 */
4628be36e5bSPeter Avalos 	new_pos = base_pos;
4631133e27eSPeter Avalos 	if (ch_seek(new_pos))
4641133e27eSPeter Avalos 	{
4651133e27eSPeter Avalos 		null_line();
4661133e27eSPeter Avalos 		return (NULL_POSITION);
4671133e27eSPeter Avalos 	}
4681133e27eSPeter Avalos 	endline = FALSE;
4691133e27eSPeter Avalos 	prewind();
4700c7ad07eSAntonio Huete Jimenez 	plinestart(new_pos);
4711133e27eSPeter Avalos     loop:
472*320d7c8aSAaron LI 	wrap_pos = NULL_POSITION;
473*320d7c8aSAaron LI 	skipped_leading = FALSE;
4741133e27eSPeter Avalos 	begin_new_pos = new_pos;
4751133e27eSPeter Avalos 	(void) ch_seek(new_pos);
47602d62a0fSDaniel Fojt 	chopped = FALSE;
4771133e27eSPeter Avalos 
478*320d7c8aSAaron LI 	for (;;)
4791133e27eSPeter Avalos 	{
4801133e27eSPeter Avalos 		c = ch_forw_get();
4811133e27eSPeter Avalos 		if (c == EOI || ABORT_SIGS())
4821133e27eSPeter Avalos 		{
4831133e27eSPeter Avalos 			null_line();
4841133e27eSPeter Avalos 			return (NULL_POSITION);
4851133e27eSPeter Avalos 		}
4861133e27eSPeter Avalos 		new_pos++;
4871133e27eSPeter Avalos 		if (c == '\n')
4881133e27eSPeter Avalos 		{
4891133e27eSPeter Avalos 			backchars = pflushmbc();
4900c7ad07eSAntonio Huete Jimenez 			if (backchars > 0 && !chop_line() && hshift == 0)
4911133e27eSPeter Avalos 			{
4921133e27eSPeter Avalos 				backchars++;
4931133e27eSPeter Avalos 				goto shift;
4941133e27eSPeter Avalos 			}
4951133e27eSPeter Avalos 			endline = TRUE;
496*320d7c8aSAaron LI 			edisp_pos = new_pos;
4971133e27eSPeter Avalos 			break;
4981133e27eSPeter Avalos 		}
4991133e27eSPeter Avalos 		backchars = pappend(c, ch_tell()-1);
5001133e27eSPeter Avalos 		if (backchars > 0)
5011133e27eSPeter Avalos 		{
5021133e27eSPeter Avalos 			/*
5031133e27eSPeter Avalos 			 * Got a full printable line, but we haven't
5041133e27eSPeter Avalos 			 * reached our curr_pos yet.  Discard the line
5051133e27eSPeter Avalos 			 * and start a new one.
5061133e27eSPeter Avalos 			 */
5070c7ad07eSAntonio Huete Jimenez 			if (chop_line() || hshift > 0)
5081133e27eSPeter Avalos 			{
5091133e27eSPeter Avalos 				endline = TRUE;
51002d62a0fSDaniel Fojt 				chopped = TRUE;
5111133e27eSPeter Avalos 				quit_if_one_screen = FALSE;
512*320d7c8aSAaron LI 				edisp_pos = new_pos;
5131133e27eSPeter Avalos 				break;
5141133e27eSPeter Avalos 			}
5151133e27eSPeter Avalos 		shift:
516*320d7c8aSAaron LI 			if (!wordwrap)
5171133e27eSPeter Avalos 			{
518*320d7c8aSAaron LI 				pshift_all();
519*320d7c8aSAaron LI 				new_pos -= backchars;
520*320d7c8aSAaron LI 			} else
521*320d7c8aSAaron LI 			{
522*320d7c8aSAaron LI 				if (c == ' ' || c == '\t')
523*320d7c8aSAaron LI 				{
524*320d7c8aSAaron LI 					for (;;)
525*320d7c8aSAaron LI 					{
526*320d7c8aSAaron LI 						c = ch_forw_get();
527*320d7c8aSAaron LI 						if (c == ' ' || c == '\t')
528*320d7c8aSAaron LI 							new_pos++;
529*320d7c8aSAaron LI 						else
530*320d7c8aSAaron LI 						{
531*320d7c8aSAaron LI 							if (c == '\r')
532*320d7c8aSAaron LI 							{
533*320d7c8aSAaron LI 								c = ch_forw_get();
534*320d7c8aSAaron LI 								if (c == '\n')
535*320d7c8aSAaron LI 									new_pos++;
536*320d7c8aSAaron LI 							}
537*320d7c8aSAaron LI 							if (c == '\n')
538*320d7c8aSAaron LI 								new_pos++;
539*320d7c8aSAaron LI 							break;
540*320d7c8aSAaron LI 						}
541*320d7c8aSAaron LI 					}
542*320d7c8aSAaron LI 					if (new_pos >= curr_pos)
543*320d7c8aSAaron LI 						break;
544*320d7c8aSAaron LI 					pshift_all();
545*320d7c8aSAaron LI 				} else
546*320d7c8aSAaron LI 				{
547*320d7c8aSAaron LI 					pshift_all();
548*320d7c8aSAaron LI 					if (wrap_pos == NULL_POSITION)
549*320d7c8aSAaron LI 						new_pos -= backchars;
550*320d7c8aSAaron LI 					else
551*320d7c8aSAaron LI 						new_pos = wrap_pos;
552*320d7c8aSAaron LI 				}
5531133e27eSPeter Avalos 			}
5541133e27eSPeter Avalos 			goto loop;
5551133e27eSPeter Avalos 		}
556*320d7c8aSAaron LI 		if (wordwrap)
557*320d7c8aSAaron LI 		{
558*320d7c8aSAaron LI 			if (c == ' ' || c == '\t')
559*320d7c8aSAaron LI 			{
560*320d7c8aSAaron LI 				if (skipped_leading)
561*320d7c8aSAaron LI 					wrap_pos = new_pos;
562*320d7c8aSAaron LI 			} else
563*320d7c8aSAaron LI 				skipped_leading = TRUE;
564*320d7c8aSAaron LI 		}
565*320d7c8aSAaron LI 		if (new_pos >= curr_pos)
566*320d7c8aSAaron LI 		{
567*320d7c8aSAaron LI 			edisp_pos = new_pos;
568*320d7c8aSAaron LI 			break;
569*320d7c8aSAaron LI 		}
570*320d7c8aSAaron LI 	}
5711133e27eSPeter Avalos 
57202d62a0fSDaniel Fojt 	pdone(endline, chopped, 0);
5738be36e5bSPeter Avalos 
5748be36e5bSPeter Avalos #if HILITE_SEARCH
5758be36e5bSPeter Avalos 	if (is_filtered(base_pos))
5768be36e5bSPeter Avalos 	{
5778be36e5bSPeter Avalos 		/*
5788be36e5bSPeter Avalos 		 * We don't want to display this line.
5798be36e5bSPeter Avalos 		 * Get the previous line.
5808be36e5bSPeter Avalos 		 */
5818be36e5bSPeter Avalos 		curr_pos = begin_new_pos;
5828be36e5bSPeter Avalos 		goto get_back_line;
5838be36e5bSPeter Avalos 	}
584*320d7c8aSAaron LI 	if (status_col)
585*320d7c8aSAaron LI 		init_status_col(base_pos, line_position(), edisp_pos, new_pos);
5868be36e5bSPeter Avalos #endif
5871133e27eSPeter Avalos 
5881133e27eSPeter Avalos 	return (begin_new_pos);
5891133e27eSPeter Avalos }
5901133e27eSPeter Avalos 
5911133e27eSPeter Avalos /*
5921133e27eSPeter Avalos  * Set attnpos.
5931133e27eSPeter Avalos  */
set_attnpos(POSITION pos)594*320d7c8aSAaron LI public void set_attnpos(POSITION pos)
5951133e27eSPeter Avalos {
5961133e27eSPeter Avalos 	int c;
5971133e27eSPeter Avalos 
5981133e27eSPeter Avalos 	if (pos != NULL_POSITION)
5991133e27eSPeter Avalos 	{
6001133e27eSPeter Avalos 		if (ch_seek(pos))
6011133e27eSPeter Avalos 			return;
6021133e27eSPeter Avalos 		for (;;)
6031133e27eSPeter Avalos 		{
6041133e27eSPeter Avalos 			c = ch_forw_get();
6051133e27eSPeter Avalos 			if (c == EOI)
6061133e27eSPeter Avalos 				break;
607fa0be7c5SJohn Marino 			if (c == '\n' || c == '\r')
608fa0be7c5SJohn Marino 			{
609fa0be7c5SJohn Marino 				(void) ch_back_get();
610fa0be7c5SJohn Marino 				break;
611fa0be7c5SJohn Marino 			}
6121133e27eSPeter Avalos 			pos++;
6131133e27eSPeter Avalos 		}
614fa0be7c5SJohn Marino 		end_attnpos = pos;
615fa0be7c5SJohn Marino 		for (;;)
616fa0be7c5SJohn Marino 		{
617fa0be7c5SJohn Marino 			c = ch_back_get();
618fa0be7c5SJohn Marino 			if (c == EOI || c == '\n' || c == '\r')
619fa0be7c5SJohn Marino 				break;
620fa0be7c5SJohn Marino 			pos--;
621fa0be7c5SJohn Marino 		}
6221133e27eSPeter Avalos 	}
6231133e27eSPeter Avalos 	start_attnpos = pos;
6241133e27eSPeter Avalos }
625