Commit | Line | Data |
---|---|---|
77e25d77 WJ |
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 | } |