xref: /openbsd-src/usr.bin/less/mark.c (revision 021cd5d5b70800b1f425d8524bcbc418a9029719)
1e3b7954bSetheisen /*
226ad794dSshadchin  * Copyright (C) 1984-2012  Mark Nudelman
3b8c1323eSnicm  * Modified for use with illumos by Garrett D'Amore.
4b8c1323eSnicm  * Copyright 2014 Garrett D'Amore <garrett@damore.org>
5e3b7954bSetheisen  *
645076018Smillert  * You may distribute under the terms of either the GNU General Public
745076018Smillert  * License or the Less License, as specified in the README file.
8e3b7954bSetheisen  *
926ad794dSshadchin  * For more information, see the README file.
10e3b7954bSetheisen  */
11e3b7954bSetheisen 
12e3b7954bSetheisen #include "less.h"
13e3b7954bSetheisen 
14e3b7954bSetheisen extern IFILE curr_ifile;
15e3b7954bSetheisen extern int sc_height;
16e3b7954bSetheisen extern int jump_sline;
17e3b7954bSetheisen 
18e3b7954bSetheisen /*
19e3b7954bSetheisen  * A mark is an ifile (input file) plus a position within the file.
20e3b7954bSetheisen  */
21e3b7954bSetheisen struct mark {
22e3b7954bSetheisen 	IFILE m_ifile;
23e3b7954bSetheisen 	struct scrpos m_scrpos;
24e3b7954bSetheisen };
25e3b7954bSetheisen 
26e3b7954bSetheisen /*
27e3b7954bSetheisen  * The table of marks.
28e3b7954bSetheisen  * Each mark is identified by a lowercase or uppercase letter.
2945076018Smillert  * The final one is lmark, for the "last mark"; addressed by the apostrophe.
30e3b7954bSetheisen  */
3145076018Smillert #define	NMARKS		((2*26)+1)	/* a-z, A-Z, lastmark */
3245076018Smillert #define	LASTMARK	(NMARKS-1)
33e3b7954bSetheisen static struct mark marks[NMARKS];
34e3b7954bSetheisen 
35e3b7954bSetheisen /*
36e3b7954bSetheisen  * Initialize the mark table to show no marks are set.
37e3b7954bSetheisen  */
38171bb95eSnicm void
init_mark(void)39171bb95eSnicm init_mark(void)
40e3b7954bSetheisen {
41e3b7954bSetheisen 	int i;
42e3b7954bSetheisen 
43e3b7954bSetheisen 	for (i = 0; i < NMARKS; i++)
44171bb95eSnicm 		marks[i].m_scrpos.pos = -1;
45e3b7954bSetheisen }
46e3b7954bSetheisen 
47e3b7954bSetheisen /*
48e3b7954bSetheisen  * See if a mark letter is valid (between a and z).
49e3b7954bSetheisen  */
50e3b7954bSetheisen static struct mark *
getumark(int c)51171bb95eSnicm getumark(int c)
52e3b7954bSetheisen {
53e3b7954bSetheisen 	if (c >= 'a' && c <= 'z')
54e3b7954bSetheisen 		return (&marks[c-'a']);
55e3b7954bSetheisen 
56e3b7954bSetheisen 	if (c >= 'A' && c <= 'Z')
57e3b7954bSetheisen 		return (&marks[c-'A'+26]);
58e3b7954bSetheisen 
59*bf1039baSderaadt 	error("Invalid mark letter", NULL);
60e3b7954bSetheisen 	return (NULL);
61e3b7954bSetheisen }
62e3b7954bSetheisen 
63e3b7954bSetheisen /*
64e3b7954bSetheisen  * Get the mark structure identified by a character.
65e3b7954bSetheisen  * The mark struct may come either from the mark table
66e3b7954bSetheisen  * or may be constructed on the fly for certain characters like ^, $.
67e3b7954bSetheisen  */
68e3b7954bSetheisen static struct mark *
getmark(int c)69171bb95eSnicm getmark(int c)
70e3b7954bSetheisen {
7138be9996Stedu 	struct mark *m;
72e3b7954bSetheisen 	static struct mark sm;
73e3b7954bSetheisen 
74171bb95eSnicm 	switch (c) {
75e3b7954bSetheisen 	case '^':
76e3b7954bSetheisen 		/*
77e3b7954bSetheisen 		 * Beginning of the current file.
78e3b7954bSetheisen 		 */
79e3b7954bSetheisen 		m = &sm;
80e3b7954bSetheisen 		m->m_scrpos.pos = ch_zero();
81e3b7954bSetheisen 		m->m_scrpos.ln = 0;
82e3b7954bSetheisen 		m->m_ifile = curr_ifile;
83e3b7954bSetheisen 		break;
84e3b7954bSetheisen 	case '$':
85e3b7954bSetheisen 		/*
86e3b7954bSetheisen 		 * End of the current file.
87e3b7954bSetheisen 		 */
88171bb95eSnicm 		if (ch_end_seek()) {
89*bf1039baSderaadt 			error("Cannot seek to end of file", NULL);
90e3b7954bSetheisen 			return (NULL);
91e3b7954bSetheisen 		}
92e3b7954bSetheisen 		m = &sm;
93e3b7954bSetheisen 		m->m_scrpos.pos = ch_tell();
94e3b7954bSetheisen 		m->m_scrpos.ln = sc_height-1;
95e3b7954bSetheisen 		m->m_ifile = curr_ifile;
96e3b7954bSetheisen 		break;
97e3b7954bSetheisen 	case '.':
98e3b7954bSetheisen 		/*
99e3b7954bSetheisen 		 * Current position in the current file.
100e3b7954bSetheisen 		 */
101e3b7954bSetheisen 		m = &sm;
10245076018Smillert 		get_scrpos(&m->m_scrpos);
103e3b7954bSetheisen 		m->m_ifile = curr_ifile;
104e3b7954bSetheisen 		break;
105e3b7954bSetheisen 	case '\'':
106e3b7954bSetheisen 		/*
107e3b7954bSetheisen 		 * The "last mark".
108e3b7954bSetheisen 		 */
10945076018Smillert 		m = &marks[LASTMARK];
110e3b7954bSetheisen 		break;
111e3b7954bSetheisen 	default:
112e3b7954bSetheisen 		/*
113e3b7954bSetheisen 		 * Must be a user-defined mark.
114e3b7954bSetheisen 		 */
115e3b7954bSetheisen 		m = getumark(c);
116e3b7954bSetheisen 		if (m == NULL)
117e3b7954bSetheisen 			break;
118171bb95eSnicm 		if (m->m_scrpos.pos == -1) {
119*bf1039baSderaadt 			error("Mark not set", NULL);
120e3b7954bSetheisen 			return (NULL);
121e3b7954bSetheisen 		}
122e3b7954bSetheisen 		break;
123e3b7954bSetheisen 	}
124e3b7954bSetheisen 	return (m);
125e3b7954bSetheisen }
126e3b7954bSetheisen 
127e3b7954bSetheisen /*
128e3b7954bSetheisen  * Is a mark letter is invalid?
129e3b7954bSetheisen  */
130171bb95eSnicm int
badmark(int c)131171bb95eSnicm badmark(int c)
132e3b7954bSetheisen {
133e3b7954bSetheisen 	return (getmark(c) == NULL);
134e3b7954bSetheisen }
135e3b7954bSetheisen 
136e3b7954bSetheisen /*
137e3b7954bSetheisen  * Set a user-defined mark.
138e3b7954bSetheisen  */
139171bb95eSnicm void
setmark(int c)140171bb95eSnicm setmark(int c)
141e3b7954bSetheisen {
14238be9996Stedu 	struct mark *m;
143e3b7954bSetheisen 	struct scrpos scrpos;
144e3b7954bSetheisen 
145e3b7954bSetheisen 	m = getumark(c);
146e3b7954bSetheisen 	if (m == NULL)
147e3b7954bSetheisen 		return;
148e3b7954bSetheisen 	get_scrpos(&scrpos);
149e3b7954bSetheisen 	m->m_scrpos = scrpos;
150e3b7954bSetheisen 	m->m_ifile = curr_ifile;
151e3b7954bSetheisen }
152e3b7954bSetheisen 
153e3b7954bSetheisen /*
154e3b7954bSetheisen  * Set lmark (the mark named by the apostrophe).
155e3b7954bSetheisen  */
156171bb95eSnicm void
lastmark(void)157171bb95eSnicm lastmark(void)
158e3b7954bSetheisen {
159e3b7954bSetheisen 	struct scrpos scrpos;
160e3b7954bSetheisen 
161168565f4Sshadchin 	if (ch_getflags() & CH_HELPFILE)
162168565f4Sshadchin 		return;
163e3b7954bSetheisen 	get_scrpos(&scrpos);
164171bb95eSnicm 	if (scrpos.pos == -1)
165e3b7954bSetheisen 		return;
16645076018Smillert 	marks[LASTMARK].m_scrpos = scrpos;
16745076018Smillert 	marks[LASTMARK].m_ifile = curr_ifile;
168e3b7954bSetheisen }
169e3b7954bSetheisen 
170e3b7954bSetheisen /*
171e3b7954bSetheisen  * Go to a mark.
172e3b7954bSetheisen  */
173171bb95eSnicm void
gomark(int c)174171bb95eSnicm gomark(int c)
175e3b7954bSetheisen {
176171bb95eSnicm 	struct mark *m;
177e3b7954bSetheisen 	struct scrpos scrpos;
178e3b7954bSetheisen 
179e3b7954bSetheisen 	m = getmark(c);
180e3b7954bSetheisen 	if (m == NULL)
181e3b7954bSetheisen 		return;
182e3b7954bSetheisen 
183e3b7954bSetheisen 	/*
184e3b7954bSetheisen 	 * If we're trying to go to the lastmark and
185e3b7954bSetheisen 	 * it has not been set to anything yet,
186e3b7954bSetheisen 	 * set it to the beginning of the current file.
187e3b7954bSetheisen 	 */
188171bb95eSnicm 	if (m == &marks[LASTMARK] && m->m_scrpos.pos == -1) {
189e3b7954bSetheisen 		m->m_ifile = curr_ifile;
190e3b7954bSetheisen 		m->m_scrpos.pos = ch_zero();
191e3b7954bSetheisen 		m->m_scrpos.ln = jump_sline;
192e3b7954bSetheisen 	}
193e3b7954bSetheisen 
194e3b7954bSetheisen 	/*
195e3b7954bSetheisen 	 * If we're using lmark, we must save the screen position now,
196e3b7954bSetheisen 	 * because if we call edit_ifile() below, lmark will change.
197e3b7954bSetheisen 	 * (We save the screen position even if we're not using lmark.)
198e3b7954bSetheisen 	 */
199e3b7954bSetheisen 	scrpos = m->m_scrpos;
200171bb95eSnicm 	if (m->m_ifile != curr_ifile) {
201e3b7954bSetheisen 		/*
202e3b7954bSetheisen 		 * Not in the current file; edit the correct file.
203e3b7954bSetheisen 		 */
204e3b7954bSetheisen 		if (edit_ifile(m->m_ifile))
205e3b7954bSetheisen 			return;
206e3b7954bSetheisen 	}
207e3b7954bSetheisen 
208e3b7954bSetheisen 	jump_loc(scrpos.pos, scrpos.ln);
209e3b7954bSetheisen }
210e3b7954bSetheisen 
211e3b7954bSetheisen /*
212e3b7954bSetheisen  * Return the position associated with a given mark letter.
213e3b7954bSetheisen  *
214e3b7954bSetheisen  * We don't return which screen line the position
215e3b7954bSetheisen  * is associated with, but this doesn't matter much,
216e3b7954bSetheisen  * because it's always the first non-blank line on the screen.
217e3b7954bSetheisen  */
218171bb95eSnicm off_t
markpos(int c)219171bb95eSnicm markpos(int c)
220e3b7954bSetheisen {
221171bb95eSnicm 	struct mark *m;
222e3b7954bSetheisen 
223e3b7954bSetheisen 	m = getmark(c);
224e3b7954bSetheisen 	if (m == NULL)
225171bb95eSnicm 		return (-1);
226e3b7954bSetheisen 
227171bb95eSnicm 	if (m->m_ifile != curr_ifile) {
228*bf1039baSderaadt 		error("Mark not in current file", NULL);
229171bb95eSnicm 		return (-1);
230e3b7954bSetheisen 	}
231e3b7954bSetheisen 	return (m->m_scrpos.pos);
232e3b7954bSetheisen }
23345076018Smillert 
23445076018Smillert /*
23545076018Smillert  * Clear the marks associated with a specified ifile.
23645076018Smillert  */
237171bb95eSnicm void
unmark(IFILE ifile)238171bb95eSnicm unmark(IFILE ifile)
23945076018Smillert {
24045076018Smillert 	int i;
24145076018Smillert 
24245076018Smillert 	for (i = 0; i < NMARKS; i++)
24345076018Smillert 		if (marks[i].m_ifile == ifile)
244171bb95eSnicm 			marks[i].m_scrpos.pos = -1;
24545076018Smillert }
246