diff options
Diffstat (limited to 'contrib/less/mark.c')
-rw-r--r-- | contrib/less/mark.c | 237 |
1 files changed, 203 insertions, 34 deletions
diff --git a/contrib/less/mark.c b/contrib/less/mark.c index fbdac6e3f461..92cb8ceaabfe 100644 --- a/contrib/less/mark.c +++ b/contrib/less/mark.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 1984-2017 Mark Nudelman + * Copyright (C) 1984-2019 Mark Nudelman * * You may distribute under the terms of either the GNU General Public * License or the Less License, as specified in the README file. @@ -14,30 +14,103 @@ extern IFILE curr_ifile; extern int sc_height; extern int jump_sline; +extern int perma_marks; + +/* + * A mark is an ifile (input file) plus a position within the file. + */ +struct mark +{ + /* + * Normally m_ifile != IFILE_NULL and m_filename == NULL. + * For restored marks we set m_filename instead of m_ifile + * because we don't want to create an ifile until the + * user explicitly requests the file (by name or mark). + */ + char m_letter; /* Associated character */ + IFILE m_ifile; /* Input file being marked */ + char *m_filename; /* Name of the input file */ + struct scrpos m_scrpos; /* Position of the mark */ +}; /* * The table of marks. * Each mark is identified by a lowercase or uppercase letter. * The final one is lmark, for the "last mark"; addressed by the apostrophe. */ -#define NMARKS ((2*26)+1) /* a-z, A-Z, lastmark */ +#define NMARKS ((2*26)+2) /* a-z, A-Z, mousemark, lastmark */ +#define NUMARKS ((2*26)+1) /* user marks (not lastmark) */ +#define MOUSEMARK (NMARKS-2) #define LASTMARK (NMARKS-1) static struct mark marks[NMARKS]; +public int marks_modified = 0; + + +/* + * Initialize a mark struct. + */ + static void +cmark(m, ifile, pos, ln) + struct mark *m; + IFILE ifile; + POSITION pos; + int ln; +{ + m->m_ifile = ifile; + m->m_scrpos.pos = pos; + m->m_scrpos.ln = ln; + m->m_filename = NULL; +} /* * Initialize the mark table to show no marks are set. */ public void -init_mark() +init_mark(VOID_PARAM) { int i; for (i = 0; i < NMARKS; i++) - marks[i].m_scrpos.pos = NULL_POSITION; + { + char letter; + switch (i) { + case MOUSEMARK: letter = '#'; break; + case LASTMARK: letter = '\''; break; + default: letter = (i < 26) ? 'a'+i : 'A'+i-26; break; + } + marks[i].m_letter = letter; + cmark(&marks[i], NULL_IFILE, NULL_POSITION, -1); + } } /* - * See if a mark letter is valid (between a and z). + * Set m_ifile and clear m_filename. + */ + static void +mark_set_ifile(m, ifile) + struct mark *m; + IFILE ifile; +{ + m->m_ifile = ifile; + /* With m_ifile set, m_filename is no longer needed. */ + free(m->m_filename); + m->m_filename = NULL; +} + +/* + * Populate the m_ifile member of a mark struct from m_filename. + */ + static void +mark_get_ifile(m) + struct mark *m; +{ + if (m->m_ifile != NULL_IFILE) + return; /* m_ifile is already set */ + mark_set_ifile(m, get_ifile(m->m_filename, prev_ifile(NULL_IFILE))); +} + +/* + * Return the user mark struct identified by a character. */ static struct mark * getumark(c) @@ -45,17 +118,17 @@ getumark(c) { if (c >= 'a' && c <= 'z') return (&marks[c-'a']); - if (c >= 'A' && c <= 'Z') return (&marks[c-'A'+26]); - + if (c == '#') + return (&marks[MOUSEMARK]); error("Invalid mark letter", NULL_PARG); return (NULL); } /* * Get the mark structure identified by a character. - * The mark struct may come either from the mark table + * The mark struct may either be in the mark table (user mark) * or may be constructed on the fly for certain characters like ^, $. */ static struct mark * @@ -72,9 +145,7 @@ getmark(c) * Beginning of the current file. */ m = &sm; - m->m_scrpos.pos = ch_zero(); - m->m_scrpos.ln = 0; - m->m_ifile = curr_ifile; + cmark(m, curr_ifile, ch_zero(), 0); break; case '$': /* @@ -86,9 +157,7 @@ getmark(c) return (NULL); } m = &sm; - m->m_scrpos.pos = ch_tell(); - m->m_scrpos.ln = sc_height; - m->m_ifile = curr_ifile; + cmark(m, curr_ifile, ch_tell(), sc_height); break; case '.': /* @@ -96,7 +165,7 @@ getmark(c) */ m = &sm; get_scrpos(&m->m_scrpos, TOP); - m->m_ifile = curr_ifile; + cmark(m, curr_ifile, m->m_scrpos.pos, m->m_scrpos.ln); break; case '\'': /* @@ -122,7 +191,7 @@ getmark(c) } /* - * Is a mark letter is invalid? + * Is a mark letter invalid? */ public int badmark(c) @@ -146,8 +215,13 @@ setmark(c, where) if (m == NULL) return; get_scrpos(&scrpos, where); - m->m_scrpos = scrpos; - m->m_ifile = curr_ifile; + if (scrpos.pos == NULL_POSITION) + { + bell(); + return; + } + cmark(m, curr_ifile, scrpos.pos, scrpos.ln); + marks_modified = 1; } /* @@ -162,14 +236,20 @@ clrmark(c) m = getumark(c); if (m == NULL) return; + if (m->m_scrpos.pos == NULL_POSITION) + { + bell(); + return; + } m->m_scrpos.pos = NULL_POSITION; + marks_modified = 1; } /* * Set lmark (the mark named by the apostrophe). */ public void -lastmark() +lastmark(VOID_PARAM) { struct scrpos scrpos; @@ -178,8 +258,7 @@ lastmark() get_scrpos(&scrpos, TOP); if (scrpos.pos == NULL_POSITION) return; - marks[LASTMARK].m_scrpos = scrpos; - marks[LASTMARK].m_ifile = curr_ifile; + cmark(&marks[LASTMARK], curr_ifile, scrpos.pos, scrpos.ln); } /* @@ -200,19 +279,14 @@ gomark(c) * If we're trying to go to the lastmark and * it has not been set to anything yet, * set it to the beginning of the current file. + * {{ Couldn't we instead set marks[LASTMARK] in edit()? }} */ if (m == &marks[LASTMARK] && m->m_scrpos.pos == NULL_POSITION) - { - m->m_ifile = curr_ifile; - m->m_scrpos.pos = ch_zero(); - m->m_scrpos.ln = jump_sline; - } + cmark(m, curr_ifile, ch_zero(), jump_sline); - /* - * If we're using lmark, we must save the screen position now, - * because if we call edit_ifile() below, lmark will change. - * (We save the screen position even if we're not using lmark.) - */ + mark_get_ifile(m); + + /* Save scrpos; if it's LASTMARK it could change in edit_ifile. */ scrpos = m->m_scrpos; if (m->m_ifile != curr_ifile) { @@ -260,13 +334,14 @@ posmark(pos) { int i; - /* Only lower case and upper case letters */ - for (i = 0; i < 26*2; i++) + /* Only user marks */ + for (i = 0; i < NUMARKS; i++) { if (marks[i].m_ifile == curr_ifile && marks[i].m_scrpos.pos == pos) { if (i < 26) return 'a' + i; - return 'A' + i - 26; + if (i < 26*2) return 'A' + (i - 26); + return '#'; } } return 0; @@ -285,3 +360,97 @@ unmark(ifile) if (marks[i].m_ifile == ifile) marks[i].m_scrpos.pos = NULL_POSITION; } + +/* + * Check if any marks refer to a specified ifile vi m_filename + * rather than m_ifile. + */ + public void +mark_check_ifile(ifile) + IFILE ifile; +{ + int i; + char *filename = lrealpath(get_filename(ifile)); + + for (i = 0; i < NMARKS; i++) + { + struct mark *m = &marks[i]; + char *mark_filename = m->m_filename; + if (mark_filename != NULL) + { + mark_filename = lrealpath(mark_filename); + if (strcmp(filename, mark_filename) == 0) + mark_set_ifile(m, ifile); + free(mark_filename); + } + } + free(filename); +} + +#if CMD_HISTORY + +/* + * Save marks to history file. + */ + public void +save_marks(fout, hdr) + FILE *fout; + char *hdr; +{ + int i; + + if (!perma_marks) + return; + + fprintf(fout, "%s\n", hdr); + for (i = 0; i < NUMARKS; i++) + { + char *filename; + struct mark *m = &marks[i]; + char pos_str[INT_STRLEN_BOUND(m->m_scrpos.pos) + 2]; + if (m->m_scrpos.pos == NULL_POSITION) + continue; + postoa(m->m_scrpos.pos, pos_str); + filename = m->m_filename; + if (filename == NULL) + filename = get_filename(m->m_ifile); + filename = lrealpath(filename); + if (strcmp(filename, "-") != 0) + fprintf(fout, "m %c %d %s %s\n", + m->m_letter, m->m_scrpos.ln, pos_str, filename); + free(filename); + } +} + +/* + * Restore one mark from the history file. + */ + public void +restore_mark(line) + char *line; +{ + struct mark *m; + int ln; + POSITION pos; + +#define skip_whitespace while (*line == ' ') line++ + if (*line++ != 'm') + return; + skip_whitespace; + m = getumark(*line++); + if (m == NULL) + return; + skip_whitespace; + ln = lstrtoi(line, &line); + if (ln < 1) + ln = 1; + if (ln > sc_height) + ln = sc_height; + skip_whitespace; + pos = lstrtopos(line, &line); + skip_whitespace; + cmark(m, NULL_IFILE, pos, ln); + m->m_filename = save(line); +} + +#endif /* CMD_HISTORY */ |