160786Sps/*
2240121Sdelphij * Copyright (C) 1984-2012  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 *
7240121Sdelphij * For more information, see the README file.
860786Sps */
960786Sps
1060786Sps
1160786Sps/*
1260786Sps * Routines which jump to a new location in the file.
1360786Sps */
1460786Sps
1560786Sps#include "less.h"
1660786Sps#include "position.h"
1760786Sps
1860786Spsextern int jump_sline;
1960786Spsextern int squished;
2060786Spsextern int screen_trashed;
2160786Spsextern int sc_width, sc_height;
2260786Spsextern int show_attn;
23161475Sdelphijextern int top_scroll;
2460786Sps
2560786Sps/*
2660786Sps * Jump to the end of the file.
2760786Sps */
2860786Sps	public void
2960786Spsjump_forw()
3060786Sps{
3160786Sps	POSITION pos;
32172468Sdelphij	POSITION end_pos;
3360786Sps
3460786Sps	if (ch_end_seek())
3560786Sps	{
3660786Sps		error("Cannot seek to end of file", NULL_PARG);
3760786Sps		return;
3860786Sps	}
39191930Sdelphij	/*
40191930Sdelphij	 * Note; lastmark will be called later by jump_loc, but it fails
41191930Sdelphij	 * because the position table has been cleared by pos_clear below.
42191930Sdelphij	 * So call it here before calling pos_clear.
43191930Sdelphij	 */
44191930Sdelphij	lastmark();
4560786Sps	/*
4660786Sps	 * Position the last line in the file at the last screen line.
4760786Sps	 * Go back one line from the end of the file
4860786Sps	 * to get to the beginning of the last line.
4960786Sps	 */
50172468Sdelphij	pos_clear();
51172468Sdelphij	end_pos = ch_tell();
52172468Sdelphij	pos = back_line(end_pos);
5360786Sps	if (pos == NULL_POSITION)
5460786Sps		jump_loc((POSITION)0, sc_height-1);
5560786Sps	else
56172468Sdelphij	{
5760786Sps		jump_loc(pos, sc_height-1);
58172468Sdelphij		if (position(sc_height-1) != end_pos)
59172468Sdelphij			repaint();
60172468Sdelphij	}
6160786Sps}
6260786Sps
6360786Sps/*
6460786Sps * Jump to line n in the file.
6560786Sps */
6660786Sps	public void
67128345Stjrjump_back(linenum)
68128345Stjr	LINENUM linenum;
6960786Sps{
7060786Sps	POSITION pos;
7160786Sps	PARG parg;
7260786Sps
7360786Sps	/*
7460786Sps	 * Find the position of the specified line.
7560786Sps	 * If we can seek there, just jump to it.
7660786Sps	 * If we can't seek, but we're trying to go to line number 1,
7760786Sps	 * use ch_beg_seek() to get as close as we can.
7860786Sps	 */
79128345Stjr	pos = find_pos(linenum);
8060786Sps	if (pos != NULL_POSITION && ch_seek(pos) == 0)
8160786Sps	{
8260786Sps		if (show_attn)
8360786Sps			set_attnpos(pos);
8460786Sps		jump_loc(pos, jump_sline);
85128345Stjr	} else if (linenum <= 1 && ch_beg_seek() == 0)
8660786Sps	{
8760786Sps		jump_loc(ch_tell(), jump_sline);
8860786Sps		error("Cannot seek to beginning of file", NULL_PARG);
8960786Sps	} else
9060786Sps	{
91128345Stjr		parg.p_linenum = linenum;
92128345Stjr		error("Cannot seek to line number %n", &parg);
9360786Sps	}
9460786Sps}
9560786Sps
9660786Sps/*
9760786Sps * Repaint the screen.
9860786Sps */
9960786Sps	public void
10060786Spsrepaint()
10160786Sps{
10260786Sps	struct scrpos scrpos;
10360786Sps	/*
10460786Sps	 * Start at the line currently at the top of the screen
10560786Sps	 * and redisplay the screen.
10660786Sps	 */
10760786Sps	get_scrpos(&scrpos);
10860786Sps	pos_clear();
10960786Sps	jump_loc(scrpos.pos, scrpos.ln);
11060786Sps}
11160786Sps
11260786Sps/*
11360786Sps * Jump to a specified percentage into the file.
11460786Sps */
11560786Sps	public void
116170256Sdelphijjump_percent(percent, fraction)
11760786Sps	int percent;
118170256Sdelphij	long fraction;
11960786Sps{
12060786Sps	POSITION pos, len;
12160786Sps
12260786Sps	/*
12360786Sps	 * Determine the position in the file
12460786Sps	 * (the specified percentage of the file's length).
12560786Sps	 */
12660786Sps	if ((len = ch_length()) == NULL_POSITION)
12760786Sps	{
12860786Sps		ierror("Determining length of file", NULL_PARG);
12960786Sps		ch_end_seek();
13060786Sps	}
13160786Sps	if ((len = ch_length()) == NULL_POSITION)
13260786Sps	{
13360786Sps		error("Don't know length of file", NULL_PARG);
13460786Sps		return;
13560786Sps	}
136170256Sdelphij	pos = percent_pos(len, percent, fraction);
13760786Sps	if (pos >= len)
13860786Sps		pos = len-1;
13960786Sps
14060786Sps	jump_line_loc(pos, jump_sline);
14160786Sps}
14260786Sps
14360786Sps/*
14460786Sps * Jump to a specified position in the file.
14560786Sps * Like jump_loc, but the position need not be
14660786Sps * the first character in a line.
14760786Sps */
14860786Sps	public void
14960786Spsjump_line_loc(pos, sline)
15060786Sps	POSITION pos;
15160786Sps	int sline;
15260786Sps{
15360786Sps	int c;
15460786Sps
15560786Sps	if (ch_seek(pos) == 0)
15660786Sps	{
15760786Sps		/*
15860786Sps		 * Back up to the beginning of the line.
15960786Sps		 */
16060786Sps		while ((c = ch_back_get()) != '\n' && c != EOI)
16160786Sps			;
16260786Sps		if (c == '\n')
16360786Sps			(void) ch_forw_get();
16460786Sps		pos = ch_tell();
16560786Sps	}
16660786Sps	if (show_attn)
16760786Sps		set_attnpos(pos);
16860786Sps	jump_loc(pos, sline);
16960786Sps}
17060786Sps
17160786Sps/*
17260786Sps * Jump to a specified position in the file.
17360786Sps * The position must be the first character in a line.
17460786Sps * Place the target line on a specified line on the screen.
17560786Sps */
17660786Sps	public void
17760786Spsjump_loc(pos, sline)
17860786Sps	POSITION pos;
17960786Sps	int sline;
18060786Sps{
18160786Sps	register int nline;
18260786Sps	POSITION tpos;
18360786Sps	POSITION bpos;
18460786Sps
18560786Sps	/*
18660786Sps	 * Normalize sline.
18760786Sps	 */
18860786Sps	sline = adjsline(sline);
18960786Sps
19060786Sps	if ((nline = onscreen(pos)) >= 0)
19160786Sps	{
19260786Sps		/*
19360786Sps		 * The line is currently displayed.
19460786Sps		 * Just scroll there.
19560786Sps		 */
19660786Sps		nline -= sline;
19760786Sps		if (nline > 0)
19860786Sps			forw(nline, position(BOTTOM_PLUS_ONE), 1, 0, 0);
19960786Sps		else
20060786Sps			back(-nline, position(TOP), 1, 0);
201191930Sdelphij#if HILITE_SEARCH
20260786Sps		if (show_attn)
20360786Sps			repaint_hilite(1);
204191930Sdelphij#endif
20560786Sps		return;
20660786Sps	}
20760786Sps
20860786Sps	/*
20960786Sps	 * Line is not on screen.
21060786Sps	 * Seek to the desired location.
21160786Sps	 */
21260786Sps	if (ch_seek(pos))
21360786Sps	{
21460786Sps		error("Cannot seek to that file position", NULL_PARG);
21560786Sps		return;
21660786Sps	}
21760786Sps
21860786Sps	/*
21960786Sps	 * See if the desired line is before or after
22060786Sps	 * the currently displayed screen.
22160786Sps	 */
22260786Sps	tpos = position(TOP);
22360786Sps	bpos = position(BOTTOM_PLUS_ONE);
22460786Sps	if (tpos == NULL_POSITION || pos >= tpos)
22560786Sps	{
22660786Sps		/*
22760786Sps		 * The desired line is after the current screen.
22860786Sps		 * Move back in the file far enough so that we can
22960786Sps		 * call forw() and put the desired line at the
23060786Sps		 * sline-th line on the screen.
23160786Sps		 */
23260786Sps		for (nline = 0;  nline < sline;  nline++)
23360786Sps		{
23460786Sps			if (bpos != NULL_POSITION && pos <= bpos)
23560786Sps			{
23660786Sps				/*
23760786Sps				 * Surprise!  The desired line is
23860786Sps				 * close enough to the current screen
23960786Sps				 * that we can just scroll there after all.
24060786Sps				 */
24160786Sps				forw(sc_height-sline+nline-1, bpos, 1, 0, 0);
242191930Sdelphij#if HILITE_SEARCH
24360786Sps				if (show_attn)
24460786Sps					repaint_hilite(1);
245191930Sdelphij#endif
24660786Sps				return;
24760786Sps			}
24860786Sps			pos = back_line(pos);
24960786Sps			if (pos == NULL_POSITION)
25060786Sps			{
25160786Sps				/*
25260786Sps				 * Oops.  Ran into the beginning of the file.
25360786Sps				 * Exit the loop here and rely on forw()
25460786Sps				 * below to draw the required number of
25560786Sps				 * blank lines at the top of the screen.
25660786Sps				 */
25760786Sps				break;
25860786Sps			}
25960786Sps		}
26060786Sps		lastmark();
26160786Sps		squished = 0;
26260786Sps		screen_trashed = 0;
26360786Sps		forw(sc_height-1, pos, 1, 0, sline-nline);
26460786Sps	} else
26560786Sps	{
26660786Sps		/*
26760786Sps		 * The desired line is before the current screen.
26860786Sps		 * Move forward in the file far enough so that we
26960786Sps		 * can call back() and put the desired line at the
27060786Sps		 * sline-th line on the screen.
27160786Sps		 */
27260786Sps		for (nline = sline;  nline < sc_height - 1;  nline++)
27360786Sps		{
27460786Sps			pos = forw_line(pos);
27560786Sps			if (pos == NULL_POSITION)
27660786Sps			{
27760786Sps				/*
27860786Sps				 * Ran into end of file.
27960786Sps				 * This shouldn't normally happen,
28060786Sps				 * but may if there is some kind of read error.
28160786Sps				 */
28260786Sps				break;
28360786Sps			}
28460786Sps			if (pos >= tpos)
28560786Sps			{
28660786Sps				/*
28760786Sps				 * Surprise!  The desired line is
28860786Sps				 * close enough to the current screen
28960786Sps				 * that we can just scroll there after all.
29060786Sps				 */
29160786Sps				back(nline+1, tpos, 1, 0);
292191930Sdelphij#if HILITE_SEARCH
29360786Sps				if (show_attn)
29460786Sps					repaint_hilite(1);
295191930Sdelphij#endif
29660786Sps				return;
29760786Sps			}
29860786Sps		}
29960786Sps		lastmark();
300170256Sdelphij		if (!top_scroll)
301161475Sdelphij			clear();
302161475Sdelphij		else
303161475Sdelphij			home();
30460786Sps		screen_trashed = 0;
30560786Sps		add_back_pos(pos);
30660786Sps		back(sc_height-1, pos, 1, 0);
30760786Sps	}
30860786Sps}
309