]> code.delx.au - gnu-emacs/blobdiff - src/textprop.c
(Fmake_network_process): Only support server sockets
[gnu-emacs] / src / textprop.c
index 5bbd7ffd92ae5322ae0951723709706008afd0fc..401e26f1a30d530dea046199f43bdeca84d74a12 100644 (file)
@@ -1,5 +1,5 @@
 /* Interface code for dealing with text properties.
 /* Interface code for dealing with text properties.
-   Copyright (C) 1993, 1994, 1995, 1997, 1999, 2000, 2001
+   Copyright (C) 1993, 1994, 1995, 1997, 1999, 2000, 2001, 2002
    Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
    Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
@@ -123,9 +123,9 @@ validate_interval_range (object, begin, end, force)
   register INTERVAL i;
   int searchpos;
 
   register INTERVAL i;
   int searchpos;
 
-  CHECK_STRING_OR_BUFFER (object, 0);
-  CHECK_NUMBER_COERCE_MARKER (*begin, 0);
-  CHECK_NUMBER_COERCE_MARKER (*end, 0);
+  CHECK_STRING_OR_BUFFER (object);
+  CHECK_NUMBER_COERCE_MARKER (*begin);
+  CHECK_NUMBER_COERCE_MARKER (*end);
 
   /* If we are asked for a point, but from a subr which operates
      on a range, then return nothing.  */
 
   /* If we are asked for a point, but from a subr which operates
      on a range, then return nothing.  */
@@ -268,6 +268,30 @@ interval_has_some_properties (plist, i)
 
   return 0;
 }
 
   return 0;
 }
+
+/* Return nonzero if the plist of interval I has any of the
+   property names in LIST, regardless of their values.  */
+
+static INLINE int
+interval_has_some_properties_list (list, i)
+     Lisp_Object list;
+     INTERVAL i;
+{
+  register Lisp_Object tail1, tail2, sym;
+
+  /* Go through each element of LIST.  */
+  for (tail1 = list; ! NILP (tail1); tail1 = XCDR (tail1))
+    {
+      sym = Fcar (tail1);
+
+      /* Go through i's plist, looking for tail1 */
+      for (tail2 = i->plist; ! NILP (tail2); tail2 = XCDR (XCDR (tail2)))
+       if (EQ (sym, XCAR (tail2)))
+         return 1;
+    }
+
+  return 0;
+}
 \f
 /* Changing the plists of individual intervals.  */
 
 \f
 /* Changing the plists of individual intervals.  */
 
@@ -414,58 +438,69 @@ add_properties (plist, i, object)
   return changed;
 }
 
   return changed;
 }
 
-/* For any members of PLIST which are properties of I, remove them
-   from I's plist.
+/* For any members of PLIST, or LIST,
+   which are properties of I, remove them from I's plist.
+   (If PLIST is non-nil, use that, otherwise use LIST.)
    OBJECT is the string or buffer containing I.  */
 
 static int
    OBJECT is the string or buffer containing I.  */
 
 static int
