* Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
static char sccsid
[] = "@(#)mark.c 9.5 (Berkeley) 12/3/94";
static LMARK
*mark_find
__P((SCR
*, ARG_CHAR_T
));
* Marks are maintained in a key sorted doubly linked list. We can't
* use arrays because we have no idea how big an index key could be.
* The underlying assumption is that users don't have more than, say,
* 10 marks at any one time, so this will be is fast enough.
* Marks are fixed, and modifications to the line don't update the mark's
* position in the line. This can be hard. If you add text to the line,
* place a mark in that text, undo the addition and use ` to move to the
* mark, the location will have disappeared. It's tempting to try to adjust
* the mark with the changes in the line, but this is hard to do, especially
* if we've given the line to v_ntext.c:v_ntext() for editing. Historic vi
* would move to the first non-blank on the line when the mark location was
* past the end of the line. This can be complicated by deleting to a mark
* that has disappeared using the ` command. Historic vi vi treated this as
* a line-mode motion and deleted the line. This implementation complains to
* In historic vi, marks returned if the operation was undone, unless the
* mark had been subsequently reset. Tricky. This is hard to start with,
* but in the presence of repeated undo it gets nasty. When a line is
* deleted, we delete (and log) any marks on that line. An undo will create
* the mark. Any mark creations are noted as to whether the user created
* it or if it was created by an undo. The former cannot be reset by another
* undo, but the latter may.
* All of these routines translate ABSMARK2 to ABSMARK1. Setting either of
* the absolute mark locations sets both, so that "m'" and "m`" work like
* they, ah, for lack of a better word, "should".
* ep MAY NOT BE THE SAME AS sp->ep, DON'T USE THE LATTER.
* ep MAY NOT BE THE SAME AS sp->ep, DON'T USE THE LATTER.
while ((lmp
= ep
->marks
.lh_first
) != NULL
) {
FREE(lmp
, sizeof(LMARK
));
* Get the location referenced by a mark.
lmp
= mark_find(sp
, key
);
if (lmp
== NULL
|| lmp
->name
!= key
) {
msgq(sp
, M_BERR
, "049|Mark %s: not set", KEY_NAME(sp
, key
));
if (F_ISSET(lmp
, MARK_DELETED
)) {
"050|Mark %s: the line was deleted", KEY_NAME(sp
, key
));
* The absolute mark is initialized to lno 1/cno 0, and historically
* you could use it in an empty file. Make such a mark always work.
if ((lmp
->lno
!= 1 || lmp
->cno
!= 0) &&
(file_gline(sp
, lmp
->lno
, &len
) == NULL
||
lmp
->cno
> len
|| lmp
->cno
== len
&& len
!= 0)) {
"051|Mark %s: cursor position no longer exists",
* Set the location referenced by a mark.
mark_set(sp
, key
, value
, userset
)
* The rules are simple. If the user is setting a mark (if it's a
* new mark this is always true), it always happens. If not, it's
* an undo, and we set it if it's not already set or if it was set
lmp
= mark_find(sp
, key
);
if (lmp
== NULL
|| lmp
->name
!= key
) {
MALLOC_RET(sp
, lmt
, LMARK
*, sizeof(LMARK
));
LIST_INSERT_HEAD(&sp
->ep
->marks
, lmt
, q
);
LIST_INSERT_AFTER(lmp
, lmt
, q
);
!F_ISSET(lmp
, MARK_DELETED
) && F_ISSET(lmp
, MARK_USERSET
))
lmp
->flags
= userset
? MARK_USERSET
: 0;
* Find the requested mark, or, the slot immediately before
* Return the requested mark or the slot immediately before
for (lastlmp
= NULL
, lmp
= sp
->ep
->marks
.lh_first
;
lmp
!= NULL
; lastlmp
= lmp
, lmp
= lmp
->q
.le_next
)
return (lmp
->name
== key
? lmp
: lastlmp
);
* Update the marks based on an insertion or deletion.
for (lmp
= sp
->ep
->marks
.lh_first
;
lmp
!= NULL
; lmp
= lmp
->q
.le_next
)
F_SET(lmp
, MARK_DELETED
);
for (lmp
= sp
->ep
->marks
.lh_first
;
lmp
!= NULL
; lmp
= lmp
->q
.le_next
)