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