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