2 * Copyright (c) 1992, 1993
3 * The Regents of the University of California. All rights reserved.
5 * %sccs.include.redist.c%
9 static char sccsid
[] = "$Id: mark.c,v 8.10 1993/11/29 14:14:48 bostic Exp $ (Berkeley) $Date: 1993/11/29 14:14:48 $";
12 #include <sys/types.h>
20 static MARK
*mark_find
__P((SCR
*, EXF
*, ARG_CHAR_T
));
23 * Marks are maintained in a key sorted doubly linked list. We can't
24 * use arrays because we have no idea how big an index key could be.
25 * The underlying assumption is that users don't have more than, say,
26 * 10 marks at any one time, so this will be is fast enough.
28 * Marks are fixed, and modifications to the line don't update the mark's
29 * position in the line. This can be hard. If you add text to the line,
30 * place a mark in that text, undo the addition and use ` to move to the
31 * mark, the location will have disappeared. It's tempting to try to adjust
32 * the mark with the changes in the line, but this is hard to do, especially
33 * if we've given the line to v_ntext.c:v_ntext() for editing. Historic vi
34 * would move to the first non-blank on the line when the mark location was
35 * past the end of the line. This can be complicated by deleting to a mark
36 * that has disappeared using the ` command. Historic vi vi treated this as
37 * a line-mode motion and deleted the line. This implementation complains to
40 * In historic vi, marks returned if the operation was undone, unless the
41 * mark had been subsequently reset. Tricky. This is hard to start with,
42 * but in the presence of repeated undo it gets nasty. When a line is
43 * deleted, we delete (and log) any marks on that line. An undo will create
44 * the mark. Any mark creations are noted as to whether the user created
45 * it or if it was created by an undo. The former cannot be reset by another
46 * undo, but the latter may.
48 * All of these routines translate ABSMARK2 to ABSMARK1. Setting either of
49 * the absolute mark locations sets both, so that "m'" and "m`" work like
50 * they, ah, for lack of a better word, "should".
65 * Make sure the marks have been set up. If they
66 * haven't, do so, and create the absolute mark.
68 if ((mp
= malloc(sizeof(MARK
))) == NULL
) {
69 msgq(sp
, M_SYSERR
, NULL
);
76 LIST_INSERT_HEAD(&ep
->marks
, mp
, q
);
91 while ((mp
= ep
->marks
.lh_first
) != NULL
) {
93 FREE(mp
, sizeof(MARK
));
100 * Get the location referenced by a mark.
103 mark_get(sp
, ep
, key
)
115 mp
= mark_find(sp
, ep
, key
);
116 if (mp
== NULL
|| mp
->name
!= key
) {
117 msgq(sp
, M_BERR
, "Mark %s: not set.", charname(sp
, key
));
120 if (F_ISSET(mp
, MARK_DELETED
)) {
122 "Mark %s: the line was deleted.", charname(sp
, key
));
125 if ((p
= file_gline(sp
, ep
, mp
->lno
, &len
)) == NULL
||
126 mp
->cno
> len
|| mp
->cno
== len
&& len
!= 0) {
127 msgq(sp
, M_BERR
, "Mark %s: cursor position no longer exists.",
136 * Set the location referenced by a mark.
139 mark_set(sp
, ep
, key
, value
, userset
)
152 * The rules are simple. If the user is setting a mark (if it's a
153 * new mark this is always true), it always happens. If not, it's
154 * an undo, and we set it if it's not already set or if it was set
155 * by a previous undo.
157 mp
= mark_find(sp
, ep
, key
);
158 if (mp
== NULL
|| mp
->name
!= key
) {
159 if ((mt
= malloc(sizeof(MARK
))) == NULL
) {
160 msgq(sp
, M_SYSERR
, NULL
);
164 LIST_INSERT_HEAD(&ep
->marks
, mt
, q
);
166 LIST_INSERT_AFTER(mp
, mt
, q
);
168 } else if (!userset
&&
169 !F_ISSET(mp
, MARK_DELETED
) && F_ISSET(mp
, MARK_USERSET
))
172 mp
->lno
= value
->lno
;
173 mp
->cno
= value
->cno
;
175 mp
->flags
= userset
? MARK_USERSET
: 0;
181 * Find the requested mark, or, the slot immediately before
185 mark_find(sp
, ep
, key
)
193 * Return the requested mark or the slot immediately before
194 * where it should go.
196 for (lastmp
= NULL
, mp
= ep
->marks
.lh_first
;
197 mp
!= NULL
; lastmp
= mp
, mp
= mp
->q
.le_next
)
199 return (mp
->name
== key
? mp
: lastmp
);
205 * Update the marks based on a deletion.
208 mark_delete(sp
, ep
, lno
)
215 for (mp
= ep
->marks
.lh_first
; mp
!= NULL
; mp
= mp
->q
.le_next
)
217 if (mp
->lno
== lno
) {
218 F_SET(mp
, MARK_DELETED
);
219 (void)log_mark(sp
, ep
, mp
);
226 * Update the marks based on an insertion.
229 mark_insert(sp
, ep
, lno
)
236 for (mp
= ep
->marks
.lh_first
; mp
!= NULL
; mp
= mp
->q
.le_next
)