1 /* $OpenBSD: mark.c,v 1.2 2001/01/29 01:58:03 niklas Exp $ */ 2 3 /* 4 * Copyright (c) 1984,1985,1989,1994,1995 Mark Nudelman 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice in the documentation and/or other materials provided with 14 * the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY 17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 22 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 30 #include "less.h" 31 #include "position.h" 32 33 extern IFILE curr_ifile; 34 extern int sc_height; 35 extern int jump_sline; 36 37 /* 38 * A mark is an ifile (input file) plus a position within the file. 39 */ 40 struct mark { 41 IFILE m_ifile; 42 struct scrpos m_scrpos; 43 }; 44 45 /* 46 * The table of marks. 47 * Each mark is identified by a lowercase or uppercase letter. 48 */ 49 #define NMARKS (2*26) /* a-z, A-Z */ 50 static struct mark marks[NMARKS]; 51 52 /* 53 * Special mark for the "last mark"; addressed by the apostrophe. 54 */ 55 static struct mark lmark; 56 57 /* 58 * Initialize the mark table to show no marks are set. 59 */ 60 public void 61 init_mark() 62 { 63 int i; 64 65 for (i = 0; i < NMARKS; i++) 66 marks[i].m_scrpos.pos = NULL_POSITION; 67 lmark.m_scrpos.pos = NULL_POSITION; 68 } 69 70 /* 71 * See if a mark letter is valid (between a and z). 72 */ 73 static struct mark * 74 getumark(c) 75 int c; 76 { 77 if (c >= 'a' && c <= 'z') 78 return (&marks[c-'a']); 79 80 if (c >= 'A' && c <= 'Z') 81 return (&marks[c-'A'+26]); 82 83 error("Invalid mark letter", NULL_PARG); 84 return (NULL); 85 } 86 87 /* 88 * Get the mark structure identified by a character. 89 * The mark struct may come either from the mark table 90 * or may be constructed on the fly for certain characters like ^, $. 91 */ 92 static struct mark * 93 getmark(c) 94 int c; 95 { 96 register struct mark *m; 97 static struct mark sm; 98 99 switch (c) 100 { 101 case '^': 102 /* 103 * Beginning of the current file. 104 */ 105 m = &sm; 106 m->m_scrpos.pos = ch_zero(); 107 m->m_scrpos.ln = 0; 108 m->m_ifile = curr_ifile; 109 break; 110 case '$': 111 /* 112 * End of the current file. 113 */ 114 if (ch_end_seek()) 115 { 116 error("Cannot seek to end of file", NULL_PARG); 117 return (NULL); 118 } 119 m = &sm; 120 m->m_scrpos.pos = ch_tell(); 121 m->m_scrpos.ln = sc_height-1; 122 m->m_ifile = curr_ifile; 123 break; 124 case '.': 125 /* 126 * Current position in the current file. 127 */ 128 m = &sm; 129 m->m_scrpos.pos = ch_tell(); 130 m->m_scrpos.ln = 0; 131 m->m_ifile = curr_ifile; 132 break; 133 case '\'': 134 /* 135 * The "last mark". 136 */ 137 m = &lmark; 138 break; 139 default: 140 /* 141 * Must be a user-defined mark. 142 */ 143 m = getumark(c); 144 if (m == NULL) 145 break; 146 if (m->m_scrpos.pos == NULL_POSITION) 147 { 148 error("Mark not set", NULL_PARG); 149 return (NULL); 150 } 151 break; 152 } 153 return (m); 154 } 155 156 /* 157 * Is a mark letter is invalid? 158 */ 159 public int 160 badmark(c) 161 int c; 162 { 163 return (getmark(c) == NULL); 164 } 165 166 /* 167 * Set a user-defined mark. 168 */ 169 public void 170 setmark(c) 171 int c; 172 { 173 register struct mark *m; 174 struct scrpos scrpos; 175 176 m = getumark(c); 177 if (m == NULL) 178 return; 179 get_scrpos(&scrpos); 180 m->m_scrpos = scrpos; 181 m->m_ifile = curr_ifile; 182 } 183 184 /* 185 * Set lmark (the mark named by the apostrophe). 186 */ 187 public void 188 lastmark() 189 { 190 struct scrpos scrpos; 191 192 get_scrpos(&scrpos); 193 if (scrpos.pos == NULL_POSITION) 194 return; 195 lmark.m_scrpos = scrpos; 196 lmark.m_ifile = curr_ifile; 197 } 198 199 /* 200 * Go to a mark. 201 */ 202 public void 203 gomark(c) 204 int c; 205 { 206 register struct mark *m; 207 struct scrpos scrpos; 208 209 m = getmark(c); 210 if (m == NULL) 211 return; 212 213 /* 214 * If we're trying to go to the lastmark and 215 * it has not been set to anything yet, 216 * set it to the beginning of the current file. 217 */ 218 if (m == &lmark && m->m_scrpos.pos == NULL_POSITION) 219 { 220 m->m_ifile = curr_ifile; 221 m->m_scrpos.pos = ch_zero(); 222 m->m_scrpos.ln = jump_sline; 223 } 224 225 /* 226 * If we're using lmark, we must save the screen position now, 227 * because if we call edit_ifile() below, lmark will change. 228 * (We save the screen position even if we're not using lmark.) 229 */ 230 scrpos = m->m_scrpos; 231 if (m->m_ifile != curr_ifile) 232 { 233 /* 234 * Not in the current file; edit the correct file. 235 */ 236 if (edit_ifile(m->m_ifile)) 237 return; 238 } 239 240 jump_loc(scrpos.pos, scrpos.ln); 241 } 242 243 /* 244 * Return the position associated with a given mark letter. 245 * 246 * We don't return which screen line the position 247 * is associated with, but this doesn't matter much, 248 * because it's always the first non-blank line on the screen. 249 */ 250 public POSITION 251 markpos(c) 252 int c; 253 { 254 register struct mark *m; 255 256 m = getmark(c); 257 if (m == NULL) 258 return (NULL_POSITION); 259 260 if (m->m_ifile != curr_ifile) 261 { 262 error("Mark not in current file", NULL_PARG); 263 return (NULL_POSITION); 264 } 265 return (m->m_scrpos.pos); 266 } 267