xref: /openbsd-src/usr.bin/less/mark.c (revision b2ea75c1b17e1a9a339660e7ed45cd24946b230e)
1 /*	$OpenBSD: mark.c,v 1.2 2001/01/29 01:58:03 niklas Exp $	*/
2 
3 /*
4  * Copyright (c) 1984,1985,1989,1994,1995  Mark Nudelman
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice in the documentation and/or other materials provided with
14  *    the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
22  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 
30 #include "less.h"
31 #include "position.h"
32 
33 extern IFILE curr_ifile;
34 extern int sc_height;
35 extern int jump_sline;
36 
37 /*
38  * A mark is an ifile (input file) plus a position within the file.
39  */
40 struct mark {
41 	IFILE m_ifile;
42 	struct scrpos m_scrpos;
43 };
44 
45 /*
46  * The table of marks.
47  * Each mark is identified by a lowercase or uppercase letter.
48  */
49 #define	NMARKS		(2*26)		/* a-z, A-Z */
50 static struct mark marks[NMARKS];
51 
52 /*
53  * Special mark for the "last mark"; addressed by the apostrophe.
54  */
55 static struct mark lmark;
56 
57 /*
58  * Initialize the mark table to show no marks are set.
59  */
60 	public void
61 init_mark()
62 {
63 	int i;
64 
65 	for (i = 0;  i < NMARKS;  i++)
66 		marks[i].m_scrpos.pos = NULL_POSITION;
67 	lmark.m_scrpos.pos = NULL_POSITION;
68 }
69 
70 /*
71  * See if a mark letter is valid (between a and z).
72  */
73 	static struct mark *
74 getumark(c)
75 	int c;
76 {
77 	if (c >= 'a' && c <= 'z')
78 		return (&marks[c-'a']);
79 
80 	if (c >= 'A' && c <= 'Z')
81 		return (&marks[c-'A'+26]);
82 
83 	error("Invalid mark letter", NULL_PARG);
84 	return (NULL);
85 }
86 
87 /*
88  * Get the mark structure identified by a character.
89  * The mark struct may come either from the mark table
90  * or may be constructed on the fly for certain characters like ^, $.
91  */
92 	static struct mark *
93 getmark(c)
94 	int c;
95 {
96 	register struct mark *m;
97 	static struct mark sm;
98 
99 	switch (c)
100 	{
101 	case '^':
102 		/*
103 		 * Beginning of the current file.
104 		 */
105 		m = &sm;
106 		m->m_scrpos.pos = ch_zero();
107 		m->m_scrpos.ln = 0;
108 		m->m_ifile = curr_ifile;
109 		break;
110 	case '$':
111 		/*
112 		 * End of the current file.
113 		 */
114 		if (ch_end_seek())
115 		{
116 			error("Cannot seek to end of file", NULL_PARG);
117 			return (NULL);
118 		}
119 		m = &sm;
120 		m->m_scrpos.pos = ch_tell();
121 		m->m_scrpos.ln = sc_height-1;
122 		m->m_ifile = curr_ifile;
123 		break;
124 	case '.':
125 		/*
126 		 * Current position in the current file.
127 		 */
128 		m = &sm;
129 		m->m_scrpos.pos = ch_tell();
130 		m->m_scrpos.ln = 0;
131 		m->m_ifile = curr_ifile;
132 		break;
133 	case '\'':
134 		/*
135 		 * The "last mark".
136 		 */
137 		m = &lmark;
138 		break;
139 	default:
140 		/*
141 		 * Must be a user-defined mark.
142 		 */
143 		m = getumark(c);
144 		if (m == NULL)
145 			break;
146 		if (m->m_scrpos.pos == NULL_POSITION)
147 		{
148 			error("Mark not set", NULL_PARG);
149 			return (NULL);
150 		}
151 		break;
152 	}
153 	return (m);
154 }
155 
156 /*
157  * Is a mark letter is invalid?
158  */
159 	public int
160 badmark(c)
161 	int c;
162 {
163 	return (getmark(c) == NULL);
164 }
165 
166 /*
167  * Set a user-defined mark.
168  */
169 	public void
170 setmark(c)
171 	int c;
172 {
173 	register struct mark *m;
174 	struct scrpos scrpos;
175 
176 	m = getumark(c);
177 	if (m == NULL)
178 		return;
179 	get_scrpos(&scrpos);
180 	m->m_scrpos = scrpos;
181 	m->m_ifile = curr_ifile;
182 }
183 
184 /*
185  * Set lmark (the mark named by the apostrophe).
186  */
187 	public void
188 lastmark()
189 {
190 	struct scrpos scrpos;
191 
192 	get_scrpos(&scrpos);
193 	if (scrpos.pos == NULL_POSITION)
194 		return;
195 	lmark.m_scrpos = scrpos;
196 	lmark.m_ifile = curr_ifile;
197 }
198 
199 /*
200  * Go to a mark.
201  */
202 	public void
203 gomark(c)
204 	int c;
205 {
206 	register struct mark *m;
207 	struct scrpos scrpos;
208 
209 	m = getmark(c);
210 	if (m == NULL)
211 		return;
212 
213 	/*
214 	 * If we're trying to go to the lastmark and
215 	 * it has not been set to anything yet,
216 	 * set it to the beginning of the current file.
217 	 */
218 	if (m == &lmark && m->m_scrpos.pos == NULL_POSITION)
219 	{
220 		m->m_ifile = curr_ifile;
221 		m->m_scrpos.pos = ch_zero();
222 		m->m_scrpos.ln = jump_sline;
223 	}
224 
225 	/*
226 	 * If we're using lmark, we must save the screen position now,
227 	 * because if we call edit_ifile() below, lmark will change.
228 	 * (We save the screen position even if we're not using lmark.)
229 	 */
230 	scrpos = m->m_scrpos;
231 	if (m->m_ifile != curr_ifile)
232 	{
233 		/*
234 		 * Not in the current file; edit the correct file.
235 		 */
236 		if (edit_ifile(m->m_ifile))
237 			return;
238 	}
239 
240 	jump_loc(scrpos.pos, scrpos.ln);
241 }
242 
243 /*
244  * Return the position associated with a given mark letter.
245  *
246  * We don't return which screen line the position
247  * is associated with, but this doesn't matter much,
248  * because it's always the first non-blank line on the screen.
249  */
250 	public POSITION
251 markpos(c)
252 	int c;
253 {
254 	register struct mark *m;
255 
256 	m = getmark(c);
257 	if (m == NULL)
258 		return (NULL_POSITION);
259 
260 	if (m->m_ifile != curr_ifile)
261 	{
262 		error("Mark not in current file", NULL_PARG);
263 		return (NULL_POSITION);
264 	}
265 	return (m->m_scrpos.pos);
266 }
267