diff src/marker.c @ 118:49342840ba00

Initial revision
author Jim Blandy <jimb@redhat.com>
date Mon, 12 Nov 1990 20:20:45 +0000
parents
children 3165b2697c78
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/marker.c	Mon Nov 12 20:20:45 1990 +0000
@@ -0,0 +1,295 @@
+/* Markers: examining, setting and killing.
+   Copyright (C) 1985 Free Software Foundation, Inc.
+
+This file is part of GNU Emacs.
+
+GNU Emacs is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+GNU Emacs is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Emacs; see the file COPYING.  If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+
+#include "config.h"
+#include "lisp.h"
+#include "buffer.h"
+
+/* Operations on markers. */
+
+DEFUN ("marker-buffer", Fmarker_buffer, Smarker_buffer, 1, 1, 0,
+  "Return the buffer that MARKER points into, or nil if none.\n\
+Returns nil if MARKER points into a dead buffer.")
+  (marker)
+     register Lisp_Object marker;
+{
+  register Lisp_Object buf;
+  CHECK_MARKER (marker, 0);
+  if (XMARKER (marker)->buffer)
+    {
+      XSET (buf, Lisp_Buffer, XMARKER (marker)->buffer);
+      /* Return marker's buffer only if it is not dead.  */
+      if (!NULL (XBUFFER (buf)->name))
+	return buf;
+    }
+  return Qnil;
+}
+
+DEFUN ("marker-position", Fmarker_position, Smarker_position, 1, 1, 0,
+  "Return the position MARKER points at, as a character number.")
+  (marker)
+     Lisp_Object marker;
+{
+  register Lisp_Object pos;
+  register int i;
+  register struct buffer *buf;
+
+  CHECK_MARKER (marker, 0);
+  if (XMARKER (marker)->buffer)
+    {
+      buf = XMARKER (marker)->buffer;
+      i = XMARKER (marker)->bufpos;
+
+      if (i > BUF_GPT (buf) + BUF_GAP_SIZE (buf))
+	i -= BUF_GAP_SIZE (buf);
+      else if (i > BUF_GPT (buf))
+	i = BUF_GPT (buf);
+
+      if (i < BUF_BEG (buf) || i > BUF_Z (buf))
+	abort ();
+
+      XFASTINT (pos) = i;
+      return pos;
+    }
+  return Qnil;
+}
+
+DEFUN ("set-marker", Fset_marker, Sset_marker, 2, 3, 0,
+  "Position MARKER before character number NUMBER in BUFFER.\n\
+BUFFER defaults to the current buffer.\n\
+If NUMBER is nil, makes marker point nowhere.\n\
+Then it no longer slows down editing in any buffer.\n\
+Returns MARKER.")
+  (marker, pos, buffer)
+     Lisp_Object marker, pos, buffer;
+{
+  register int charno;
+  register struct buffer *b;
+  register struct Lisp_Marker *m;
+
+  CHECK_MARKER (marker, 0);
+  /* If position is nil or a marker that points nowhere,
+     make this marker point nowhere.  */
+  if (NULL (pos)
+      || (XTYPE (pos) == Lisp_Marker && !XMARKER (pos)->buffer))
+    {
+      unchain_marker (marker);
+      return marker;
+    }
+
+  CHECK_NUMBER_COERCE_MARKER (pos, 1);
+  if (NULL (buffer))
+    b = current_buffer;
+  else
+    {
+      CHECK_BUFFER (buffer, 1);
+      b = XBUFFER (buffer);
+      /* If buffer is dead, set marker to point nowhere.  */
+      if (EQ (b->name, Qnil))
+	{
+	  unchain_marker (marker);
+	  return marker;
+	}
+    }
+
+  charno = XINT (pos);
+  m = XMARKER (marker);
+
+  if (charno < BUF_BEG (b))
+    charno = BUF_BEG (b);
+  if (charno > BUF_Z (b))
+    charno = BUF_Z (b);
+  if (charno > BUF_GPT (b)) charno += BUF_GAP_SIZE (b);
+  m->bufpos = charno;
+
+  if (m->buffer != b)
+    {
+      unchain_marker (marker);
+      m->chain = b->markers;
+      b->markers = marker;
+      m->buffer = b;
+    }
+  
+  return marker;
+}
+
+/* This version of Fset_marker won't let the position
+   be outside the visible part.  */
+
+Lisp_Object 
+set_marker_restricted (marker, pos, buffer)
+     Lisp_Object marker, pos, buffer;
+{
+  register int charno;
+  register struct buffer *b;
+  register struct Lisp_Marker *m;
+
+  CHECK_MARKER (marker, 0);
+  /* If position is nil or a marker that points nowhere,
+     make this marker point nowhere.  */
+  if (NULL (pos) ||
+      (XTYPE (pos) == Lisp_Marker && !XMARKER (pos)->buffer))
+    {
+      unchain_marker (marker);
+      return marker;
+    }
+
+  CHECK_NUMBER_COERCE_MARKER (pos, 1);
+  if (NULL (buffer))
+    b = current_buffer;
+  else
+    {
+      CHECK_BUFFER (buffer, 1);
+      b = XBUFFER (buffer);
+      /* If buffer is dead, set marker to point nowhere.  */
+      if (EQ (b->name, Qnil))
+	{
+	  unchain_marker (marker);
+	  return marker;
+	}
+    }
+
+  charno = XINT (pos);
+  m = XMARKER (marker);
+
+  if (charno < BUF_BEGV (b))
+    charno = BUF_BEGV (b);
+  if (charno > BUF_ZV (b))
+    charno = BUF_ZV (b);
+  if (charno > BUF_GPT (b))
+    charno += BUF_GAP_SIZE (b);
+  m->bufpos = charno;
+
+  if (m->buffer != b)
+    {
+      unchain_marker (marker);
+      m->chain = b->markers;
+      b->markers = marker;
+      m->buffer = b;
+    }
+  
+  return marker;
+}
+
+/* This is called during garbage collection,
+   so we must be careful to ignore and preserve mark bits,
+   including those in chain fields of markers.  */
+
+unchain_marker (marker)
+     register Lisp_Object marker;
+{
+  register Lisp_Object tail, prev, next;
+  register int omark;
+  register struct buffer *b;
+
+  b = XMARKER (marker)->buffer;
+  if (b == 0)
+    return;
+
+  if (EQ (b->name, Qnil))
+    abort ();
+
+  tail = b->markers;
+  prev = Qnil;
+  while (XSYMBOL (tail) != XSYMBOL (Qnil))
+    {
+      next = XMARKER (tail)->chain;
+      XUNMARK (next);
+
+      if (XMARKER (marker) == XMARKER (tail))
+	{
+	  if (NULL (prev))
+	    {
+	      b->markers = next;
+	      /* Deleting first marker from the buffer's chain.
+		 Crash if new first marker in chain does not say
+		 it belongs to this buffer.  */
+	      if (!EQ (next, Qnil) && b != XMARKER (next)->buffer)
+		abort ();
+	    }
+	  else
+	    {
+	      omark = XMARKBIT (XMARKER (prev)->chain);
+	      XMARKER (prev)->chain = next;
+	      XSETMARKBIT (XMARKER (prev)->chain, omark);
+	    }
+	  break;
+	}
+      else
+	prev = tail;
+      tail = next;
+    }
+  XMARKER (marker)->buffer = 0;
+}
+
+marker_position (marker)
+     Lisp_Object marker;
+{
+  register struct Lisp_Marker *m = XMARKER (marker);
+  register struct buffer *buf = m->buffer;
+  register int i = m->bufpos;
+
+  if (!buf)
+    error ("Marker does not point anywhere");
+
+  if (i > BUF_GPT (buf) + BUF_GAP_SIZE (buf))
+    i -= BUF_GAP_SIZE (buf);
+  else if (i > BUF_GPT (buf))
+    i = BUF_GPT (buf);
+
+  if (i < BUF_BEG (buf) || i > BUF_Z (buf))
+    abort ();
+
+  return i;
+}
+
+DEFUN ("copy-marker", Fcopy_marker, Scopy_marker, 1, 1, 0,
+  "Return a new marker pointing at the same place as MARKER.\n\
+If argument is a number, makes a new marker pointing\n\
+at that position in the current buffer.")
+  (marker)
+     register Lisp_Object marker;
+{
+  register Lisp_Object new;
+
+  while (1)
+    {
+      if (XTYPE (marker) == Lisp_Int
+	  || XTYPE (marker) == Lisp_Marker)
+	{
+	  new = Fmake_marker ();
+	  Fset_marker (new, marker,
+		       ((XTYPE (marker) == Lisp_Marker)
+			? Fmarker_buffer (marker)
+			: Qnil));
+	  return new;
+	}
+      else
+	marker = wrong_type_argument (Qinteger_or_marker_p, marker);
+    }
+}
+
+syms_of_marker ()
+{
+  defsubr (&Smarker_position);
+  defsubr (&Smarker_buffer);
+  defsubr (&Sset_marker);
+  defsubr (&Scopy_marker);
+}