jump.c revision 172468
1/*
2 * Copyright (C) 1984-2007  Mark Nudelman
3 *
4 * You may distribute under the terms of either the GNU General Public
5 * License or the Less License, as specified in the README file.
6 *
7 * For more information about less, or for information on how to
8 * contact the author, see the README file.
9 */
10
11
12/*
13 * Routines which jump to a new location in the file.
14 */
15
16#include "less.h"
17#include "position.h"
18
19extern int hit_eof;
20extern int jump_sline;
21extern int squished;
22extern int screen_trashed;
23extern int sc_width, sc_height;
24extern int show_attn;
25extern int top_scroll;
26
27/*
28 * Jump to the end of the file.
29 */
30	public void
31jump_forw()
32{
33	POSITION pos;
34	POSITION end_pos;
35
36	if (ch_end_seek())
37	{
38		error("Cannot seek to end of file", NULL_PARG);
39		return;
40	}
41	/*
42	 * Position the last line in the file at the last screen line.
43	 * Go back one line from the end of the file
44	 * to get to the beginning of the last line.
45	 */
46	pos_clear();
47	end_pos = ch_tell();
48	pos = back_line(end_pos);
49	if (pos == NULL_POSITION)
50		jump_loc((POSITION)0, sc_height-1);
51	else
52	{
53		jump_loc(pos, sc_height-1);
54		if (position(sc_height-1) != end_pos)
55			repaint();
56	}
57}
58
59/*
60 * Jump to line n in the file.
61 */
62	public void
63jump_back(linenum)
64	LINENUM linenum;
65{
66	POSITION pos;
67	PARG parg;
68
69	/*
70	 * Find the position of the specified line.
71	 * If we can seek there, just jump to it.
72	 * If we can't seek, but we're trying to go to line number 1,
73	 * use ch_beg_seek() to get as close as we can.
74	 */
75	pos = find_pos(linenum);
76	if (pos != NULL_POSITION && ch_seek(pos) == 0)
77	{
78		if (show_attn)
79			set_attnpos(pos);
80		jump_loc(pos, jump_sline);
81	} else if (linenum <= 1 && ch_beg_seek() == 0)
82	{
83		jump_loc(ch_tell(), jump_sline);
84		error("Cannot seek to beginning of file", NULL_PARG);
85	} else
86	{
87		parg.p_linenum = linenum;
88		error("Cannot seek to line number %n", &parg);
89	}
90}
91
92/*
93 * Repaint the screen.
94 */
95	public void
96repaint()
97{
98	struct scrpos scrpos;
99	/*
100	 * Start at the line currently at the top of the screen
101	 * and redisplay the screen.
102	 */
103	get_scrpos(&scrpos);
104	pos_clear();
105	jump_loc(scrpos.pos, scrpos.ln);
106}
107
108/*
109 * Jump to a specified percentage into the file.
110 */
111	public void
112jump_percent(percent, fraction)
113	int percent;
114	long fraction;
115{
116	POSITION pos, len;
117
118	/*
119	 * Determine the position in the file
120	 * (the specified percentage of the file's length).
121	 */
122	if ((len = ch_length()) == NULL_POSITION)
123	{
124		ierror("Determining length of file", NULL_PARG);
125		ch_end_seek();
126	}
127	if ((len = ch_length()) == NULL_POSITION)
128	{
129		error("Don't know length of file", NULL_PARG);
130		return;
131	}
132	pos = percent_pos(len, percent, fraction);
133	if (pos >= len)
134		pos = len-1;
135
136	jump_line_loc(pos, jump_sline);
137}
138
139/*
140 * Jump to a specified position in the file.
141 * Like jump_loc, but the position need not be
142 * the first character in a line.
143 */
144	public void
145jump_line_loc(pos, sline)
146	POSITION pos;
147	int sline;
148{
149	int c;
150
151	if (ch_seek(pos) == 0)
152	{
153		/*
154		 * Back up to the beginning of the line.
155		 */
156		while ((c = ch_back_get()) != '\n' && c != EOI)
157			;
158		if (c == '\n')
159			(void) ch_forw_get();
160		pos = ch_tell();
161	}
162	if (show_attn)
163		set_attnpos(pos);
164	jump_loc(pos, sline);
165}
166
167/*
168 * Jump to a specified position in the file.
169 * The position must be the first character in a line.
170 * Place the target line on a specified line on the screen.
171 */
172	public void
173jump_loc(pos, sline)
174	POSITION pos;
175	int sline;
176{
177	register int nline;
178	POSITION tpos;
179	POSITION bpos;
180
181	/*
182	 * Normalize sline.
183	 */
184	sline = adjsline(sline);
185
186	if ((nline = onscreen(pos)) >= 0)
187	{
188		/*
189		 * The line is currently displayed.
190		 * Just scroll there.
191		 */
192		nline -= sline;
193		if (nline > 0)
194			forw(nline, position(BOTTOM_PLUS_ONE), 1, 0, 0);
195		else
196			back(-nline, position(TOP), 1, 0);
197		if (show_attn)
198			repaint_hilite(1);
199		return;
200	}
201
202	/*
203	 * Line is not on screen.
204	 * Seek to the desired location.
205	 */
206	if (ch_seek(pos))
207	{
208		error("Cannot seek to that file position", NULL_PARG);
209		return;
210	}
211
212	/*
213	 * See if the desired line is before or after
214	 * the currently displayed screen.
215	 */
216	tpos = position(TOP);
217	bpos = position(BOTTOM_PLUS_ONE);
218	if (tpos == NULL_POSITION || pos >= tpos)
219	{
220		/*
221		 * The desired line is after the current screen.
222		 * Move back in the file far enough so that we can
223		 * call forw() and put the desired line at the
224		 * sline-th line on the screen.
225		 */
226		for (nline = 0;  nline < sline;  nline++)
227		{
228			if (bpos != NULL_POSITION && pos <= bpos)
229			{
230				/*
231				 * Surprise!  The desired line is
232				 * close enough to the current screen
233				 * that we can just scroll there after all.
234				 */
235				forw(sc_height-sline+nline-1, bpos, 1, 0, 0);
236				if (show_attn)
237					repaint_hilite(1);
238				return;
239			}
240			pos = back_line(pos);
241			if (pos == NULL_POSITION)
242			{
243				/*
244				 * Oops.  Ran into the beginning of the file.
245				 * Exit the loop here and rely on forw()
246				 * below to draw the required number of
247				 * blank lines at the top of the screen.
248				 */
249				break;
250			}
251		}
252		lastmark();
253		hit_eof = 0;
254		squished = 0;
255		screen_trashed = 0;
256		forw(sc_height-1, pos, 1, 0, sline-nline);
257	} else
258	{
259		/*
260		 * The desired line is before the current screen.
261		 * Move forward in the file far enough so that we
262		 * can call back() and put the desired line at the
263		 * sline-th line on the screen.
264		 */
265		for (nline = sline;  nline < sc_height - 1;  nline++)
266		{
267			pos = forw_line(pos);
268			if (pos == NULL_POSITION)
269			{
270				/*
271				 * Ran into end of file.
272				 * This shouldn't normally happen,
273				 * but may if there is some kind of read error.
274				 */
275				break;
276			}
277			if (pos >= tpos)
278			{
279				/*
280				 * Surprise!  The desired line is
281				 * close enough to the current screen
282				 * that we can just scroll there after all.
283				 */
284				back(nline+1, tpos, 1, 0);
285				if (show_attn)
286					repaint_hilite(1);
287				return;
288			}
289		}
290		lastmark();
291		if (!top_scroll)
292			clear();
293		else
294			home();
295		screen_trashed = 0;
296		add_back_pos(pos);
297		back(sc_height-1, pos, 1, 0);
298	}
299}
300