]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/less/forwback.c
This commit was generated by cvs2svn to compensate for changes in r155131,
[FreeBSD/FreeBSD.git] / contrib / less / forwback.c
1 /* $FreeBSD$ */
2 /*
3  * Copyright (C) 1984-2002  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                 /*
130                  * Forget any current line shift we might have
131                  * (from the last line of the previous screenful).
132                  */
133                 extern int cshift;
134                 cshift = 0;
135
136                 if (top_scroll && n >= sc_height - 1 && pos != ch_length())
137                 {
138                         /*
139                          * Start a new screen.
140                          * {{ This is not really desirable if we happen
141                          *    to hit eof in the middle of this screen,
142                          *    but we don't yet know if that will happen. }}
143                          */
144                         pos_clear();
145                         add_forw_pos(pos);
146                         force = 1;
147                         if (more_mode == 0)
148                         {
149                                 if (top_scroll == OPT_ONPLUS || first_time)
150                                         clear();
151                                 home();
152                         }
153                 } else
154                 {
155                         clear_bot();
156                 }
157
158                 if (pos != position(BOTTOM_PLUS_ONE) || empty_screen())
159                 {
160                         /*
161                          * This is not contiguous with what is
162                          * currently displayed.  Clear the screen image 
163                          * (position table) and start a new screen.
164                          */
165                         pos_clear();
166                         add_forw_pos(pos);
167                         force = 1;
168                         if (top_scroll)
169                         {
170                                 if (top_scroll == OPT_ONPLUS)
171                                         clear();
172                                 home();
173                         } else if (!first_time)
174                         {
175                                 putstr("...skipping...\n");
176                         }
177                 }
178         }
179
180         while (--n >= 0)
181         {
182                 /*
183                  * Read the next line of input.
184                  */
185                 if (nblank > 0)
186                 {
187                         /*
188                          * Still drawing blanks; don't get a line 
189                          * from the file yet.
190                          * If this is the last blank line, get ready to
191                          * read a line starting at ch_zero() next time.
192                          */
193                         if (--nblank == 0)
194                                 pos = ch_zero();
195                 } else
196                 {
197                         /* 
198                          * Get the next line from the file.
199                          */
200                         pos = forw_line(pos);
201                         if (pos == NULL_POSITION)
202                         {
203                                 /*
204                                  * End of file: stop here unless the top line 
205                                  * is still empty, or "force" is true.
206                                  * Even if force is true, stop when the last
207                                  * line in the file reaches the top of screen.
208                                  */
209                                 eof = 1;
210                                 if (!force && position(TOP) != NULL_POSITION)
211                                         break;
212                                 if (!empty_lines(0, 0) && 
213                                     !empty_lines(1, 1) &&
214                                      empty_lines(2, sc_height-1))
215                                         break;
216                         }
217                 }
218                 /*
219                  * Add the position of the next line to the position table.
220                  * Display the current line on the screen.
221                  */
222                 add_forw_pos(pos);
223                 nlines++;
224                 if (do_repaint)
225                         continue;
226                 /*
227                  * If this is the first screen displayed and
228                  * we hit an early EOF (i.e. before the requested
229                  * number of lines), we "squish" the display down
230                  * at the bottom of the screen.
231                  * But don't do this if a + option or a -t option
232                  * was given.  These options can cause us to
233                  * start the display after the beginning of the file,
234                  * and it is not appropriate to squish in that case.
235                  */
236                 if ((first_time || more_mode) &&
237                     pos == NULL_POSITION && !top_scroll && 
238 #if TAGS
239                     tagoption == NULL &&
240 #endif
241                     !plusoption)
242                 {
243                         squished = 1;
244                         continue;
245                 }
246                 if (top_scroll == OPT_ON)
247                         clear_eol();
248                 put_line();
249                 if (clear_bg && final_attr != AT_NORMAL)
250                 {
251                         /*
252                          * Writing the last character on the last line
253                          * of the display may have scrolled the screen.
254                          * If we were in standout mode, clear_bg terminals 
255                          * will fill the new line with the standout color.
256                          * Now we're in normal mode again, so clear the line.
257                          */
258                         clear_eol();
259                 }
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         (void) currline(BOTTOM);
326 }
327
328 /*
329  * Display n more lines, forward.
330  * Start just after the line currently displayed at the bottom of the screen.
331  */
332         public void
333 forward(n, force, only_last)
334         int n;
335         int force;
336         int only_last;
337 {
338         POSITION pos;
339
340         if (quit_at_eof && hit_eof && !(ch_getflags() & CH_HELPFILE))
341         {
342                 /*
343                  * If the -e flag is set and we're trying to go
344                  * forward from end-of-file, go on to the next file.
345                  */
346                 if (edit_next(1))
347                         quit(QUIT_OK);
348                 return;
349         }
350
351         pos = position(BOTTOM_PLUS_ONE);
352         if (pos == NULL_POSITION && (!force || empty_lines(2, sc_height-1)))
353         {
354                 if (ignore_eoi)
355                 {
356                         /*
357                          * ignore_eoi is to support A_F_FOREVER.
358                          * Back up until there is a line at the bottom
359                          * of the screen.
360                          */
361                         if (empty_screen())
362                                 pos = ch_zero();
363                         else
364                         {
365                                 do
366                                 {
367                                         back(1, position(TOP), 1, 0);
368                                         pos = position(BOTTOM_PLUS_ONE);
369                                 } while (pos == NULL_POSITION);
370                         }
371                 } else
372                 {
373                         eof_bell();
374                         hit_eof++;
375                         return;
376                 }
377         }
378         forw(n, pos, force, only_last, 0);
379 }
380
381 /*
382  * Display n more lines, backward.
383  * Start just before the line currently displayed at the top of the screen.
384  */
385         public void
386 backward(n, force, only_last)
387         int n;
388         int force;
389         int only_last;
390 {
391         POSITION pos;
392
393         pos = position(TOP);
394         if (pos == NULL_POSITION && (!force || position(BOTTOM) == 0))
395         {
396                 eof_bell();
397                 return;   
398         }
399         back(n, pos, force, only_last);
400 }
401
402 /*
403  * Get the backwards scroll limit.
404  * Must call this function instead of just using the value of
405  * back_scroll, because the default case depends on sc_height and
406  * top_scroll, as well as back_scroll.
407  */
408         public int
409 get_back_scroll()
410 {
411         if (no_back_scroll)
412                 return (0);
413         if (back_scroll >= 0)
414                 return (back_scroll);
415         if (top_scroll)
416                 return (sc_height - 2);
417         return (10000); /* infinity */
418 }