upgrade to 466 version
[platform/upstream/less.git] / 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 eof = 0;
132         int nlines = 0;
133         int do_repaint;
134         static int first_time = 1;
135
136         squish_check();
137
138         /*
139          * do_repaint tells us not to display anything till the end, 
140          * then just repaint the entire screen.
141          * We repaint if we are supposed to display only the last 
142          * screenful and the request is for more than a screenful.
143          * Also if the request exceeds the forward scroll limit
144          * (but not if the request is for exactly a screenful, since
145          * repainting itself involves scrolling forward a screenful).
146          */
147         do_repaint = (only_last && n > sc_height-1) || 
148                 (forw_scroll >= 0 && n > forw_scroll && n != sc_height-1);
149
150 #if HILITE_SEARCH
151         prep_hilite(pos, pos + 3*size_linebuf, ignore_eoi ? 1 : -1);
152         pos = next_unfiltered(pos);
153 #endif
154
155         if (!do_repaint)
156         {
157                 if (top_scroll && n >= sc_height - 1 && pos != ch_length())
158                 {
159                         /*
160                          * Start a new screen.
161                          * {{ This is not really desirable if we happen
162                          *    to hit eof in the middle of this screen,
163                          *    but we don't yet know if that will happen. }}
164                          */
165                         pos_clear();
166                         add_forw_pos(pos);
167                         force = 1;
168                         clear();
169                         home();
170                 }
171
172                 if (pos != position(BOTTOM_PLUS_ONE) || empty_screen())
173                 {
174                         /*
175                          * This is not contiguous with what is
176                          * currently displayed.  Clear the screen image 
177                          * (position table) and start a new screen.
178                          */
179                         pos_clear();
180                         add_forw_pos(pos);
181                         force = 1;
182                         if (top_scroll)
183                         {
184                                 clear();
185                                 home();
186                         } else if (!first_time)
187                         {
188                                 putstr("...skipping...\n");
189                         }
190                 }
191         }
192
193         while (--n >= 0)
194         {
195                 /*
196                  * Read the next line of input.
197                  */
198                 if (nblank > 0)
199                 {
200                         /*
201                          * Still drawing blanks; don't get a line 
202                          * from the file yet.
203                          * If this is the last blank line, get ready to
204                          * read a line starting at ch_zero() next time.
205                          */
206                         if (--nblank == 0)
207                                 pos = ch_zero();
208                 } else
209                 {
210                         /* 
211                          * Get the next line from the file.
212                          */
213                         pos = forw_line(pos);
214 #if HILITE_SEARCH
215                         pos = next_unfiltered(pos);
216 #endif
217                         if (pos == NULL_POSITION)
218                         {
219                                 /*
220                                  * End of file: stop here unless the top line 
221                                  * is still empty, or "force" is true.
222                                  * Even if force is true, stop when the last
223                                  * line in the file reaches the top of screen.
224                                  */
225                                 eof = 1;
226                                 if (!force && position(TOP) != NULL_POSITION)
227                                         break;
228                                 if (!empty_lines(0, 0) && 
229                                     !empty_lines(1, 1) &&
230                                      empty_lines(2, sc_height-1))
231                                         break;
232                         }
233                 }
234                 /*
235                  * Add the position of the next line to the position table.
236                  * Display the current line on the screen.
237                  */
238                 add_forw_pos(pos);
239                 nlines++;
240                 if (do_repaint)
241                         continue;
242                 /*
243                  * If this is the first screen displayed and
244                  * we hit an early EOF (i.e. before the requested
245                  * number of lines), we "squish" the display down
246                  * at the bottom of the screen.
247                  * But don't do this if a + option or a -t option
248                  * was given.  These options can cause us to
249                  * start the display after the beginning of the file,
250                  * and it is not appropriate to squish in that case.
251                  */
252                 if (first_time && pos == NULL_POSITION && !top_scroll && 
253 #if TAGS
254                     tagoption == NULL &&
255 #endif
256                     !plusoption)
257                 {
258                         squished = 1;
259                         continue;
260                 }
261                 put_line();
262 #if 0
263                 /* {{ 
264                  * Can't call clear_eol here.  The cursor might be at end of line
265                  * on an ignaw terminal, so clear_eol would clear the last char
266                  * of the current line instead of all of the next line.
267                  * If we really need to do this on clear_bg terminals, we need
268                  * to find a better way.
269                  * }}
270                  */
271                 if (clear_bg && apply_at_specials(final_attr) != AT_NORMAL)
272                 {
273                         /*
274                          * Writing the last character on the last line
275                          * of the display may have scrolled the screen.
276                          * If we were in standout mode, clear_bg terminals 
277                          * will fill the new line with the standout color.
278                          * Now we're in normal mode again, so clear the line.
279                          */
280                         clear_eol();
281                 }
282 #endif
283                 forw_prompt = 1;
284         }
285
286         if (nlines == 0 && same_pos_bell)
287                 eof_bell();
288         else if (do_repaint)
289                 repaint();
290         first_time = 0;
291         (void) currline(BOTTOM);
292 }
293
294 /*
295  * Display n lines, scrolling backward.
296  */
297         public void
298 back(n, pos, force, only_last)
299         register int n;
300         POSITION pos;
301         int force;
302         int only_last;
303 {
304         int nlines = 0;
305         int do_repaint;
306
307         squish_check();
308         do_repaint = (n > get_back_scroll() || (only_last && n > sc_height-1));
309 #if HILITE_SEARCH
310         prep_hilite((pos < 3*size_linebuf) ?  0 : pos - 3*size_linebuf, pos, -1);
311 #endif
312         while (--n >= 0)
313         {
314                 /*
315                  * Get the previous line of input.
316                  */
317 #if HILITE_SEARCH
318                 pos = prev_unfiltered(pos);
319 #endif
320
321                 pos = back_line(pos);
322                 if (pos == NULL_POSITION)
323                 {
324                         /*
325                          * Beginning of file: stop here unless "force" is true.
326                          */
327                         if (!force)
328                                 break;
329                 }
330                 /*
331                  * Add the position of the previous line to the position table.
332                  * Display the line on the screen.
333                  */
334                 add_back_pos(pos);
335                 nlines++;
336                 if (!do_repaint)
337                 {
338                         home();
339                         add_line();
340                         put_line();
341                 }
342         }
343
344         if (nlines == 0 && same_pos_bell)
345                 eof_bell();
346         else if (do_repaint)
347                 repaint();
348         else if (!oldbot)
349                 lower_left();
350         (void) currline(BOTTOM);
351 }
352
353 /*
354  * Display n more lines, forward.
355  * Start just after the line currently displayed at the bottom of the screen.
356  */
357         public void
358 forward(n, force, only_last)
359         int n;
360         int force;
361         int only_last;
362 {
363         POSITION pos;
364
365         if (get_quit_at_eof() && eof_displayed() && !(ch_getflags() & CH_HELPFILE))
366         {
367                 /*
368                  * If the -e flag is set and we're trying to go
369                  * forward from end-of-file, go on to the next file.
370                  */
371                 if (edit_next(1))
372                         quit(QUIT_OK);
373                 return;
374         }
375
376         pos = position(BOTTOM_PLUS_ONE);
377         if (pos == NULL_POSITION && (!force || empty_lines(2, sc_height-1)))
378         {
379                 if (ignore_eoi)
380                 {
381                         /*
382                          * ignore_eoi is to support A_F_FOREVER.
383                          * Back up until there is a line at the bottom
384                          * of the screen.
385                          */
386                         if (empty_screen())
387                                 pos = ch_zero();
388                         else
389                         {
390                                 do
391                                 {
392                                         back(1, position(TOP), 1, 0);
393                                         pos = position(BOTTOM_PLUS_ONE);
394                                 } while (pos == NULL_POSITION);
395                         }
396                 } else
397                 {
398                         eof_bell();
399                         return;
400                 }
401         }
402         forw(n, pos, force, only_last, 0);
403 }
404
405 /*
406  * Display n more lines, backward.
407  * Start just before the line currently displayed at the top of the screen.
408  */
409         public void
410 backward(n, force, only_last)
411         int n;
412         int force;
413         int only_last;
414 {
415         POSITION pos;
416
417         pos = position(TOP);
418         if (pos == NULL_POSITION && (!force || position(BOTTOM) == 0))
419         {
420                 eof_bell();
421                 return;   
422         }
423         back(n, pos, force, only_last);
424 }
425
426 /*
427  * Get the backwards scroll limit.
428  * Must call this function instead of just using the value of
429  * back_scroll, because the default case depends on sc_height and
430  * top_scroll, as well as back_scroll.
431  */
432         public int
433 get_back_scroll()
434 {
435         if (no_back_scroll)
436                 return (0);
437         if (back_scroll >= 0)
438                 return (back_scroll);
439         if (top_scroll)
440                 return (sc_height - 2);
441         return (10000); /* infinity */
442 }