Add HAMMER support to the installer
[dragonfly.git] / contrib / less-4 / jump.c
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
19 extern int hit_eof;
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
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          * 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
63 jump_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
96 repaint()
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
112 jump_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
145 jump_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
173 jump_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 }