1238730Sdelphij/*
2330571Sdelphij * Copyright (C) 1984-2017  Mark Nudelman
3238730Sdelphij *
4238730Sdelphij * You may distribute under the terms of either the GNU General Public
5238730Sdelphij * License or the Less License, as specified in the README file.
6238730Sdelphij *
7238730Sdelphij * For more information, see the README file.
8238730Sdelphij */
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
39330571Sdelphijposition(sindex)
40330571Sdelphij	int sindex;
4160786Sps{
42330571Sdelphij	switch (sindex)
4360786Sps	{
4460786Sps	case BOTTOM:
45330571Sdelphij		sindex = sc_height - 2;
4660786Sps		break;
4760786Sps	case BOTTOM_PLUS_ONE:
48330571Sdelphij		sindex = sc_height - 1;
4960786Sps		break;
5060786Sps	case MIDDLE:
51330571Sdelphij		sindex = (sc_height - 1) / 2;
52330571Sdelphij		break;
5360786Sps	}
54330571Sdelphij	return (table[sindex]);
5560786Sps}
5660786Sps
5760786Sps/*
5860786Sps * Add a new file position to the bottom of the position table.
5960786Sps */
6060786Sps	public void
6160786Spsadd_forw_pos(pos)
6260786Sps	POSITION pos;
6360786Sps{
64330571Sdelphij	int i;
6560786Sps
6660786Sps	/*
6760786Sps	 * Scroll the position table up.
6860786Sps	 */
6960786Sps	for (i = 1;  i < sc_height;  i++)
7060786Sps		table[i-1] = table[i];
7160786Sps	table[sc_height - 1] = pos;
7260786Sps}
7360786Sps
7460786Sps/*
7560786Sps * Add a new file position to the top of the position table.
7660786Sps */
7760786Sps	public void
7860786Spsadd_back_pos(pos)
7960786Sps	POSITION pos;
8060786Sps{
81330571Sdelphij	int i;
8260786Sps
8360786Sps	/*
8460786Sps	 * Scroll the position table down.
8560786Sps	 */
8660786Sps	for (i = sc_height - 1;  i > 0;  i--)
8760786Sps		table[i] = table[i-1];
8860786Sps	table[0] = pos;
8960786Sps}
9060786Sps
9160786Sps/*
9260786Sps * Initialize the position table, done whenever we clear the screen.
9360786Sps */
9460786Sps	public void
9560786Spspos_clear()
9660786Sps{
97330571Sdelphij	int i;
9860786Sps
9960786Sps	for (i = 0;  i < sc_height;  i++)
10060786Sps		table[i] = NULL_POSITION;
10160786Sps}
10260786Sps
10360786Sps/*
10460786Sps * Allocate or reallocate the position table.
10560786Sps */
10660786Sps	public void
10760786Spspos_init()
10860786Sps{
10960786Sps	struct scrpos scrpos;
11060786Sps
11160786Sps	if (sc_height <= table_size)
11260786Sps		return;
11360786Sps	/*
11460786Sps	 * If we already have a table, remember the first line in it
11560786Sps	 * before we free it, so we can copy that line to the new table.
11660786Sps	 */
11760786Sps	if (table != NULL)
11860786Sps	{
119330571Sdelphij		get_scrpos(&scrpos, TOP);
12060786Sps		free((char*)table);
12160786Sps	} else
12260786Sps		scrpos.pos = NULL_POSITION;
12360786Sps	table = (POSITION *) ecalloc(sc_height, sizeof(POSITION));
12460786Sps	table_size = sc_height;
12560786Sps	pos_clear();
12660786Sps	if (scrpos.pos != NULL_POSITION)
12760786Sps		table[scrpos.ln-1] = scrpos.pos;
12860786Sps}
12960786Sps
13060786Sps/*
13160786Sps * See if the byte at a specified position is currently on the screen.
13260786Sps * Check the position table to see if the position falls within its range.
13360786Sps * Return the position table entry if found, -1 if not.
13460786Sps */
13560786Sps	public int
13660786Spsonscreen(pos)
13760786Sps	POSITION pos;
13860786Sps{
139330571Sdelphij	int i;
14060786Sps
14160786Sps	if (pos < table[0])
14260786Sps		return (-1);
14360786Sps	for (i = 1;  i < sc_height;  i++)
14460786Sps		if (pos < table[i])
14560786Sps			return (i-1);
14660786Sps	return (-1);
14760786Sps}
14860786Sps
14960786Sps/*
15060786Sps * See if the entire screen is empty.
15160786Sps */
15260786Sps	public int
15360786Spsempty_screen()
15460786Sps{
15560786Sps	return (empty_lines(0, sc_height-1));
15660786Sps}
15760786Sps
15860786Sps	public int
15960786Spsempty_lines(s, e)
16060786Sps	int s;
16160786Sps	int e;
16260786Sps{
163330571Sdelphij	int i;
16460786Sps
16560786Sps	for (i = s;  i <= e;  i++)
166242584Sdelphij		if (table[i] != NULL_POSITION && table[i] != 0)
16760786Sps			return (0);
16860786Sps	return (1);
16960786Sps}
17060786Sps
17160786Sps/*
17260786Sps * Get the current screen position.
17360786Sps * The screen position consists of both a file position and
17460786Sps * a screen line number where the file position is placed on the screen.
17560786Sps * Normally the screen line number is 0, but if we are positioned
17660786Sps * such that the top few lines are empty, we may have to set
17760786Sps * the screen line to a number > 0.
17860786Sps */
17960786Sps	public void
180330571Sdelphijget_scrpos(scrpos, where)
18160786Sps	struct scrpos *scrpos;
182330571Sdelphij	int where;
18360786Sps{
184330571Sdelphij	int i;
185330571Sdelphij	int dir;
186330571Sdelphij	int last;
18760786Sps
188330571Sdelphij	switch (where)
189330571Sdelphij	{
190330571Sdelphij	case TOP: i = 0; dir = +1; last = sc_height-2; break;
191330571Sdelphij	default:  i = sc_height-2; dir = -1; last = 0; break;
192330571Sdelphij	}
193330571Sdelphij
19460786Sps	/*
19560786Sps	 * Find the first line on the screen which has something on it,
19660786Sps	 * and return the screen line number and the file position.
19760786Sps	 */
198330571Sdelphij	for (;; i += dir)
199330571Sdelphij	{
20060786Sps		if (table[i] != NULL_POSITION)
20160786Sps		{
20260786Sps			scrpos->ln = i+1;
20360786Sps			scrpos->pos = table[i];
20460786Sps			return;
20560786Sps		}
206330571Sdelphij		if (i == last) break;
207330571Sdelphij	}
20860786Sps	/*
20960786Sps	 * The screen is empty.
21060786Sps	 */
21160786Sps	scrpos->pos = NULL_POSITION;
21260786Sps}
21360786Sps
21460786Sps/*
21560786Sps * Adjust a screen line number to be a simple positive integer
21660786Sps * in the range { 0 .. sc_height-2 }.
21760786Sps * (The bottom line, sc_height-1, is reserved for prompts, etc.)
21860786Sps * The given "sline" may be in the range { 1 .. sc_height-1 }
21960786Sps * to refer to lines relative to the top of the screen (starting from 1),
22060786Sps * or it may be in { -1 .. -(sc_height-1) } to refer to lines
22160786Sps * relative to the bottom of the screen.
22260786Sps */
22360786Sps	public int
224330571Sdelphijsindex_from_sline(sline)
22560786Sps	int sline;
22660786Sps{
22760786Sps	/*
22860786Sps	 * Negative screen line number means
22960786Sps	 * relative to the bottom of the screen.
23060786Sps	 */
23160786Sps	if (sline < 0)
23260786Sps		sline += sc_height;
23360786Sps	/*
234330571Sdelphij	 * Can't be less than 1 or greater than sc_height.
23560786Sps	 */
23660786Sps	if (sline <= 0)
23760786Sps		sline = 1;
238330571Sdelphij	if (sline > sc_height)
239330571Sdelphij		sline = sc_height;
24060786Sps	/*
24160786Sps	 * Return zero-based line number, not one-based.
24260786Sps	 */
24360786Sps	return (sline-1);
24460786Sps}
245