29d7b190c2
compiler-time type checking, and also causes problems for targets where multiple incompatible calling conventions may be selected based on argument types. This change switches less(1) to ANSI prototypes. While there, we also remove use of "register", and attempt to use "const" a bit better now that the compiler can check argument types. Reviewed by: cem, emaste MFC after: 3 weeks Sponsored by: DARPA, AFRL Differential Revision: https://reviews.freebsd.org/D10152
437 lines
9.4 KiB
C
437 lines
9.4 KiB
C
/* $FreeBSD$ */
|
|
/*
|
|
* Copyright (C) 1984-2015 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, 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 screen_trashed;
|
|
public int squished;
|
|
public int no_back_scroll = 0;
|
|
public int forw_prompt;
|
|
public int same_pos_bell = 1;
|
|
|
|
extern int sigs;
|
|
extern int top_scroll;
|
|
extern int quiet;
|
|
extern int sc_width, sc_height;
|
|
extern int less_is_more;
|
|
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 HILITE_SEARCH
|
|
extern int size_linebuf;
|
|
extern int hilite_search;
|
|
extern int status_col;
|
|
#endif
|
|
#if TAGS
|
|
extern char *tagoption;
|
|
#endif
|
|
|
|
/*
|
|
* Sound the bell to indicate user is trying to move past end of file.
|
|
*/
|
|
static void
|
|
eof_bell(void)
|
|
{
|
|
if (quiet == NOT_QUIET)
|
|
bell();
|
|
else
|
|
vbell();
|
|
}
|
|
|
|
/*
|
|
* Check to see if the end of file is currently displayed.
|
|
*/
|
|
public int
|
|
eof_displayed(void)
|
|
{
|
|
POSITION pos;
|
|
|
|
if (ignore_eoi)
|
|
return (0);
|
|
|
|
if (ch_length() == NULL_POSITION)
|
|
/*
|
|
* If the file length is not known,
|
|
* we can't possibly be displaying EOF.
|
|
*/
|
|
return (0);
|
|
|
|
/*
|
|
* 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);
|
|
return (pos == NULL_POSITION || pos == ch_length());
|
|
}
|
|
|
|
/*
|
|
* Check to see if the entire file is currently displayed.
|
|
*/
|
|
public int
|
|
entire_file_displayed(void)
|
|
{
|
|
POSITION pos;
|
|
|
|
/* Make sure last line of file is displayed. */
|
|
if (!eof_displayed())
|
|
return (0);
|
|
|
|
/* Make sure first line of file is displayed. */
|
|
pos = position(0);
|
|
return (pos == NULL_POSITION || pos == 0);
|
|
}
|
|
|
|
/*
|
|
* 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(void)
|
|
{
|
|
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(int n, POSITION pos, int force, int only_last, int nblank)
|
|
{
|
|
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 HILITE_SEARCH
|
|
if (hilite_search == OPT_ONPLUS || is_filtering() || status_col) {
|
|
prep_hilite(pos, pos + 4*size_linebuf, ignore_eoi ? 1 : -1);
|
|
pos = next_unfiltered(pos);
|
|
}
|
|
#endif
|
|
|
|
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;
|
|
if (less_is_more == 0) {
|
|
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 HILITE_SEARCH
|
|
pos = next_unfiltered(pos);
|
|
#endif
|
|
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.
|
|
*/
|
|
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 || less_is_more) &&
|
|
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 (nlines == 0 && same_pos_bell)
|
|
eof_bell();
|
|
else if (do_repaint)
|
|
repaint();
|
|
first_time = 0;
|
|
(void) currline(BOTTOM);
|
|
}
|
|
|
|
/*
|
|
* Display n lines, scrolling backward.
|
|
*/
|
|
public void
|
|
back(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));
|
|
#if HILITE_SEARCH
|
|
if (hilite_search == OPT_ONPLUS || is_filtering() || status_col) {
|
|
prep_hilite((pos < 3*size_linebuf) ? 0 : pos - 3*size_linebuf, pos, -1);
|
|
}
|
|
#endif
|
|
while (--n >= 0)
|
|
{
|
|
/*
|
|
* Get the previous line of input.
|
|
*/
|
|
#if HILITE_SEARCH
|
|
pos = prev_unfiltered(pos);
|
|
#endif
|
|
|
|
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();
|
|
}
|
|
}
|
|
|
|
if (nlines == 0 && same_pos_bell)
|
|
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(int n, int force, int only_last)
|
|
{
|
|
POSITION pos;
|
|
|
|
if (get_quit_at_eof() && eof_displayed() && !(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();
|
|
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(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(void)
|
|
{
|
|
if (no_back_scroll)
|
|
return (0);
|
|
if (back_scroll >= 0)
|
|
return (back_scroll);
|
|
if (top_scroll)
|
|
return (sc_height - 2);
|
|
return (10000); /* infinity */
|
|
}
|