jump.c revision 60786
160786Sps/*
260786Sps * Copyright (C) 1984-2000  Mark Nudelman
360786Sps *
460786Sps * You may distribute under the terms of either the GNU General Public
560786Sps * License or the Less License, as specified in the README file.
660786Sps *
760786Sps * For more information about less, or for information on how to
860786Sps * contact the author, see the README file.
960786Sps */
1060786Sps
1160786Sps
1260786Sps/*
1360786Sps * Routines which jump to a new location in the file.
1460786Sps */
1560786Sps
1660786Sps#include "less.h"
1760786Sps#include "position.h"
1860786Sps
1960786Spsextern int hit_eof;
2060786Spsextern int jump_sline;
2160786Spsextern int squished;
2260786Spsextern int screen_trashed;
2360786Spsextern int sc_width, sc_height;
2460786Spsextern int show_attn;
2560786Sps
2660786Sps/*
2760786Sps * Jump to the end of the file.
2860786Sps */
2960786Sps	public void
3060786Spsjump_forw()
3160786Sps{
3260786Sps	POSITION pos;
3360786Sps
3460786Sps	if (ch_end_seek())
3560786Sps	{
3660786Sps		error("Cannot seek to end of file", NULL_PARG);
3760786Sps		return;
3860786Sps	}
3960786Sps	/*
4060786Sps	 * Position the last line in the file at the last screen line.
4160786Sps	 * Go back one line from the end of the file
4260786Sps	 * to get to the beginning of the last line.
4360786Sps	 */
4460786Sps	pos = back_line(ch_tell());
4560786Sps	if (pos == NULL_POSITION)
4660786Sps		jump_loc((POSITION)0, sc_height-1);
4760786Sps	else
4860786Sps		jump_loc(pos, sc_height-1);
4960786Sps}
5060786Sps
5160786Sps/*
5260786Sps * Jump to line n in the file.
5360786Sps */
5460786Sps	public void
5560786Spsjump_back(n)
5660786Sps	int n;
5760786Sps{
5860786Sps	POSITION pos;
5960786Sps	PARG parg;
6060786Sps
6160786Sps	/*
6260786Sps	 * Find the position of the specified line.
6360786Sps	 * If we can seek there, just jump to it.
6460786Sps	 * If we can't seek, but we're trying to go to line number 1,
6560786Sps	 * use ch_beg_seek() to get as close as we can.
6660786Sps	 */
6760786Sps	pos = find_pos(n);
6860786Sps	if (pos != NULL_POSITION && ch_seek(pos) == 0)
6960786Sps	{
7060786Sps		if (show_attn)
7160786Sps			set_attnpos(pos);
7260786Sps		jump_loc(pos, jump_sline);
7360786Sps	} else if (n <= 1 && ch_beg_seek() == 0)
7460786Sps	{
7560786Sps		jump_loc(ch_tell(), jump_sline);
7660786Sps		error("Cannot seek to beginning of file", NULL_PARG);
7760786Sps	} else
7860786Sps	{
7960786Sps		parg.p_int = n;
8060786Sps		error("Cannot seek to line number %d", &parg);
8160786Sps	}
8260786Sps}
8360786Sps
8460786Sps/*
8560786Sps * Repaint the screen.
8660786Sps */
8760786Sps	public void
8860786Spsrepaint()
8960786Sps{
9060786Sps	struct scrpos scrpos;
9160786Sps	/*
9260786Sps	 * Start at the line currently at the top of the screen
9360786Sps	 * and redisplay the screen.
9460786Sps	 */
9560786Sps	get_scrpos(&scrpos);
9660786Sps	pos_clear();
9760786Sps	jump_loc(scrpos.pos, scrpos.ln);
9860786Sps}
9960786Sps
10060786Sps/*
10160786Sps * Jump to a specified percentage into the file.
10260786Sps */
10360786Sps	public void
10460786Spsjump_percent(percent)
10560786Sps	int percent;
10660786Sps{
10760786Sps	POSITION pos, len;
10860786Sps
10960786Sps	/*
11060786Sps	 * Determine the position in the file
11160786Sps	 * (the specified percentage of the file's length).
11260786Sps	 */
11360786Sps	if ((len = ch_length()) == NULL_POSITION)
11460786Sps	{
11560786Sps		ierror("Determining length of file", NULL_PARG);
11660786Sps		ch_end_seek();
11760786Sps	}
11860786Sps	if ((len = ch_length()) == NULL_POSITION)
11960786Sps	{
12060786Sps		error("Don't know length of file", NULL_PARG);
12160786Sps		return;
12260786Sps	}
12360786Sps	pos = percent_pos(len, percent);
12460786Sps	if (pos >= len)
12560786Sps		pos = len-1;
12660786Sps
12760786Sps	jump_line_loc(pos, jump_sline);
12860786Sps}
12960786Sps
13060786Sps/*
13160786Sps * Jump to a specified position in the file.
13260786Sps * Like jump_loc, but the position need not be
13360786Sps * the first character in a line.
13460786Sps */
13560786Sps	public void
13660786Spsjump_line_loc(pos, sline)
13760786Sps	POSITION pos;
13860786Sps	int sline;
13960786Sps{
14060786Sps	int c;
14160786Sps
14260786Sps	if (ch_seek(pos) == 0)
14360786Sps	{
14460786Sps		/*
14560786Sps		 * Back up to the beginning of the line.
14660786Sps		 */
14760786Sps		while ((c = ch_back_get()) != '\n' && c != EOI)
14860786Sps			;
14960786Sps		if (c == '\n')
15060786Sps			(void) ch_forw_get();
15160786Sps		pos = ch_tell();
15260786Sps	}
15360786Sps	if (show_attn)
15460786Sps		set_attnpos(pos);
15560786Sps	jump_loc(pos, sline);
15660786Sps}
15760786Sps
15860786Sps/*
15960786Sps * Jump to a specified position in the file.
16060786Sps * The position must be the first character in a line.
16160786Sps * Place the target line on a specified line on the screen.
16260786Sps */
16360786Sps	public void
16460786Spsjump_loc(pos, sline)
16560786Sps	POSITION pos;
16660786Sps	int sline;
16760786Sps{
16860786Sps	register int nline;
16960786Sps	POSITION tpos;
17060786Sps	POSITION bpos;
17160786Sps
17260786Sps	/*
17360786Sps	 * Normalize sline.
17460786Sps	 */
17560786Sps	sline = adjsline(sline);
17660786Sps
17760786Sps	if ((nline = onscreen(pos)) >= 0)
17860786Sps	{
17960786Sps		/*
18060786Sps		 * The line is currently displayed.
18160786Sps		 * Just scroll there.
18260786Sps		 */
18360786Sps		nline -= sline;
18460786Sps		if (nline > 0)
18560786Sps			forw(nline, position(BOTTOM_PLUS_ONE), 1, 0, 0);
18660786Sps		else
18760786Sps			back(-nline, position(TOP), 1, 0);
18860786Sps		if (show_attn)
18960786Sps			repaint_hilite(1);
19060786Sps		return;
19160786Sps	}
19260786Sps
19360786Sps	/*
19460786Sps	 * Line is not on screen.
19560786Sps	 * Seek to the desired location.
19660786Sps	 */
19760786Sps	if (ch_seek(pos))
19860786Sps	{
19960786Sps		error("Cannot seek to that file position", NULL_PARG);
20060786Sps		return;
20160786Sps	}
20260786Sps
20360786Sps	/*
20460786Sps	 * See if the desired line is before or after
20560786Sps	 * the currently displayed screen.
20660786Sps	 */
20760786Sps	tpos = position(TOP);
20860786Sps	bpos = position(BOTTOM_PLUS_ONE);
20960786Sps	if (tpos == NULL_POSITION || pos >= tpos)
21060786Sps	{
21160786Sps		/*
21260786Sps		 * The desired line is after the current screen.
21360786Sps		 * Move back in the file far enough so that we can
21460786Sps		 * call forw() and put the desired line at the
21560786Sps		 * sline-th line on the screen.
21660786Sps		 */
21760786Sps		for (nline = 0;  nline < sline;  nline++)
21860786Sps		{
21960786Sps			if (bpos != NULL_POSITION && pos <= bpos)
22060786Sps			{
22160786Sps				/*
22260786Sps				 * Surprise!  The desired line is
22360786Sps				 * close enough to the current screen
22460786Sps				 * that we can just scroll there after all.
22560786Sps				 */
22660786Sps				forw(sc_height-sline+nline-1, bpos, 1, 0, 0);
22760786Sps				if (show_attn)
22860786Sps					repaint_hilite(1);
22960786Sps				return;
23060786Sps			}
23160786Sps			pos = back_line(pos);
23260786Sps			if (pos == NULL_POSITION)
23360786Sps			{
23460786Sps				/*
23560786Sps				 * Oops.  Ran into the beginning of the file.
23660786Sps				 * Exit the loop here and rely on forw()
23760786Sps				 * below to draw the required number of
23860786Sps				 * blank lines at the top of the screen.
23960786Sps				 */
24060786Sps				break;
24160786Sps			}
24260786Sps		}
24360786Sps		lastmark();
24460786Sps		hit_eof = 0;
24560786Sps		squished = 0;
24660786Sps		screen_trashed = 0;
24760786Sps		forw(sc_height-1, pos, 1, 0, sline-nline);
24860786Sps	} else
24960786Sps	{
25060786Sps		/*
25160786Sps		 * The desired line is before the current screen.
25260786Sps		 * Move forward in the file far enough so that we
25360786Sps		 * can call back() and put the desired line at the
25460786Sps		 * sline-th line on the screen.
25560786Sps		 */
25660786Sps		for (nline = sline;  nline < sc_height - 1;  nline++)
25760786Sps		{
25860786Sps			pos = forw_line(pos);
25960786Sps			if (pos == NULL_POSITION)
26060786Sps			{
26160786Sps				/*
26260786Sps				 * Ran into end of file.
26360786Sps				 * This shouldn't normally happen,
26460786Sps				 * but may if there is some kind of read error.
26560786Sps				 */
26660786Sps				break;
26760786Sps			}
26860786Sps			if (pos >= tpos)
26960786Sps			{
27060786Sps				/*
27160786Sps				 * Surprise!  The desired line is
27260786Sps				 * close enough to the current screen
27360786Sps				 * that we can just scroll there after all.
27460786Sps				 */
27560786Sps				back(nline+1, tpos, 1, 0);
27660786Sps				if (show_attn)
27760786Sps					repaint_hilite(1);
27860786Sps				return;
27960786Sps			}
28060786Sps		}
28160786Sps		lastmark();
28260786Sps		clear();
28360786Sps		screen_trashed = 0;
28460786Sps		add_back_pos(pos);
28560786Sps		back(sc_height-1, pos, 1, 0);
28660786Sps	}
28760786Sps}
288