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