(Fclrhash): Return TABLE.
[bpt/emacs.git] / src / intervals.c
index a9e36f8..39e3656 100644 (file)
@@ -1,11 +1,12 @@
 /* Code for doing intervals.
-   Copyright (C) 1993, 1994, 1995, 1997, 1998, 2002, 2003 Free Software Foundation, Inc.
+   Copyright (C) 1993, 1994, 1995, 1997, 1998, 2001, 2002, 2003, 2004,
+                 2005, 2006, 2007, 2008  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 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
 any later version.
 
 GNU Emacs is distributed in the hope that it will be useful,
@@ -15,8 +16,8 @@ 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, Inc., 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
 
 
 /* NOTES:
@@ -124,18 +125,24 @@ merge_properties (source, target)
   while (CONSP (o))
     {
       sym = XCAR (o);
-      val = Fmemq (sym, target->plist);
+      o = XCDR (o);
+      CHECK_CONS (o);
+
+      val = target->plist;
+      while (CONSP (val) && !EQ (XCAR (val), sym))
+       {
+         val = XCDR (val);
+         if (!CONSP (val))
+           break;
+         val = XCDR (val);
+       }
 
       if (NILP (val))
        {
-         o = XCDR (o);
-         CHECK_CONS (o);
          val = XCAR (o);
          target->plist = Fcons (sym, Fcons (val, target->plist));
-         o = XCDR (o);
        }
-      else
-       o = Fcdr (XCDR (o));
+      o = XCDR (o);
     }
 }
 
@@ -146,8 +153,8 @@ int
 intervals_equal (i0, i1)
      INTERVAL i0, i1;
 {
-  register Lisp_Object i0_cdr, i0_sym, i1_val;
-  register int i1_len;
+  register Lisp_Object i0_cdr, i0_sym;
+  register Lisp_Object i1_cdr, i1_val;
 
   if (DEFAULT_INTERVAL_P (i0) && DEFAULT_INTERVAL_P (i1))
     return 1;
@@ -155,39 +162,43 @@ intervals_equal (i0, i1)
   if (DEFAULT_INTERVAL_P (i0) || DEFAULT_INTERVAL_P (i1))
     return 0;
 
-  i1_len = XFASTINT (Flength (i1->plist));
-  if (i1_len & 0x1)            /* Paranoia -- plists are always even */
-    abort ();
-  i1_len /= 2;
   i0_cdr = i0->plist;
-  while (CONSP (i0_cdr))
+  i1_cdr = i1->plist;
+  while (CONSP (i0_cdr) && CONSP (i1_cdr))
     {
-      /* Lengths of the two plists were unequal.  */
-      if (i1_len == 0)
-       return 0;
-
       i0_sym = XCAR (i0_cdr);
-      i1_val = Fmemq (i0_sym, i1->plist);
+      i0_cdr = XCDR (i0_cdr);
+      if (!CONSP (i0_cdr))
+       return 0;               /* abort (); */
+      i1_val = i1->plist;
+      while (CONSP (i1_val) && !EQ (XCAR (i1_val), i0_sym))
+       {
+         i1_val = XCDR (i1_val);
+         if (!CONSP (i1_val))
+           return 0;           /* abort (); */
+         i1_val = XCDR (i1_val);
+       }
 
       /* i0 has something i1 doesn't.  */
       if (EQ (i1_val, Qnil))
        return 0;
 
       /* i0 and i1 both have sym, but it has different values in each.  */
-      i0_cdr = XCDR (i0_cdr);
-      CHECK_CONS (i0_cdr);
-      if (!EQ (Fcar (Fcdr (i1_val)), XCAR (i0_cdr)))
+      if (!CONSP (i1_val)
+         || (i1_val = XCDR (i1_val), !CONSP (i1_val))
+         || !EQ (XCAR (i1_val), XCAR (i0_cdr)))
        return 0;
 
       i0_cdr = XCDR (i0_cdr);
-      i1_len--;
-    }
 
-  /* Lengths of the two plists were unequal.  */
-  if (i1_len > 0)
-    return 0;
+      i1_cdr = XCDR (i1_cdr);
+      if (!CONSP (i1_cdr))
+       return 0;               /* abort (); */
+      i1_cdr = XCDR (i1_cdr);
+    }
 
