]> code.delx.au - gnu-emacs/blobdiff - src/textprop.c
Don't install keyboard hook when debugged on MS-Windows
[gnu-emacs] / src / textprop.c
index c8d238e666e123da7409689ed6def15dbe0c2e9e..7af8c6987365e79fb35140f7659afaad5f3a7e1a 100644 (file)
@@ -1,13 +1,13 @@
 /* Interface code for dealing with text properties.
-   Copyright (C) 1993-1995, 1997, 1999-2015 Free Software Foundation,
+   Copyright (C) 1993-1995, 1997, 1999-2016 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 3 of the License, or
-(at your option) any later version.
+the Free Software Foundation, either version 3 of the License, 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
@@ -21,7 +21,6 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "lisp.h"
 #include "intervals.h"
-#include "character.h"
 #include "buffer.h"
 #include "window.h"
 
@@ -44,21 +43,6 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
   is enforced by the subrs installing properties onto the intervals.  */
 
 \f
-/* Types of hooks.  */
-static Lisp_Object Qmouse_left;
-static Lisp_Object Qmouse_entered;
-Lisp_Object Qpoint_left;
-Lisp_Object Qpoint_entered;
-Lisp_Object Qcategory;
-Lisp_Object Qlocal_map;
-
-/* Visual properties text (including strings) may have.  */
-static Lisp_Object Qforeground, Qbackground, Qunderline;
-Lisp_Object Qfont;
-static Lisp_Object Qstipple;
-Lisp_Object Qinvisible, Qintangible, Qmouse_face;
-static Lisp_Object Qread_only;
-Lisp_Object Qminibuffer_prompt;
 
 enum property_set_type
 {
@@ -67,11 +51,8 @@ enum property_set_type
   TEXT_PROPERTY_APPEND
 };
 
-/* Sticky properties.  */
-Lisp_Object Qfront_sticky, Qrear_nonsticky;
-
-/* If o1 is a cons whose cdr is a cons, return non-zero and set o2 to
-   the o1's cdr.  Otherwise, return zero.  This is handy for
+/* If o1 is a cons whose cdr is a cons, return true and set o2 to
+   the o1's cdr.  Otherwise, return false.  This is handy for
    traversing plists.  */
 #define PLIST_ELT_P(o1, o2) (CONSP (o1) && ((o2)=XCDR (o1), CONSP (o2)))
 
@@ -141,13 +122,12 @@ CHECK_STRING_OR_BUFFER (Lisp_Object x)
    Fprevious_property_change which call this function with BEGIN == END.
    Handle this case specially.
 
-   If FORCE is soft (0), it's OK to return NULL.  Otherwise,
+   If FORCE is soft (false), it's OK to return NULL.  Otherwise,
    create an interval tree for OBJECT if one doesn't exist, provided
    the object actually contains text.  In the current design, if there
    is no text, there can be no text properties.  */
 
-#define soft 0
-#define hard 1
+enum { soft = false, hard = true };
 
 INTERVAL
 validate_interval_range (Lisp_Object object, Lisp_Object *begin,
@@ -224,15 +204,17 @@ validate_plist (Lisp_Object list)
 
   if (CONSP (list))
     {
-      bool odd_length = 0;
-      Lisp_Object tail;
-      for (tail = list; CONSP (tail); tail = XCDR (tail))
+      Lisp_Object tail = list;
+      do
        {
-         odd_length ^= 1;
+         tail = XCDR (tail);
+         if (! CONSP (tail))
+           error ("Odd length text property list");
+         tail = XCDR (tail);
          QUIT;
        }
-      if (odd_length)
-       error ("Odd length text property list");
+      while (CONSP (tail));
+
       return list;
     }
 
@@ -251,27 +233,27 @@ interval_has_all_properties (Lisp_Object plist, INTERVAL i)
   for (tail1 = plist; CONSP (tail1); tail1 = Fcdr (XCDR (tail1)))
     {
       Lisp_Object sym1 = XCAR (tail1);
-      bool found = 0;
+      bool found = false;
 
       /* Go through I's plist, looking for sym1 */
       for (tail2 = i->plist; CONSP (tail2); tail2 = Fcdr (XCDR (tail2)))
        if (EQ (sym1, XCAR (tail2)))
          {
            /* Found the same property on both lists.  If the
-              values are unequal, return zero.  */
+              values are unequal, return false.  */
            if (! EQ (Fcar (XCDR (tail1)), Fcar (XCDR (tail2))))
-             return 0;
+             return false;
 
            /* Property has same value on both lists; go to next one.  */
-           found = 1;
+           found = true;
            break;
          }
 
       if (! found)
-       return 0;
+       return false;
     }
 
-  return 1;
+  return true;
 }
 
 /* Return true if the plist of interval I has any of the
@@ -290,13 +272,13 @@ interval_has_some_properties (Lisp_Object plist, INTERVAL i)
       /* Go through i's plist, looking for tail1 */
       for (tail2 = i->plist; CONSP (tail2); tail2 = Fcdr (XCDR (tail2)))
        if (EQ (sym, XCAR (tail2)))
