mark.c revision 191930
1214501Srpaulo/*
2214501Srpaulo * Copyright (C) 1984-2008  Mark Nudelman
3214501Srpaulo *
4214501Srpaulo * You may distribute under the terms of either the GNU General Public
5252726Srpaulo * License or the Less License, as specified in the README file.
6252726Srpaulo *
7214501Srpaulo * For more information about less, or for information on how to
8214501Srpaulo * contact the author, see the README file.
9214501Srpaulo */
10214501Srpaulo
11214501Srpaulo
12214501Srpaulo#include "less.h"
13252726Srpaulo
14214501Srpauloextern IFILE curr_ifile;
15214501Srpauloextern int sc_height;
16214501Srpauloextern int jump_sline;
17214501Srpaulo
18214501Srpaulo/*
19214501Srpaulo * A mark is an ifile (input file) plus a position within the file.
20214501Srpaulo */
21214501Srpaulostruct mark {
22214501Srpaulo	IFILE m_ifile;
23214501Srpaulo	struct scrpos m_scrpos;
24214501Srpaulo};
25214501Srpaulo
26214501Srpaulo/*
27214501Srpaulo * The table of marks.
28214501Srpaulo * Each mark is identified by a lowercase or uppercase letter.
29214501Srpaulo * The final one is lmark, for the "last mark"; addressed by the apostrophe.
30214501Srpaulo */
31214501Srpaulo#define	NMARKS		((2*26)+1)	/* a-z, A-Z, lastmark */
32214501Srpaulo#define	LASTMARK	(NMARKS-1)
33214501Srpaulostatic struct mark marks[NMARKS];
34214501Srpaulo
35214501Srpaulo/*
36214501Srpaulo * Initialize the mark table to show no marks are set.
37214501Srpaulo */
38214501Srpaulo	public void
39214501Srpauloinit_mark()
40214501Srpaulo{
41214501Srpaulo	int i;
42214501Srpaulo
43214501Srpaulo	for (i = 0;  i < NMARKS;  i++)
44214501Srpaulo		marks[i].m_scrpos.pos = NULL_POSITION;
45214501Srpaulo}
46214501Srpaulo
47214501Srpaulo/*
48214501Srpaulo * See if a mark letter is valid (between a and z).
49214501Srpaulo */
50214501Srpaulo	static struct mark *
51214501Srpaulogetumark(c)
52214501Srpaulo	int c;
53214501Srpaulo{
54214501Srpaulo	if (c >= 'a' && c <= 'z')
55214501Srpaulo		return (&marks[c-'a']);
56214501Srpaulo
57214501Srpaulo	if (c >= 'A' && c <= 'Z')
58214501Srpaulo		return (&marks[c-'A'+26]);
59214501Srpaulo
60214501Srpaulo	error("Invalid mark letter", NULL_PARG);
61214501Srpaulo	return (NULL);
62214501Srpaulo}
63214501Srpaulo
64214501Srpaulo/*
65214501Srpaulo * Get the mark structure identified by a character.
66214501Srpaulo * The mark struct may come either from the mark table
67214501Srpaulo * or may be constructed on the fly for certain characters like ^, $.
68214501Srpaulo */
69214501Srpaulo	static struct mark *
70214501Srpaulogetmark(c)
71214501Srpaulo	int c;
72214501Srpaulo{
73214501Srpaulo	register struct mark *m;
74346981Scy	static struct mark sm;
75346981Scy
76214501Srpaulo	switch (c)
77214501Srpaulo	{
78214501Srpaulo	case '^':
79214501Srpaulo		/*
80214501Srpaulo		 * Beginning of the current file.
81214501Srpaulo		 */
82214501Srpaulo		m = &sm;
83214501Srpaulo		m->m_scrpos.pos = ch_zero();
84214501Srpaulo		m->m_scrpos.ln = 0;
85214501Srpaulo		m->m_ifile = curr_ifile;
86214501Srpaulo		break;
87214501Srpaulo	case '$':
88214501Srpaulo		/*
89214501Srpaulo		 * End of the current file.
90214501Srpaulo		 */
91214501Srpaulo		if (ch_end_seek())
92214501Srpaulo		{
93281806Srpaulo			error("Cannot seek to end of file", NULL_PARG);
94214501Srpaulo			return (NULL);
95214501Srpaulo		}
96214501Srpaulo		m = &sm;
97214501Srpaulo		m->m_scrpos.pos = ch_tell();
98214501Srpaulo		m->m_scrpos.ln = sc_height-1;
99214501Srpaulo		m->m_ifile = curr_ifile;
100214501Srpaulo		break;
101214501Srpaulo	case '.':
102214501Srpaulo		/*
103214501Srpaulo		 * Current position in the current file.
104214501Srpaulo		 */
105252726Srpaulo		m = &sm;
106214501Srpaulo		get_scrpos(&m->m_scrpos);
107214501Srpaulo		m->m_ifile = curr_ifile;
108214501Srpaulo		break;
109214501Srpaulo	case '\'':
110214501Srpaulo		/*
111214501Srpaulo		 * The "last mark".
112281806Srpaulo		 */
113214501Srpaulo		m = &marks[LASTMARK];
114214501Srpaulo		break;
115214501Srpaulo	default:
116214501Srpaulo		/*
117214501Srpaulo		 * Must be a user-defined mark.
118214501Srpaulo		 */
119214501Srpaulo		m = getumark(c);
120214501Srpaulo		if (m == NULL)
121214501Srpaulo			break;
122214501Srpaulo		if (m->m_scrpos.pos == NULL_POSITION)
123214501Srpaulo		{
124214501Srpaulo			error("Mark not set", NULL_PARG);
125214501Srpaulo			return (NULL);
126214501Srpaulo		}
127214501Srpaulo		break;
128214501Srpaulo	}
129214501Srpaulo	return (m);
130214501Srpaulo}
131214501Srpaulo
132214501Srpaulo/*
133214501Srpaulo * Is a mark letter is invalid?
134281806Srpaulo */
135214501Srpaulo	public int
136214501Srpaulobadmark(c)
137214501Srpaulo	int c;
138214501Srpaulo{
139214501Srpaulo	return (getmark(c) == NULL);
140214501Srpaulo}
141214501Srpaulo
142214501Srpaulo/*
143214501Srpaulo * Set a user-defined mark.
144214501Srpaulo */
145214501Srpaulo	public void
146214501Srpaulosetmark(c)
147214501Srpaulo	int c;
148214501Srpaulo{
149214501Srpaulo	register struct mark *m;
150214501Srpaulo	struct scrpos scrpos;
151214501Srpaulo
152214501Srpaulo	m = getumark(c);
153214501Srpaulo	if (m == NULL)
154214501Srpaulo		return;
155214501Srpaulo	get_scrpos(&scrpos);
156214501Srpaulo	m->m_scrpos = scrpos;
157214501Srpaulo	m->m_ifile = curr_ifile;
158214501Srpaulo}
159214501Srpaulo
160214501Srpaulo/*
161214501Srpaulo * Set lmark (the mark named by the apostrophe).
162214501Srpaulo */
163214501Srpaulo	public void
164214501Srpaulolastmark()
165214501Srpaulo{
166214501Srpaulo	struct scrpos scrpos;
167214501Srpaulo
168214501Srpaulo	if (ch_getflags() & CH_HELPFILE)
169214501Srpaulo		return;
170214501Srpaulo	get_scrpos(&scrpos);
171214501Srpaulo	if (scrpos.pos == NULL_POSITION)
172214501Srpaulo		return;
173214501Srpaulo	marks[LASTMARK].m_scrpos = scrpos;
174214501Srpaulo	marks[LASTMARK].m_ifile = curr_ifile;
175214501Srpaulo}
176214501Srpaulo
177214501Srpaulo/*
178214501Srpaulo * Go to a mark.
179214501Srpaulo */
180214501Srpaulo	public void
181214501Srpaulogomark(c)
182214501Srpaulo	int c;
183214501Srpaulo{
184214501Srpaulo	register struct mark *m;
185214501Srpaulo	struct scrpos scrpos;
186214501Srpaulo
187214501Srpaulo	m = getmark(c);
188214501Srpaulo	if (m == NULL)
189214501Srpaulo		return;
190214501Srpaulo
191214501Srpaulo	/*
192214501Srpaulo	 * If we're trying to go to the lastmark and
193214501Srpaulo	 * it has not been set to anything yet,
194214501Srpaulo	 * set it to the beginning of the current file.
195214501Srpaulo	 */
196214501Srpaulo	if (m == &marks[LASTMARK] && m->m_scrpos.pos == NULL_POSITION)
197214501Srpaulo	{
198214501Srpaulo		m->m_ifile = curr_ifile;
199214501Srpaulo		m->m_scrpos.pos = ch_zero();
200214501Srpaulo		m->m_scrpos.ln = jump_sline;
201214501Srpaulo	}
202214501Srpaulo
203214501Srpaulo	/*
204214501Srpaulo	 * If we're using lmark, we must save the screen position now,
205214501Srpaulo	 * because if we call edit_ifile() below, lmark will change.
206214501Srpaulo	 * (We save the screen position even if we're not using lmark.)
207214501Srpaulo	 */
208214501Srpaulo	scrpos = m->m_scrpos;
209214501Srpaulo	if (m->m_ifile != curr_ifile)
210214501Srpaulo	{
211214501Srpaulo		/*
212214501Srpaulo		 * Not in the current file; edit the correct file.
213214501Srpaulo		 */
214214501Srpaulo		if (edit_ifile(m->m_ifile))
215214501Srpaulo			return;
216214501Srpaulo	}
217214501Srpaulo
218214501Srpaulo	jump_loc(scrpos.pos, scrpos.ln);
219214501Srpaulo}
220214501Srpaulo
221214501Srpaulo/*
222214501Srpaulo * Return the position associated with a given mark letter.
223214501Srpaulo *
224214501Srpaulo * We don't return which screen line the position
225214501Srpaulo * is associated with, but this doesn't matter much,
226214501Srpaulo * because it's always the first non-blank line on the screen.
227214501Srpaulo */
228214501Srpaulo	public POSITION
229214501Srpaulomarkpos(c)
230214501Srpaulo	int c;
231214501Srpaulo{
232214501Srpaulo	register struct mark *m;
233214501Srpaulo
234214501Srpaulo	m = getmark(c);
235214501Srpaulo	if (m == NULL)
236214501Srpaulo		return (NULL_POSITION);
237214501Srpaulo
238214501Srpaulo	if (m->m_ifile != curr_ifile)
239214501Srpaulo	{
240214501Srpaulo		error("Mark not in current file", NULL_PARG);
241214501Srpaulo		return (NULL_POSITION);
242214501Srpaulo	}
243214501Srpaulo	return (m->m_scrpos.pos);
244214501Srpaulo}
245214501Srpaulo
246214501Srpaulo/*
247214501Srpaulo * Clear the marks associated with a specified ifile.
248214501Srpaulo */
249214501Srpaulo	public void
250214501Srpaulounmark(ifile)
251214501Srpaulo	IFILE ifile;
252214501Srpaulo{
253214501Srpaulo	int i;
254214501Srpaulo
255214501Srpaulo	for (i = 0;  i < NMARKS;  i++)
256214501Srpaulo		if (marks[i].m_ifile == ifile)
257214501Srpaulo			marks[i].m_scrpos.pos = NULL_POSITION;
258214501Srpaulo}
259214501Srpaulo