Added all of the MH sources, including RCS files, in
[mmh] / docs / historical / mh-6.8.5 / miscellany / less-177 / mark.c
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 }