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