1 /*- 2 * Copyright (c) 1992, 1993, 1994 3 * The Regents of the University of California. All rights reserved. 4 * Copyright (c) 1992, 1993, 1994, 1995, 1996 5 * Keith Bostic. All rights reserved. 6 * 7 * See the LICENSE file for redistribution information. 8 */ 9 10 #include "config.h" 11 12 #include <sys/types.h> 13 #include <sys/queue.h> 14 #include <sys/time.h> 15 16 #include <bitstring.h> 17 #include <errno.h> 18 #include <limits.h> 19 #include <stdio.h> 20 #include <stdlib.h> 21 #include <string.h> 22 23 #include "common.h" 24 25 static LMARK *mark_find(SCR *, ARG_CHAR_T); 26 27 /* 28 * Marks are maintained in a key sorted singly linked list. We can't 29 * use arrays because we have no idea how big an index key could be. 30 * The underlying assumption is that users don't have more than, say, 31 * 10 marks at any one time, so this will be is fast enough. 32 * 33 * Marks are fixed, and modifications to the line don't update the mark's 34 * position in the line. This can be hard. If you add text to the line, 35 * place a mark in that text, undo the addition and use ` to move to the 36 * mark, the location will have disappeared. It's tempting to try to adjust 37 * the mark with the changes in the line, but this is hard to do, especially 38 * if we've given the line to v_ntext.c:v_ntext() for editing. Historic vi 39 * would move to the first non-blank on the line when the mark location was 40 * past the end of the line. This can be complicated by deleting to a mark 41 * that has disappeared using the ` command. Historic vi treated this as 42 * a line-mode motion and deleted the line. This implementation complains to 43 * the user. 44 * 45 * In historic vi, marks returned if the operation was undone, unless the 46 * mark had been subsequently reset. Tricky. This is hard to start with, 47 * but in the presence of repeated undo it gets nasty. When a line is 48 * deleted, we delete (and log) any marks on that line. An undo will create 49 * the mark. Any mark creations are noted as to whether the user created 50 * it or if it was created by an undo. The former cannot be reset by another 51 * undo, but the latter may. 52 * 53 * All of these routines translate ABSMARK2 to ABSMARK1. Setting either of 54 * the absolute mark locations sets both, so that "m'" and "m`" work like 55 * they, ah, for lack of a better word, "should". 56 */ 57 58 /* 59 * mark_init -- 60 * Set up the marks. 61 * 62 * PUBLIC: int mark_init(SCR *, EXF *); 63 */ 64 int 65 mark_init(SCR *sp, EXF *ep) 66 { 67 /* 68 * !!! 69 * ep MAY NOT BE THE SAME AS sp->ep, DON'T USE THE LATTER. 70 * 71 * Set up the marks. 72 */ 73 SLIST_INIT(ep->marks); 74 return (0); 75 } 76 77 /* 78 * mark_end -- 79 * Free up the marks. 80 * 81 * PUBLIC: int mark_end(SCR *, EXF *); 82 */ 83 int 84 mark_end(SCR *sp, EXF *ep) 85 { 86 LMARK *lmp; 87 88 /* 89 * !!! 90 * ep MAY NOT BE THE SAME AS sp->ep, DON'T USE THE LATTER. 91 */ 92 while ((lmp = SLIST_FIRST(ep->marks)) != NULL) { 93 SLIST_REMOVE_HEAD(ep->marks, q); 94 free(lmp); 95 } 96 return (0); 97 } 98 99 /* 100 * mark_get -- 101 * Get the location referenced by a mark. 102 * 103 * PUBLIC: int mark_get(SCR *, ARG_CHAR_T, MARK *, mtype_t); 104 */ 105 int 106 mark_get(SCR *sp, ARG_CHAR_T key, MARK *mp, mtype_t mtype) 107 { 108 LMARK *lmp; 109 110 if (key == ABSMARK2) 111 key = ABSMARK1; 112 113 lmp = mark_find(sp, key); 114 if (lmp == NULL || lmp->name != key) { 115 msgq(sp, mtype, "017|Mark %s: not set", KEY_NAME(sp, key)); 116 return (1); 117 } 118 if (F_ISSET(lmp, MARK_DELETED)) { 119 msgq(sp, mtype, 120 "018|Mark %s: the line was deleted", KEY_NAME(sp, key)); 121 return (1); 122 } 123 124 /* 125 * !!! 126 * The absolute mark is initialized to lno 1/cno 0, and historically 127 * you could use it in an empty file. Make such a mark always work. 128 */ 129 if ((lmp->lno != 1 || lmp->cno != 0) && !db_exist(sp, lmp->lno)) { 130 msgq(sp, mtype, 131 "019|Mark %s: cursor position no longer exists", 132 KEY_NAME(sp, key)); 133 return (1); 134 } 135 mp->lno = lmp->lno; 136 mp->cno = lmp->cno; 137 return (0); 138 } 139 140 /* 141 * mark_set -- 142 * Set the location referenced by a mark. 143 * 144 * PUBLIC: int mark_set(SCR *, ARG_CHAR_T, MARK *, int); 145 */ 146 int 147 mark_set(SCR *sp, ARG_CHAR_T key, MARK *value, int userset) 148 { 149 LMARK *lmp, *lmt; 150 151 if (key == ABSMARK2) 152 key = ABSMARK1; 153 154 /* 155 * The rules are simple. If the user is setting a mark (if it's a 156 * new mark this is always true), it always happens. If not, it's 157 * an undo, and we set it if it's not already set or if it was set 158 * by a previous undo. 159 */ 160 lmp = mark_find(sp, key); 161 if (lmp == NULL || lmp->name != key) { 162 MALLOC_RET(sp, lmt, sizeof(LMARK)); 163 if (lmp == NULL) { 164 SLIST_INSERT_HEAD(sp->ep->marks, lmt, q); 165 } else 166 SLIST_INSERT_AFTER(lmp, lmt, q); 167 lmp = lmt; 168 } else if (!userset && 169 !F_ISSET(lmp, MARK_DELETED) && F_ISSET(lmp, MARK_USERSET)) 170 return (0); 171 172 lmp->lno = value->lno; 173 lmp->cno = value->cno; 174 lmp->name = key; 175 lmp->flags = userset ? MARK_USERSET : 0; 176 return (0); 177 } 178 179 /* 180 * mark_find -- 181 * Find the requested mark, or, the slot immediately before 182 * where it would go. 183 */ 184 static LMARK * 185 mark_find(SCR *sp, ARG_CHAR_T key) 186 { 187 LMARK *lmp, *lastlmp = NULL; 188 189 /* 190 * Return the requested mark or the slot immediately before 191 * where it should go. 192 */ 193 SLIST_FOREACH(lmp, sp->ep->marks, q) { 194 if (lmp->name >= key) 195 return (lmp->name == key ? lmp : lastlmp); 196 lastlmp = lmp; 197 } 198 return (lastlmp); 199 } 200 201 /* 202 * mark_insdel -- 203 * Update the marks based on an insertion or deletion. 204 * 205 * PUBLIC: int mark_insdel(SCR *, lnop_t, recno_t); 206 */ 207 int 208 mark_insdel(SCR *sp, lnop_t op, recno_t lno) 209 { 210 LMARK *lmp; 211 recno_t lline; 212 213 switch (op) { 214 case LINE_APPEND: 215 /* All insert/append operations are done as inserts. */ 216 abort(); 217 case LINE_DELETE: 218 SLIST_FOREACH(lmp, sp->ep->marks, q) 219 if (lmp->lno >= lno) { 220 if (lmp->lno == lno) { 221 F_SET(lmp, MARK_DELETED); 222 (void)log_mark(sp, lmp); 223 } else 224 --lmp->lno; 225 } 226 break; 227 case LINE_INSERT: 228 /* 229 * XXX 230 * Very nasty special case. If the file was empty, then we're 231 * adding the first line, which is a replacement. So, we don't 232 * modify the marks. This is a hack to make: 233 * 234 * mz:r!echo foo<carriage-return>'z 235 * 236 * work, i.e. historically you could mark the "line" in an empty 237 * file and replace it, and continue to use the mark. Insane, 238 * well, yes, I know, but someone complained. 239 * 240 * Check for line #2 before going to the end of the file. 241 */ 242 if (!db_exist(sp, 2)) { 243 if (db_last(sp, &lline)) 244 return (1); 245 if (lline == 1) 246 return (0); 247 } 248 249 SLIST_FOREACH(lmp, sp->ep->marks, q) 250 if (lmp->lno >= lno) 251 ++lmp->lno; 252 break; 253 case LINE_RESET: 254 break; 255 } 256 return (0); 257 } 258