mark.c revision 60786
160786Sps/*
260786Sps * Copyright (C) 1984-2000  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 *
760786Sps * For more information about less, or for information on how to
860786Sps * contact the author, see the README file.
960786Sps */
1060786Sps
1160786Sps
1260786Sps#include "less.h"
1360786Sps
1460786Spsextern IFILE curr_ifile;
1560786Spsextern int sc_height;
1660786Spsextern int jump_sline;
1760786Sps
1860786Sps/*
1960786Sps * A mark is an ifile (input file) plus a position within the file.
2060786Sps */
2160786Spsstruct mark {
2260786Sps	IFILE m_ifile;
2360786Sps	struct scrpos m_scrpos;
2460786Sps};
2560786Sps
2660786Sps/*
2760786Sps * The table of marks.
2860786Sps * Each mark is identified by a lowercase or uppercase letter.
2960786Sps * The final one is lmark, for the "last mark"; addressed by the apostrophe.
3060786Sps */
3160786Sps#define	NMARKS		((2*26)+1)	/* a-z, A-Z, lastmark */
3260786Sps#define	LASTMARK	(NMARKS-1)
3360786Spsstatic struct mark marks[NMARKS];
3460786Sps
3560786Sps/*
3660786Sps * Initialize the mark table to show no marks are set.
3760786Sps */
3860786Sps	public void
3960786Spsinit_mark()
4060786Sps{
4160786Sps	int i;
4260786Sps
4360786Sps	for (i = 0;  i < NMARKS;  i++)
4460786Sps		marks[i].m_scrpos.pos = NULL_POSITION;
4560786Sps}
4660786Sps
4760786Sps/*
4860786Sps * See if a mark letter is valid (between a and z).
4960786Sps */
5060786Sps	static struct mark *
5160786Spsgetumark(c)
5260786Sps	int c;
5360786Sps{
5460786Sps	if (c >= 'a' && c <= 'z')
5560786Sps		return (&marks[c-'a']);
5660786Sps
5760786Sps	if (c >= 'A' && c <= 'Z')
5860786Sps		return (&marks[c-'A'+26]);
5960786Sps
6060786Sps	error("Invalid mark letter", NULL_PARG);
6160786Sps	return (NULL);
6260786Sps}
6360786Sps
6460786Sps/*
6560786Sps * Get the mark structure identified by a character.
6660786Sps * The mark struct may come either from the mark table
6760786Sps * or may be constructed on the fly for certain characters like ^, $.
6860786Sps */
6960786Sps	static struct mark *
7060786Spsgetmark(c)
7160786Sps	int c;
7260786Sps{
7360786Sps	register struct mark *m;
7460786Sps	static struct mark sm;
7560786Sps
7660786Sps	switch (c)
7760786Sps	{
7860786Sps	case '^':
7960786Sps		/*
8060786Sps		 * Beginning of the current file.
8160786Sps		 */
8260786Sps		m = &sm;
8360786Sps		m->m_scrpos.pos = ch_zero();
8460786Sps		m->m_scrpos.ln = 0;
8560786Sps		m->m_ifile = curr_ifile;
8660786Sps		break;
8760786Sps	case '$':
8860786Sps		/*
8960786Sps		 * End of the current file.
9060786Sps		 */
9160786Sps		if (ch_end_seek())
9260786Sps		{
9360786Sps			error("Cannot seek to end of file", NULL_PARG);
9460786Sps			return (NULL);
9560786Sps		}
9660786Sps		m = &sm;
9760786Sps		m->m_scrpos.pos = ch_tell();
9860786Sps		m->m_scrpos.ln = sc_height-1;
9960786Sps		m->m_ifile = curr_ifile;
10060786Sps		break;
10160786Sps	case '.':
10260786Sps		/*
10360786Sps		 * Current position in the current file.
10460786Sps		 */
10560786Sps		m = &sm;
10660786Sps		get_scrpos(&m->m_scrpos);
10760786Sps		m->m_ifile = curr_ifile;
10860786Sps		break;
10960786Sps	case '\'':
11060786Sps		/*
11160786Sps		 * The "last mark".
11260786Sps		 */
11360786Sps		m = &marks[LASTMARK];
11460786Sps		break;
11560786Sps	default:
11660786Sps		/*
11760786Sps		 * Must be a user-defined mark.
11860786Sps		 */
11960786Sps		m = getumark(c);
12060786Sps		if (m == NULL)
12160786Sps			break;
12260786Sps		if (m->m_scrpos.pos == NULL_POSITION)
12360786Sps		{
12460786Sps			error("Mark not set", NULL_PARG);
12560786Sps			return (NULL);
12660786Sps		}
12760786Sps		break;
12860786Sps	}
12960786Sps	return (m);
13060786Sps}
13160786Sps
13260786Sps/*
13360786Sps * Is a mark letter is invalid?
13460786Sps */
13560786Sps	public int
13660786Spsbadmark(c)
13760786Sps	int c;
13860786Sps{
13960786Sps	return (getmark(c) == NULL);
14060786Sps}
14160786Sps
14260786Sps/*
14360786Sps * Set a user-defined mark.
14460786Sps */
14560786Sps	public void
14660786Spssetmark(c)
14760786Sps	int c;
14860786Sps{
14960786Sps	register struct mark *m;
15060786Sps	struct scrpos scrpos;
15160786Sps
15260786Sps	m = getumark(c);
15360786Sps	if (m == NULL)
15460786Sps		return;
15560786Sps	get_scrpos(&scrpos);
15660786Sps	m->m_scrpos = scrpos;
15760786Sps	m->m_ifile = curr_ifile;
15860786Sps}
15960786Sps
16060786Sps/*
16160786Sps * Set lmark (the mark named by the apostrophe).
16260786Sps */
16360786Sps	public void
16460786Spslastmark()
16560786Sps{
16660786Sps	struct scrpos scrpos;
16760786Sps
16860786Sps	if (ch_getflags() & CH_HELPFILE)
16960786Sps		return;
17060786Sps	get_scrpos(&scrpos);
17160786Sps	if (scrpos.pos == NULL_POSITION)
17260786Sps		return;
17360786Sps	marks[LASTMARK].m_scrpos = scrpos;
17460786Sps	marks[LASTMARK].m_ifile = curr_ifile;
17560786Sps}
17660786Sps
17760786Sps/*
17860786Sps * Go to a mark.
17960786Sps */
18060786Sps	public void
18160786Spsgomark(c)
18260786Sps	int c;
18360786Sps{
18460786Sps	register struct mark *m;
18560786Sps	struct scrpos scrpos;
18660786Sps
18760786Sps	m = getmark(c);
18860786Sps	if (m == NULL)
18960786Sps		return;
19060786Sps
19160786Sps	/*
19260786Sps	 * If we're trying to go to the lastmark and
19360786Sps	 * it has not been set to anything yet,
19460786Sps	 * set it to the beginning of the current file.
19560786Sps	 */
19660786Sps	if (m == &marks[LASTMARK] && m->m_scrpos.pos == NULL_POSITION)
19760786Sps	{
19860786Sps		m->m_ifile = curr_ifile;
19960786Sps		m->m_scrpos.pos = ch_zero();
20060786Sps		m->m_scrpos.ln = jump_sline;
20160786Sps	}
20260786Sps
20360786Sps	/*
20460786Sps	 * If we're using lmark, we must save the screen position now,
20560786Sps	 * because if we call edit_ifile() below, lmark will change.
20660786Sps	 * (We save the screen position even if we're not using lmark.)
20760786Sps	 */
20860786Sps	scrpos = m->m_scrpos;
20960786Sps	if (m->m_ifile != curr_ifile)
21060786Sps	{
21160786Sps		/*
21260786Sps		 * Not in the current file; edit the correct file.
21360786Sps		 */
21460786Sps		if (edit_ifile(m->m_ifile))
21560786Sps			return;
21660786Sps	}
21760786Sps
21860786Sps	jump_loc(scrpos.pos, scrpos.ln);
21960786Sps}
22060786Sps
22160786Sps/*
22260786Sps * Return the position associated with a given mark letter.
22360786Sps *
22460786Sps * We don't return which screen line the position
22560786Sps * is associated with, but this doesn't matter much,
22660786Sps * because it's always the first non-blank line on the screen.
22760786Sps */
22860786Sps	public POSITION
22960786Spsmarkpos(c)
23060786Sps	int c;
23160786Sps{
23260786Sps	register struct mark *m;
23360786Sps
23460786Sps	m = getmark(c);
23560786Sps	if (m == NULL)
23660786Sps		return (NULL_POSITION);
23760786Sps
23860786Sps	if (m->m_ifile != curr_ifile)
23960786Sps	{
24060786Sps		error("Mark not in current file", NULL_PARG);
24160786Sps		return (NULL_POSITION);
24260786Sps	}
24360786Sps	return (m->m_scrpos.pos);
24460786Sps}
24560786Sps
24660786Sps/*
24760786Sps * Clear the marks associated with a specified ifile.
24860786Sps */
24960786Sps	public void
25060786Spsunmark(ifile)
25160786Sps	IFILE ifile;
25260786Sps{
25360786Sps	int i;
25460786Sps
25560786Sps	for (i = 0;  i < NMARKS;  i++)
25660786Sps		if (marks[i].m_ifile == ifile)
25760786Sps			marks[i].m_scrpos.pos = NULL_POSITION;
25860786Sps}
25960786Sps