-  return 1;
+  /* Lengths of the two plists were equal.  */
+  return (NILP (i0_cdr) && NILP (i1_cdr));
 }
 \f
 
@@ -416,7 +427,7 @@ balance_an_interval (i)
          /* Since the left child is longer, there must be one.  */
          new_diff = i->total_length - i->left->total_length
            + RIGHT_TOTAL_LENGTH (i->left) - LEFT_TOTAL_LENGTH (i->left);
-         if (abs (new_diff) >= old_diff)
+         if (eabs (new_diff) >= old_diff)
            break;
          i = rotate_right (i);
          balance_an_interval (i->right);
@@ -426,7 +437,7 @@ balance_an_interval (i)
          /* Since the right child is longer, there must be one.  */
          new_diff = i->total_length - i->right->total_length
            + LEFT_TOTAL_LENGTH (i->right) - RIGHT_TOTAL_LENGTH (i->right);
-         if (abs (new_diff) >= -old_diff)
+         if (eabs (new_diff) >= -old_diff)
            break;
          i = rotate_left (i);
          balance_an_interval (i->left);
@@ -790,14 +801,14 @@ update_interval (i, pos)
          /* Move right. */
          if (pos < INTERVAL_LAST_POS (i) + TOTAL_LENGTH (i->right))
            {
-             i->right->position = INTERVAL_LAST_POS (i) +
-               LEFT_TOTAL_LENGTH (i->right);
+             i->right->position = INTERVAL_LAST_POS (i)
+               LEFT_TOTAL_LENGTH (i->right);
              i = i->right;             /* Move to the right child */
            }
          else if (NULL_PARENT (i))
-           error ("Point after end of properties");
+           error ("Point %d after end of properties", pos);
          else
-             i = INTERVAL_PARENT (i);
+            i = INTERVAL_PARENT (i);
          continue;
        }
       else
