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