mark.c revision 191930
1214501Srpaulo/* 2214501Srpaulo * Copyright (C) 1984-2008 Mark Nudelman 3214501Srpaulo * 4214501Srpaulo * You may distribute under the terms of either the GNU General Public 5252726Srpaulo * License or the Less License, as specified in the README file. 6252726Srpaulo * 7214501Srpaulo * For more information about less, or for information on how to 8214501Srpaulo * contact the author, see the README file. 9214501Srpaulo */ 10214501Srpaulo 11214501Srpaulo 12214501Srpaulo#include "less.h" 13252726Srpaulo 14214501Srpauloextern IFILE curr_ifile; 15214501Srpauloextern int sc_height; 16214501Srpauloextern int jump_sline; 17214501Srpaulo 18214501Srpaulo/* 19214501Srpaulo * A mark is an ifile (input file) plus a position within the file. 20214501Srpaulo */ 21214501Srpaulostruct mark { 22214501Srpaulo IFILE m_ifile; 23214501Srpaulo struct scrpos m_scrpos; 24214501Srpaulo}; 25214501Srpaulo 26214501Srpaulo/* 27214501Srpaulo * The table of marks. 28214501Srpaulo * Each mark is identified by a lowercase or uppercase letter. 29214501Srpaulo * The final one is lmark, for the "last mark"; addressed by the apostrophe. 30214501Srpaulo */ 31214501Srpaulo#define NMARKS ((2*26)+1) /* a-z, A-Z, lastmark */ 32214501Srpaulo#define LASTMARK (NMARKS-1) 33214501Srpaulostatic struct mark marks[NMARKS]; 34214501Srpaulo 35214501Srpaulo/* 36214501Srpaulo * Initialize the mark table to show no marks are set. 37214501Srpaulo */ 38214501Srpaulo public void 39214501Srpauloinit_mark() 40214501Srpaulo{ 41214501Srpaulo int i; 42214501Srpaulo 43214501Srpaulo for (i = 0; i < NMARKS; i++) 44214501Srpaulo marks[i].m_scrpos.pos = NULL_POSITION; 45214501Srpaulo} 46214501Srpaulo 47214501Srpaulo/* 48214501Srpaulo * See if a mark letter is valid (between a and z). 49214501Srpaulo */ 50214501Srpaulo static struct mark * 51214501Srpaulogetumark(c) 52214501Srpaulo int c; 53214501Srpaulo{ 54214501Srpaulo if (c >= 'a' && c <= 'z') 55214501Srpaulo return (&marks[c-'a']); 56214501Srpaulo 57214501Srpaulo if (c >= 'A' && c <= 'Z') 58214501Srpaulo return (&marks[c-'A'+26]); 59214501Srpaulo 60214501Srpaulo error("Invalid mark letter", NULL_PARG); 61214501Srpaulo return (NULL); 62214501Srpaulo} 63214501Srpaulo 64214501Srpaulo/* 65214501Srpaulo * Get the mark structure identified by a character. 66214501Srpaulo * The mark struct may come either from the mark table 67214501Srpaulo * or may be constructed on the fly for certain characters like ^, $. 68214501Srpaulo */ 69214501Srpaulo static struct mark * 70214501Srpaulogetmark(c) 71214501Srpaulo int c; 72214501Srpaulo{ 73214501Srpaulo register struct mark *m; 74346981Scy static struct mark sm; 75346981Scy 76214501Srpaulo switch (c) 77214501Srpaulo { 78214501Srpaulo case '^': 79214501Srpaulo /* 80214501Srpaulo * Beginning of the current file. 81214501Srpaulo */ 82214501Srpaulo m = &sm; 83214501Srpaulo m->m_scrpos.pos = ch_zero(); 84214501Srpaulo m->m_scrpos.ln = 0; 85214501Srpaulo m->m_ifile = curr_ifile; 86214501Srpaulo break; 87214501Srpaulo case '$': 88214501Srpaulo /* 89214501Srpaulo * End of the current file. 90214501Srpaulo */ 91214501Srpaulo if (ch_end_seek()) 92214501Srpaulo { 93281806Srpaulo error("Cannot seek to end of file", NULL_PARG); 94214501Srpaulo return (NULL); 95214501Srpaulo } 96214501Srpaulo m = &sm; 97214501Srpaulo m->m_scrpos.pos = ch_tell(); 98214501Srpaulo m->m_scrpos.ln = sc_height-1; 99214501Srpaulo m->m_ifile = curr_ifile; 100214501Srpaulo break; 101214501Srpaulo case '.': 102214501Srpaulo /* 103214501Srpaulo * Current position in the current file. 104214501Srpaulo */ 105252726Srpaulo m = &sm; 106214501Srpaulo get_scrpos(&m->m_scrpos); 107214501Srpaulo m->m_ifile = curr_ifile; 108214501Srpaulo break; 109214501Srpaulo case '\'': 110214501Srpaulo /* 111214501Srpaulo * The "last mark". 112281806Srpaulo */ 113214501Srpaulo m = &marks[LASTMARK]; 114214501Srpaulo break; 115214501Srpaulo default: 116214501Srpaulo /* 117214501Srpaulo * Must be a user-defined mark. 118214501Srpaulo */ 119214501Srpaulo m = getumark(c); 120214501Srpaulo if (m == NULL) 121214501Srpaulo break; 122214501Srpaulo if (m->m_scrpos.pos == NULL_POSITION) 123214501Srpaulo { 124214501Srpaulo error("Mark not set", NULL_PARG); 125214501Srpaulo return (NULL); 126214501Srpaulo } 127214501Srpaulo break; 128214501Srpaulo } 129214501Srpaulo return (m); 130214501Srpaulo} 131214501Srpaulo 132214501Srpaulo/* 133214501Srpaulo * Is a mark letter is invalid? 134281806Srpaulo */ 135214501Srpaulo public int 136214501Srpaulobadmark(c) 137214501Srpaulo int c; 138214501Srpaulo{ 139214501Srpaulo return (getmark(c) == NULL); 140214501Srpaulo} 141214501Srpaulo 142214501Srpaulo/* 143214501Srpaulo * Set a user-defined mark. 144214501Srpaulo */ 145214501Srpaulo public void 146214501Srpaulosetmark(c) 147214501Srpaulo int c; 148214501Srpaulo{ 149214501Srpaulo register struct mark *m; 150214501Srpaulo struct scrpos scrpos; 151214501Srpaulo 152214501Srpaulo m = getumark(c); 153214501Srpaulo if (m == NULL) 154214501Srpaulo return; 155214501Srpaulo get_scrpos(&scrpos); 156214501Srpaulo m->m_scrpos = scrpos; 157214501Srpaulo m->m_ifile = curr_ifile; 158214501Srpaulo} 159214501Srpaulo 160214501Srpaulo/* 161214501Srpaulo * Set lmark (the mark named by the apostrophe). 162214501Srpaulo */ 163214501Srpaulo public void 164214501Srpaulolastmark() 165214501Srpaulo{ 166214501Srpaulo struct scrpos scrpos; 167214501Srpaulo 168214501Srpaulo if (ch_getflags() & CH_HELPFILE) 169214501Srpaulo return; 170214501Srpaulo get_scrpos(&scrpos); 171214501Srpaulo if (scrpos.pos == NULL_POSITION) 172214501Srpaulo return; 173214501Srpaulo marks[LASTMARK].m_scrpos = scrpos; 174214501Srpaulo marks[LASTMARK].m_ifile = curr_ifile; 175214501Srpaulo} 176214501Srpaulo 177214501Srpaulo/* 178214501Srpaulo * Go to a mark. 179214501Srpaulo */ 180214501Srpaulo public void 181214501Srpaulogomark(c) 182214501Srpaulo int c; 183214501Srpaulo{ 184214501Srpaulo register struct mark *m; 185214501Srpaulo struct scrpos scrpos; 186214501Srpaulo 187214501Srpaulo m = getmark(c); 188214501Srpaulo if (m == NULL) 189214501Srpaulo return; 190214501Srpaulo 191214501Srpaulo /* 192214501Srpaulo * If we're trying to go to the lastmark and 193214501Srpaulo * it has not been set to anything yet, 194214501Srpaulo * set it to the beginning of the current file. 195214501Srpaulo */ 196214501Srpaulo if (m == &marks[LASTMARK] && m->m_scrpos.pos == NULL_POSITION) 197214501Srpaulo { 198214501Srpaulo m->m_ifile = curr_ifile; 199214501Srpaulo m->m_scrpos.pos = ch_zero(); 200214501Srpaulo m->m_scrpos.ln = jump_sline; 201214501Srpaulo } 202214501Srpaulo 203214501Srpaulo /* 204214501Srpaulo * If we're using lmark, we must save the screen position now, 205214501Srpaulo * because if we call edit_ifile() below, lmark will change. 206214501Srpaulo * (We save the screen position even if we're not using lmark.) 207214501Srpaulo */ 208214501Srpaulo scrpos = m->m_scrpos; 209214501Srpaulo if (m->m_ifile != curr_ifile) 210214501Srpaulo { 211214501Srpaulo /* 212214501Srpaulo * Not in the current file; edit the correct file. 213214501Srpaulo */ 214214501Srpaulo if (edit_ifile(m->m_ifile)) 215214501Srpaulo return; 216214501Srpaulo } 217214501Srpaulo 218214501Srpaulo jump_loc(scrpos.pos, scrpos.ln); 219214501Srpaulo} 220214501Srpaulo 221214501Srpaulo/* 222214501Srpaulo * Return the position associated with a given mark letter. 223214501Srpaulo * 224214501Srpaulo * We don't return which screen line the position 225214501Srpaulo * is associated with, but this doesn't matter much, 226214501Srpaulo * because it's always the first non-blank line on the screen. 227214501Srpaulo */ 228214501Srpaulo public POSITION 229214501Srpaulomarkpos(c) 230214501Srpaulo int c; 231214501Srpaulo{ 232214501Srpaulo register struct mark *m; 233214501Srpaulo 234214501Srpaulo m = getmark(c); 235214501Srpaulo if (m == NULL) 236214501Srpaulo return (NULL_POSITION); 237214501Srpaulo 238214501Srpaulo if (m->m_ifile != curr_ifile) 239214501Srpaulo { 240214501Srpaulo error("Mark not in current file", NULL_PARG); 241214501Srpaulo return (NULL_POSITION); 242214501Srpaulo } 243214501Srpaulo return (m->m_scrpos.pos); 244214501Srpaulo} 245214501Srpaulo 246214501Srpaulo/* 247214501Srpaulo * Clear the marks associated with a specified ifile. 248214501Srpaulo */ 249214501Srpaulo public void 250214501Srpaulounmark(ifile) 251214501Srpaulo IFILE ifile; 252214501Srpaulo{ 253214501Srpaulo int i; 254214501Srpaulo 255214501Srpaulo for (i = 0; i < NMARKS; i++) 256214501Srpaulo if (marks[i].m_ifile == ifile) 257214501Srpaulo marks[i].m_scrpos.pos = NULL_POSITION; 258214501Srpaulo} 259214501Srpaulo