-remove_properties (plist, i, object)
-     Lisp_Object plist;
+remove_properties (plist, list, i, object)
+     Lisp_Object plist, list;
      INTERVAL i;
      Lisp_Object object;
 {
   register Lisp_Object tail1, tail2, sym, current_plist;
   register int changed = 0;
 
      INTERVAL i;
      Lisp_Object object;
 {
   register Lisp_Object tail1, tail2, sym, current_plist;
   register int changed = 0;
 
+  /* Nonzero means tail1 is a plist, otherwise it is a list.  */
+  int use_plist;
+
   current_plist = i->plist;
   current_plist = i->plist;
-  /* Go through each element of plist.  */
-  for (tail1 = plist; ! NILP (tail1); tail1 = Fcdr (Fcdr (tail1)))
+
+  if (! NILP (plist))
+    tail1 = plist, use_plist = 1;
+  else
+    tail1 = list, use_plist = 0;
+
+  /* Go through each element of LIST or PLIST.  */
+  while (CONSP (tail1))
     {
     {
-      sym = Fcar (tail1);
+      sym = XCAR (tail1);
 
 
-      /* First, remove the symbol if its at the head of the list */
-      while (! NILP (current_plist) && EQ (sym, Fcar (current_plist)))
+      /* First, remove the symbol if it's at the head of the list */
+      while (CONSP (current_plist) && EQ (sym, XCAR (current_plist)))
        {
          if (BUFFERP (object))
        {
          if (BUFFERP (object))
-           {
-             record_property_change (i->position, LENGTH (i),
-                                     sym, Fcar (Fcdr (current_plist)),
-                                     object);
-           }
+           record_property_change (i->position, LENGTH (i),
+                                   sym, XCAR (XCDR (current_plist)),
+                                   object);
 
 
-         current_plist = Fcdr (Fcdr (current_plist));
+         current_plist = XCDR (XCDR (current_plist));
          changed++;
        }
 
          changed++;
        }
 
-      /* Go through i's plist, looking for sym */
+      /* Go through I's plist, looking for SYM.  */
       tail2 = current_plist;
       while (! NILP (tail2))
        {
          register Lisp_Object this;
       tail2 = current_plist;
       while (! NILP (tail2))
        {
          register Lisp_Object this;
-         this = Fcdr (Fcdr (tail2));
-         if (EQ (sym, Fcar (this)))
+         this = XCDR (XCDR (tail2));
+         if (CONSP (this) && EQ (sym, XCAR (this)))
            {
              if (BUFFERP (object))
            {
              if (BUFFERP (object))
-               {
-                 record_property_change (i->position, LENGTH (i),
-                                         sym, Fcar (Fcdr (this)), object);
-               }
+               record_property_change (i->position, LENGTH (i),
+                                       sym, XCAR (XCDR (this)), object);
 
 
-             Fsetcdr (Fcdr (tail2), Fcdr (Fcdr (this)));
+             Fsetcdr (XCDR (tail2), XCDR (XCDR (this)));
              changed++;
            }
          tail2 = this;
        }
              changed++;
            }
          tail2 = this;
        }
+
+      /* Advance thru TAIL1 one way or the other.  */
+      tail1 = XCDR (tail1);
+      if (use_plist && CONSP (tail1))
+       tail1 = XCDR (tail1);
     }
 
   if (changed)
     }
 
   if (changed)
@@ -505,7 +540,7 @@ interval_of (position, object)
   else if (EQ (object, Qt))
     return NULL_INTERVAL;
 
   else if (EQ (object, Qt))
     return NULL_INTERVAL;
 
-  CHECK_STRING_OR_BUFFER (object, 0);
+  CHECK_STRING_OR_BUFFER (object);
 
   if (BUFFERP (object))
     {
 
   if (BUFFERP (object))
     {
@@ -534,11 +569,11 @@ interval_of (position, object)
 \f
 DEFUN ("text-properties-at", Ftext_properties_at,
        Stext_properties_at, 1, 2, 0,
 \f
 DEFUN ("text-properties-at", Ftext_properties_at,
        Stext_properties_at, 1, 2, 0,
-  "Return the list of properties of the character at POSITION in OBJECT.\n\
-OBJECT is the string or buffer to look for the properties in;\n\
-nil means the current buffer.\n\
-If POSITION is at the end of OBJECT, the value is nil.")
-  (position, object)
+       doc: /* Return the list of properties of the character at POSITION in OBJECT.
+OBJECT is the string or buffer to look for the properties in;
+nil means the current buffer.
+If POSITION is at the end of OBJECT, the value is nil.  */)
+     (position, object)
      Lisp_Object position, object;
 {
   register INTERVAL i;
      Lisp_Object position, object;
 {
   register INTERVAL i;
@@ -560,10 +595,10 @@ If POSITION is at the end of OBJECT, the value is nil.")
 }
 
 DEFUN ("get-text-property", Fget_text_property, Sget_text_property, 2, 3, 0,
 }
 
 DEFUN ("get-text-property", Fget_text_property, Sget_text_property, 2, 3, 0,
-  "Return the value of POSITION's property PROP, in OBJECT.\n\
-OBJECT is optional and defaults to the current buffer.\n\
-If POSITION is at the end of OBJECT, the value is nil.")
-  (position, prop, object)
+       doc: /* Return the value of POSITION's property PROP, in OBJECT.
+OBJECT is optional and defaults to the current buffer.
+If POSITION is at the end of OBJECT, the value is nil.  */)
+     (position, prop, object)
      Lisp_Object position, object;
      Lisp_Object prop;
 {
      Lisp_Object position, object;
      Lisp_Object prop;
 {
@@ -589,7 +624,7 @@ get_char_property_and_overlay (position, prop, object, overlay)
 {
   struct window *w = 0;
 
 {
   struct window *w = 0;
 
-  CHECK_NUMBER_COERCE_MARKER (position, 0);
+  CHECK_NUMBER_COERCE_MARKER (position);
 
   if (NILP (object))
     XSETBUFFER (object, current_buffer);
 
   if (NILP (object))
     XSETBUFFER (object, current_buffer);
@@ -654,14 +689,15 @@ get_char_property_and_overlay (position, prop, object, overlay)
 }
 
 DEFUN ("get-char-property", Fget_char_property, Sget_char_property, 2, 3, 0,
 }
 
 DEFUN ("get-char-property", Fget_char_property, Sget_char_property, 2, 3, 0,
-  "Return the value of POSITION's property PROP, in OBJECT.\n\
-OBJECT is optional and defaults to the current buffer.\n\
-If POSITION is at the end of OBJECT, the value is nil.\n\
-If OBJECT is a buffer, then overlay properties are considered as well as\n\
-text properties.\n\
-If OBJECT is a window, then that window's buffer is used, but window-specific\n\
-overlays are considered only if they are associated with OBJECT.")
-  (position, prop, object)
+       doc: /* Return the value of POSITION's property PROP, in OBJECT.
+Both overlay properties and text properties are checked.
+OBJECT is optional and defaults to the current buffer.
+If POSITION is at the end of OBJECT, the value is nil.
+If OBJECT is a buffer, then overlay properties are considered as well as
+text properties.
+If OBJECT is a window, then that window's buffer is used, but window-specific
+overlays are considered only if they are associated with OBJECT.  */)
+     (position, prop, object)
      Lisp_Object position, object;
      register Lisp_Object prop;
 {
      Lisp_Object position, object;
      register Lisp_Object prop;
 {
@@ -670,15 +706,15 @@ overlays are considered only if they are associated with OBJECT.")
 \f
 DEFUN ("next-char-property-change", Fnext_char_property_change,
        Snext_char_property_change, 1, 2, 0,
 \f
 DEFUN ("next-char-property-change", Fnext_char_property_change,
        Snext_char_property_change, 1, 2, 0,
-  "Return the position of next text property or overlay change.\n\
-This scans characters forward from POSITION in OBJECT till it finds\n\
-a change in some text property, or the beginning or end of an overlay,\n\
-and returns the position of that.\n\
-If none is found, the function returns (point-max).\n\
-\n\
-If the optional third argument LIMIT is non-nil, don't search\n\
-past position LIMIT; return LIMIT if nothing is found before LIMIT.")
-  (position, limit)
+       doc: /* Return the position of next text property or overlay change.
+This scans characters forward 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, the function returns (point-max).
+
+If the optional third argument LIMIT is non-nil, don't search
+past position LIMIT; return LIMIT if nothing is found before LIMIT.  */)
+     (position, limit)
      Lisp_Object position, limit;
 {
   Lisp_Object temp;
      Lisp_Object position, limit;
 {
   Lisp_Object temp;
@@ -686,7 +722,7 @@ past position LIMIT; return LIMIT if nothing is found before LIMIT.")
   temp = Fnext_overlay_change (position);
   if (! NILP (limit))
     {
   temp = Fnext_overlay_change (position);
   if (! NILP (limit))
     {
-      CHECK_NUMBER (limit, 2);
+      CHECK_NUMBER (limit);
       if (XINT (limit) < XINT (temp))
        temp = limit;
     }
       if (XINT (limit) < XINT (temp))
        temp = limit;
     }
@@ -695,15 +731,15 @@ past position LIMIT; return LIMIT if nothing is found before LIMIT.")
 
 DEFUN ("previous-char-property-change", Fprevious_char_property_change,
        Sprevious_char_property_change, 1, 2, 0,
 
 DEFUN ("previous-char-property-change", Fprevious_char_property_change,
        Sprevious_char_property_change, 1, 2, 0,
-  "Return the position of previous text property or overlay change.\n\
-Scans characters backward from POSITION in OBJECT till it finds\n\
-a change in some text property, or the beginning or end of an overlay,\n\
-and returns the position of that.\n\
-If none is found, the function returns (point-max).\n\
-\n\
-If the optional third argument LIMIT is non-nil, don't search\n\
-past position LIMIT; return LIMIT if nothing is found before LIMIT.")
-  (position, limit)
+       doc: /* Return the position of previous text property or overlay change.
+Scans characters backward 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, the function returns (point-max).
+
+If the optional third argument LIMIT is non-nil, don't search
+past position LIMIT; return LIMIT if nothing is found before LIMIT.  */)
+     (position, limit)
      Lisp_Object position, limit;
 {
   Lisp_Object temp;
      Lisp_Object position, limit;
 {
   Lisp_Object temp;
@@ -711,7 +747,7 @@ past position LIMIT; return LIMIT if nothing is found before LIMIT.")
   temp = Fprevious_overlay_change (position);
   if (! NILP (limit))
     {
   temp = Fprevious_overlay_change (position);
   if (! NILP (limit))
     {
-      CHECK_NUMBER (limit, 2);
+      CHECK_NUMBER (limit);
       if (XINT (limit) > XINT (temp))
        temp = limit;
     }
       if (XINT (limit) > XINT (temp))
        temp = limit;
     }
@@ -721,16 +757,16 @@ past position LIMIT; return LIMIT if nothing is found before LIMIT.")
 
 DEFUN ("next-single-char-property-change", Fnext_single_char_property_change,
        Snext_single_char_property_change, 2, 4, 0,
 
 DEFUN ("next-single-char-property-change", Fnext_single_char_property_change,
        Snext_single_char_property_change, 2, 4, 0,
-  "Return the position of next text property or overlay change for a specific property.\n\
-Scans characters forward from POSITION till it finds\n\
-a change in the PROP property, then returns the position of the change.\n\
-The optional third argument OBJECT is the string or buffer to scan.\n\
-The property values are compared with `eq'.\n\
-If the property is constant all the way to the end of OBJECT, return the\n\
-last valid position in OBJECT.\n\
-If the optional fourth argument LIMIT is non-nil, don't search\n\
-past position LIMIT; return LIMIT if nothing is found before LIMIT.")
-  (position, prop, object, limit)
+       doc: /* Return the position of next text property or overlay change for a specific property.
+Scans characters forward from POSITION till it finds
+a change in the PROP property, then returns the position of the change.
+The optional third argument OBJECT is the string or buffer to scan.
+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.  */)
+     (position, prop, object, limit)
      Lisp_Object prop, position, object, limit;
 {
   if (STRINGP (object))
      Lisp_Object prop, position, object, limit;
 {
   if (STRINGP (object))
@@ -750,7 +786,7 @@ past position LIMIT; return LIMIT if nothing is found before LIMIT.")
       int count = specpdl_ptr - specpdl;
 
       if (! NILP (object))
       int count = specpdl_ptr - specpdl;
 
       if (! NILP (object))
-       CHECK_BUFFER (object, 0);
+       CHECK_BUFFER (object);
       
       if (BUFFERP (object) && current_buffer != XBUFFER (object))
        {
       
       if (BUFFERP (object) && current_buffer != XBUFFER (object))
        {
@@ -763,7 +799,7 @@ past position LIMIT; return LIMIT if nothing is found before LIMIT.")
       if (NILP (limit))
        XSETFASTINT (limit, BUF_ZV (current_buffer));
       else
       if (NILP (limit))
        XSETFASTINT (limit, BUF_ZV (current_buffer));
       else
-       CHECK_NUMBER_COERCE_MARKER (limit, 0);
+       CHECK_NUMBER_COERCE_MARKER (limit);
 
       for (;;)
        {
 
       for (;;)
        {
@@ -787,16 +823,16 @@ past position LIMIT; return LIMIT if nothing is found before LIMIT.")
 DEFUN ("previous-single-char-property-change",
        Fprevious_single_char_property_change,
        Sprevious_single_char_property_change, 2, 4, 0,
 DEFUN ("previous-single-char-property-change",
        Fprevious_single_char_property_change,
        Sprevious_single_char_property_change, 2, 4, 0,
-  "Return the position of previous text property or overlay change for a specific property.\n\
-Scans characters backward from POSITION till it finds\n\
-a change in the PROP property, then returns the position of the change.\n\
-The optional third argument OBJECT is the string or buffer to scan.\n\
-The property values are compared with `eq'.\n\
-If the property is constant all the way to the start of OBJECT, return the\n\
-first valid position in OBJECT.\n\
-If the optional fourth argument LIMIT is non-nil, don't search\n\
-back past position LIMIT; return LIMIT if nothing is found before LIMIT.")
-  (position, prop, object, limit)
+       doc: /* Return the position of previous text property or overlay change for a specific property.
+Scans characters backward from POSITION till it finds
+a change in the PROP property, then returns the position of the change.
+The optional third argument OBJECT is the string or buffer to scan.
+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 LIMIT.  */)
+     (position, prop, object, limit)
      Lisp_Object prop, position, object, limit;
 {
   if (STRINGP (object))
      Lisp_Object prop, position, object, limit;
 {
   if (STRINGP (object))
@@ -815,7 +851,7 @@ back past position LIMIT; return LIMIT if nothing is found before LIMIT.")
       int count = specpdl_ptr - specpdl;
 
       if (! NILP (object))
       int count = specpdl_ptr - specpdl;
 
       if (! NILP (object))
-       CHECK_BUFFER (object, 0);
+       CHECK_BUFFER (object);
       
       if (BUFFERP (object) && current_buffer != XBUFFER (object))
        {
       
       if (BUFFERP (object) && current_buffer != XBUFFER (object))
        {
@@ -826,7 +862,7 @@ back past position LIMIT; return LIMIT if nothing is found before LIMIT.")
       if (NILP (limit))
        XSETFASTINT (limit, BUF_BEGV (current_buffer));
       else
       if (NILP (limit))
        XSETFASTINT (limit, BUF_BEGV (current_buffer));
       else
-       CHECK_NUMBER_COERCE_MARKER (limit, 0);
+       CHECK_NUMBER_COERCE_MARKER (limit);
 
       if (XFASTINT (position) <= XFASTINT (limit))
        position = limit;
 
       if (XFASTINT (position) <= XFASTINT (limit))
        position = limit;
@@ -865,15 +901,16 @@ back past position LIMIT; return LIMIT if nothing is found before LIMIT.")
 \f
 DEFUN ("next-property-change", Fnext_property_change,
        Snext_property_change, 1, 3, 0,
 \f
 DEFUN ("next-property-change", Fnext_property_change,
        Snext_property_change, 1, 3, 0,
-  "Return the position of next property change.\n\
-Scans characters forward from POSITION in OBJECT till it finds\n\
-a change in some text property, then returns the position of the change.\n\
-The optional second argument OBJECT is the string or buffer to scan.\n\
-Return nil if the property is constant all the way to the end of OBJECT.\n\
-If the value is non-nil, it is a position greater than POSITION, never equal.\n\n\
-If the optional third argument LIMIT is non-nil, don't search\n\
-past position LIMIT; return LIMIT if nothing is found before LIMIT.")
-  (position, object, limit)
+       doc: /* Return the position of next property change.
+Scans characters forward from POSITION in OBJECT till it finds
+a change in some text property, then returns the position of the change.
+The optional second argument OBJECT is the string or buffer to scan.
+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.
+
+If the optional third argument LIMIT is non-nil, don't search
+past position LIMIT; return LIMIT if nothing is found before LIMIT.  */)
+     (position, object, limit)
      Lisp_Object position, object, limit;
 {
   register INTERVAL i, next;
      Lisp_Object position, object, limit;
 {
   register INTERVAL i, next;
@@ -881,8 +918,8 @@ past position LIMIT; return LIMIT if nothing is found before LIMIT.")
   if (NILP (object))
     XSETBUFFER (object, current_buffer);
 
   if (NILP (object))
     XSETBUFFER (object, current_buffer);
 
-  if (! NILP (limit) && ! EQ (limit, Qt))
-    CHECK_NUMBER_COERCE_MARKER (limit, 0);
+  if (!NILP (limit) && !EQ (limit, Qt))
+    CHECK_NUMBER_COERCE_MARKER (limit);
 
   i = validate_interval_range (object, &position, &position, soft);
 
 
   i = validate_interval_range (object, &position, &position, soft);
 
@@ -909,13 +946,17 @@ past position LIMIT; return LIMIT if nothing is found before LIMIT.")
 
   next = next_interval (i);
 
 
   next = next_interval (i);
 
-  while (! NULL_INTERVAL_P (next) && intervals_equal (i, next)
+  while (!NULL_INTERVAL_P (next) && intervals_equal (i, next)
         && (NILP (limit) || next->position < XFASTINT (limit)))
     next = next_interval (next);
 
   if (NULL_INTERVAL_P (next))
     return limit;
         && (NILP (limit) || next->position < XFASTINT (limit)))
     next = next_interval (next);
 
   if (NULL_INTERVAL_P (next))
     return limit;
-  if (! NILP (limit) && !(next->position < XFASTINT (limit)))
+  if (NILP (limit))
+    XSETFASTINT (limit, (STRINGP (object)
+                        ? XSTRING (object)->size
+                        : BUF_ZV (XBUFFER (object))));
+  if (!(next->position < XFASTINT (limit)))
     return limit;
 
   XSETFASTINT (position, next->position);
     return limit;
 
   XSETFASTINT (position, next->position);
@@ -956,16 +997,17 @@ property_change_between_p (beg, end)
 
 DEFUN ("next-single-property-change", Fnext_single_property_change,
        Snext_single_property_change, 2, 4, 0,
 
 DEFUN ("next-single-property-change", Fnext_single_property_change,
        Snext_single_property_change, 2, 4, 0,
-  "Return the position of next property change for a specific property.\n\
-Scans characters forward from POSITION till it finds\n\
-a change in the PROP property, then returns the position of the change.\n\
-The optional third argument OBJECT is the string or buffer to scan.\n\
-The property values are compared with `eq'.\n\
-Return nil if the property is constant all the way to the end of OBJECT.\n\
-If the value is non-nil, it is a position greater than POSITION, never equal.\n\n\
-If the optional fourth argument LIMIT is non-nil, don't search\n\
-past position LIMIT; return LIMIT if nothing is found before LIMIT.")
-  (position, prop, object, limit)
+       doc: /* Return the position of next property change for a specific property.
+Scans characters forward from POSITION till it finds
+a change in the PROP property, then returns the position of the change.
+The optional third argument OBJECT is the string or buffer to scan.
+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.
+
+If the optional fourth argument LIMIT is non-nil, don't search
+past position LIMIT; return LIMIT if nothing is found before LIMIT.  */)
+     (position, prop, object, limit)
      Lisp_Object position, prop, object, limit;
 {
   register INTERVAL i, next;
      Lisp_Object position, prop, object, limit;
 {
   register INTERVAL i, next;
@@ -975,7 +1017,7 @@ past position LIMIT; return LIMIT if nothing is found before LIMIT.")
     XSETBUFFER (object, current_buffer);
 
   if (!NILP (limit))
     XSETBUFFER (object, current_buffer);
 
   if (!NILP (limit))
-    CHECK_NUMBER_COERCE_MARKER (limit, 0);
+    CHECK_NUMBER_COERCE_MARKER (limit);
 
   i = validate_interval_range (object, &position, &position, soft);
   if (NULL_INTERVAL_P (i))
 
   i = validate_interval_range (object, &position, &position, soft);
   if (NULL_INTERVAL_P (i))
@@ -990,7 +1032,11 @@ past position LIMIT; return LIMIT if nothing is found before LIMIT.")
 
   if (NULL_INTERVAL_P (next))
     return limit;
 
   if (NULL_INTERVAL_P (next))
     return limit;
-  if (! NILP (limit) && !(next->position < XFASTINT (limit)))
+  if (NILP (limit))
+    XSETFASTINT (limit, (STRINGP (object)
+                        ? XSTRING (object)->size
+                        : BUF_ZV (XBUFFER (object))));
+  if (!(next->position < XFASTINT (limit)))
     return limit;
 
   return make_number (next->position);
     return limit;
 
   return make_number (next->position);
@@ -998,15 +1044,16 @@ past position LIMIT; return LIMIT if nothing is found before LIMIT.")
 
 DEFUN ("previous-property-change", Fprevious_property_change,
        Sprevious_property_change, 1, 3, 0,
 
 DEFUN ("previous-property-change", Fprevious_property_change,
        Sprevious_property_change, 1, 3, 0,
-  "Return the position of previous property change.\n\
-Scans characters backwards from POSITION in OBJECT till it finds\n\
-a change in some text property, then returns the position of the change.\n\
-The optional second argument OBJECT is the string or buffer to scan.\n\
-Return nil if the property is constant all the way to the start of OBJECT.\n\
-If the value is non-nil, it is a position less than POSITION, never equal.\n\n\
-If the optional third argument LIMIT is non-nil, don't search\n\
-back past position LIMIT; return LIMIT if nothing is found until LIMIT.")
-  (position, object, limit)
+       doc: /* Return the position of previous property change.
+Scans characters backwards from POSITION in OBJECT till it finds
+a change in some text property, then returns the position of the change.
+The optional second argument OBJECT is the string or buffer to scan.
+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.
+
+If the optional third argument LIMIT is non-nil, don't search
+back past position LIMIT; return LIMIT if nothing is found until LIMIT.  */)
+     (position, object, limit)
      Lisp_Object position, object, limit;
 {
   register INTERVAL i, previous;
      Lisp_Object position, object, limit;
 {
   register INTERVAL i, previous;
@@ -1015,7 +1062,7 @@ back past position LIMIT; return LIMIT if nothing is found until LIMIT.")
     XSETBUFFER (object, current_buffer);
 
   if (!NILP (limit))
     XSETBUFFER (object, current_buffer);
 
   if (!NILP (limit))
-    CHECK_NUMBER_COERCE_MARKER (limit, 0);
+    CHECK_NUMBER_COERCE_MARKER (limit);
 
   i = validate_interval_range (object, &position, &position, soft);
   if (NULL_INTERVAL_P (i))
 
   i = validate_interval_range (object, &position, &position, soft);
   if (NULL_INTERVAL_P (i))
@@ -1026,14 +1073,15 @@ back past position LIMIT; return LIMIT if nothing is found until LIMIT.")
     i = previous_interval (i);
 
   previous = previous_interval (i);
     i = previous_interval (i);
 
   previous = previous_interval (i);
-  while (! NULL_INTERVAL_P (previous) && intervals_equal (previous, i)
+  while (!NULL_INTERVAL_P (previous) && intervals_equal (previous, i)
         && (NILP (limit)
             || (previous->position + LENGTH (previous) > XFASTINT (limit))))
     previous = previous_interval (previous);
   if (NULL_INTERVAL_P (previous))
     return limit;
         && (NILP (limit)
             || (previous->position + LENGTH (previous) > XFASTINT (limit))))
     previous = previous_interval (previous);
   if (NULL_INTERVAL_P (previous))
     return limit;
-  if (!NILP (limit)
-      && !(previous->position + LENGTH (previous) > XFASTINT (limit)))
+  if (NILP (limit))
+    XSETFASTINT (limit, (STRINGP (object) ? 0 : BUF_BEGV (XBUFFER (object))));
+  if (!(previous->position + LENGTH (previous) > XFASTINT (limit)))
     return limit;
 
   return make_number (previous->position + LENGTH (previous));
     return limit;
 
   return make_number (previous->position + LENGTH (previous));
@@ -1041,15 +1089,16 @@ back past position LIMIT; return LIMIT if nothing is found until LIMIT.")
 
 DEFUN ("previous-single-property-change", Fprevious_single_property_change,
        Sprevious_single_property_change, 2, 4, 0,
 
 DEFUN ("previous-single-property-change", Fprevious_single_property_change,
        Sprevious_single_property_change, 2, 4, 0,
-  "Return the position of previous property change for a specific property.\n\
-Scans characters backward from POSITION till it finds\n\
-a change in the PROP property, then returns the position of the change.\n\
-The optional third argument OBJECT is the string or buffer to scan.\n\
-The property values are compared with `eq'.\n\
-Return nil if the property is constant all the way to the start of OBJECT.\n\
-If the value is non-nil, it is a position less than POSITION, never equal.\n\n\
-If the optional fourth argument LIMIT is non-nil, don't search\n\
-back past position LIMIT; return LIMIT if nothing is found until LIMIT.")
+       doc: /* Return the position of previous property change for a specific property.
+Scans characters backward from POSITION till it finds
+a change in the PROP property, then returns the position of the change.
+The optional third argument OBJECT is the string or buffer to scan.
+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.
+
+If the optional fourth argument LIMIT is non-nil, don't search
+back past position LIMIT; return LIMIT if nothing is found until LIMIT.  */)
      (position, prop, object, limit)
      Lisp_Object position, prop, object, limit;
 {
      (position, prop, object, limit)
      Lisp_Object position, prop, object, limit;
 {
@@ -1060,12 +1109,12 @@ back past position LIMIT; return LIMIT if nothing is found until LIMIT.")
     XSETBUFFER (object, current_buffer);
 
   if (!NILP (limit))
     XSETBUFFER (object, current_buffer);
 
   if (!NILP (limit))
-    CHECK_NUMBER_COERCE_MARKER (limit, 0);
+    CHECK_NUMBER_COERCE_MARKER (limit);
 
   i = validate_interval_range (object, &position, &position, soft);
 
   /* Start with the interval containing the char before point.  */
 
   i = validate_interval_range (object, &position, &position, soft);
 
   /* Start with the interval containing the char before point.  */
-  if (! NULL_INTERVAL_P (i) && i->position == XFASTINT (position))
+  if (!NULL_INTERVAL_P (i) && i->position == XFASTINT (position))
     i = previous_interval (i);
 
   if (NULL_INTERVAL_P (i))
     i = previous_interval (i);
 
   if (NULL_INTERVAL_P (i))
@@ -1073,15 +1122,16 @@ back past position LIMIT; return LIMIT if nothing is found until LIMIT.")
 
   here_val = textget (i->plist, prop);
   previous = previous_interval (i);
 
   here_val = textget (i->plist, prop);
   previous = previous_interval (i);
-  while (! NULL_INTERVAL_P (previous)
+  while (!NULL_INTERVAL_P (previous)
         && EQ (here_val, textget (previous->plist, prop))
         && (NILP (limit)
             || (previous->position + LENGTH (previous) > XFASTINT (limit))))
     previous = previous_interval (previous);
   if (NULL_INTERVAL_P (previous))
     return limit;
         && EQ (here_val, textget (previous->plist, prop))
         && (NILP (limit)
             || (previous->position + LENGTH (previous) > XFASTINT (limit))))
     previous = previous_interval (previous);
   if (NULL_INTERVAL_P (previous))
     return limit;
-  if (!NILP (limit)
-      && !(previous->position + LENGTH (previous) > XFASTINT (limit)))
+  if (NILP (limit))
+    XSETFASTINT (limit, (STRINGP (object) ? 0 : BUF_BEGV (XBUFFER (object))));
+  if (!(previous->position + LENGTH (previous) > XFASTINT (limit)))
     return limit;
 
   return make_number (previous->position + LENGTH (previous));
     return limit;
 
   return make_number (previous->position + LENGTH (previous));
@@ -1091,13 +1141,13 @@ back past position LIMIT; return LIMIT if nothing is found until LIMIT.")
 
 DEFUN ("add-text-properties", Fadd_text_properties,
        Sadd_text_properties, 3, 4, 0,
 
 DEFUN ("add-text-properties", Fadd_text_properties,
        Sadd_text_properties, 3, 4, 0,
-  "Add properties to the text from START to END.\n\
-The third argument PROPERTIES is a property list\n\
-specifying the property values to add.\n\
-The optional fourth argument, OBJECT,\n\
-is the string or buffer containing the text.\n\
-Return t if any property value actually changed, nil otherwise.")
-  (start, end, properties, object)
+       doc: /* Add properties to the text from START to END.
+The third argument PROPERTIES is a property list
+specifying the property values to add.
+The optional fourth argument, OBJECT,
+is the string or buffer containing the text.
+Return t if any property value actually changed, nil otherwise.  */)
+     (start, end, properties, object)
      Lisp_Object start, end, properties, object;
 {
   register INTERVAL i, unchanged;
      Lisp_Object start, end, properties, object;
 {
   register INTERVAL i, unchanged;
@@ -1199,12 +1249,12 @@ Return t if any property value actually changed, nil otherwise.")
 
 DEFUN ("put-text-property", Fput_text_property,
        Sput_text_property, 4, 5, 0,
 
 DEFUN ("put-text-property", Fput_text_property,
        Sput_text_property, 4, 5, 0,
-  "Set one property of the text from START to END.\n\
-The third and fourth arguments PROPERTY and VALUE\n\
-specify the property to add.\n\
-The optional fifth argument, OBJECT,\n\
-is the string or buffer containing the text.")
-  (start, end, property, value, object)
+       doc: /* Set one property of the text from START to END.
+The third and fourth arguments PROPERTY and VALUE
+specify the property to add.
+The optional fifth argument, OBJECT,
+is the string or buffer containing the text.  */)
+     (start, end, property, value, object)
      Lisp_Object start, end, property, value, object;
 {
   Fadd_text_properties (start, end,
      Lisp_Object start, end, property, value, object;
 {
   Fadd_text_properties (start, end,
@@ -1215,14 +1265,14 @@ is the string or buffer containing the text.")
 
 DEFUN ("set-text-properties", Fset_text_properties,
        Sset_text_properties, 3, 4, 0,
 
 DEFUN ("set-text-properties", Fset_text_properties,
        Sset_text_properties, 3, 4, 0,
-  "Completely replace properties of text from START to END.\n\
-The third argument PROPERTIES is the new property list.\n\
-The optional fourth argument, OBJECT,\n\
-is the string or buffer containing the text.\n\
-If OBJECT is omitted or nil, it defaults to the current buffer.\n\
-If PROPERTIES is nil, the effect is to remove all properties from\n\
-the designated part of OBJECT.")
-  (start, end, properties, object)
+       doc: /* Completely replace properties of text from START to END.
+The third argument PROPERTIES is the new property list.
+The optional fourth argument, OBJECT,
+is the string or buffer containing the text.
+If OBJECT is omitted or nil, it defaults to the current buffer.
+If PROPERTIES is nil, the effect is to remove all properties from
+the designated part of OBJECT.  */)
+     (start, end, properties, object)
      Lisp_Object start, end, properties, object;
 {
   return set_text_properties (start, end, properties, object, Qt);
      Lisp_Object start, end, properties, object;
 {
   return set_text_properties (start, end, properties, object, Qt);
@@ -1240,9 +1290,7 @@ Lisp_Object
 set_text_properties (start, end, properties, object, signal_after_change_p)
      Lisp_Object start, end, properties, object, signal_after_change_p;
 {
 set_text_properties (start, end, properties, object, signal_after_change_p)
      Lisp_Object start, end, properties, object, signal_after_change_p;
 {
-  register INTERVAL i, unchanged;
-  register INTERVAL prev_changed = NULL_INTERVAL;
-  register int s, len;
+  register INTERVAL i;
   Lisp_Object ostart, oend;
 
   ostart = start;
   Lisp_Object ostart, oend;
 
   ostart = start;
@@ -1285,11 +1333,45 @@ set_text_properties (start, end, properties, object, signal_after_change_p)
        return Qnil;
     }
 
        return Qnil;
     }
 
+  if (BUFFERP (object))
+    modify_region (XBUFFER (object), XINT (start), XINT (end));
+
+  set_text_properties_1 (start, end, properties, object, i);
+
+  if (BUFFERP (object) && !NILP (signal_after_change_p))
+    signal_after_change (XINT (start), XINT (end) - XINT (start),
+                        XINT (end) - XINT (start));
+  return Qt;
+}
+
+/* Replace properties of text from START to END with new list of
+   properties PROPERTIES.  BUFFER is the buffer containing
+   the text.  This does not obey any hooks.
+   You can provide the interval that START is located in as I,
+   or pass NULL for I and this function will find it.
+   START and END can be in any order.  */
+
+void
+set_text_properties_1 (start, end, properties, buffer, i)
+     Lisp_Object start, end, properties, buffer;
+     INTERVAL i;
+{
+  register INTERVAL prev_changed = NULL_INTERVAL;
+  register int s, len;
+  INTERVAL unchanged;
+
   s = XINT (start);
   len = XINT (end) - s;
   s = XINT (start);
   len = XINT (end) - s;
+  if (len == 0)
+    return;
+  if (len < 0)
+    {
+      s = s + len;
+      len = - len;
+    }
 
 
-  if (BUFFERP (object))
-    modify_region (XBUFFER (object), XINT (start), XINT (end));
+  if (i == 0)
+    i = find_interval (BUF_INTERVALS (XBUFFER (buffer)), s);
 
   if (i->position != s)
     {
 
   if (i->position != s)
     {
@@ -1300,24 +1382,14 @@ set_text_properties (start, end, properties, object, signal_after_change_p)
        {
          copy_properties (unchanged, i);
          i = split_interval_left (i, len);
        {
          copy_properties (unchanged, i);
          i = split_interval_left (i, len);
-         set_properties (properties, i, object);
-         if (BUFFERP (object) && !NILP (signal_after_change_p))
-           signal_after_change (XINT (start), XINT (end) - XINT (start),
-                                XINT (end) - XINT (start));
-
-         return Qt;
+         set_properties (properties, i, buffer);
+         return;
        }
 
        }
 
-      set_properties (properties, i, object);
+      set_properties (properties, i, buffer);
 
       if (LENGTH (i) == len)
 
       if (LENGTH (i) == len)
-       {
-         if (BUFFERP (object) && !NILP (signal_after_change_p))
-           signal_after_change (XINT (start), XINT (end) - XINT (start),
-                                XINT (end) - XINT (start));
-
-         return Qt;
-       }
+       return;
 
       prev_changed = i;
       len -= LENGTH (i);
 
       prev_changed = i;
       len -= LENGTH (i);
@@ -1338,13 +1410,10 @@ set_text_properties (start, end, properties, object, signal_after_change_p)
          /* We have to call set_properties even if we are going to
             merge the intervals, so as to make the undo records
             and cause redisplay to happen.  */
          /* We have to call set_properties even if we are going to
             merge the intervals, so as to make the undo records
             and cause redisplay to happen.  */
-         set_properties (properties, i, object);
+         set_properties (properties, i, buffer);
          if (!NULL_INTERVAL_P (prev_changed))
            merge_interval_left (i);
          if (!NULL_INTERVAL_P (prev_changed))
            merge_interval_left (i);
-         if (BUFFERP (object) && !NILP (signal_after_change_p))
-           signal_after_change (XINT (start), XINT (end) - XINT (start),
-                                XINT (end) - XINT (start));
-         return Qt;
+         return;
        }
 
       len -= LENGTH (i);
        }
 
       len -= LENGTH (i);
@@ -1352,7 +1421,7 @@ set_text_properties (start, end, properties, object, signal_after_change_p)
       /* We have to call set_properties even if we are going to
         merge the intervals, so as to make the undo records
         and cause redisplay to happen.  */
       /* We have to call set_properties even if we are going to
         merge the intervals, so as to make the undo records
         and cause redisplay to happen.  */
-      set_properties (properties, i, object);
+      set_properties (properties, i, buffer);
       if (NULL_INTERVAL_P (prev_changed))
        prev_changed = i;
       else
       if (NULL_INTERVAL_P (prev_changed))
        prev_changed = i;
       else
@@ -1360,23 +1429,18 @@ set_text_properties (start, end, properties, object, signal_after_change_p)
 
       i = next_interval (i);
     }
 
       i = next_interval (i);
     }
-
-  if (BUFFERP (object) && !NILP (signal_after_change_p))
-    signal_after_change (XINT (start), XINT (end) - XINT (start),
-                        XINT (end) - XINT (start));
-  return Qt;
 }
 
 DEFUN ("remove-text-properties", Fremove_text_properties,
        Sremove_text_properties, 3, 4, 0,
 }
 
 DEFUN ("remove-text-properties", Fremove_text_properties,
        Sremove_text_properties, 3, 4, 0,
-  "Remove some properties from text from START to END.\n\
-The third argument PROPERTIES is a property list\n\
-whose property names specify the properties to remove.\n\
-\(The values stored in PROPERTIES are ignored.)\n\
-The optional fourth argument, OBJECT,\n\
-is the string or buffer containing the text.\n\
-Return t if any property was actually removed, nil otherwise.")
-  (start, end, properties, object)
+       doc: /* Remove some properties from text from START to END.
+The third argument PROPERTIES is a property list
+whose property names specify the properties to remove.
+\(The values stored in PROPERTIES are ignored.)
+The optional fourth argument, OBJECT,
+is the string or buffer containing the text.
+Return t if any property was actually removed, nil otherwise.  */)
+     (start, end, properties, object)
      Lisp_Object start, end, properties, object;
 {
   register INTERVAL i, unchanged;
      Lisp_Object start, end, properties, object;
 {
   register INTERVAL i, unchanged;
@@ -1430,7 +1494,94 @@ Return t if any property was actually removed, nil otherwise.")
 
          if (LENGTH (i) == len)
            {
 
          if (LENGTH (i) == len)
            {
-             remove_properties (properties, i, object);
+             remove_properties (properties, Qnil, i, object);
+             if (BUFFERP (object))
+               signal_after_change (XINT (start), XINT (end) - XINT (start),
+                                    XINT (end) - XINT (start));
+             return Qt;
+           }
+
+         /* i has the properties, and goes past the change limit */
+         unchanged = i;
+         i = split_interval_left (i, len);
+         copy_properties (unchanged, i);
+         remove_properties (properties, Qnil, i, object);
+         if (BUFFERP (object))
+           signal_after_change (XINT (start), XINT (end) - XINT (start),
+                                XINT (end) - XINT (start));
+         return Qt;
+       }
+
+      len -= LENGTH (i);
+      modified += remove_properties (properties, Qnil, i, object);
+      i = next_interval (i);
+    }
+}
+
+DEFUN ("remove-list-of-text-properties", Fremove_list_of_text_properties,
+       Sremove_list_of_text_properties, 3, 4, 0,
+       doc: /* Remove some properties from text from START to END.
+The third argument LIST-OF-PROPERTIES is a list of property names to remove.
+The optional fourth argument, OBJECT,
+is the string or buffer containing the text, defaulting to the current buffer.
+Return t if any property was actually removed, nil otherwise.  */)
+     (start, end, list_of_properties, object)
+     Lisp_Object start, end, list_of_properties, object;
+{
+  register INTERVAL i, unchanged;
+  register int s, len, modified = 0;
+  Lisp_Object properties;
+  properties = list_of_properties;
+
+  if (NILP (object))
+    XSETBUFFER (object, current_buffer);
+
+  i = validate_interval_range (object, &start, &end, soft);
+  if (NULL_INTERVAL_P (i))
+    return Qnil;
+
+  s = XINT (start);
+  len = XINT (end) - s;
+
+  if (i->position != s)
+    {
+      /* No properties on this first interval -- return if
+         it covers the entire region.  */
+      if (! interval_has_some_properties_list (properties, i))
+       {
+         int got = (LENGTH (i) - (s - i->position));
+         if (got >= len)
+           return Qnil;
+         len -= got;
+         i = next_interval (i);
+       }
+      /* Split away the beginning of this interval; what we don't
+        want to modify.  */
+      else
+       {
+         unchanged = i;
+         i = split_interval_right (unchanged, s - unchanged->position);
+         copy_properties (unchanged, i);
+       }
+    }
+
+  if (BUFFERP (object))
+    modify_region (XBUFFER (object), XINT (start), XINT (end));
+
+  /* We are at the beginning of an interval, with len to scan */
+  for (;;)
+    {
+      if (i == 0)
+       abort ();
+
+      if (LENGTH (i) >= len)
+       {
+         if (! interval_has_some_properties_list (properties, i))
+           return modified ? Qt : Qnil;
+
+         if (LENGTH (i) == len)
+           {
+             remove_properties (Qnil, properties, i, object);
              if (BUFFERP (object))
                signal_after_change (XINT (start), XINT (end) - XINT (start),
                                     XINT (end) - XINT (start));
              if (BUFFERP (object))
                signal_after_change (XINT (start), XINT (end) - XINT (start),
                                     XINT (end) - XINT (start));
@@ -1441,7 +1592,7 @@ Return t if any property was actually removed, nil otherwise.")
          unchanged = i;
          i = split_interval_left (i, len);
          copy_properties (unchanged, i);
          unchanged = i;
          i = split_interval_left (i, len);
          copy_properties (unchanged, i);
-         remove_properties (properties, i, object);
+         remove_properties (Qnil, properties, i, object);
          if (BUFFERP (object))
            signal_after_change (XINT (start), XINT (end) - XINT (start),
                                 XINT (end) - XINT (start));
          if (BUFFERP (object))
            signal_after_change (XINT (start), XINT (end) - XINT (start),
                                 XINT (end) - XINT (start));
@@ -1449,20 +1600,20 @@ Return t if any property was actually removed, nil otherwise.")
        }
 
       len -= LENGTH (i);
        }
 
       len -= LENGTH (i);
-      modified += remove_properties (properties, i, object);
+      modified += remove_properties (Qnil, properties, i, object);
       i = next_interval (i);
     }
 }
 \f
 DEFUN ("text-property-any", Ftext_property_any,
        Stext_property_any, 4, 5, 0,
       i = next_interval (i);
     }
 }
 \f
 DEFUN ("text-property-any", Ftext_property_any,
        Stext_property_any, 4, 5, 0,
-  "Check text from START to END for property PROPERTY equalling VALUE.\n\
-If so, return the position of the first character whose property PROPERTY\n\
-is `eq' to VALUE.  Otherwise return nil.\n\
-The optional fifth argument, OBJECT, is the string or buffer\n\
-containing the text.")
-  (start, end, property, value, object)
-       Lisp_Object start, end, property, value, object;
+       doc: /* Check text from START to END for property PROPERTY equalling VALUE.
+If so, return the position of the first character whose property PROPERTY
+is `eq' to VALUE.  Otherwise return nil.
+The optional fifth argument, OBJECT, is the string or buffer
+containing the text.  */)
+     (start, end, property, value, object)
+     Lisp_Object start, end, property, value, object;
 {
   register INTERVAL i;
   register int e, pos;
 {
   register INTERVAL i;
   register int e, pos;
@@ -1492,13 +1643,13 @@ containing the text.")
 
 DEFUN ("text-property-not-all", Ftext_property_not_all,
        Stext_property_not_all, 4, 5, 0,
 
 DEFUN ("text-property-not-all", Ftext_property_not_all,
        Stext_property_not_all, 4, 5, 0,
-  "Check text from START to END for property PROPERTY not equalling VALUE.\n\
-If so, return the position of the first character whose property PROPERTY\n\
-is not `eq' to VALUE.  Otherwise, return nil.\n\
-The optional fifth argument, OBJECT, is the string or buffer\n\
-containing the text.")
-  (start, end, property, value, object)
-       Lisp_Object start, end, property, value, object;
+       doc: /* Check text from START to END for property PROPERTY not equalling VALUE.
+If so, return the position of the first character whose property PROPERTY
+is not `eq' to VALUE.  Otherwise, return nil.
+The optional fifth argument, OBJECT, is the string or buffer
+containing the text.  */)
+     (start, end, property, value, object)
+     Lisp_Object start, end, property, value, object;
 {
   register INTERVAL i;
   register int s, e;
 {
   register INTERVAL i;
   register int s, e;
@@ -1525,6 +1676,63 @@ containing the text.")
     }
   return Qnil;
 }
     }
   return Qnil;
 }
+
+\f
+/* Return the direction from which the text-property PROP would be
+   inherited by any new text inserted at POS: 1 if it would be
+   inherited from the char after POS, -1 if it would be inherited from
+   the char before POS, and 0 if from neither.  */
+
+int
+text_property_stickiness (prop, pos)
+     Lisp_Object prop;
+     Lisp_Object pos;
+{
+  Lisp_Object prev_pos, front_sticky;
+  int is_rear_sticky = 1, is_front_sticky = 0; /* defaults */
+
+  if (XINT (pos) > BEGV)
+    /* Consider previous character.  */
+    {
+      Lisp_Object rear_non_sticky;
+
+      prev_pos = make_number (XINT (pos) - 1);
+      rear_non_sticky = Fget_text_property (prev_pos, Qrear_nonsticky, Qnil);
+
+      if (!NILP (CONSP (rear_non_sticky)
+                ? Fmemq (prop, rear_non_sticky)
+                : rear_non_sticky))
+       /* PROP is rear-non-sticky.  */
+       is_rear_sticky = 0;
+    }
+
+  /* Consider following character.  */
+  front_sticky = Fget_text_property (pos, Qfront_sticky, Qnil);
+
+  if (EQ (front_sticky, Qt)
+      || (CONSP (front_sticky)
+         && !NILP (Fmemq (prop, front_sticky))))
+    /* PROP is inherited from after.  */
+    is_front_sticky = 1;
+
+  /* Simple cases, where the properties are consistent.  */
+  if (is_rear_sticky && !is_front_sticky)
+    return -1;
+  else if (!is_rear_sticky && is_front_sticky)
+    return 1;
+  else if (!is_rear_sticky && !is_front_sticky)
+    return 0;
+
+  /* The stickiness properties are inconsistent, so we have to
+     disambiguate.  Basically, rear-sticky wins, _except_ if the
+     property that would be inherited has a value of nil, in which case
+     front-sticky wins.  */
+  if (XINT (pos) == BEGV || NILP (Fget_text_property (prev_pos, prop, Qnil)))
+    return 1;
+  else
+    return -1;
+}
+
 \f
 /* I don't think this is the right interface to export; how often do you
    want to do something like this, other than when you're copying objects
 \f
 /* I don't think this is the right interface to export; how often do you
    want to do something like this, other than when you're copying objects
@@ -1557,7 +1765,7 @@ copy_text_properties (start, end, src, pos, dest, prop)
   if (NULL_INTERVAL_P (i))
     return Qnil;
 
   if (NULL_INTERVAL_P (i))
     return Qnil;
 
-  CHECK_NUMBER_COERCE_MARKER (pos, 0);
+  CHECK_NUMBER_COERCE_MARKER (pos);
   {
     Lisp_Object dest_start, dest_end;
 
   {
     Lisp_Object dest_start, dest_end;
 
@@ -1738,7 +1946,7 @@ extend_property_ranges (list, old_end, new_end)
       end = XCAR (XCDR (item));
 
       if (EQ (end, old_end))
       end = XCAR (XCDR (item));
 
       if (EQ (end, old_end))
-       XCAR (XCDR (item)) = new_end;
+       XSETCAR (XCDR (item), new_end);
     }
 }
 
     }
 }
 
@@ -1964,25 +2172,25 @@ void
 syms_of_textprop ()
 {
   DEFVAR_LISP ("default-text-properties", &Vdefault_text_properties,
 syms_of_textprop ()
 {
   DEFVAR_LISP ("default-text-properties", &Vdefault_text_properties,
-   "Property-list used as default values.\n\
-The value of a property in this list is seen as the value for every\n\
-character that does not have its own value for that property.");
+              doc: /* Property-list used as default values.
+The value of a property in this list is seen as the value for every
+character that does not have its own value for that property.  */);
   Vdefault_text_properties = Qnil;
 
   DEFVAR_LISP ("inhibit-point-motion-hooks", &Vinhibit_point_motion_hooks,
   Vdefault_text_properties = Qnil;
 
   DEFVAR_LISP ("inhibit-point-motion-hooks", &Vinhibit_point_motion_hooks,
-   "If non-nil, don't run `point-left' and `point-entered' text properties.\n\
-This also inhibits the use of the `intangible' text property.");
+              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;
 
   DEFVAR_LISP ("text-property-default-nonsticky",
               &Vtext_property_default_nonsticky,
   Vinhibit_point_motion_hooks = Qnil;
 
   DEFVAR_LISP ("text-property-default-nonsticky",
               &Vtext_property_default_nonsticky,
-    "Alist of properties vs the corresponding non-stickinesses.\n\
-Each element has the form (PROPERTY . NONSTICKINESS).\n\
-\n\
-If a character in a buffer has PROPERTY, new text inserted adjacent to\n\
-the character doesn't inherit PROPERTY if NONSTICKINESS is non-nil,\n\
-inherits it if NONSTICKINESS is nil.  The front-sticky and\n\
-rear-nonsticky properties of the character overrides NONSTICKINESS.");
+              doc: /* Alist of properties vs the corresponding non-stickinesses.
+Each element has the form (PROPERTY . NONSTICKINESS).
+
+If a character in a buffer has PROPERTY, new text inserted adjacent to
+the character doesn't inherit PROPERTY if NONSTICKINESS is non-nil,
+inherits it if NONSTICKINESS is nil.  The front-sticky and
+rear-nonsticky properties of the character overrides NONSTICKINESS.  */);
   Vtext_property_default_nonsticky = Qnil;
 
   staticpro (&interval_insert_behind_hooks);
   Vtext_property_default_nonsticky = Qnil;
 
   staticpro (&interval_insert_behind_hooks);
@@ -2046,6 +2254,7 @@ rear-nonsticky properties of the character overrides NONSTICKINESS.");
   defsubr (&Sput_text_property);
   defsubr (&Sset_text_properties);
   defsubr (&Sremove_text_properties);
   defsubr (&Sput_text_property);
   defsubr (&Sset_text_properties);
   defsubr (&Sremove_text_properties);
+  defsubr (&Sremove_list_of_text_properties);
   defsubr (&Stext_property_any);
   defsubr (&Stext_property_not_all);
 /*  defsubr (&Serase_text_properties); */
   defsubr (&Stext_property_any);
   defsubr (&Stext_property_not_all);
 /*  defsubr (&Serase_text_properties); */