e2f0cae0c434f7197b5295eee04d41333dad8a82
[dragonfly.git] / contrib / less / mark.c
1 /*
2  * Copyright (C) 1984-2014  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()
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(c)
43         int c;
44 {
45         if (c >= 'a' && c <= 'z')
46                 return (&marks[c-'a']);
47
48         if (c >= 'A' && c <= 'Z')
49                 return (&marks[c-'A'+26]);
50
51         error("Invalid mark letter", NULL_PARG);
52         return (NULL);
53 }
54
55 /*
56  * Get the mark structure identified by a character.
57  * The mark struct may come either from the mark table
58  * or may be constructed on the fly for certain characters like ^, $.
59  */
60         static struct mark *
61 getmark(c)
62         int c;
63 {
64         register struct mark *m;
65         static struct mark sm;
66
67         switch (c)
68         {
69         case '^':
70                 /*
71                  * Beginning of the current file.
72                  */
73                 m = &sm;
74                 m->m_scrpos.pos = ch_zero();
75                 m->m_scrpos.ln = 0;
76                 m->m_ifile = curr_ifile;
77                 break;
78         case '$':
79                 /*
80                  * End of the current file.
81                  */
82                 if (ch_end_seek())
83                 {
84                         error("Cannot seek to end of file", NULL_PARG);
85                         return (NULL);
86                 }
87                 m = &sm;
88                 m->m_scrpos.pos = ch_tell();
89                 m->m_scrpos.ln = sc_height-1;
90                 m->m_ifile = curr_ifile;
91                 break;
92         case '.':
93                 /*
94                  * Current position in the current file.
95                  */
96                 m = &sm;
97                 get_scrpos(&m->m_scrpos);
98                 m->m_ifile = curr_ifile;
99                 break;
100         case '\'':
101                 /*
102                  * The "last mark".
103                  */
104                 m = &marks[LASTMARK];
105                 break;
106         default:
107                 /*
108                  * Must be a user-defined mark.
109                  */
110                 m = getumark(c);
111                 if (m == NULL)
112                         break;
113                 if (m->m_scrpos.pos == NULL_POSITION)
114                 {
115                         error("Mark not set", NULL_PARG);
116                         return (NULL);
117                 }
118                 break;
119         }
120         return (m);
121 }
122
123 /*
124  * Is a mark letter is invalid?
125  */
126         public int
127 badmark(c)
128         int c;
129 {
130         return (getmark(c) == NULL);
131 }
132
133 /*
134  * Set a user-defined mark.
135  */
136         public void
137 setmark(c)
138         int c;
139 {
140         register struct mark *m;
141         struct scrpos scrpos;
142
143         m = getumark(c);
144         if (m == NULL)
145                 return;
146         get_scrpos(&scrpos);
147         m->m_scrpos = scrpos;
148         m->m_ifile = curr_ifile;
149 }
150
151 /*
152  * Set lmark (the mark named by the apostrophe).
153  */
154         public void
155 lastmark()
156 {
157         struct scrpos scrpos;
158
159         if (ch_getflags() & CH_HELPFILE)
160                 return;
161         get_scrpos(&scrpos);
162         if (scrpos.pos == NULL_POSITION)
163                 return;
164         marks[LASTMARK].m_scrpos = scrpos;
165         marks[LASTMARK].m_ifile = curr_ifile;
166 }
167
168 /*
169  * Go to a mark.
170  */
171         public void
172 gomark(c)
173         int c;
174 {
175         register struct mark *m;
176         struct scrpos scrpos;
177
178         m = getmark(c);
179         if (m == NULL)
180                 return;
181
182         /*
183          * If we're trying to go to the lastmark and 
184          * it has not been set to anything yet,
185          * set it to the beginning of the current file.
186          */
187         if (m == &marks[LASTMARK] && m->m_scrpos.pos == NULL_POSITION)
188         {
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                 /*
203                  * Not in the current file; edit the correct file.
204                  */
205                 if (edit_ifile(m->m_ifile))
206                         return;
207         }
208
209         jump_loc(scrpos.pos, scrpos.ln);
210 }
211
212 /*
213  * Return the position associated with a given mark letter.
214  *
215  * We don't return which screen line the position 
216  * is associated with, but this doesn't matter much,
217  * because it's always the first non-blank line on the screen.
218  */
219         public POSITION
220 markpos(c)
221         int c;
222 {
223         register struct mark *m;
224
225         m = getmark(c);
226         if (m == NULL)
227                 return (NULL_POSITION);
228
229         if (m->m_ifile != curr_ifile)
230         {
231                 error("Mark not in current file", NULL_PARG);
232                 return (NULL_POSITION);
233         }
234         return (m->m_scrpos.pos);
235 }
236
237 /*
238  * Clear the marks associated with a specified ifile.
239  */
240         public void
241 unmark(ifile)
242         IFILE ifile;
243 {
244         int i;
245
246         for (i = 0;  i < NMARKS;  i++)
247                 if (marks[i].m_ifile == ifile)
248                         marks[i].m_scrpos.pos = NULL_POSITION;
249 }