Upgrade to less-429.
[dragonfly.git] / contrib / less / forwback.c
1 /*
2  * Copyright (C) 1984-2008  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  * Primitives for displaying the file on the screen,
14  * scrolling either forward or backward.
15  */
16
17 #include "less.h"
18 #include "position.h"
19
20 public int screen_trashed;
21 public int squished;
22 public int no_back_scroll = 0;
23 public int forw_prompt;
24
25 extern int sigs;
26 extern int top_scroll;
27 extern int quiet;
28 extern int sc_width, sc_height;
29 extern int plusoption;
30 extern int forw_scroll;
31 extern int back_scroll;
32 extern int ignore_eoi;
33 extern int clear_bg;
34 extern int final_attr;
35 extern int oldbot;
36 #if TAGS
37 extern char *tagoption;
38 #endif
39
40 /*
41  * Sound the bell to indicate user is trying to move past end of file.
42  */
43         static void
44 eof_bell()
45 {
46         if (quiet == NOT_QUIET)
47                 bell();
48         else
49                 vbell();
50 }
51
52 /*
53  * Check to see if the end of file is currently displayed.
54  */
55         public int
56 eof_displayed()
57 {
58         POSITION pos;
59
60         if (ignore_eoi)
61                 return (0);
62
63         if (ch_length() == NULL_POSITION)
64                 /*
65                  * If the file length is not known,
66                  * we can't possibly be displaying EOF.
67                  */
68                 return (0);
69
70         /*
71          * If the bottom line is empty, we are at EOF.
72          * If the bottom line ends at the file length,
73          * we must be just at EOF.
74          */
75         pos = position(BOTTOM_PLUS_ONE);
76         return (pos == NULL_POSITION || pos == ch_length());
77 }
78
79 /*
80  * Check to see if the entire file is currently displayed.
81  */
82         public int
83 entire_file_displayed()
84 {
85         POSITION pos;
86
87         /* Make sure last line of file is displayed. */
88         if (!eof_displayed())
89                 return (0);
90
91         /* Make sure first line of file is displayed. */
92         pos = position(0);
93         return (pos == NULL_POSITION || pos == 0);
94 }
95
96 /*
97  * If the screen is "squished", repaint it.
98  * "Squished" means the first displayed line is not at the top
99  * of the screen; this can happen when we display a short file
100  * for the first time.
101  */
102         public void
103 squish_check()
104 {
105         if (!squished)
106                 return;
107         squished = 0;
108         repaint();
109 }
110
111 /*
112  * Display n lines, scrolling forward, 
113  * starting at position pos in the input file.
114  * "force" means display the n lines even if we hit end of file.
115  * "only_last" means display only the last screenful if n > screen size.
116  * "nblank" is the number of blank lines to draw before the first
117  *   real line.  If nblank > 0, the pos must be NULL_POSITION.
118  *   The first real line after the blanks will start at ch_zero().
119  */
120         public void
121 forw(n, pos, force, only_last, nblank)
122         register int n;
123         POSITION pos;
124         int force;
125         int only_last;
126         int nblank;
127 {
128         int eof = 0;
129         int nlines = 0;
130         int do_repaint;
131         static int first_time = 1;
132
133         squish_check();
134
135         /*
136          * do_repaint tells us not to display anything till the end, 
137          * then just repaint the entire screen.
138          * We repaint if we are supposed to display only the last 
139          * screenful and the request is for more than a screenful.
140          * Also if the request exceeds the forward scroll limit
141          * (but not if the request is for exactly a screenful, since
142          * repainting itself involves scrolling forward a screenful).
143          */
144         do_repaint = (only_last && n > sc_height-1) || 
145                 (forw_scroll >= 0 && n > forw_scroll && n != sc_height-1);
146
147         if (!do_repaint)
148         {
149                 if (top_scroll && n >= sc_height - 1 && pos != ch_length())
150                 {
151                         /*
152                          * Start a new screen.
153                          * {{ This is not really desirable if we happen
154                          *    to hit eof in the middle of this screen,
155                          *    but we don't yet know if that will happen. }}
156                          */
157                         pos_clear();
158                         add_forw_pos(pos);
159                         force = 1;
160                         clear();
161                         home();
162                 }
163
164                 if (pos != position(BOTTOM_PLUS_ONE) || empty_screen())
165                 {
166                         /*
167                          * This is not contiguous with what is
168                          * currently displayed.  Clear the screen image 
169                          * (position table) and start a new screen.
170                          */
171                         pos_clear();
172                         add_forw_pos(pos);
173                         force = 1;
174                         if (top_scroll)
175                         {
176                                 clear();
177                                 home();
178                         } else if (!first_time)
179                         {
180                                 putstr("...skipping...\n");
181                         }
182                 }
183         }
184
185         while (--n >= 0)
186         {
187                 /*
188                  * Read the next line of input.
189                  */
190                 if (nblank > 0)
191                 {
192                         /*
193                          * Still drawing blanks; don't get a line 
194                          * from the file yet.
195                          * If this is the last blank line, get ready to
196                          * read a line starting at ch_zero() next time.
197                          */
198                         if (--nblank == 0)
199                                 pos = ch_zero();
200                 } else
201                 {
202                         /* 
203                          * Get the next line from the file.
204                          */
205                         pos = forw_line(pos);
206                         if (pos == NULL_POSITION)
207                         {
208                                 /*
209                                  * End of file: stop here unless the top line 
210                                  * is still empty, or "force" is true.
211                                  * Even if force is true, stop when the last
212                                  * line in the file reaches the top of screen.
213                                  */
214                                 eof = 1;
215                                 if (!force && position(TOP) != NULL_POSITION)
216                                         break;
217                                 if (!empty_lines(0, 0) && 
218                                     !empty_lines(1, 1) &&
219                                      empty_lines(2, sc_height-1))
220                                         break;
221                         }
222                 }
223                 /*
224                  * Add the position of the next line to the position table.
225                  * Display the current line on the screen.
226                  */
227                 add_forw_pos(pos);
228                 nlines++;
229                 if (do_repaint)
230                         continue;
231                 /*
232                  * If this is the first screen displayed and
233                  * we hit an early EOF (i.e. before the requested
234                  * number of lines), we "squish" the display down
235                  * at the bottom of the screen.
236                  * But don't do this if a + option or a -t option
237                  * was given.  These options can cause us to
238                  * start the display after the beginning of the file,
239                  * and it is not appropriate to squish in that case.
240                  */
241                 if (first_time && pos == NULL_POSITION && !top_scroll && 
242 #if TAGS
243                     tagoption == NULL &&
244 #endif
245                     !plusoption)
246                 {
247                         squished = 1;
248                         continue;
249                 }
250                 put_line();
251 #if 0
252                 /* {{ 
253                  * Can't call clear_eol here.  The cursor might be at end of line
254                  * on an ignaw terminal, so clear_eol would clear the last char
255                  * of the current line instead of all of the next line.
256                  * If we really need to do this on clear_bg terminals, we need
257                  * to find a better way.
258                  * }}
259                  */
260                 if (clear_bg && apply_at_specials(final_attr) != AT_NORMAL)
261                 {
262                         /*
263                          * Writing the last character on the last line
264                          * of the display may have scrolled the screen.
265                          * If we were in standout mode, clear_bg terminals 
266                          * will fill the new line with the standout color.
267                          * Now we're in normal mode again, so clear the line.
268                          */
269                         clear_eol();
270                 }
271 #endif
272                 forw_prompt = 1;
273         }
274
275         if (nlines == 0)
276                 eof_bell();
277         else if (do_repaint)
278                 repaint();
279         first_time = 0;
280         (void) currline(BOTTOM);
281 }
282
283 /*
284  * Display n lines, scrolling backward.
285  */
286         public void
287 back(n, pos, force, only_last)
288         register int n;
289         POSITION pos;
290         int force;
291         int only_last;
292 {
293         int nlines = 0;
294         int do_repaint;
295
296         squish_check();
297         do_repaint = (n > get_back_scroll() || (only_last && n > sc_height-1));
298         while (--n >= 0)
299         {
300                 /*
301                  * Get the previous line of input.
302                  */
303                 pos = back_line(pos);
304                 if (pos == NULL_POSITION)
305                 {
306                         /*
307                          * Beginning of file: stop here unless "force" is true.
308                          */
309                         if (!force)
310                                 break;
311                 }
312                 /*
313                  * Add the position of the previous line to the position table.
314                  * Display the line on the screen.
315                  */
316                 add_back_pos(pos);
317                 nlines++;
318                 if (!do_repaint)
319                 {
320                         home();
321                         add_line();
322                         put_line();
323                 }
324         }
325
326         if (nlines == 0)
327                 eof_bell();
328         else if (do_repaint)
329                 repaint();
330         else if (!oldbot)
331                 lower_left();
332         (void) currline(BOTTOM);
333 }
334
335 /*
336  * Display n more lines, forward.
337  * Start just after the line currently displayed at the bottom of the screen.
338  */
339         public void
340 forward(n, force, only_last)
341         int n;
342         int force;
343         int only_last;
344 {
345         POSITION pos;
346
347         if (get_quit_at_eof() && eof_displayed() && !(ch_getflags() & CH_HELPFILE))
348         {
349                 /*
350                  * If the -e flag is set and we're trying to go
351                  * forward from end-of-file, go on to the next file.
352                  */
353                 if (edit_next(1))
354                         quit(QUIT_OK);
355                 return;
356         }
357
358         pos = position(BOTTOM_PLUS_ONE);
359         if (pos == NULL_POSITION && (!force || empty_lines(2, sc_height-1)))
360         {
361                 if (ignore_eoi)
362                 {
363                         /*
364                          * ignore_eoi is to support A_F_FOREVER.
365                          * Back up until there is a line at the bottom
366                          * of the screen.
367                          */
368                         if (empty_screen())
369                                 pos = ch_zero();
370                         else
371                         {
372                                 do
373                                 {
374                                         back(1, position(TOP), 1, 0);
375                                         pos = position(BOTTOM_PLUS_ONE);
376                                 } while (pos == NULL_POSITION);
377                         }
378                 } else
379                 {
380                         eof_bell();
381                         return;
382                 }
383         }
384         forw(n, pos, force, only_last, 0);
385 }
386
387 /*
388  * Display n more lines, backward.
389  * Start just before the line currently displayed at the top of the screen.
390  */
391         public void
392 backward(n, force, only_last)
393         int n;
394         int force;
395         int only_last;
396 {
397         POSITION pos;
398
399         pos = position(TOP);
400         if (pos == NULL_POSITION && (!force || position(BOTTOM) == 0))
401         {
402                 eof_bell();
403                 return;   
404         }
405         back(n, pos, force, only_last);
406 }
407
408 /*
409  * Get the backwards scroll limit.
410  * Must call this function instead of just using the value of
411  * back_scroll, because the default case depends on sc_height and
412  * top_scroll, as well as back_scroll.
413  */
414         public int
415 get_back_scroll()
416 {
417         if (no_back_scroll)
418                 return (0);
419         if (back_scroll >= 0)
420                 return (back_scroll);
421         if (top_scroll)
422                 return (sc_height - 2);
423         return (10000); /* infinity */
424 }