mark.c revision 60786
1104862Sru/* 2104862Sru * Copyright (C) 1984-2000 Mark Nudelman 3104862Sru * 4104862Sru * You may distribute under the terms of either the GNU General Public 5114402Sru * License or the Less License, as specified in the README file. 6114402Sru * 7114402Sru * For more information about less, or for information on how to 8114402Sru * contact the author, see the README file. 9114402Sru */ 10114402Sru 11114402Sru 12114402Sru#include "less.h" 13114402Sru 14114402Sruextern IFILE curr_ifile; 15114402Sruextern int sc_height; 16114402Sruextern int jump_sline; 17114402Sru 18114402Sru/* 19114402Sru * A mark is an ifile (input file) plus a position within the file. 20114402Sru */ 21114402Srustruct mark { 22114402Sru IFILE m_ifile; 23114402Sru struct scrpos m_scrpos; 24114402Sru}; 25114402Sru 26114402Sru/* 27114402Sru * The table of marks. 28114402Sru * Each mark is identified by a lowercase or uppercase letter. 29114402Sru * The final one is lmark, for the "last mark"; addressed by the apostrophe. 30114402Sru */ 31114402Sru#define NMARKS ((2*26)+1) /* a-z, A-Z, lastmark */ 32114402Sru#define LASTMARK (NMARKS-1) 33114402Srustatic struct mark marks[NMARKS]; 34114402Sru 35114402Sru/* 36114402Sru * Initialize the mark table to show no marks are set. 37114402Sru */ 38114402Sru public void 39114402Sruinit_mark() 40114402Sru{ 41114402Sru int i; 42114402Sru 43114402Sru for (i = 0; i < NMARKS; i++) 44114402Sru marks[i].m_scrpos.pos = NULL_POSITION; 45114402Sru} 46114402Sru 47114402Sru/* 48114402Sru * See if a mark letter is valid (between a and z). 49114402Sru */ 50114402Sru static struct mark * 51114402Srugetumark(c) 52114402Sru int c; 53114402Sru{ 54114402Sru if (c >= 'a' && c <= 'z') 55114402Sru return (&marks[c-'a']); 56114402Sru 57114402Sru if (c >= 'A' && c <= 'Z') 58114402Sru return (&marks[c-'A'+26]); 59114402Sru 60114402Sru error("Invalid mark letter", NULL_PARG); 61114402Sru return (NULL); 62114402Sru} 63114402Sru 64114402Sru/* 65114402Sru * Get the mark structure identified by a character. 66114402Sru * The mark struct may come either from the mark table 67114402Sru * or may be constructed on the fly for certain characters like ^, $. 68114402Sru */ 69114402Sru static struct mark * 70114402Srugetmark(c) 71114402Sru int c; 72114402Sru{ 73114402Sru register struct mark *m; 74114402Sru static struct mark sm; 75114402Sru 76104862Sru switch (c) 77104862Sru { 78114402Sru case '^': 79114402Sru /* 80114402Sru * Beginning of the current file. 81114402Sru */ 82114402Sru m = &sm; 83114402Sru m->m_scrpos.pos = ch_zero(); 84114402Sru m->m_scrpos.ln = 0; 85114402Sru m->m_ifile = curr_ifile; 86114402Sru break; 87114402Sru case '$': 88114402Sru /* 89114402Sru * End of the current file. 90114402Sru */ 91114402Sru if (ch_end_seek()) 92114402Sru { 93114402Sru error("Cannot seek to end of file", NULL_PARG); 94114402Sru return (NULL); 95114402Sru } 96114402Sru m = &sm; 97114402Sru m->m_scrpos.pos = ch_tell(); 98114402Sru m->m_scrpos.ln = sc_height-1; 99114402Sru m->m_ifile = curr_ifile; 100114402Sru break; 101104862Sru case '.': 102 /* 103 * Current position in the current file. 104 */ 105 m = &sm; 106 get_scrpos(&m->m_scrpos); 107 m->m_ifile = curr_ifile; 108 break; 109 case '\'': 110 /* 111 * The "last mark". 112 */ 113 m = &marks[LASTMARK]; 114 break; 115 default: 116 /* 117 * Must be a user-defined mark. 118 */ 119 m = getumark(c); 120 if (m == NULL) 121 break; 122 if (m->m_scrpos.pos == NULL_POSITION) 123 { 124 error("Mark not set", NULL_PARG); 125 return (NULL); 126 } 127 break; 128 } 129 return (m); 130} 131 132/* 133 * Is a mark letter is invalid? 134 */ 135 public int 136badmark(c) 137 int c; 138{ 139 return (getmark(c) == NULL); 140} 141 142/* 143 * Set a user-defined mark. 144 */ 145 public void 146setmark(c) 147 int c; 148{ 149 register struct mark *m; 150 struct scrpos scrpos; 151 152 m = getumark(c); 153 if (m == NULL) 154 return; 155 get_scrpos(&scrpos); 156 m->m_scrpos = scrpos; 157 m->m_ifile = curr_ifile; 158} 159 160/* 161 * Set lmark (the mark named by the apostrophe). 162 */ 163 public void 164lastmark() 165{ 166 struct scrpos scrpos; 167 168 if (ch_getflags() & CH_HELPFILE) 169 return; 170 get_scrpos(&scrpos); 171 if (scrpos.pos == NULL_POSITION) 172 return; 173 marks[LASTMARK].m_scrpos = scrpos; 174 marks[LASTMARK].m_ifile = curr_ifile; 175} 176 177/* 178 * Go to a mark. 179 */ 180 public void 181gomark(c) 182 int c; 183{ 184 register struct mark *m; 185 struct scrpos scrpos; 186 187 m = getmark(c); 188 if (m == NULL) 189 return; 190 191 /* 192 * If we're trying to go to the lastmark and 193 * it has not been set to anything yet, 194 * set it to the beginning of the current file. 195 */ 196 if (m == &marks[LASTMARK] && m->m_scrpos.pos == NULL_POSITION) 197 { 198 m->m_ifile = curr_ifile; 199 m->m_scrpos.pos = ch_zero(); 200 m->m_scrpos.ln = jump_sline; 201 } 202 203 /* 204 * If we're using lmark, we must save the screen position now, 205 * because if we call edit_ifile() below, lmark will change. 206 * (We save the screen position even if we're not using lmark.) 207 */ 208 scrpos = m->m_scrpos; 209 if (m->m_ifile != curr_ifile) 210 { 211 /* 212 * Not in the current file; edit the correct file. 213 */ 214 if (edit_ifile(m->m_ifile)) 215 return; 216 } 217 218 jump_loc(scrpos.pos, scrpos.ln); 219} 220 221/* 222 * Return the position associated with a given mark letter. 223 * 224 * We don't return which screen line the position 225 * is associated with, but this doesn't matter much, 226 * because it's always the first non-blank line on the screen. 227 */ 228 public POSITION 229markpos(c) 230 int c; 231{ 232 register struct mark *m; 233 234 m = getmark(c); 235 if (m == NULL) 236 return (NULL_POSITION); 237 238 if (m->m_ifile != curr_ifile) 239 { 240 error("Mark not in current file", NULL_PARG); 241 return (NULL_POSITION); 242 } 243 return (m->m_scrpos.pos); 244} 245 246/* 247 * Clear the marks associated with a specified ifile. 248 */ 249 public void 250unmark(ifile) 251 IFILE ifile; 252{ 253 int i; 254 255 for (i = 0; i < NMARKS; i++) 256 if (marks[i].m_ifile == ifile) 257 marks[i].m_scrpos.pos = NULL_POSITION; 258} 259