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