Merge branch 'vendor/LIBPCAP'
[dragonfly.git] / contrib / less / jump.c
1 /*
2  * Copyright (C) 1984-2015  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         jump_loc(scrpos.pos, scrpos.ln);
128 }
129
130 /*
131  * Jump to a specified percentage into the file.
132  */
133         public void
134 jump_percent(percent, fraction)
135         int percent;
136         long fraction;
137 {
138         POSITION pos, len;
139
140         /*
141          * Determine the position in the file
142          * (the specified percentage of the file's length).
143          */
144         if ((len = ch_length()) == NULL_POSITION)
145         {
146                 ierror("Determining length of file", NULL_PARG);
147                 ch_end_seek();
148         }
149         if ((len = ch_length()) == NULL_POSITION)
150         {
151                 error("Don't know length of file", NULL_PARG);
152                 return;
153         }
154         pos = percent_pos(len, percent, fraction);
155         if (pos >= len)
156                 pos = len-1;
157
158         jump_line_loc(pos, jump_sline);
159 }
160
161 /*
162  * Jump to a specified position in the file.
163  * Like jump_loc, but the position need not be 
164  * the first character in a line.
165  */
166         public void
167 jump_line_loc(pos, sline)
168         POSITION pos;
169         int sline;
170 {
171         int c;
172
173         if (ch_seek(pos) == 0)
174         {
175                 /*
176                  * Back up to the beginning of the line.
177                  */
178                 while ((c = ch_back_get()) != '\n' && c != EOI)
179                         ;
180                 if (c == '\n')
181                         (void) ch_forw_get();
182                 pos = ch_tell();
183         }
184         if (show_attn)
185                 set_attnpos(pos);
186         jump_loc(pos, sline);
187 }
188
189 /*
190  * Jump to a specified position in the file.
191  * The position must be the first character in a line.
192  * Place the target line on a specified line on the screen.
193  */
194         public void
195 jump_loc(pos, sline)
196         POSITION pos;
197         int sline;
198 {
199         register int nline;
200         POSITION tpos;
201         POSITION bpos;
202
203         /*
204          * Normalize sline.
205          */
206         sline = adjsline(sline);
207
208         if ((nline = onscreen(pos)) >= 0)
209         {
210                 /*
211                  * The line is currently displayed.  
212                  * Just scroll there.
213                  */
214                 nline -= sline;
215                 if (nline > 0)
216                         forw(nline, position(BOTTOM_PLUS_ONE), 1, 0, 0);
217                 else
218                         back(-nline, position(TOP), 1, 0);
219 #if HILITE_SEARCH
220                 if (show_attn)
221                         repaint_hilite(1);
222 #endif
223                 return;
224         }
225
226         /*
227          * Line is not on screen.
228          * Seek to the desired location.
229          */
230         if (ch_seek(pos))
231         {
232                 error("Cannot seek to that file position", NULL_PARG);
233                 return;
234         }
235
236         /*
237          * See if the desired line is before or after 
238          * the currently displayed screen.
239          */
240         tpos = position(TOP);
241         bpos = position(BOTTOM_PLUS_ONE);
242         if (tpos == NULL_POSITION || pos >= tpos)
243         {
244                 /*
245                  * The desired line is after the current screen.
246                  * Move back in the file far enough so that we can
247                  * call forw() and put the desired line at the 
248                  * sline-th line on the screen.
249                  */
250                 for (nline = 0;  nline < sline;  nline++)
251                 {
252                         if (bpos != NULL_POSITION && pos <= bpos)
253                         {
254                                 /*
255                                  * Surprise!  The desired line is
256                                  * close enough to the current screen
257                                  * that we can just scroll there after all.
258                                  */
259                                 forw(sc_height-sline+nline-1, bpos, 1, 0, 0);
260 #if HILITE_SEARCH
261                                 if (show_attn)
262                                         repaint_hilite(1);
263 #endif
264                                 return;
265                         }
266                         pos = back_line(pos);
267                         if (pos == NULL_POSITION)
268                         {
269                                 /*
270                                  * Oops.  Ran into the beginning of the file.
271                                  * Exit the loop here and rely on forw()
272                                  * below to draw the required number of
273                                  * blank lines at the top of the screen.
274                                  */
275                                 break;
276                         }
277                 }
278                 lastmark();
279                 squished = 0;
280                 screen_trashed = 0;
281                 forw(sc_height-1, pos, 1, 0, sline-nline);
282         } else
283         {
284                 /*
285                  * The desired line is before the current screen.
286                  * Move forward in the file far enough so that we
287                  * can call back() and put the desired line at the 
288                  * sline-th line on the screen.
289                  */
290                 for (nline = sline;  nline < sc_height - 1;  nline++)
291                 {
292                         pos = forw_line(pos);
293                         if (pos == NULL_POSITION)
294                         {
295                                 /*
296                                  * Ran into end of file.
297                                  * This shouldn't normally happen, 
298                                  * but may if there is some kind of read error.
299                                  */
300                                 break;
301                         }
302 #if HILITE_SEARCH
303                         pos = next_unfiltered(pos);
304 #endif
305                         if (pos >= tpos)
306                         {
307                                 /* 
308                                  * Surprise!  The desired line is
309                                  * close enough to the current screen
310                                  * that we can just scroll there after all.
311                                  */
312                                 back(nline+1, tpos, 1, 0);
313 #if HILITE_SEARCH
314                                 if (show_attn)
315                                         repaint_hilite(1);
316 #endif
317                                 return;
318                         }
319                 }
320                 lastmark();
321                 if (!top_scroll)
322                         clear();
323                 else
324                         home();
325                 screen_trashed = 0;
326                 add_back_pos(pos);
327                 back(sc_height-1, pos, 1, 0);
328         }
329 }