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