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