@@ -1712,6 +1723,7 @@ graft_intervals_into_buffer (source, position, length, buffer, inherit)
 {
   register INTERVAL under, over, this, prev;
   register INTERVAL tree;
+  int over_used;
 
   tree = BUF_INTERVALS (buffer);
 
@@ -1745,6 +1757,7 @@ graft_intervals_into_buffer (source, position, length, buffer, inherit)
          XSETBUFFER (buf, buffer);
          BUF_INTERVALS (buffer) = reproduce_tree_obj (source, buf);
          BUF_INTERVALS (buffer)->position = BEG;
+         BUF_INTERVALS (buffer)->up_obj = 1;
 
          /* Explicitly free the old tree here?  */
 
@@ -1767,6 +1780,7 @@ graft_intervals_into_buffer (source, position, length, buffer, inherit)
     {
       BUF_INTERVALS (buffer) = reproduce_tree (source, INTERVAL_PARENT (tree));
       BUF_INTERVALS (buffer)->position = BEG;
+      BUF_INTERVALS (buffer)->up_obj = 1;
       /* Explicitly free the old tree here.  */
 
       return;
@@ -1814,21 +1828,42 @@ graft_intervals_into_buffer (source, position, length, buffer, inherit)
      adjust_intervals_for_insertion, so stickiness has
      already been taken care of.  */
 
+  /* OVER is the interval we are copying from next.
+     OVER_USED says how many characters' worth of OVER
+     have already been copied into target intervals.
+     UNDER is the next interval in the target.  */
+  over_used = 0;
   while (! NULL_INTERVAL_P (over))
     {
-      if (LENGTH (over) < LENGTH (under))
+      /* If UNDER is longer than OVER, split it.  */
+      if (LENGTH (over) - over_used < LENGTH (under))
        {
-         this = split_interval_left (under, LENGTH (over));
+         this = split_interval_left (under, LENGTH (over) - over_used);
          copy_properties (under, this);
        }
       else
        this = under;
-      copy_properties (over, this);
+
+      /* THIS is now the interval to copy or merge into.
+        OVER covers all of it.  */
       if (inherit)
        merge_properties (over, this);
       else
        copy_properties (over, this);
-      over = next_interval (over);
+
+      /* If THIS and OVER end at the same place,
+        advance OVER to a new source interval.  */
+      if (LENGTH (this) == LENGTH (over) - over_used)
+       {
+         over = next_interval (over);
+         over_used = 0;
+       }
+      else
+       /* Otherwise just record that more of OVER has been used.  */
+       over_used += LENGTH (this);
+
+      /* Always advance to a new target interval.  */
+      under = next_interval (this);
     }
 
   if (! NULL_INTERVAL_P (BUF_INTERVALS (buffer)))
@@ -1875,11 +1910,13 @@ lookup_char_property (plist, prop, textprop)
     return fallback;
   /* Check for alternative properties */
   tail = Fassq (prop, Vchar_property_alias_alist);
-  if (NILP (tail))
-    return tail;
-  tail = XCDR (tail);
-  for (; NILP (fallback) && CONSP (tail); tail = XCDR (tail))
-    fallback = Fplist_get (plist, XCAR (tail));
+  if (! NILP (tail))
+    {
+      tail = XCDR (tail);
+      for (; NILP (fallback) && CONSP (tail); tail = XCDR (tail))
+       fallback = Fplist_get (plist, XCAR (tail));
+    }
+
   if (textprop && NILP (fallback) && CONSP (Vdefault_text_properties))
     fallback = Fplist_get (Vdefault_text_properties, prop);
   return fallback;
@@ -1989,6 +2026,10 @@ set_point_both (buffer, charpos, bytepos)
   register INTERVAL to, from, toprev, fromprev;
   int buffer_point;
   int old_position = BUF_PT (buffer);
+  /* This ensures that we move forward past intangible text when the
+     initial position is the same as the destination, in the rare
+     instances where this is important, e.g. in line-move-finish
+     (simple.el).  */
   int backwards = (charpos < old_position ? 1 : 0);
   int have_overlays;
   int original_position;
@@ -2009,8 +2050,7 @@ set_point_both (buffer, charpos, bytepos)
   if (charpos > BUF_ZV (buffer) || charpos < BUF_BEGV (buffer))
     abort ();
 
-  have_overlays = (! NILP (buffer->overlays_before)
-                  || ! NILP (buffer->overlays_after));
+  have_overlays = (buffer->overlays_before || buffer->overlays_after);
 
   /* If we have no text properties and overlays,
      then we can do it quickly.  */
@@ -2160,7 +2200,7 @@ set_point_both (buffer, charpos, bytepos)
 
   temp_set_point_both (buffer, charpos, bytepos);
 
-  /* We run point-left and point-entered hooks here, iff the
+  /* We run point-left and point-entered hooks here, if the
      two intervals are not equivalent.  These hooks take
      (old_point, new_point) as arguments.  */
   if (NILP (Vinhibit_point_motion_hooks)
@@ -2170,36 +2210,38 @@ set_point_both (buffer, charpos, bytepos)
       Lisp_Object leave_after, leave_before, enter_after, enter_before;
 
       if (fromprev)
-       leave_after = textget (fromprev->plist, Qpoint_left);
+       leave_before = textget (fromprev->plist, Qpoint_left);
       else
-       leave_after = Qnil;
+       leave_before = Qnil;
+
       if (from)
-       leave_before = textget (from->plist, Qpoint_left);
+       leave_after = textget (from->plist, Qpoint_left);
       else
-       leave_before = Qnil;
+       leave_after = Qnil;
 
       if (toprev)
-       enter_after = textget (toprev->plist, Qpoint_entered);
+       enter_before = textget (toprev->plist, Qpoint_entered);
       else
-       enter_after = Qnil;
+       enter_before = Qnil;
+
       if (to)
-       enter_before = textget (to->plist, Qpoint_entered);
+       enter_after = textget (to->plist, Qpoint_entered);
       else
-       enter_before = Qnil;
+       enter_after = Qnil;
 
       if (! EQ (leave_before, enter_before) && !NILP (leave_before))
-       call2 (leave_before, make_number (old_position),
-              make_number (charpos));
+       call2 (leave_before, make_number (old_position),
+              make_number (charpos));
       if (! EQ (leave_after, enter_after) && !NILP (leave_after))
-       call2 (leave_after, make_number (old_position),
-              make_number (charpos));
+       call2 (leave_after, make_number (old_position),
+              make_number (charpos));
 
       if (! EQ (enter_before, leave_before) && !NILP (enter_before))
-       call2 (enter_before, make_number (old_position),
-              make_number (charpos));
+       call2 (enter_before, make_number (old_position),
+              make_number (charpos));
       if (! EQ (enter_after, leave_after) && !NILP (enter_after))
-       call2 (enter_after, make_number (old_position),
-              make_number (charpos));
+       call2 (enter_after, make_number (old_position),
+              make_number (charpos));
     }
 }
 \f
@@ -2250,6 +2292,10 @@ move_if_not_intangible (position)
          pos = Fnext_char_property_change (pos, Qnil);
 
     }