-         return 1;
+         return true;
     }
 
-  return 0;
+  return false;
 }
 
-/* Return nonzero if the plist of interval I has any of the
+/* Return true if the plist of interval I has any of the
    property names in LIST, regardless of their values.  */
 
 static bool
@@ -312,10 +294,10 @@ interval_has_some_properties_list (Lisp_Object list, INTERVAL i)
       /* Go through i's plist, looking for tail1 */
       for (tail2 = i->plist; CONSP (tail2); tail2 = XCDR (XCDR (tail2)))
        if (EQ (sym, XCAR (tail2)))
-         return 1;
+         return true;
     }
 
-  return 0;
+  return false;
 }
 \f
 /* Changing the plists of individual intervals.  */
@@ -391,21 +373,16 @@ add_properties (Lisp_Object plist, INTERVAL i, Lisp_Object object,
                enum property_set_type set_type)
 {
   Lisp_Object tail1, tail2, sym1, val1;
-  bool changed = 0;
-  struct gcpro gcpro1, gcpro2, gcpro3;
+  bool changed = false;
 
   tail1 = plist;
   sym1 = Qnil;
   val1 = Qnil;
-  /* No need to protect OBJECT, because we can GC only in the case
-     where it is a buffer, and live buffers are always protected.
-     I and its plist are also protected, via OBJECT.  */
-  GCPRO3 (tail1, sym1, val1);
 
   /* Go through each element of PLIST.  */
   for (tail1 = plist; CONSP (tail1); tail1 = Fcdr (XCDR (tail1)))
     {
-      bool found = 0;
+      bool found = false;
       sym1 = XCAR (tail1);
       val1 = Fcar (XCDR (tail1));
 
@@ -413,13 +390,11 @@ add_properties (Lisp_Object plist, INTERVAL i, Lisp_Object object,
       for (tail2 = i->plist; CONSP (tail2); tail2 = Fcdr (XCDR (tail2)))
        if (EQ (sym1, XCAR (tail2)))
          {
-           /* No need to gcpro, because tail2 protects this
-              and it must be a cons cell (we get an error otherwise).  */
-           register Lisp_Object this_cdr;
+           Lisp_Object this_cdr;
 
            this_cdr = XCDR (tail2);
            /* Found the property.  Now check its value.  */
-           found = 1;
+           found = true;
 
            /* The properties have the same value on both lists.
               Continue to the next property.  */
@@ -456,7 +431,7 @@ add_properties (Lisp_Object plist, INTERVAL i, Lisp_Object object,
                  Fsetcar (this_cdr, list2 (Fcar (this_cdr), val1));
              }
            }
-           changed = 1;
+           changed = true;
            break;
          }
 
@@ -469,12 +444,10 @@ add_properties (Lisp_Object plist, INTERVAL i, Lisp_Object object,
                                      sym1, Qnil, object);
            }
          set_interval_plist (i, Fcons (sym1, Fcons (val1, i->plist)));
-         changed = 1;
+         changed = true;
        }
     }
 
-  UNGCPRO;
-
   return changed;
 }
 
