GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/less/less/../mark.c Lines: 11 70 15.7 %
Date: 2017-11-13 Branches: 5 41 12.2 %

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