jump.c revision 128345
1189251Ssam/*
2189251Ssam * Copyright (C) 1984-2002  Mark Nudelman
3189251Ssam *
4189251Ssam * You may distribute under the terms of either the GNU General Public
5189251Ssam * License or the Less License, as specified in the README file.
6189251Ssam *
7189251Ssam * For more information about less, or for information on how to
8189251Ssam * contact the author, see the README file.
9189251Ssam */
10189251Ssam
11189251Ssam
12189251Ssam/*
13189251Ssam * Routines which jump to a new location in the file.
14189251Ssam */
15189251Ssam
16189251Ssam#include "less.h"
17189251Ssam#include "position.h"
18214734Srpaulo
19189251Ssamextern int hit_eof;
20189251Ssamextern int jump_sline;
21189251Ssamextern int squished;
22189251Ssamextern int screen_trashed;
23189251Ssamextern int sc_width, sc_height;
24189251Ssamextern int show_attn;
25214734Srpaulo
26214734Srpaulo/*
27214734Srpaulo * Jump to the end of the file.
28214734Srpaulo */
29214734Srpaulo	public void
30214734Srpaulojump_forw()
31214734Srpaulo{
32214734Srpaulo	POSITION pos;
33189251Ssam
34189251Ssam	if (ch_end_seek())
35214734Srpaulo	{
36214734Srpaulo		error("Cannot seek to end of file", NULL_PARG);
37214734Srpaulo		return;
38214734Srpaulo	}
39214734Srpaulo	/*
40214734Srpaulo	 * Position the last line in the file at the last screen line.
41214734Srpaulo	 * Go back one line from the end of the file
42214734Srpaulo	 * to get to the beginning of the last line.
43214734Srpaulo	 */
44189251Ssam	pos = back_line(ch_tell());
45189251Ssam	if (pos == NULL_POSITION)
46189251Ssam		jump_loc((POSITION)0, sc_height-1);
47189251Ssam	else
48189251Ssam		jump_loc(pos, sc_height-1);
49189251Ssam}
50189251Ssam
51189251Ssam/*
52189251Ssam * Jump to line n in the file.
53189251Ssam */
54189251Ssam	public void
55189251Ssamjump_back(linenum)
56189251Ssam	LINENUM linenum;
57189251Ssam{
58189251Ssam	POSITION pos;
59189251Ssam	PARG parg;
60189251Ssam
61189251Ssam	/*
62189251Ssam	 * Find the position of the specified line.
63189251Ssam	 * If we can seek there, just jump to it.
64189251Ssam	 * If we can't seek, but we're trying to go to line number 1,
65189251Ssam	 * use ch_beg_seek() to get as close as we can.
66189251Ssam	 */
67189251Ssam	pos = find_pos(linenum);
68189251Ssam	if (pos != NULL_POSITION && ch_seek(pos) == 0)
69189251Ssam	{
70189251Ssam		if (show_attn)
71189251Ssam			set_attnpos(pos);
72189251Ssam		jump_loc(pos, jump_sline);
73189251Ssam	} else if (linenum <= 1 && ch_beg_seek() == 0)
74189251Ssam	{
75189251Ssam		jump_loc(ch_tell(), jump_sline);
76189251Ssam		error("Cannot seek to beginning of file", NULL_PARG);
77189251Ssam	} else
78189251Ssam	{
79189251Ssam		parg.p_linenum = linenum;
80189251Ssam		error("Cannot seek to line number %n", &parg);
81189251Ssam	}
82189251Ssam}
83189251Ssam
84189251Ssam/*
85189251Ssam * Repaint the screen.
86189251Ssam */
87189251Ssam	public void
88189251Ssamrepaint()
89189251Ssam{
90189251Ssam	struct scrpos scrpos;
91189251Ssam	/*
92189251Ssam	 * Start at the line currently at the top of the screen
93189251Ssam	 * and redisplay the screen.
94189251Ssam	 */
95189251Ssam	get_scrpos(&scrpos);
96189251Ssam	pos_clear();
97189251Ssam	jump_loc(scrpos.pos, scrpos.ln);
98189251Ssam}
99189251Ssam
100189251Ssam/*
101189251Ssam * Jump to a specified percentage into the file.
102189251Ssam */
103189251Ssam	public void
104189251Ssamjump_percent(percent)
105189251Ssam	int percent;
106189251Ssam{
107189251Ssam	POSITION pos, len;
108189251Ssam
109189251Ssam	/*
110189251Ssam	 * Determine the position in the file
111189251Ssam	 * (the specified percentage of the file's length).
112189251Ssam	 */
113189251Ssam	if ((len = ch_length()) == NULL_POSITION)
114189251Ssam	{
115189251Ssam		ierror("Determining length of file", NULL_PARG);
116189251Ssam		ch_end_seek();
117189251Ssam	}
118189251Ssam	if ((len = ch_length()) == NULL_POSITION)
119189251Ssam	{
120189251Ssam		error("Don't know length of file", NULL_PARG);
121189251Ssam		return;
122189251Ssam	}
123189251Ssam	pos = percent_pos(len, percent);
124189251Ssam	if (pos >= len)
125189251Ssam		pos = len-1;
126189251Ssam
127189251Ssam	jump_line_loc(pos, jump_sline);
128189251Ssam}
129189251Ssam
130189251Ssam/*
131189251Ssam * Jump to a specified position in the file.
132189251Ssam * Like jump_loc, but the position need not be
133189251Ssam * the first character in a line.
134189251Ssam */
135189251Ssam	public void
136189251Ssamjump_line_loc(pos, sline)
137189251Ssam	POSITION pos;
138189251Ssam	int sline;
139189251Ssam{
140189251Ssam	int c;
141189251Ssam
142189251Ssam	if (ch_seek(pos) == 0)
143189251Ssam	{
144189251Ssam		/*
145189251Ssam		 * Back up to the beginning of the line.
146189251Ssam		 */
147189251Ssam		while ((c = ch_back_get()) != '\n' && c != EOI)
148189251Ssam			;
149189251Ssam		if (c == '\n')
150189251Ssam			(void) ch_forw_get();
151189251Ssam		pos = ch_tell();
152189251Ssam	}
153189251Ssam	if (show_attn)
154189251Ssam		set_attnpos(pos);
155189251Ssam	jump_loc(pos, sline);
156214734Srpaulo}
157189251Ssam
158189251Ssam/*
159189251Ssam * Jump to a specified position in the file.
160189251Ssam * The position must be the first character in a line.
161189251Ssam * Place the target line on a specified line on the screen.
162189251Ssam */
163189251Ssam	public void
164214734Srpaulojump_loc(pos, sline)
165214734Srpaulo	POSITION pos;
166214734Srpaulo	int sline;
167214734Srpaulo{
168189251Ssam	register int nline;
169214734Srpaulo	POSITION tpos;
170214734Srpaulo	POSITION bpos;
171214734Srpaulo
172214734Srpaulo	/*
173214734Srpaulo	 * Normalize sline.
174214734Srpaulo	 */
175214734Srpaulo	sline = adjsline(sline);
176214734Srpaulo
177214734Srpaulo	if ((nline = onscreen(pos)) >= 0)
178189251Ssam	{
179189251Ssam		/*
180189251Ssam		 * The line is currently displayed.
181189251Ssam		 * Just scroll there.
182189251Ssam		 */
183189251Ssam		nline -= sline;
184189251Ssam		if (nline > 0)
185189251Ssam			forw(nline, position(BOTTOM_PLUS_ONE), 1, 0, 0);
186189251Ssam		else
187189251Ssam			back(-nline, position(TOP), 1, 0);
188189251Ssam		if (show_attn)
189189251Ssam			repaint_hilite(1);
190189251Ssam		return;
191189251Ssam	}
192189251Ssam
193189251Ssam	/*
194189251Ssam	 * Line is not on screen.
195189251Ssam	 * Seek to the desired location.
196189251Ssam	 */
197189251Ssam	if (ch_seek(pos))
198189251Ssam	{
199189251Ssam		error("Cannot seek to that file position", NULL_PARG);
200189251Ssam		return;
201189251Ssam	}
202189251Ssam
203189251Ssam	/*
204189251Ssam	 * See if the desired line is before or after
205189251Ssam	 * the currently displayed screen.
206189251Ssam	 */
207189251Ssam	tpos = position(TOP);
208189251Ssam	bpos = position(BOTTOM_PLUS_ONE);
209189251Ssam	if (tpos == NULL_POSITION || pos >= tpos)
210189251Ssam	{
211189251Ssam		/*
212189251Ssam		 * The desired line is after the current screen.
213189251Ssam		 * Move back in the file far enough so that we can
214189251Ssam		 * call forw() and put the desired line at the
215189251Ssam		 * sline-th line on the screen.
216189251Ssam		 */
217189251Ssam		for (nline = 0;  nline < sline;  nline++)
218189251Ssam		{
219189251Ssam			if (bpos != NULL_POSITION && pos <= bpos)
220189251Ssam			{
221189251Ssam				/*
222189251Ssam				 * Surprise!  The desired line is
223189251Ssam				 * close enough to the current screen
224189251Ssam				 * that we can just scroll there after all.
225189251Ssam				 */
226189251Ssam				forw(sc_height-sline+nline-1, bpos, 1, 0, 0);
227189251Ssam				if (show_attn)
228189251Ssam					repaint_hilite(1);
229189251Ssam				return;
230189251Ssam			}
231189251Ssam			pos = back_line(pos);
232189251Ssam			if (pos == NULL_POSITION)
233189251Ssam			{
234189251Ssam				/*
235189251Ssam				 * Oops.  Ran into the beginning of the file.
236189251Ssam				 * Exit the loop here and rely on forw()
237189251Ssam				 * below to draw the required number of
238189251Ssam				 * blank lines at the top of the screen.
239189251Ssam				 */
240189251Ssam				break;
241189251Ssam			}
242189251Ssam		}
243189251Ssam		lastmark();
244189251Ssam		hit_eof = 0;
245189251Ssam		squished = 0;
246189251Ssam		screen_trashed = 0;
247189251Ssam		forw(sc_height-1, pos, 1, 0, sline-nline);
248189251Ssam	} else
249189251Ssam	{
250189251Ssam		/*
251189251Ssam		 * The desired line is before the current screen.
252189251Ssam		 * Move forward in the file far enough so that we
253189251Ssam		 * can call back() and put the desired line at the
254189251Ssam		 * sline-th line on the screen.
255189251Ssam		 */
256189251Ssam		for (nline = sline;  nline < sc_height - 1;  nline++)
257189251Ssam		{
258189251Ssam			pos = forw_line(pos);
259189251Ssam			if (pos == NULL_POSITION)
260189251Ssam			{
261189251Ssam				/*
262189251Ssam				 * Ran into end of file.
263189251Ssam				 * This shouldn't normally happen,
264189251Ssam				 * but may if there is some kind of read error.
265189251Ssam				 */
266189251Ssam				break;
267189251Ssam			}
268189251Ssam			if (pos >= tpos)
269189251Ssam			{
270189251Ssam				/*
271189251Ssam				 * Surprise!  The desired line is
272189251Ssam				 * close enough to the current screen
273189251Ssam				 * that we can just scroll there after all.
274189251Ssam				 */
275189251Ssam				back(nline+1, tpos, 1, 0);
276189251Ssam				if (show_attn)
277189251Ssam					repaint_hilite(1);
278189251Ssam				return;
279189251Ssam			}
280189251Ssam		}
281189251Ssam		lastmark();
282189251Ssam		clear();
283189251Ssam		screen_trashed = 0;
284189251Ssam		add_back_pos(pos);
285189251Ssam		back(sc_height-1, pos, 1, 0);
286189251Ssam	}
287189251Ssam}
288189251Ssam