@@ -486,23 +459,18 @@ add_properties (Lisp_Object plist, INTERVAL i, Lisp_Object object,
 static bool
 remove_properties (Lisp_Object plist, Lisp_Object list, INTERVAL i, Lisp_Object object)
 {
-  Lisp_Object tail1, tail2, sym, current_plist;
-  bool changed = 0;
+  bool changed = false;
 
   /* True means tail1 is a plist, otherwise it is a list.  */
-  bool use_plist;
-
-  current_plist = i->plist;
+  bool use_plist = ! NILP (plist);
+  Lisp_Object tail1 = use_plist ? plist : list;
 
-  if (! NILP (plist))
-    tail1 = plist, use_plist = 1;
-  else
-    tail1 = list, use_plist = 0;
+  Lisp_Object current_plist = i->plist;
 
   /* Go through each element of LIST or PLIST.  */
   while (CONSP (tail1))
     {
-      sym = XCAR (tail1);
+      Lisp_Object sym = XCAR (tail1);
 
       /* First, remove the symbol if it's at the head of the list */
       while (CONSP (current_plist) && EQ (sym, XCAR (current_plist)))
@@ -513,15 +481,14 @@ remove_properties (Lisp_Object plist, Lisp_Object list, INTERVAL i, Lisp_Object
                                    object);
 
          current_plist = XCDR (XCDR (current_plist));
-         changed = 1;
+         changed = true;
        }
 
       /* Go through I's plist, looking for SYM.  */
-      tail2 = current_plist;
+      Lisp_Object tail2 = current_plist;
       while (! NILP (tail2))
        {
-         register Lisp_Object this;
-         this = XCDR (XCDR (tail2));
+         Lisp_Object this = XCDR (XCDR (tail2));
          if (CONSP (this) && EQ (sym, XCAR (this)))
            {
              if (BUFFERP (object))
@@ -529,7 +496,7 @@ remove_properties (Lisp_Object plist, Lisp_Object list, INTERVAL i, Lisp_Object
                                        sym, XCAR (XCDR (this)), object);
 
              Fsetcdr (XCDR (tail2), XCDR (XCDR (this)));
-             changed = 1;
+             changed = true;
            }
          tail2 = this;
        }
@@ -660,7 +627,8 @@ get_char_property_and_overlay (Lisp_Object position, register Lisp_Object prop,
 
       set_buffer_temp (XBUFFER (object));
 
-      GET_OVERLAYS_AT (XINT (position), overlay_vec, noverlays, NULL, 0);
+      USE_SAFE_ALLOCA;
+      GET_OVERLAYS_AT (XINT (position), overlay_vec, noverlays, NULL, false);
       noverlays = sort_overlays (overlay_vec, noverlays, w);
 
       set_buffer_temp (obuf);
@@ -674,9 +642,11 @@ get_char_property_and_overlay (Lisp_Object position, register Lisp_Object prop,
              if (overlay)
                /* Return the overlay we got the property from.  */
                *overlay = overlay_vec[noverlays];
+             SAFE_FREE ();
              return tem;
            }
        }
+      SAFE_FREE ();
     }
 
   if (overlay)
@@ -731,11 +701,12 @@ DEFUN ("next-char-property-change", Fnext_char_property_change,
 This scans characters forward in the current buffer from POSITION till
 it finds a change in some text property, or the beginning or end of an
 overlay, and returns the position of that.
-If none is found up to (point-max), the function returns (point-max).
+If none is found, and LIMIT is nil or omitted, the function
+returns (point-max).
 
-If the optional second argument LIMIT is non-nil, don't search
-past position LIMIT; return LIMIT if nothing is found before LIMIT.
-LIMIT is a no-op if it is greater than (point-max).  */)
+If the optional second argument LIMIT is non-nil, the function doesn't
+search past position LIMIT, and returns LIMIT if nothing is found
+before LIMIT.  LIMIT is a no-op if it is greater than (point-max).  */)
   (Lisp_Object position, Lisp_Object limit)
 {
   Lisp_Object temp;
@@ -756,11 +727,12 @@ DEFUN ("previous-char-property-change", Fprevious_char_property_change,
 Scans characters backward in the current buffer from POSITION till it
 finds a change in some text property, or the beginning or end of an
 overlay, and returns the position of that.
-If none is found since (point-min), the function returns (point-min).
+If none is found, and LIMIT is nil or omitted, the function
+returns (point-min).
 
-If the optional second argument LIMIT is non-nil, don't search
-past position LIMIT; return LIMIT if nothing is found before LIMIT.
-LIMIT is a no-op if it is less than (point-min).  */)
+If the optional second argument LIMIT is non-nil, the function doesn't
+search before position LIMIT, and returns LIMIT if nothing is found
+before LIMIT.  LIMIT is a no-op if it is less than (point-min).  */)
   (Lisp_Object position, Lisp_Object limit)
 {
   Lisp_Object temp;
@@ -785,14 +757,15 @@ If the optional third argument OBJECT is a buffer (or nil, which means
 the current buffer), POSITION is a buffer position (integer or marker).
 If OBJECT is a string, POSITION is a 0-based index into it.
 
-In a string, scan runs to the end of the string.
-In a buffer, it runs to (point-max), and the value cannot exceed that.
+In a string, scan runs to the end of the string, unless LIMIT is non-nil.
+In a buffer, if LIMIT is nil or omitted, it runs to (point-max), and the
+value cannot exceed that.
+If the optional fourth argument LIMIT is non-nil, don't search
+past position LIMIT; return LIMIT if nothing is found before LIMIT.
 
 The property values are compared with `eq'.
 If the property is constant all the way to the end of OBJECT, return the
-last valid position in OBJECT.
-If the optional fourth argument LIMIT is non-nil, don't search
-past position LIMIT; return LIMIT if nothing is found before LIMIT.  */)
+last valid position in OBJECT.  */)
   (Lisp_Object position, Lisp_Object prop, Lisp_Object object, Lisp_Object limit)
 {
   if (STRINGP (object))
@@ -839,7 +812,7 @@ past position LIMIT; return LIMIT if nothing is found before LIMIT.  */)
            XSETFASTINT (position, ZV);
        }
       else
-       while (1)
+       while (true)
          {
            position = Fnext_char_property_change (position, limit);
            if (XFASTINT (position) >= XFASTINT (limit))
@@ -869,14 +842,15 @@ If the optional third argument OBJECT is a buffer (or nil, which means
 the current buffer), POSITION is a buffer position (integer or marker).
 If OBJECT is a string, POSITION is a 0-based index into it.
 
-In a string, scan runs to the start of the string.
-In a buffer, it runs to (point-min), and the value cannot be less than that.
+In a string, scan runs to the start of the string, unless LIMIT is non-nil.
+In a buffer, if LIMIT is nil or omitted, it runs to (point-min), and the
+value cannot be less than that.
+If the optional fourth argument LIMIT is non-nil, don't search back past
+position LIMIT; return LIMIT if nothing is found before reaching LIMIT.
 
 The property values are compared with `eq'.
 If the property is constant all the way to the start of OBJECT, return the
-first valid position in OBJECT.
-If the optional fourth argument LIMIT is non-nil, don't search back past
-position LIMIT; return LIMIT if nothing is found before reaching LIMIT.  */)
+first valid position in OBJECT.  */)
   (Lisp_Object position, Lisp_Object prop, Lisp_Object object, Lisp_Object limit)
 {
   if (STRINGP (object))
@@ -925,7 +899,7 @@ position LIMIT; return LIMIT if nothing is found before reaching LIMIT.  */)
            = Fget_char_property (make_number (XFASTINT (position) - 1),
                                  prop, object);
 