+  else if (position < BEGV)
+    position = BEGV;
+  else if (position > ZV)
+    position = ZV;
 
   /* If the whole stretch between PT and POSITION isn't intangible,
      try moving to POSITION (which means we actually move farther
@@ -2309,7 +2355,9 @@ get_property_and_range (pos, prop, val, start, end, object)
 /* Return the proper local keymap TYPE for position POSITION in
    BUFFER; TYPE should be one of `keymap' or `local-map'.  Use the map
    specified by the PROP property, if any.  Otherwise, if TYPE is
-   `local-map' use BUFFER's local map.  */
+   `local-map' use BUFFER's local map.
+
+   POSITION must be in the accessible part of BUFFER.  */
 
 Lisp_Object
 get_local_map (position, buffer, type)
@@ -2321,7 +2369,7 @@ get_local_map (position, buffer, type)
   int old_begv, old_zv, old_begv_byte, old_zv_byte;
 
   /* Perhaps we should just change `position' to the limit.  */
-  if (position > BUF_Z (buffer) || position < BUF_BEG (buffer))
+  if (position > BUF_ZV (buffer) || position < BUF_BEGV (buffer))
     abort ();
 
   /* Ignore narrowing, so that a local map continues to be valid even if
@@ -2335,10 +2383,6 @@ get_local_map (position, buffer, type)
   BUF_BEGV_BYTE (buffer) = BUF_BEG_BYTE (buffer);
   BUF_ZV_BYTE (buffer) = BUF_Z_BYTE (buffer);
 
-  /* There are no properties at the end of the buffer, so in that case
-     check for a local map on the last character of the buffer instead.  */
-  if (position == BUF_Z (buffer) && BUF_Z (buffer) > BUF_BEG (buffer))
-    --position;
   XSETFASTINT (lispy_position, position);
   XSETBUFFER (lispy_buffer, buffer);
   /* First check if the CHAR has any property.  This is because when
@@ -2504,7 +2548,7 @@ set_intervals_multibyte_1 (i, multi_flag, start, start_byte, end, end_byte)
          temp = CHAR_TO_BYTE (left_end);
 
          /* If LEFT_END_BYTE is in the middle of a character,
-            adjust it and LEFT_END to a char boundary.  */ 
+            adjust it and LEFT_END to a char boundary.  */
          if (left_end_byte > temp)
            {
              left_end_byte = temp;
@@ -2536,7 +2580,7 @@ set_intervals_multibyte_1 (i, multi_flag, start, start_byte, end, end_byte)
          right_start = BYTE_TO_CHAR (right_start_byte);
 
          /* If RIGHT_START_BYTE is in the middle of a character,
-            adjust it and RIGHT_START to a char boundary.  */ 
+            adjust it and RIGHT_START to a char boundary.  */
          temp = CHAR_TO_BYTE (right_start);
 
          if (right_start_byte < temp)
@@ -2592,3 +2636,6 @@ set_intervals_multibyte (multi_flag)
     set_intervals_multibyte_1 (BUF_INTERVALS (current_buffer), multi_flag,
                               BEG, BEG_BYTE, Z, Z_BYTE);
 }
+
+/* arch-tag: 3d402b60-083c-4271-b4a3-ebd9a74bfe27
+   (do not change this comment) */