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