-         while (1)
+         while (true)
            {
              position = Fprevious_char_property_change (position, limit);
 
@@ -960,8 +934,9 @@ a change in some text property, then returns the position of the change.
 If the optional second argument OBJECT is a buffer (or nil, which means
 the current buffer), POSITION is a buffer position (integer or marker).
 If OBJECT is a string, POSITION is a 0-based index into it.
-Return nil if the property is constant all the way to the end of OBJECT.
-If the value is non-nil, it is a position greater than POSITION, never equal.
+Return nil if LIMIT is nil or omitted, and the property is constant all
+the way to the end of OBJECT; if the value is non-nil, it is a position
+greater than POSITION, never equal.
 
 If the optional third argument LIMIT is non-nil, don't search
 past position LIMIT; return LIMIT if nothing is found before LIMIT.  */)
@@ -1025,8 +1000,9 @@ If the optional third argument OBJECT is a buffer (or nil, which means
 the current buffer), POSITION is a buffer position (integer or marker).
 If OBJECT is a string, POSITION is a 0-based index into it.
 The property values are compared with `eq'.
-Return nil if the property is constant all the way to the end of OBJECT.
-If the value is non-nil, it is a position greater than POSITION, never equal.
+Return nil if LIMIT is nil or omitted, and the property is constant all
+the way to the end of OBJECT; if the value is non-nil, it is a position
+greater than POSITION, never equal.
 
 If the optional fourth argument LIMIT is non-nil, don't search
 past position LIMIT; return LIMIT if nothing is found before LIMIT.  */)
@@ -1072,8 +1048,9 @@ a change in some text property, then returns the position of the change.
 If the optional second argument OBJECT is a buffer (or nil, which means
 the current buffer), POSITION is a buffer position (integer or marker).
 If OBJECT is a string, POSITION is a 0-based index into it.
-Return nil if the property is constant all the way to the start of OBJECT.
-If the value is non-nil, it is a position less than POSITION, never equal.
+Return nil if LIMIT is nil or omitted, and the property is constant all
+the way to the start of OBJECT; if the value is non-nil, it is a position
+less than POSITION, never equal.
 
 If the optional third argument LIMIT is non-nil, don't search
 back past position LIMIT; return LIMIT if nothing is found until LIMIT.  */)
@@ -1120,8 +1097,9 @@ If the optional third argument OBJECT is a buffer (or nil, which means
 the current buffer), POSITION is a buffer position (integer or marker).
 If OBJECT is a string, POSITION is a 0-based index into it.
 The property values are compared with `eq'.
