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