]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/less/mark.c
Optionally bind ktls threads to NUMA domains
[FreeBSD/FreeBSD.git] / contrib / less / mark.c
1 /*
2  * Copyright (C) 1984-2020  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 #include "position.h"
13
14 extern IFILE curr_ifile;
15 extern int sc_height;
16 extern int jump_sline;
17 extern int perma_marks;
18
19 /*
20  * A mark is an ifile (input file) plus a position within the file.
21  */
22 struct mark 
23 {
24         /*
25          * Normally m_ifile != IFILE_NULL and m_filename == NULL.
26          * For restored marks we set m_filename instead of m_ifile
27          * because we don't want to create an ifile until the 
28          * user explicitly requests the file (by name or mark).
29          */
30         char m_letter;           /* Associated character */
31         IFILE m_ifile;           /* Input file being marked */
32         char *m_filename;        /* Name of the input file */
33         struct scrpos m_scrpos;  /* Position of the mark */
34 };
35
36 /*
37  * The table of marks.
38  * Each mark is identified by a lowercase or uppercase letter.
39  * The final one is lmark, for the "last mark"; addressed by the apostrophe.
40  */
41 #define NMARKS          ((2*26)+2)      /* a-z, A-Z, mousemark, lastmark */
42 #define NUMARKS         ((2*26)+1)      /* user marks (not lastmark) */
43 #define MOUSEMARK       (NMARKS-2)
44 #define LASTMARK        (NMARKS-1)
45 static struct mark marks[NMARKS];
46 public int marks_modified = 0;
47
48
49 /*
50  * Initialize a mark struct.
51  */
52         static void
53 cmark(m, ifile, pos, ln)
54         struct mark *m;
55         IFILE ifile;
56         POSITION pos;
57         int ln;
58 {
59         m->m_ifile = ifile;
60         m->m_scrpos.pos = pos;
61         m->m_scrpos.ln = ln;
62         m->m_filename = NULL;
63 }
64
65 /*
66  * Initialize the mark table to show no marks are set.
67  */
68         public void
69 init_mark(VOID_PARAM)
70 {
71         int i;
72
73         for (i = 0;  i < NMARKS;  i++)
74         {
75                 char letter;
76                 switch (i) {
77                 case MOUSEMARK: letter = '#'; break;
78                 case LASTMARK: letter = '\''; break;
79                 default: letter = (i < 26) ? 'a'+i : 'A'+i-26; break;
80                 }
81                 marks[i].m_letter = letter;
82                 cmark(&marks[i], NULL_IFILE, NULL_POSITION, -1);
83         }
84 }
85
86 /*
87  * Set m_ifile and clear m_filename.
88  */
89         static void
90 mark_set_ifile(m, ifile)
91         struct mark *m;
92         IFILE ifile;
93 {
94         m->m_ifile = ifile;
95         /* With m_ifile set, m_filename is no longer needed. */
96         free(m->m_filename);
97         m->m_filename = NULL;
98 }
99
100 /*
101  * Populate the m_ifile member of a mark struct from m_filename.
102  */
103         static void
104 mark_get_ifile(m)
105         struct mark *m;
106 {
107         if (m->m_ifile != NULL_IFILE)
108                 return; /* m_ifile is already set */
109         mark_set_ifile(m, get_ifile(m->m_filename, prev_ifile(NULL_IFILE)));
110 }
111
112 /*
113  * Return the user mark struct identified by a character.
114  */
115         static struct mark *
116 getumark(c)
117         int c;
118 {
119         if (c >= 'a' && c <= 'z')
120                 return (&marks[c-'a']);
121         if (c >= 'A' && c <= 'Z')
122                 return (&marks[c-'A'+26]);
123         if (c == '#')
124                 return (&marks[MOUSEMARK]);
125         error("Invalid mark letter", NULL_PARG);
126         return (NULL);
127 }
128
129 /*
130  * Get the mark structure identified by a character.
131  * The mark struct may either be in the mark table (user mark)
132  * or may be constructed on the fly for certain characters like ^, $.
133  */
134         static struct mark *
135 getmark(c)
136         int c;
137 {
138         struct mark *m;
139         static struct mark sm;
140
141         switch (c)
142         {
143         case '^':
144                 /*
145                  * Beginning of the current file.
146                  */
147                 m = &sm;
148                 cmark(m, curr_ifile, ch_zero(), 0);
149                 break;
150         case '$':
151                 /*
152                  * End of the current file.
153                  */
154                 if (ch_end_seek())
155                 {
156                         error("Cannot seek to end of file", NULL_PARG);
157                         return (NULL);
158                 }
159                 m = &sm;
160                 cmark(m, curr_ifile, ch_tell(), sc_height);
161                 break;
162         case '.':
163                 /*
164                  * Current position in the current file.
165                  */
166                 m = &sm;
167                 get_scrpos(&m->m_scrpos, TOP);
168                 cmark(m, curr_ifile, m->m_scrpos.pos, m->m_scrpos.ln);
169                 break;
170         case '\'':
171                 /*
172                  * The "last mark".
173                  */
174                 m = &marks[LASTMARK];
175                 break;
176         default:
177                 /*
178                  * Must be a user-defined mark.
179                  */
180                 m = getumark(c);
181                 if (m == NULL)
182                         break;
183                 if (m->m_scrpos.pos == NULL_POSITION)
184                 {
185                         error("Mark not set", NULL_PARG);
186                         return (NULL);
187                 }
188                 break;
189         }
190         return (m);
191 }
192
193 /*
194  * Is a mark letter invalid?
195  */
196         public int
197 badmark(c)
198         int c;
199 {
200         return (getmark(c) == NULL);
201 }
202
203 /*
204  * Set a user-defined mark.
205  */
206         public void
207 setmark(c, where)
208         int c;
209         int where;
210 {
211         struct mark *m;
212         struct scrpos scrpos;
213
214         m = getumark(c);
215         if (m == NULL)
216                 return;
217         get_scrpos(&scrpos, where);
218         if (scrpos.pos == NULL_POSITION)
219         {
220                 bell();
221                 return;
222         }
223         cmark(m, curr_ifile, scrpos.pos, scrpos.ln);
224         marks_modified = 1;
225 }
226
227 /*
228  * Clear a user-defined mark.
229  */
230         public void
231 clrmark(c)
232         int c;
233 {
234         struct mark *m;
235
236         m = getumark(c);
237         if (m == NULL)
238                 return;
239         if (m->m_scrpos.pos == NULL_POSITION)
240         {
241                 bell();
242                 return;
243         }
244         m->m_scrpos.pos = NULL_POSITION;
245         marks_modified = 1;
246 }
247
248 /*
249  * Set lmark (the mark named by the apostrophe).
250  */
251         public void
252 lastmark(VOID_PARAM)
253 {
254         struct scrpos scrpos;
255
256         if (ch_getflags() & CH_HELPFILE)
257                 return;
258         get_scrpos(&scrpos, TOP);
259         if (scrpos.pos == NULL_POSITION)
260                 return;
261         cmark(&marks[LASTMARK], curr_ifile, scrpos.pos, scrpos.ln);
262 }
263
264 /*
265  * Go to a mark.
266  */
267         public void
268 gomark(c)
269         int c;
270 {
271         struct mark *m;
272         struct scrpos scrpos;
273
274         m = getmark(c);
275         if (m == NULL)
276                 return;
277
278         /*
279          * If we're trying to go to the lastmark and 
280          * it has not been set to anything yet,
281          * set it to the beginning of the current file.
282          * {{ Couldn't we instead set marks[LASTMARK] in edit()? }}
283          */
284         if (m == &marks[LASTMARK] && m->m_scrpos.pos == NULL_POSITION)
285                 cmark(m, curr_ifile, ch_zero(), jump_sline);
286
287         mark_get_ifile(m);
288
289         /* Save scrpos; if it's LASTMARK it could change in edit_ifile. */
290         scrpos = m->m_scrpos;
291         if (m->m_ifile != curr_ifile)
292         {
293                 /*
294                  * Not in the current file; edit the correct file.
295                  */
296                 if (edit_ifile(m->m_ifile))
297                         return;
298         }
299
300         jump_loc(scrpos.pos, scrpos.ln);
301 }
302
303 /*
304  * Return the position associated with a given mark letter.
305  *
306  * We don't return which screen line the position 
307  * is associated with, but this doesn't matter much,
308  * because it's always the first non-blank line on the screen.
309  */
310         public POSITION
311 markpos(c)
312         int c;
313 {
314         struct mark *m;
315
316         m = getmark(c);
317         if (m == NULL)
318                 return (NULL_POSITION);
319
320         if (m->m_ifile != curr_ifile)
321         {
322                 error("Mark not in current file", NULL_PARG);
323                 return (NULL_POSITION);
324         }
325         return (m->m_scrpos.pos);
326 }
327
328 /*
329  * Return the mark associated with a given position, if any.
330  */
331         public char
332 posmark(pos)
333         POSITION pos;
334 {
335         int i;
336
337         /* Only user marks */
338         for (i = 0;  i < NUMARKS;  i++)
339         {
340                 if (marks[i].m_ifile == curr_ifile && marks[i].m_scrpos.pos == pos)
341                 {
342                         if (i < 26) return 'a' + i;
343                         if (i < 26*2) return 'A' + (i - 26);
344                         return '#';
345                 }
346         }
347         return 0;
348 }
349
350 /*
351  * Clear the marks associated with a specified ifile.
352  */
353         public void
354 unmark(ifile)
355         IFILE ifile;
356 {
357         int i;
358
359         for (i = 0;  i < NMARKS;  i++)
360                 if (marks[i].m_ifile == ifile)
361                         marks[i].m_scrpos.pos = NULL_POSITION;
362 }
363
364 /*
365  * Check if any marks refer to a specified ifile vi m_filename
366  * rather than m_ifile.
367  */
368         public void
369 mark_check_ifile(ifile)
370         IFILE ifile;
371 {
372         int i;
373         char *filename = lrealpath(get_filename(ifile));
374
375         for (i = 0;  i < NMARKS;  i++)
376         {
377                 struct mark *m = &marks[i];
378                 char *mark_filename = m->m_filename;
379                 if (mark_filename != NULL)
380                 {
381                         mark_filename = lrealpath(mark_filename);
382                         if (strcmp(filename, mark_filename) == 0)
383                                 mark_set_ifile(m, ifile);
384                         free(mark_filename);
385                 }
386         }
387         free(filename);
388 }
389
390 #if CMD_HISTORY
391
392 /*
393  * Save marks to history file.
394  */
395         public void
396 save_marks(fout, hdr)
397         FILE *fout;
398         char *hdr;
399 {
400         int i;
401
402         if (!perma_marks)
403                 return;
404
405         fprintf(fout, "%s\n", hdr);
406         for (i = 0;  i < NUMARKS;  i++)
407         {
408                 char *filename;
409                 struct mark *m = &marks[i];
410                 char pos_str[INT_STRLEN_BOUND(m->m_scrpos.pos) + 2];
411                 if (m->m_scrpos.pos == NULL_POSITION)
412                         continue;
413                 postoa(m->m_scrpos.pos, pos_str);
414                 filename = m->m_filename;
415                 if (filename == NULL)
416                         filename = get_filename(m->m_ifile);
417                 filename = lrealpath(filename);
418                 if (strcmp(filename, "-") != 0)
419                         fprintf(fout, "m %c %d %s %s\n",
420                                 m->m_letter, m->m_scrpos.ln, pos_str, filename);
421                 free(filename);
422         }
423 }
424
425 /*
426  * Restore one mark from the history file.
427  */
428         public void
429 restore_mark(line)
430         char *line;
431 {
432         struct mark *m;
433         int ln;
434         POSITION pos;
435
436 #define skip_whitespace while (*line == ' ') line++
437         if (*line++ != 'm')
438                 return;
439         skip_whitespace;
440         m = getumark(*line++);
441         if (m == NULL)
442                 return;
443         skip_whitespace;
444         ln = lstrtoi(line, &line);
445         if (ln < 1)
446                 ln = 1;
447         if (ln > sc_height)
448                 ln = sc_height;
449         skip_whitespace;
450         pos = lstrtopos(line, &line);
451         skip_whitespace;
452         cmark(m, NULL_IFILE, pos, ln);
453         m->m_filename = save(line);
454 }
455
456 #endif /* CMD_HISTORY */