]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - contrib/less/jump.c
MFC r368207,368607:
[FreeBSD/stable/10.git] / contrib / less / jump.c
1 /*
2  * Copyright (C) 1984-2017  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(ch_zero(), 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, TOP);
126         pos_clear();
127         if (scrpos.pos == NULL_POSITION)
128                 /* Screen hasn't been drawn yet. */
129                 jump_loc(ch_zero(), 1);
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         int nline;
204         int sindex;
205         POSITION tpos;
206         POSITION bpos;
207
208         /*
209          * Normalize sline.
210          */
211         sindex = sindex_from_sline(sline);
212
213         if ((nline = onscreen(pos)) >= 0)
214         {
215                 /*
216                  * The line is currently displayed.  
217                  * Just scroll there.
218                  */
219                 nline -= sindex;
220                 if (nline > 0)
221                         forw(nline, position(BOTTOM_PLUS_ONE), 1, 0, 0);
222                 else if (nline < 0)
223                         back(-nline, position(TOP), 1, 0);
224 #if HILITE_SEARCH
225                 if (show_attn)
226                         repaint_hilite(1);
227 #endif
228                 return;
229         }
230
231         /*
232          * Line is not on screen.
233          * Seek to the desired location.
234          */
235         if (ch_seek(pos))
236         {
237                 error("Cannot seek to that file position", NULL_PARG);
238                 return;
239         }
240
241         /*
242          * See if the desired line is before or after 
243          * the currently displayed screen.
244          */
245         tpos = position(TOP);
246         bpos = position(BOTTOM_PLUS_ONE);
247         if (tpos == NULL_POSITION || pos >= tpos)
248         {
249                 /*
250                  * The desired line is after the current screen.
251                  * Move back in the file far enough so that we can
252                  * call forw() and put the desired line at the 
253                  * sline-th line on the screen.
254                  */
255                 for (nline = 0;  nline < sindex;  nline++)
256                 {
257                         if (bpos != NULL_POSITION && pos <= bpos)
258                         {
259                                 /*
260                                  * Surprise!  The desired line is
261                                  * close enough to the current screen
262                                  * that we can just scroll there after all.
263                                  */
264                                 forw(sc_height-sindex+nline-1, bpos, 1, 0, 0);
265 #if HILITE_SEARCH
266                                 if (show_attn)
267                                         repaint_hilite(1);
268 #endif
269                                 return;
270                         }
271                         pos = back_line(pos);
272                         if (pos == NULL_POSITION)
273                         {
274                                 /*
275                                  * Oops.  Ran into the beginning of the file.
276                                  * Exit the loop here and rely on forw()
277                                  * below to draw the required number of
278                                  * blank lines at the top of the screen.
279                                  */
280                                 break;
281                         }
282                 }
283                 lastmark();
284                 squished = 0;
285                 screen_trashed = 0;
286                 forw(sc_height-1, pos, 1, 0, sindex-nline);
287         } else
288         {
289                 /*
290                  * The desired line is before the current screen.
291                  * Move forward in the file far enough so that we
292                  * can call back() and put the desired line at the 
293                  * sindex-th line on the screen.
294                  */
295                 for (nline = sindex;  nline < sc_height - 1;  nline++)
296                 {
297                         pos = forw_line(pos);
298                         if (pos == NULL_POSITION)
299                         {
300                                 /*
301                                  * Ran into end of file.
302                                  * This shouldn't normally happen, 
303                                  * but may if there is some kind of read error.
304                                  */
305                                 break;
306                         }
307 #if HILITE_SEARCH
308                         pos = next_unfiltered(pos);
309 #endif
310                         if (pos >= tpos)
311                         {
312                                 /* 
313                                  * Surprise!  The desired line is
314                                  * close enough to the current screen
315                                  * that we can just scroll there after all.
316                                  */
317                                 back(nline+1, tpos, 1, 0);
318 #if HILITE_SEARCH
319                                 if (show_attn)
320                                         repaint_hilite(1);
321 #endif
322                                 return;
323                         }
324                 }
325                 lastmark();
326                 if (!top_scroll)
327                         clear();
328                 else
329                         home();
330                 screen_trashed = 0;
331                 add_back_pos(pos);
332                 back(sc_height-1, pos, 1, 0);
333         }
334 }