-Return nil if the property is constant all the way to the start of OBJECT.
-If the value is non-nil, it is a position less than POSITION, never equal.
+Return nil if LIMIT is nil or omitted, and the property is constant all
+the way to the start of OBJECT; if the value is non-nil, it is a position
+less than POSITION, never equal.
 
 If the optional fourth argument LIMIT is non-nil, don't search
 back past position LIMIT; return LIMIT if nothing is found until LIMIT.  */)
@@ -1171,9 +1149,8 @@ add_text_properties_1 (Lisp_Object start, Lisp_Object end,
                       enum property_set_type set_type) {
   INTERVAL i, unchanged;
   ptrdiff_t s, len;
-  bool modified = 0;
-  struct gcpro gcpro1;
-  bool first_time = 1;
+  bool modified = false;
+  bool first_time = true;
 
   properties = validate_plist (properties);
   if (NILP (properties))
@@ -1190,10 +1167,6 @@ add_text_properties_1 (Lisp_Object start, Lisp_Object end,
   s = XINT (start);
   len = XINT (end) - s;
 
-  /* No need to protect OBJECT, because we GC only if it's a buffer,
-     and live buffers are always protected.  */
-  GCPRO1 (properties);
-
   /* If this interval already has the properties, we can skip it.  */
   if (interval_has_all_properties (properties, i))
     {
@@ -1202,7 +1175,7 @@ add_text_properties_1 (Lisp_Object start, Lisp_Object end,
       do
        {
          if (got >= len)
-           RETURN_UNGCPRO (Qnil);
+           return Qnil;
          len -= got;
          i = next_interval (i);
          got = LENGTH (i);
@@ -1233,7 +1206,7 @@ add_text_properties_1 (Lisp_Object start, Lisp_Object end,
       if (TOTAL_LENGTH (i) != prev_total_length
          || i->position != prev_pos)
        {
-         first_time = 0;
+         first_time = false;
          goto retry;
        }
     }
@@ -1245,11 +1218,6 @@ add_text_properties_1 (Lisp_Object start, Lisp_Object end,
 
       if (LENGTH (i) >= len)
        {
-         /* We can UNGCPRO safely here, because there will be just
-            one more chance to gc, in the next call to add_properties,
-            and after that we will not need PROPERTIES or OBJECT again.  */
-         UNGCPRO;
-
          if (interval_has_all_properties (properties, i))
            {
              if (BUFFERP (object))
@@ -1314,9 +1282,11 @@ specify the property to add.
 If the optional fifth argument OBJECT is a buffer (or nil, which means
 the current buffer), START and END are buffer positions (integers or
 markers).  If OBJECT is a string, START and END are 0-based indices into it.  */)
-  (Lisp_Object start, Lisp_Object end, Lisp_Object property, Lisp_Object value, Lisp_Object object)
+  (Lisp_Object start, Lisp_Object end, Lisp_Object property,
+   Lisp_Object value, Lisp_Object object)
 {
-  Fadd_text_properties (start, end, list2 (property, value), object);
+  AUTO_LIST2 (properties, property, value);
+  Fadd_text_properties (start, end, properties, object);
   return Qnil;
 }
 
@@ -1357,7 +1327,8 @@ into it.  */)
   (Lisp_Object start, Lisp_Object end, Lisp_Object face,
    Lisp_Object append, Lisp_Object object)
 {
-  add_text_properties_1 (start, end, list2 (Qface, face), object,
+  AUTO_LIST2 (properties, Qface, face);
+  add_text_properties_1 (start, end, properties, object,
                         (NILP (append)
                          ? TEXT_PROPERTY_PREPEND
                          : TEXT_PROPERTY_APPEND));
@@ -1533,8 +1504,8 @@ Use `set-text-properties' if you want to remove all text properties.  */)
 {
   INTERVAL i, unchanged;
   ptrdiff_t s, len;
-  bool modified = 0;
-  bool first_time = 1;
+  bool modified = false;
+  bool first_time = true;
 
   if (NILP (object))
     XSETBUFFER (object, current_buffer);
@@ -1586,7 +1557,7 @@ Use `set-text-properties' if you want to remove all text properties.  */)
       if (TOTAL_LENGTH (i) != prev_total_length
          || i->position != prev_pos)
        {
-         first_time = 0;
+         first_time = false;
          goto retry;
        }
     }
@@ -1645,7 +1616,7 @@ Return t if any property was actually removed, nil otherwise.  */)
 {
   INTERVAL i, unchanged;
   ptrdiff_t s, len;
-  bool modified = 0;
+  bool modified = false;
   Lisp_Object properties;
   properties = list_of_properties;
 
@@ -1684,11 +1655,11 @@ Return t if any property was actually removed, nil otherwise.  */)
     }
 
   /* We are at the beginning of an interval, with len to scan.
-     The flag `modified' records if changes have been made.
+     The flag MODIFIED records if changes have been made.
      When object is a buffer, we must call modify_text_properties
      before changes are made and signal_after_change when we are done.
-     We call modify_text_properties before calling remove_properties if modified == 0,
-     and we call signal_after_change before returning if modified != 0. */
+     Call modify_text_properties before calling remove_properties if !MODIFIED,
+     and call signal_after_change before returning if MODIFIED. */
   for (;;)
     {
       eassert (i != 0);
@@ -1737,7 +1708,7 @@ Return t if any property was actually removed, nil otherwise.  */)
          if (!modified && BUFFERP (object))
            modify_text_properties (object, start, end);
          remove_properties (Qnil, properties, i, object);
-         modified = 1;
+         modified = true;
        }
       len -= LENGTH (i);
       i = next_interval (i);
@@ -1906,15 +1877,15 @@ text_property_stickiness (Lisp_Object prop, Lisp_Object pos, Lisp_Object buffer)
 /* Note this can GC when DEST is a buffer.  */
 
 Lisp_Object
-copy_text_properties (Lisp_Object start, Lisp_Object end, Lisp_Object src, Lisp_Object pos, Lisp_Object dest, Lisp_Object prop)
+copy_text_properties (Lisp_Object start, Lisp_Object end, Lisp_Object src,
+                     Lisp_Object pos, Lisp_Object dest, Lisp_Object prop)
 {
   INTERVAL i;
   Lisp_Object res;
   Lisp_Object stuff;
   Lisp_Object plist;
   ptrdiff_t s, e, e2, p, len;
-  bool modified = 0;
-  struct gcpro gcpro1, gcpro2;
+  bool modified = false;
 
   i = validate_interval_range (src, &start, &end, soft);
   if (!i)
@@ -1959,12 +1930,10 @@ copy_text_properties (Lisp_Object start, Lisp_Object end, Lisp_Object src, Lisp_
            plist = Fcdr (Fcdr (plist));
          }
       if (! NILP (plist))
-       {
-         /* Must defer modifications to the interval tree in case src
-            and dest refer to the same string or buffer.  */
-         stuff = Fcons (list3 (make_number (p), make_number (p + len), plist),
-                        stuff);
-       }
+       /* Must defer modifications to the interval tree in case
+          src and dest refer to the same string or buffer.  */
+       stuff = Fcons (list3 (make_number (p), make_number (p + len), plist),
+                      stuff);
 
       i = next_interval (i);
       if (!i)
@@ -1974,20 +1943,16 @@ copy_text_properties (Lisp_Object start, Lisp_Object end, Lisp_Object src, Lisp_
       s = i->position;
     }
 
-  GCPRO2 (stuff, dest);
-
   while (! NILP (stuff))
     {
       res = Fcar (stuff);
       res = Fadd_text_properties (Fcar (res), Fcar (Fcdr (res)),
                                  Fcar (Fcdr (Fcdr (res))), dest);
       if (! NILP (res))
-       modified = 1;
+       modified = true;
       stuff = Fcdr (stuff);
     }
 
-  UNGCPRO;
-
   return modified ? Qt : Qnil;
 }
 
@@ -2057,10 +2022,6 @@ text_property_list (Lisp_Object object, Lisp_Object start, Lisp_Object end, Lisp
 void
 add_text_properties_from_list (Lisp_Object object, Lisp_Object list, Lisp_Object delta)
 {
-  struct gcpro gcpro1, gcpro2;
-
-  GCPRO2 (list, object);
-
   for (; CONSP (list); list = XCDR (list))
     {
       Lisp_Object item, start, end, plist;
@@ -2072,8 +2033,6 @@ add_text_properties_from_list (Lisp_Object object, Lisp_Object list, Lisp_Object
 
       Fadd_text_properties (start, end, plist, object);
     }
-
-  UNGCPRO;
 }
 
 
@@ -2084,18 +2043,19 @@ add_text_properties_from_list (Lisp_Object object, Lisp_Object list, Lisp_Object
    end-points to NEW_END.  */
 
 Lisp_Object
-extend_property_ranges (Lisp_Object list, Lisp_Object new_end)
+extend_property_ranges (Lisp_Object list, Lisp_Object old_end, Lisp_Object new_end)
 {
   Lisp_Object prev = Qnil, head = list;
   ptrdiff_t max = XINT (new_end);
 
   for (; CONSP (list); prev = list, list = XCDR (list))
     {
-      Lisp_Object item, beg, end;
+      Lisp_Object item, beg;
+      ptrdiff_t end;
 
       item = XCAR (list);
       beg = XCAR (item);
-      end = XCAR (XCDR (item));
+      end = XINT (XCAR (XCDR (item)));
 
       if (XINT (beg) >= max)
        {
@@ -2106,9 +2066,16 @@ extend_property_ranges (Lisp_Object list, Lisp_Object new_end)
          else
            XSETCDR (prev, XCDR (list));
        }
-      else if (XINT (end) > max)
-       /* The end-point is past the end of the new string.  */
-       XSETCAR (XCDR (item), new_end);
+      else if ((end == XINT (old_end) && end != max)
+              || end > max)
+       {
+         /* Either the end-point is past the end of the new string,
+            and we need to discard the properties past the new end,
+            or the caller is extending the property range, and we
+            should update all end-points that are on the old end of
+            the range to reflect that.  */
+         XSETCAR (XCDR (item), new_end);
+       }
     }
 
   return head;
@@ -2121,14 +2088,11 @@ extend_property_ranges (Lisp_Object list, Lisp_Object new_end)
 static void
 call_mod_hooks (Lisp_Object list, Lisp_Object start, Lisp_Object end)
 {
-  struct gcpro gcpro1;
-  GCPRO1 (list);
   while (!NILP (list))
     {
       call2 (Fcar (list), start, end);
       list = Fcdr (list);
     }
-  UNGCPRO;
 }
 
 /* Check for read-only intervals between character positions START ... END,
@@ -2148,7 +2112,6 @@ verify_interval_modification (struct buffer *buf,
   Lisp_Object hooks;
   Lisp_Object prev_mod_hooks;
   Lisp_Object mod_hooks;
-  struct gcpro gcpro1;
 
   hooks = Qnil;
   prev_mod_hooks = Qnil;
@@ -2293,6 +2256,11 @@ verify_interval_modification (struct buffer *buf,
                }
            }
 
+         if (i->position + LENGTH (i) < end
+             && (!NILP (BVAR (current_buffer, read_only))
+                 && NILP (Vinhibit_read_only)))
+           xsignal1 (Qbuffer_read_only, Fcurrent_buffer ());
+
          i = next_interval (i);
        }
       /* Keep going thru the interval containing the char before END.  */
@@ -2300,7 +2268,6 @@ verify_interval_modification (struct buffer *buf,
 
       if (!inhibit_modification_hooks)
        {
-         GCPRO1 (hooks);
          hooks = Fnreverse (hooks);
          while (! EQ (hooks, Qnil))
            {
@@ -2308,7 +2275,6 @@ verify_interval_modification (struct buffer *buf,
                              make_number (end));
              hooks = Fcdr (hooks);
            }
-         UNGCPRO;
        }
     }
 }
@@ -2349,8 +2315,16 @@ returned. */);
 
   DEFVAR_LISP ("inhibit-point-motion-hooks", Vinhibit_point_motion_hooks,
               doc: /* If non-nil, don't run `point-left' and `point-entered' text properties.
-This also inhibits the use of the `intangible' text property.  */);
-  Vinhibit_point_motion_hooks = Qnil;
+This also inhibits the use of the `intangible' text property.
+
+This variable is obsolete since Emacs-25.1.  Use `cursor-intangible-mode'
+or `cursor-sensor-mode' instead.  */);
+  /* FIXME: We should make-obsolete-variable, but that signals too many
+     warnings in code which does (let ((inhibit-point-motion-hooks t)) ...)
+     Ideally, make-obsolete-variable should let us specify that only the nil
+     value is obsolete, but that requires too many changes in bytecomp.el,
+     so for now we'll keep it "obsolete via the docstring".  */
+  Vinhibit_point_motion_hooks = Qt;
 
   DEFVAR_LISP ("text-property-default-nonsticky",
               Vtext_property_default_nonsticky,
@@ -2364,8 +2338,7 @@ inherits it if NONSTICKINESS is nil.  The `front-sticky' and
   /* Text properties `syntax-table'and `display' should be nonsticky
      by default.  */
   Vtext_property_default_nonsticky
-    = list2 (Fcons (intern_c_string ("syntax-table"), Qt),
-            Fcons (intern_c_string ("display"), Qt));
+    = list2 (Fcons (Qsyntax_table, Qt), Fcons (Qdisplay, Qt));
 
   staticpro (&interval_insert_behind_hooks);
   staticpro (&interval_insert_in_front_hooks);
@@ -2373,14 +2346,10 @@ inherits it if NONSTICKINESS is nil.  The `front-sticky' and
   interval_insert_in_front_hooks = Qnil;
 
 
-  /* Common attributes one might give text */
+  /* Common attributes one might give text */
 
-  DEFSYM (Qforeground, "foreground");
-  DEFSYM (Qbackground, "background");
   DEFSYM (Qfont, "font");
   DEFSYM (Qface, "face");
-  DEFSYM (Qstipple, "stipple");
-  DEFSYM (Qunderline, "underline");
   DEFSYM (Qread_only, "read-only");
   DEFSYM (Qinvisible, "invisible");
   DEFSYM (Qintangible, "intangible");
@@ -2391,10 +2360,8 @@ inherits it if NONSTICKINESS is nil.  The `front-sticky' and
   DEFSYM (Qmouse_face, "mouse-face");
   DEFSYM (Qminibuffer_prompt, "minibuffer-prompt");
 
-  /* Properties that text might use to specify certain actions */
+  /* Properties that text might use to specify certain actions */
 
-  DEFSYM (Qmouse_left, "mouse-left");
-  DEFSYM (Qmouse_entered, "mouse-entered");
   DEFSYM (Qpoint_left, "point-left");
   DEFSYM (Qpoint_entered, "point-entered");