Merge illumos-gate
[unleashed.git] / bin / less / mark.c
blob044f8c456e677895736b86af2e14f72c8e2075ec
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>
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.
9 * For more information, see the README file.
12 #include "less.h"
14 extern IFILE curr_ifile;
15 extern int sc_height;
16 extern int jump_sline;
19 * A mark is an ifile (input file) plus a position within the file.
21 struct mark {
22 IFILE m_ifile;
23 struct scrpos m_scrpos;
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.
31 #define NMARKS ((2*26)+1) /* a-z, A-Z, lastmark */
32 #define LASTMARK (NMARKS-1)
33 static struct mark marks[NMARKS];
36 * Initialize the mark table to show no marks are set.
38 void
39 init_mark(void)
41 int i;
43 for (i = 0; i < NMARKS; i++)
44 marks[i].m_scrpos.pos = -1;
48 * See if a mark letter is valid (between a and z).
50 static struct mark *
51 getumark(int c)
53 if (c >= 'a' && c <= 'z')
54 return (&marks[c-'a']);
56 if (c >= 'A' && c <= 'Z')
57 return (&marks[c-'A'+26]);
59 error("Invalid mark letter", NULL);
60 return (NULL);
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 ^, $.
68 static struct mark *
69 getmark(int c)
71 struct mark *m;
72 static struct mark sm;
74 switch (c) {
75 case '^':
77 * Beginning of the current file.
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 '$':
86 * End of the current file.
88 if (ch_end_seek()) {
89 error("Cannot seek to end of file", NULL);
90 return (NULL);
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 '.':
99 * Current position in the current file.
101 m = &sm;
102 get_scrpos(&m->m_scrpos);
103 m->m_ifile = curr_ifile;
104 break;
105 case '\'':
107 * The "last mark".
109 m = &marks[LASTMARK];
110 break;
111 default:
113 * Must be a user-defined mark.
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);
122 break;
124 return (m);
128 * Is a mark letter is invalid?
131 badmark(int c)
133 return (getmark(c) == NULL);
137 * Set a user-defined mark.
139 void
140 setmark(int c)
142 struct mark *m;
143 struct scrpos scrpos;
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;
154 * Set lmark (the mark named by the apostrophe).
156 void
157 lastmark(void)
159 struct scrpos scrpos;
161 if (ch_getflags() & CH_HELPFILE)
162 return;
163 get_scrpos(&scrpos);
164 if (scrpos.pos == -1)
165 return;
166 marks[LASTMARK].m_scrpos = scrpos;
167 marks[LASTMARK].m_ifile = curr_ifile;
171 * Go to a mark.
173 void
174 gomark(int c)
176 struct mark *m;
177 struct scrpos scrpos;
179 m = getmark(c);
180 if (m == NULL)
181 return;
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.
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;
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.)
199 scrpos = m->m_scrpos;
200 if (m->m_ifile != curr_ifile) {
202 * Not in the current file; edit the correct file.
204 if (edit_ifile(m->m_ifile))
205 return;
208 jump_loc(scrpos.pos, scrpos.ln);
212 * Return the position associated with a given mark letter.
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.
218 off_t
219 markpos(int c)
221 struct mark *m;
223 m = getmark(c);
224 if (m == NULL)
225 return (-1);
227 if (m->m_ifile != curr_ifile) {
228 error("Mark not in current file", NULL);
229 return (-1);
231 return (m->m_scrpos.pos);
235 * Clear the marks associated with a specified ifile.
237 void
238 unmark(IFILE ifile)
240 int i;
242 for (i = 0; i < NMARKS; i++)
243 if (marks[i].m_ifile == ifile)
244 marks[i].m_scrpos.pos = -1;