160786Sps/*
2240121Sdelphij * Copyright (C) 1984-2012  Mark Nudelman
360786Sps *
460786Sps * You may distribute under the terms of either the GNU General Public
560786Sps * License or the Less License, as specified in the README file.
660786Sps *
7240121Sdelphij * For more information, see the README file.
860786Sps */
960786Sps
1060786Sps
1160786Sps/*
1260786Sps * Routines dealing with the "position" table.
1360786Sps * This is a table which tells the position (in the input file) of the
1460786Sps * first char on each currently displayed line.
1560786Sps *
1660786Sps * {{ The position table is scrolled by moving all the entries.
1760786Sps *    Would be better to have a circular table
1860786Sps *    and just change a couple of pointers. }}
1960786Sps */
2060786Sps
2160786Sps#include "less.h"
2260786Sps#include "position.h"
2360786Sps
2460786Spsstatic POSITION *table = NULL;	/* The position table */
2560786Spsstatic int table_size;
2660786Sps
2760786Spsextern int sc_width, sc_height;
2860786Sps
2960786Sps/*
3060786Sps * Return the starting file position of a line displayed on the screen.
3160786Sps * The line may be specified as a line number relative to the top
3260786Sps * of the screen, but is usually one of these special cases:
3360786Sps *	the top (first) line on the screen
3460786Sps *	the second line on the screen
3560786Sps *	the bottom line on the screen
3660786Sps *	the line after the bottom line on the screen
3760786Sps */
3860786Sps	public POSITION
3960786Spsposition(where)
4060786Sps	int where;
4160786Sps{
4260786Sps	switch (where)
4360786Sps	{
4460786Sps	case BOTTOM:
4560786Sps		where = sc_height - 2;
4660786Sps		break;
4760786Sps	case BOTTOM_PLUS_ONE:
4860786Sps		where = sc_height - 1;
4960786Sps		break;
5060786Sps	case MIDDLE:
5160786Sps		where = (sc_height - 1) / 2;
5260786Sps	}
5360786Sps	return (table[where]);
5460786Sps}
5560786Sps
5660786Sps/*
5760786Sps * Add a new file position to the bottom of the position table.
5860786Sps */
5960786Sps	public void
6060786Spsadd_forw_pos(pos)
6160786Sps	POSITION pos;
6260786Sps{
6360786Sps	register int i;
6460786Sps
6560786Sps	/*
6660786Sps	 * Scroll the position table up.
6760786Sps	 */
6860786Sps	for (i = 1;  i < sc_height;  i++)
6960786Sps		table[i-1] = table[i];
7060786Sps	table[sc_height - 1] = pos;
7160786Sps}
7260786Sps
7360786Sps/*
7460786Sps * Add a new file position to the top of the position table.
7560786Sps */
7660786Sps	public void
7760786Spsadd_back_pos(pos)
7860786Sps	POSITION pos;
7960786Sps{
8060786Sps	register int i;
8160786Sps
8260786Sps	/*
8360786Sps	 * Scroll the position table down.
8460786Sps	 */
8560786Sps	for (i = sc_height - 1;  i > 0;  i--)
8660786Sps		table[i] = table[i-1];
8760786Sps	table[0] = pos;
8860786Sps}
8960786Sps
9060786Sps/*
9160786Sps * Initialize the position table, done whenever we clear the screen.
9260786Sps */
9360786Sps	public void
9460786Spspos_clear()
9560786Sps{
9660786Sps	register int i;
9760786Sps
9860786Sps	for (i = 0;  i < sc_height;  i++)
9960786Sps		table[i] = NULL_POSITION;
10060786Sps}
10160786Sps
10260786Sps/*
10360786Sps * Allocate or reallocate the position table.
10460786Sps */
10560786Sps	public void
10660786Spspos_init()
10760786Sps{
10860786Sps	struct scrpos scrpos;
10960786Sps
11060786Sps	if (sc_height <= table_size)
11160786Sps		return;
11260786Sps	/*
11360786Sps	 * If we already have a table, remember the first line in it
11460786Sps	 * before we free it, so we can copy that line to the new table.
11560786Sps	 */
11660786Sps	if (table != NULL)
11760786Sps	{
11860786Sps		get_scrpos(&scrpos);
11960786Sps		free((char*)table);
12060786Sps	} else
12160786Sps		scrpos.pos = NULL_POSITION;
12260786Sps	table = (POSITION *) ecalloc(sc_height, sizeof(POSITION));
12360786Sps	table_size = sc_height;
12460786Sps	pos_clear();
12560786Sps	if (scrpos.pos != NULL_POSITION)
12660786Sps		table[scrpos.ln-1] = scrpos.pos;
12760786Sps}
12860786Sps
12960786Sps/*
13060786Sps * See if the byte at a specified position is currently on the screen.
13160786Sps * Check the position table to see if the position falls within its range.
13260786Sps * Return the position table entry if found, -1 if not.
13360786Sps */
13460786Sps	public int
13560786Spsonscreen(pos)
13660786Sps	POSITION pos;
13760786Sps{
13860786Sps	register int i;
13960786Sps
14060786Sps	if (pos < table[0])
14160786Sps		return (-1);
14260786Sps	for (i = 1;  i < sc_height;  i++)
14360786Sps		if (pos < table[i])
14460786Sps			return (i-1);
14560786Sps	return (-1);
14660786Sps}
14760786Sps
14860786Sps/*
14960786Sps * See if the entire screen is empty.
15060786Sps */
15160786Sps	public int
15260786Spsempty_screen()
15360786Sps{
15460786Sps	return (empty_lines(0, sc_height-1));
15560786Sps}
15660786Sps
15760786Sps	public int
15860786Spsempty_lines(s, e)
15960786Sps	int s;
16060786Sps	int e;
16160786Sps{
16260786Sps	register int i;
16360786Sps
16460786Sps	for (i = s;  i <= e;  i++)
165251154Sdelphij		if (table[i] != NULL_POSITION && table[i] != 0)
16660786Sps			return (0);
16760786Sps	return (1);
16860786Sps}
16960786Sps
17060786Sps/*
17160786Sps * Get the current screen position.
17260786Sps * The screen position consists of both a file position and
17360786Sps * a screen line number where the file position is placed on the screen.
17460786Sps * Normally the screen line number is 0, but if we are positioned
17560786Sps * such that the top few lines are empty, we may have to set
17660786Sps * the screen line to a number > 0.
17760786Sps */
17860786Sps	public void
17960786Spsget_scrpos(scrpos)
18060786Sps	struct scrpos *scrpos;
18160786Sps{
18260786Sps	register int i;
18360786Sps
18460786Sps	/*
18560786Sps	 * Find the first line on the screen which has something on it,
18660786Sps	 * and return the screen line number and the file position.
18760786Sps	 */
18860786Sps	for (i = 0; i < sc_height;  i++)
18960786Sps		if (table[i] != NULL_POSITION)
19060786Sps		{
19160786Sps			scrpos->ln = i+1;
19260786Sps			scrpos->pos = table[i];
19360786Sps			return;
19460786Sps		}
19560786Sps	/*
19660786Sps	 * The screen is empty.
19760786Sps	 */
19860786Sps	scrpos->pos = NULL_POSITION;
19960786Sps}
20060786Sps
20160786Sps/*
20260786Sps * Adjust a screen line number to be a simple positive integer
20360786Sps * in the range { 0 .. sc_height-2 }.
20460786Sps * (The bottom line, sc_height-1, is reserved for prompts, etc.)
20560786Sps * The given "sline" may be in the range { 1 .. sc_height-1 }
20660786Sps * to refer to lines relative to the top of the screen (starting from 1),
20760786Sps * or it may be in { -1 .. -(sc_height-1) } to refer to lines
20860786Sps * relative to the bottom of the screen.
20960786Sps */
21060786Sps	public int
21160786Spsadjsline(sline)
21260786Sps	int sline;
21360786Sps{
21460786Sps	/*
21560786Sps	 * Negative screen line number means
21660786Sps	 * relative to the bottom of the screen.
21760786Sps	 */
21860786Sps	if (sline < 0)
21960786Sps		sline += sc_height;
22060786Sps	/*
22160786Sps	 * Can't be less than 1 or greater than sc_height-1.
22260786Sps	 */
22360786Sps	if (sline <= 0)
22460786Sps		sline = 1;
22560786Sps	if (sline >= sc_height)
22660786Sps		sline = sc_height - 1;
22760786Sps	/*
22860786Sps	 * Return zero-based line number, not one-based.
22960786Sps	 */
23060786Sps	return (sline-1);
23160786Sps}
232