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