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