diff options
Diffstat (limited to 'forwback.c')
-rw-r--r-- | forwback.c | 412 |
1 files changed, 412 insertions, 0 deletions
diff --git a/forwback.c b/forwback.c new file mode 100644 index 0000000..7b5bb2d --- /dev/null +++ b/forwback.c @@ -0,0 +1,412 @@ +/* + * Copyright (C) 1984-2007 Mark Nudelman + * + * You may distribute under the terms of either the GNU General Public + * License or the Less License, as specified in the README file. + * + * For more information about less, or for information on how to + * contact the author, see the README file. + */ + + +/* + * Primitives for displaying the file on the screen, + * scrolling either forward or backward. + */ + +#include "less.h" +#include "position.h" + +public int hit_eof; /* Keeps track of how many times we hit end of file */ +public int screen_trashed; +public int squished; +public int no_back_scroll = 0; +public int forw_prompt; + +extern int sigs; +extern int top_scroll; +extern int quiet; +extern int sc_width, sc_height; +extern int plusoption; +extern int forw_scroll; +extern int back_scroll; +extern int ignore_eoi; +extern int clear_bg; +extern int final_attr; +extern int oldbot; +#if TAGS +extern char *tagoption; +#endif + +/* + * Sound the bell to indicate user is trying to move past end of file. + */ + static void +eof_bell() +{ + if (quiet == NOT_QUIET) + bell(); + else + vbell(); +} + +/* + * Check to see if the end of file is currently "displayed". + */ + static void +eof_check() +{ + POSITION pos; + + if (ignore_eoi) + return; + if (ABORT_SIGS()) + return; + /* + * If the bottom line is empty, we are at EOF. + * If the bottom line ends at the file length, + * we must be just at EOF. + */ + pos = position(BOTTOM_PLUS_ONE); + if (pos == NULL_POSITION || pos == ch_length()) + hit_eof++; +} + +/* + * If the screen is "squished", repaint it. + * "Squished" means the first displayed line is not at the top + * of the screen; this can happen when we display a short file + * for the first time. + */ + public void +squish_check() +{ + if (!squished) + return; + squished = 0; + repaint(); +} + +/* + * Display n lines, scrolling forward, + * starting at position pos in the input file. + * "force" means display the n lines even if we hit end of file. + * "only_last" means display only the last screenful if n > screen size. + * "nblank" is the number of blank lines to draw before the first + * real line. If nblank > 0, the pos must be NULL_POSITION. + * The first real line after the blanks will start at ch_zero(). + */ + public void +forw(n, pos, force, only_last, nblank) + register int n; + POSITION pos; + int force; + int only_last; + int nblank; +{ + int eof = 0; + int nlines = 0; + int do_repaint; + static int first_time = 1; + + squish_check(); + + /* + * do_repaint tells us not to display anything till the end, + * then just repaint the entire screen. + * We repaint if we are supposed to display only the last + * screenful and the request is for more than a screenful. + * Also if the request exceeds the forward scroll limit + * (but not if the request is for exactly a screenful, since + * repainting itself involves scrolling forward a screenful). + */ + do_repaint = (only_last && n > sc_height-1) || + (forw_scroll >= 0 && n > forw_scroll && n != sc_height-1); + + if (!do_repaint) + { + if (top_scroll && n >= sc_height - 1 && pos != ch_length()) + { + /* + * Start a new screen. + * {{ This is not really desirable if we happen + * to hit eof in the middle of this screen, + * but we don't yet know if that will happen. }} + */ + pos_clear(); + add_forw_pos(pos); + force = 1; + clear(); + home(); + } + + if (pos != position(BOTTOM_PLUS_ONE) || empty_screen()) + { + /* + * This is not contiguous with what is + * currently displayed. Clear the screen image + * (position table) and start a new screen. + */ + pos_clear(); + add_forw_pos(pos); + force = 1; + if (top_scroll) + { + clear(); + home(); + } else if (!first_time) + { + putstr("...skipping...\n"); + } + } + } + + while (--n >= 0) + { + /* + * Read the next line of input. + */ + if (nblank > 0) + { + /* + * Still drawing blanks; don't get a line + * from the file yet. + * If this is the last blank line, get ready to + * read a line starting at ch_zero() next time. + */ + if (--nblank == 0) + pos = ch_zero(); + } else + { + /* + * Get the next line from the file. + */ + pos = forw_line(pos); + if (pos == NULL_POSITION) + { + /* + * End of file: stop here unless the top line + * is still empty, or "force" is true. + * Even if force is true, stop when the last + * line in the file reaches the top of screen. + */ + eof = 1; + if (!force && position(TOP) != NULL_POSITION) + break; + if (!empty_lines(0, 0) && + !empty_lines(1, 1) && + empty_lines(2, sc_height-1)) + break; + } + } + /* + * Add the position of the next line to the position table. + * Display the current line on the screen. + */ + add_forw_pos(pos); + nlines++; + if (do_repaint) + continue; + /* + * If this is the first screen displayed and + * we hit an early EOF (i.e. before the requested + * number of lines), we "squish" the display down + * at the bottom of the screen. + * But don't do this if a + option or a -t option + * was given. These options can cause us to + * start the display after the beginning of the file, + * and it is not appropriate to squish in that case. + */ + if (first_time && pos == NULL_POSITION && !top_scroll && +#if TAGS + tagoption == NULL && +#endif + !plusoption) + { + squished = 1; + continue; + } + put_line(); +#if 0 + /* {{ + * Can't call clear_eol here. The cursor might be at end of line + * on an ignaw terminal, so clear_eol would clear the last char + * of the current line instead of all of the next line. + * If we really need to do this on clear_bg terminals, we need + * to find a better way. + * }} + */ + if (clear_bg && apply_at_specials(final_attr) != AT_NORMAL) + { + /* + * Writing the last character on the last line + * of the display may have scrolled the screen. + * If we were in standout mode, clear_bg terminals + * will fill the new line with the standout color. + * Now we're in normal mode again, so clear the line. + */ + clear_eol(); + } +#endif + forw_prompt = 1; + } + + if (ignore_eoi) + hit_eof = 0; + else if (eof && !ABORT_SIGS()) + hit_eof++; + else + eof_check(); + if (nlines == 0) + eof_bell(); + else if (do_repaint) + repaint(); + first_time = 0; + (void) currline(BOTTOM); +} + +/* + * Display n lines, scrolling backward. + */ + public void +back(n, pos, force, only_last) + register int n; + POSITION pos; + int force; + int only_last; +{ + int nlines = 0; + int do_repaint; + + squish_check(); + do_repaint = (n > get_back_scroll() || (only_last && n > sc_height-1)); + hit_eof = 0; + while (--n >= 0) + { + /* + * Get the previous line of input. + */ + pos = back_line(pos); + if (pos == NULL_POSITION) + { + /* + * Beginning of file: stop here unless "force" is true. + */ + if (!force) + break; + } + /* + * Add the position of the previous line to the position table. + * Display the line on the screen. + */ + add_back_pos(pos); + nlines++; + if (!do_repaint) + { + home(); + add_line(); + put_line(); + } + } + + eof_check(); + if (nlines == 0) + eof_bell(); + else if (do_repaint) + repaint(); + else if (!oldbot) + lower_left(); + (void) currline(BOTTOM); +} + +/* + * Display n more lines, forward. + * Start just after the line currently displayed at the bottom of the screen. + */ + public void +forward(n, force, only_last) + int n; + int force; + int only_last; +{ + POSITION pos; + + if (get_quit_at_eof() && hit_eof && !(ch_getflags() & CH_HELPFILE)) + { + /* + * If the -e flag is set and we're trying to go + * forward from end-of-file, go on to the next file. + */ + if (edit_next(1)) + quit(QUIT_OK); + return; + } + + pos = position(BOTTOM_PLUS_ONE); + if (pos == NULL_POSITION && (!force || empty_lines(2, sc_height-1))) + { + if (ignore_eoi) + { + /* + * ignore_eoi is to support A_F_FOREVER. + * Back up until there is a line at the bottom + * of the screen. + */ + if (empty_screen()) + pos = ch_zero(); + else + { + do + { + back(1, position(TOP), 1, 0); + pos = position(BOTTOM_PLUS_ONE); + } while (pos == NULL_POSITION); + } + } else + { + eof_bell(); + hit_eof++; + return; + } + } + forw(n, pos, force, only_last, 0); +} + +/* + * Display n more lines, backward. + * Start just before the line currently displayed at the top of the screen. + */ + public void +backward(n, force, only_last) + int n; + int force; + int only_last; +{ + POSITION pos; + + pos = position(TOP); + if (pos == NULL_POSITION && (!force || position(BOTTOM) == 0)) + { + eof_bell(); + return; + } + back(n, pos, force, only_last); +} + +/* + * Get the backwards scroll limit. + * Must call this function instead of just using the value of + * back_scroll, because the default case depends on sc_height and + * top_scroll, as well as back_scroll. + */ + public int +get_back_scroll() +{ + if (no_back_scroll) + return (0); + if (back_scroll >= 0) + return (back_scroll); + if (top_scroll) + return (sc_height - 2); + return (10000); /* infinity */ +} |