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