xref: /freebsd/contrib/less/mark.c (revision 96e55cc7)
1a5f0fb15SPaul Saab /*
296e55cc7SXin LI  * Copyright (C) 1984-2012  Mark Nudelman
3a5f0fb15SPaul Saab  *
4a5f0fb15SPaul Saab  * You may distribute under the terms of either the GNU General Public
5a5f0fb15SPaul Saab  * License or the Less License, as specified in the README file.
6a5f0fb15SPaul Saab  *
796e55cc7SXin LI  * For more information, see the README file.
8a5f0fb15SPaul Saab  */
9a5f0fb15SPaul Saab 
10a5f0fb15SPaul Saab 
11a5f0fb15SPaul Saab #include "less.h"
12a5f0fb15SPaul Saab 
13a5f0fb15SPaul Saab extern IFILE curr_ifile;
14a5f0fb15SPaul Saab extern int sc_height;
15a5f0fb15SPaul Saab extern int jump_sline;
16a5f0fb15SPaul Saab 
17a5f0fb15SPaul Saab /*
18a5f0fb15SPaul Saab  * A mark is an ifile (input file) plus a position within the file.
19a5f0fb15SPaul Saab  */
20a5f0fb15SPaul Saab struct mark {
21a5f0fb15SPaul Saab 	IFILE m_ifile;
22a5f0fb15SPaul Saab 	struct scrpos m_scrpos;
23a5f0fb15SPaul Saab };
24a5f0fb15SPaul Saab 
25a5f0fb15SPaul Saab /*
26a5f0fb15SPaul Saab  * The table of marks.
27a5f0fb15SPaul Saab  * Each mark is identified by a lowercase or uppercase letter.
28a5f0fb15SPaul Saab  * The final one is lmark, for the "last mark"; addressed by the apostrophe.
29a5f0fb15SPaul Saab  */
30a5f0fb15SPaul Saab #define	NMARKS		((2*26)+1)	/* a-z, A-Z, lastmark */
31a5f0fb15SPaul Saab #define	LASTMARK	(NMARKS-1)
32a5f0fb15SPaul Saab static struct mark marks[NMARKS];
33a5f0fb15SPaul Saab 
34a5f0fb15SPaul Saab /*
35a5f0fb15SPaul Saab  * Initialize the mark table to show no marks are set.
36a5f0fb15SPaul Saab  */
37a5f0fb15SPaul Saab 	public void
38a5f0fb15SPaul Saab init_mark()
39a5f0fb15SPaul Saab {
40a5f0fb15SPaul Saab 	int i;
41a5f0fb15SPaul Saab 
42a5f0fb15SPaul Saab 	for (i = 0;  i < NMARKS;  i++)
43a5f0fb15SPaul Saab 		marks[i].m_scrpos.pos = NULL_POSITION;
44a5f0fb15SPaul Saab }
45a5f0fb15SPaul Saab 
46a5f0fb15SPaul Saab /*
47a5f0fb15SPaul Saab  * See if a mark letter is valid (between a and z).
48a5f0fb15SPaul Saab  */
49a5f0fb15SPaul Saab 	static struct mark *
50a5f0fb15SPaul Saab getumark(c)
51a5f0fb15SPaul Saab 	int c;
52a5f0fb15SPaul Saab {
53a5f0fb15SPaul Saab 	if (c >= 'a' && c <= 'z')
54a5f0fb15SPaul Saab 		return (&marks[c-'a']);
55a5f0fb15SPaul Saab 
56a5f0fb15SPaul Saab 	if (c >= 'A' && c <= 'Z')
57a5f0fb15SPaul Saab 		return (&marks[c-'A'+26]);
58a5f0fb15SPaul Saab 
59a5f0fb15SPaul Saab 	error("Invalid mark letter", NULL_PARG);
60a5f0fb15SPaul Saab 	return (NULL);
61a5f0fb15SPaul Saab }
62a5f0fb15SPaul Saab 
63a5f0fb15SPaul Saab /*
64a5f0fb15SPaul Saab  * Get the mark structure identified by a character.
65a5f0fb15SPaul Saab  * The mark struct may come either from the mark table
66a5f0fb15SPaul Saab  * or may be constructed on the fly for certain characters like ^, $.
67a5f0fb15SPaul Saab  */
68a5f0fb15SPaul Saab 	static struct mark *
69a5f0fb15SPaul Saab getmark(c)
70a5f0fb15SPaul Saab 	int c;
71a5f0fb15SPaul Saab {
72a5f0fb15SPaul Saab 	register struct mark *m;
73a5f0fb15SPaul Saab 	static struct mark sm;
74a5f0fb15SPaul Saab 
75a5f0fb15SPaul Saab 	switch (c)
76a5f0fb15SPaul Saab 	{
77a5f0fb15SPaul Saab 	case '^':
78a5f0fb15SPaul Saab 		/*
79a5f0fb15SPaul Saab 		 * Beginning of the current file.
80a5f0fb15SPaul Saab 		 */
81a5f0fb15SPaul Saab 		m = &sm;
82a5f0fb15SPaul Saab 		m->m_scrpos.pos = ch_zero();
83a5f0fb15SPaul Saab 		m->m_scrpos.ln = 0;
84a5f0fb15SPaul Saab 		m->m_ifile = curr_ifile;
85a5f0fb15SPaul Saab 		break;
86a5f0fb15SPaul Saab 	case '$':
87a5f0fb15SPaul Saab 		/*
88a5f0fb15SPaul Saab 		 * End of the current file.
89a5f0fb15SPaul Saab 		 */
90a5f0fb15SPaul Saab 		if (ch_end_seek())
91a5f0fb15SPaul Saab 		{
92a5f0fb15SPaul Saab 			error("Cannot seek to end of file", NULL_PARG);
93a5f0fb15SPaul Saab 			return (NULL);
94a5f0fb15SPaul Saab 		}
95a5f0fb15SPaul Saab 		m = &sm;
96a5f0fb15SPaul Saab 		m->m_scrpos.pos = ch_tell();
97a5f0fb15SPaul Saab 		m->m_scrpos.ln = sc_height-1;
98a5f0fb15SPaul Saab 		m->m_ifile = curr_ifile;
99a5f0fb15SPaul Saab 		break;
100a5f0fb15SPaul Saab 	case '.':
101a5f0fb15SPaul Saab 		/*
102a5f0fb15SPaul Saab 		 * Current position in the current file.
103a5f0fb15SPaul Saab 		 */
104a5f0fb15SPaul Saab 		m = &sm;
105a5f0fb15SPaul Saab 		get_scrpos(&m->m_scrpos);
106a5f0fb15SPaul Saab 		m->m_ifile = curr_ifile;
107a5f0fb15SPaul Saab 		break;
108a5f0fb15SPaul Saab 	case '\'':
109a5f0fb15SPaul Saab 		/*
110a5f0fb15SPaul Saab 		 * The "last mark".
111a5f0fb15SPaul Saab 		 */
112a5f0fb15SPaul Saab 		m = &marks[LASTMARK];
113a5f0fb15SPaul Saab 		break;
114a5f0fb15SPaul Saab 	default:
115a5f0fb15SPaul Saab 		/*
116a5f0fb15SPaul Saab 		 * Must be a user-defined mark.
117a5f0fb15SPaul Saab 		 */
118a5f0fb15SPaul Saab 		m = getumark(c);
119a5f0fb15SPaul Saab 		if (m == NULL)
120a5f0fb15SPaul Saab 			break;
121a5f0fb15SPaul Saab 		if (m->m_scrpos.pos == NULL_POSITION)
122a5f0fb15SPaul Saab 		{
123a5f0fb15SPaul Saab 			error("Mark not set", NULL_PARG);
124a5f0fb15SPaul Saab 			return (NULL);
125a5f0fb15SPaul Saab 		}
126a5f0fb15SPaul Saab 		break;
127a5f0fb15SPaul Saab 	}
128a5f0fb15SPaul Saab 	return (m);
129a5f0fb15SPaul Saab }
130a5f0fb15SPaul Saab 
131a5f0fb15SPaul Saab /*
132a5f0fb15SPaul Saab  * Is a mark letter is invalid?
133a5f0fb15SPaul Saab  */
134a5f0fb15SPaul Saab 	public int
135a5f0fb15SPaul Saab badmark(c)
136a5f0fb15SPaul Saab 	int c;
137a5f0fb15SPaul Saab {
138a5f0fb15SPaul Saab 	return (getmark(c) == NULL);
139a5f0fb15SPaul Saab }
140a5f0fb15SPaul Saab 
141a5f0fb15SPaul Saab /*
142a5f0fb15SPaul Saab  * Set a user-defined mark.
143a5f0fb15SPaul Saab  */
144a5f0fb15SPaul Saab 	public void
145a5f0fb15SPaul Saab setmark(c)
146a5f0fb15SPaul Saab 	int c;
147a5f0fb15SPaul Saab {
148a5f0fb15SPaul Saab 	register struct mark *m;
149a5f0fb15SPaul Saab 	struct scrpos scrpos;
150a5f0fb15SPaul Saab 
151a5f0fb15SPaul Saab 	m = getumark(c);
152a5f0fb15SPaul Saab 	if (m == NULL)
153a5f0fb15SPaul Saab 		return;
154a5f0fb15SPaul Saab 	get_scrpos(&scrpos);
155a5f0fb15SPaul Saab 	m->m_scrpos = scrpos;
156a5f0fb15SPaul Saab 	m->m_ifile = curr_ifile;
157a5f0fb15SPaul Saab }
158a5f0fb15SPaul Saab 
159a5f0fb15SPaul Saab /*
160a5f0fb15SPaul Saab  * Set lmark (the mark named by the apostrophe).
161a5f0fb15SPaul Saab  */
162a5f0fb15SPaul Saab 	public void
163a5f0fb15SPaul Saab lastmark()
164a5f0fb15SPaul Saab {
165a5f0fb15SPaul Saab 	struct scrpos scrpos;
166a5f0fb15SPaul Saab 
167a5f0fb15SPaul Saab 	if (ch_getflags() & CH_HELPFILE)
168a5f0fb15SPaul Saab 		return;
169a5f0fb15SPaul Saab 	get_scrpos(&scrpos);
170a5f0fb15SPaul Saab 	if (scrpos.pos == NULL_POSITION)
171a5f0fb15SPaul Saab 		return;
172a5f0fb15SPaul Saab 	marks[LASTMARK].m_scrpos = scrpos;
173a5f0fb15SPaul Saab 	marks[LASTMARK].m_ifile = curr_ifile;
174a5f0fb15SPaul Saab }
175a5f0fb15SPaul Saab 
176a5f0fb15SPaul Saab /*
177a5f0fb15SPaul Saab  * Go to a mark.
178a5f0fb15SPaul Saab  */
179a5f0fb15SPaul Saab 	public void
180a5f0fb15SPaul Saab gomark(c)
181a5f0fb15SPaul Saab 	int c;
182a5f0fb15SPaul Saab {
183a5f0fb15SPaul Saab 	register struct mark *m;
184a5f0fb15SPaul Saab 	struct scrpos scrpos;
185a5f0fb15SPaul Saab 
186a5f0fb15SPaul Saab 	m = getmark(c);
187a5f0fb15SPaul Saab 	if (m == NULL)
188a5f0fb15SPaul Saab 		return;
189a5f0fb15SPaul Saab 
190a5f0fb15SPaul Saab 	/*
191a5f0fb15SPaul Saab 	 * If we're trying to go to the lastmark and
192a5f0fb15SPaul Saab 	 * it has not been set to anything yet,
193a5f0fb15SPaul Saab 	 * set it to the beginning of the current file.
194a5f0fb15SPaul Saab 	 */
195a5f0fb15SPaul Saab 	if (m == &marks[LASTMARK] && m->m_scrpos.pos == NULL_POSITION)
196a5f0fb15SPaul Saab 	{
197a5f0fb15SPaul Saab 		m->m_ifile = curr_ifile;
198a5f0fb15SPaul Saab 		m->m_scrpos.pos = ch_zero();
199a5f0fb15SPaul Saab 		m->m_scrpos.ln = jump_sline;
200a5f0fb15SPaul Saab 	}
201a5f0fb15SPaul Saab 
202a5f0fb15SPaul Saab 	/*
203a5f0fb15SPaul Saab 	 * If we're using lmark, we must save the screen position now,
204a5f0fb15SPaul Saab 	 * because if we call edit_ifile() below, lmark will change.
205a5f0fb15SPaul Saab 	 * (We save the screen position even if we're not using lmark.)
206a5f0fb15SPaul Saab 	 */
207a5f0fb15SPaul Saab 	scrpos = m->m_scrpos;
208a5f0fb15SPaul Saab 	if (m->m_ifile != curr_ifile)
209a5f0fb15SPaul Saab 	{
210a5f0fb15SPaul Saab 		/*
211a5f0fb15SPaul Saab 		 * Not in the current file; edit the correct file.
212a5f0fb15SPaul Saab 		 */
213a5f0fb15SPaul Saab 		if (edit_ifile(m->m_ifile))
214a5f0fb15SPaul Saab 			return;
215a5f0fb15SPaul Saab 	}
216a5f0fb15SPaul Saab 
217a5f0fb15SPaul Saab 	jump_loc(scrpos.pos, scrpos.ln);
218a5f0fb15SPaul Saab }
219a5f0fb15SPaul Saab 
220a5f0fb15SPaul Saab /*
221a5f0fb15SPaul Saab  * Return the position associated with a given mark letter.
222a5f0fb15SPaul Saab  *
223a5f0fb15SPaul Saab  * We don't return which screen line the position
224a5f0fb15SPaul Saab  * is associated with, but this doesn't matter much,
225a5f0fb15SPaul Saab  * because it's always the first non-blank line on the screen.
226a5f0fb15SPaul Saab  */
227a5f0fb15SPaul Saab 	public POSITION
228a5f0fb15SPaul Saab markpos(c)
229a5f0fb15SPaul Saab 	int c;
230a5f0fb15SPaul Saab {
231a5f0fb15SPaul Saab 	register struct mark *m;
232a5f0fb15SPaul Saab 
233a5f0fb15SPaul Saab 	m = getmark(c);
234a5f0fb15SPaul Saab 	if (m == NULL)
235a5f0fb15SPaul Saab 		return (NULL_POSITION);
236a5f0fb15SPaul Saab 
237a5f0fb15SPaul Saab 	if (m->m_ifile != curr_ifile)
238a5f0fb15SPaul Saab 	{
239a5f0fb15SPaul Saab 		error("Mark not in current file", NULL_PARG);
240a5f0fb15SPaul Saab 		return (NULL_POSITION);
241a5f0fb15SPaul Saab 	}
242a5f0fb15SPaul Saab 	return (m->m_scrpos.pos);
243a5f0fb15SPaul Saab }
244a5f0fb15SPaul Saab 
245a5f0fb15SPaul Saab /*
246a5f0fb15SPaul Saab  * Clear the marks associated with a specified ifile.
247a5f0fb15SPaul Saab  */
248a5f0fb15SPaul Saab 	public void
249a5f0fb15SPaul Saab unmark(ifile)
250a5f0fb15SPaul Saab 	IFILE ifile;
251a5f0fb15SPaul Saab {
252a5f0fb15SPaul Saab 	int i;
253a5f0fb15SPaul Saab 
254a5f0fb15SPaul Saab 	for (i = 0;  i < NMARKS;  i++)
255a5f0fb15SPaul Saab 		if (marks[i].m_ifile == ifile)
256a5f0fb15SPaul Saab 			marks[i].m_scrpos.pos = NULL_POSITION;
257a5f0fb15SPaul Saab }
258