]> code.delx.au - gnu-emacs/blobdiff - src/textprop.c
Replace conditional (require 'ispell) with defvar.
[gnu-emacs] / src / textprop.c
index 3e742476a12320df9314f6d394f6c63c09e149b9..a039c17ae6479137aef85284beb2e2698473dc99 100644 (file)
@@ -1,6 +1,6 @@
 /* Interface code for dealing with text properties.
-   Copyright (C) 1993, 1994, 1995, 1997, 1999, 2000, 2001, 2002
-   Free Software Foundation, Inc.
+   Copyright (C) 1993, 1994, 1995, 1997, 1999, 2000, 2001, 2002, 2003,
+                 2004, 2005, 2006 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -16,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.  */
 
 #include <config.h>
 #include "lisp.h"
@@ -78,14 +78,20 @@ Lisp_Object Vtext_property_default_nonsticky;
 Lisp_Object interval_insert_behind_hooks;
 Lisp_Object interval_insert_in_front_hooks;
 
+static void text_read_only P_ ((Lisp_Object)) NO_RETURN;
+
 
 /* Signal a `text-read-only' error.  This function makes it easier
    to capture that error in GDB by putting a breakpoint on it.  */
 
 static void
-text_read_only ()
+text_read_only (propval)
+     Lisp_Object propval;
 {
-  Fsignal (Qtext_read_only, Qnil);
+  if (STRINGP (propval))
+    xsignal1 (Qtext_read_only, propval);
+
+  xsignal0 (Qtext_read_only);
 }
 
 
@@ -158,17 +164,17 @@ validate_interval_range (object, begin, end, force)
     }
   else
     {
-      register struct Lisp_String *s = XSTRING (object);
+      int len = SCHARS (object);
 
       if (! (0 <= XINT (*begin) && XINT (*begin) <= XINT (*end)
-            && XINT (*end) <= s->size))
+            && XINT (*end) <= len))
        args_out_of_range (*begin, *end);
       XSETFASTINT (*begin, XFASTINT (*begin));
       if (begin != end)
        XSETFASTINT (*end, XFASTINT (*end));
-      i = s->intervals;
+      i = STRING_INTERVALS (object);
 
-      if (s->size == 0)
+      if (len == 0)
        return NULL_INTERVAL;
 
       searchpos = XINT (*begin);
@@ -176,7 +182,7 @@ validate_interval_range (object, begin, end, force)
 
   if (NULL_INTERVAL_P (i))
     return (force ? create_root_interval (object) : i);
-    
+
   return find_interval (i, searchpos);
 }
 
@@ -525,7 +531,7 @@ erase_properties (i)
 }
 #endif
 \f
-/* Returns the interval of POSITION in OBJECT. 
+/* Returns the interval of POSITION in OBJECT.
    POSITION is BEG-based.  */
 
 INTERVAL
@@ -553,26 +559,25 @@ interval_of (position, object)
     }
   else
     {
-      register struct Lisp_String *s = XSTRING (object);
-
       beg = 0;
-      end = s->size;
-      i = s->intervals;
+      end = SCHARS (object);
+      i = STRING_INTERVALS (object);
     }
 
   if (!(beg <= position && position <= end))
     args_out_of_range (make_number (position), make_number (position));
   if (beg == end || NULL_INTERVAL_P (i))
     return NULL_INTERVAL;
-    
+
   return find_interval (i, position);
 }
 \f
 DEFUN ("text-properties-at", Ftext_properties_at,
        Stext_properties_at, 1, 2, 0,
        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 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.
 If POSITION is at the end of OBJECT, the value is nil.  */)
      (position, object)
      Lisp_Object position, object;
@@ -606,7 +611,7 @@ If POSITION is at the end of OBJECT, the value is nil.  */)
   return textget (Ftext_properties_at (position, object), prop);
 }
 
-/* Return the value of POSITION's property PROP, in OBJECT.
+/* Return the value of char's property PROP, in OBJECT at POSITION.
    OBJECT is optional and defaults to the current buffer.
    If OVERLAY is non-0, then in the case that the returned property is from
    an overlay, the overlay found is returned in *OVERLAY, otherwise nil is
@@ -637,31 +642,13 @@ get_char_property_and_overlay (position, prop, object, overlay)
     }
   if (BUFFERP (object))
     {
-      int posn = XINT (position);
       int noverlays;
-      Lisp_Object *overlay_vec, tem;
-      int next_overlay;
-      int len;
+      Lisp_Object *overlay_vec;
       struct buffer *obuf = current_buffer;
 
       set_buffer_temp (XBUFFER (object));
 
-      /* First try with room for 40 overlays.  */
-      len = 40;
-      overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
-
-      noverlays = overlays_at (posn, 0, &overlay_vec, &len,
-                              &next_overlay, NULL, 0);
-
-      /* If there are more than 40,
-        make enough space for all, and try again.  */
-      if (noverlays > len)
-       {
-         len = noverlays;
-         overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
-         noverlays = overlays_at (posn, 0, &overlay_vec, &len,
-                                  &next_overlay, NULL, 0);
-       }
+      GET_OVERLAYS_AT (XINT (position), overlay_vec, noverlays, NULL, 0);
       noverlays = sort_overlays (overlay_vec, noverlays, w);
 
       set_buffer_temp (obuf);
@@ -669,7 +656,7 @@ get_char_property_and_overlay (position, prop, object, overlay)
       /* Now check the overlays in order of decreasing priority.  */
       while (--noverlays >= 0)
        {
-         tem = Foverlay_get (overlay_vec[noverlays], prop);
+         Lisp_Object tem = Foverlay_get (overlay_vec[noverlays], prop);
          if (!NILP (tem))
            {
              if (overlay)
@@ -704,17 +691,43 @@ overlays are considered only if they are associated with OBJECT.  */)
 {
   return get_char_property_and_overlay (position, prop, object, 0);
 }
+
+DEFUN ("get-char-property-and-overlay", Fget_char_property_and_overlay,
+       Sget_char_property_and_overlay, 2, 3, 0,
+       doc: /* Like `get-char-property', but with extra overlay information.
+The value is a cons cell.  Its car is the return value of `get-char-property'
+with the same arguments--that is, the value of POSITION's property
+PROP in OBJECT.  Its cdr is the overlay in which the property was
+found, or nil, if it was found as a text property or not found at all.
+
+OBJECT is optional and defaults to the current buffer.  OBJECT may be
+a string, a buffer or a window.  For strings, the cdr of the return
+value is always nil, since strings do not have overlays.  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.  If
+POSITION is at the end of OBJECT, both car and cdr are nil.  */)
+     (position, prop, object)
+     Lisp_Object position, object;
+     register Lisp_Object prop;
+{
+  Lisp_Object overlay;
+  Lisp_Object val
+    = get_char_property_and_overlay (position, prop, object, &overlay);
+  return Fcons(val, overlay);
+}
+
 \f
 DEFUN ("next-char-property-change", Fnext_char_property_change,
        Snext_char_property_change, 1, 2, 0,
        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.  */)
+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 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).  */)
      (position, limit)
      Lisp_Object position, limit;
 {
@@ -723,7 +736,7 @@ past position LIMIT; return LIMIT if nothing is found before LIMIT.  */)
   temp = Fnext_overlay_change (position);
   if (! NILP (limit))
     {
-      CHECK_NUMBER (limit);
+      CHECK_NUMBER_COERCE_MARKER (limit);
       if (XINT (limit) < XINT (temp))
        temp = limit;
     }
@@ -733,13 +746,14 @@ 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,
        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.  */)
+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 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).  */)
      (position, limit)
      Lisp_Object position, limit;
 {
@@ -748,7 +762,7 @@ past position LIMIT; return LIMIT if nothing is found before LIMIT.  */)
   temp = Fprevious_overlay_change (position);
   if (! NILP (limit))
     {
-      CHECK_NUMBER (limit);
+      CHECK_NUMBER_COERCE_MARKER (limit);
       if (XINT (limit) > XINT (temp))
        temp = limit;
     }
@@ -761,7 +775,13 @@ DEFUN ("next-single-char-property-change", Fnext_single_char_property_change,
        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.
+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.
+
 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.
@@ -776,9 +796,12 @@ past position LIMIT; return LIMIT if nothing is found before LIMIT.  */)
       if (NILP (position))
        {
          if (NILP (limit))
-           position = make_number (XSTRING (object)->size);
+           position = make_number (SCHARS (object));
          else
-           position = limit;
+           {
+             CHECK_NUMBER (limit);
+             position = limit;
+           }
        }
     }
   else
@@ -788,32 +811,42 @@ past position LIMIT; return LIMIT if nothing is found before LIMIT.  */)
 
       if (! NILP (object))
        CHECK_BUFFER (object);
-      
+
       if (BUFFERP (object) && current_buffer != XBUFFER (object))
        {
          record_unwind_protect (Fset_buffer, Fcurrent_buffer ());
          Fset_buffer (object);
        }
 
+      CHECK_NUMBER_COERCE_MARKER (position);
+
       initial_value = Fget_char_property (position, prop, object);
-      
+
       if (NILP (limit))
-       XSETFASTINT (limit, BUF_ZV (current_buffer));
+       XSETFASTINT (limit, ZV);
       else
        CHECK_NUMBER_COERCE_MARKER (limit);
 
-      for (;;)
+      if (XFASTINT (position) >= XFASTINT (limit))
        {
-         position = Fnext_char_property_change (position, limit);
-         if (XFASTINT (position) >= XFASTINT (limit)) {
-           position = limit;
-           break;
-         }
-
-         value = Fget_char_property (position, prop, object);
-         if (!EQ (value, initial_value))
-           break;
+         position = limit;
+         if (XFASTINT (position) > ZV)
+           XSETFASTINT (position, ZV);
        }
+      else
+       while (1)
+         {
+           position = Fnext_char_property_change (position, limit);
+           if (XFASTINT (position) >= XFASTINT (limit))
+             {
+               position = limit;
+               break;
+             }
+
+           value = Fget_char_property (position, prop, object);
+           if (!EQ (value, initial_value))
+             break;
+         }
 
       unbind_to (count, Qnil);
     }
@@ -827,7 +860,13 @@ DEFUN ("previous-single-char-property-change",
        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.
+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.
+
 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.
@@ -842,9 +881,12 @@ back past position LIMIT; return LIMIT if nothing is found before LIMIT.  */)
       if (NILP (position))
        {
          if (NILP (limit))
-           position = make_number (XSTRING (object)->size);
+           position = make_number (SCHARS (object));
          else
-           position = limit;
+           {
+             CHECK_NUMBER (limit);
+             position = limit;
+           }
        }
     }
   else
@@ -853,27 +895,33 @@ back past position LIMIT; return LIMIT if nothing is found before LIMIT.  */)
 
       if (! NILP (object))
        CHECK_BUFFER (object);
-      
+
       if (BUFFERP (object) && current_buffer != XBUFFER (object))
        {
          record_unwind_protect (Fset_buffer, Fcurrent_buffer ());
          Fset_buffer (object);
        }
-      
+
+      CHECK_NUMBER_COERCE_MARKER (position);
+
       if (NILP (limit))
-       XSETFASTINT (limit, BUF_BEGV (current_buffer));
+       XSETFASTINT (limit, BEGV);
       else
        CHECK_NUMBER_COERCE_MARKER (limit);
 
       if (XFASTINT (position) <= XFASTINT (limit))
-       position = limit;
+       {
+         position = limit;
+         if (XFASTINT (position) < BEGV)
+           XSETFASTINT (position, BEGV);
+       }
       else
        {
-         Lisp_Object initial_value =
-           Fget_char_property (make_number (XFASTINT (position) - 1),
-                               prop, object);
-      
-         for (;;)
+         Lisp_Object initial_value
+           Fget_char_property (make_number (XFASTINT (position) - 1),
+                                 prop, object);
+
+         while (1)
            {
              position = Fprevious_char_property_change (position, limit);
 
@@ -884,9 +932,9 @@ back past position LIMIT; return LIMIT if nothing is found before LIMIT.  */)
                }
              else
                {
-                 Lisp_Object value =
-                   Fget_char_property (make_number (XFASTINT (position) - 1),
-                                       prop, object);
+                 Lisp_Object value
+                   Fget_char_property (make_number (XFASTINT (position) - 1),
+                                         prop, object);
 
                  if (!EQ (value, initial_value))
                    break;
@@ -905,7 +953,9 @@ DEFUN ("next-property-change", Fnext_property_change,
        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.
+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.
 
@@ -932,10 +982,10 @@ past position LIMIT; return LIMIT if nothing is found before LIMIT.  */)
        next = i;
       else
        next = next_interval (i);
-       
+
       if (NULL_INTERVAL_P (next))
        XSETFASTINT (position, (STRINGP (object)
-                               ? XSTRING (object)->size
+                               ? SCHARS (object)
                                : BUF_ZV (XBUFFER (object))));
       else
        XSETFASTINT (position, next->position);
@@ -951,17 +1001,16 @@ past position LIMIT; return LIMIT if nothing is found before LIMIT.  */)
         && (NILP (limit) || next->position < XFASTINT (limit)))
     next = next_interval (next);
 
-  if (NULL_INTERVAL_P (next))
-    return limit;
-  if (NILP (limit))
-    XSETFASTINT (limit, (STRINGP (object)
-                        ? XSTRING (object)->size
-                        : BUF_ZV (XBUFFER (object))));
-  if (!(next->position < XFASTINT (limit)))
+  if (NULL_INTERVAL_P (next)
+      || (next->position
+         >= (INTEGERP (limit)
+             ? XFASTINT (limit)
+             : (STRINGP (object)
+                ? SCHARS (object)
+                : BUF_ZV (XBUFFER (object))))))
     return limit;
-
-  XSETFASTINT (position, next->position);
-  return position;
+  else
+    return make_number (next->position);
 }
 
 /* Return 1 if there's a change in some property between BEG and END.  */
@@ -1001,7 +1050,9 @@ DEFUN ("next-single-property-change", Fnext_single_property_change,
        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.
+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.
@@ -1026,21 +1077,21 @@ past position LIMIT; return LIMIT if nothing is found before LIMIT.  */)
 
   here_val = textget (i->plist, prop);
   next = next_interval (i);
-  while (! NULL_INTERVAL_P (next) 
+  while (! NULL_INTERVAL_P (next)
         && EQ (here_val, textget (next->plist, prop))
         && (NILP (limit) || next->position < XFASTINT (limit)))
     next = next_interval (next);
 
-  if (NULL_INTERVAL_P (next))
-    return limit;
-  if (NILP (limit))
-    XSETFASTINT (limit, (STRINGP (object)
-                        ? XSTRING (object)->size
-                        : BUF_ZV (XBUFFER (object))));
-  if (!(next->position < XFASTINT (limit)))
+  if (NULL_INTERVAL_P (next)
+      || (next->position
+         >= (INTEGERP (limit)
+             ? XFASTINT (limit)
+             : (STRINGP (object)
+                ? SCHARS (object)
+                : BUF_ZV (XBUFFER (object))))))
     return limit;
-
-  return make_number (next->position);
+  else
+    return make_number (next->position);
 }
 
 DEFUN ("previous-property-change", Fprevious_property_change,
@@ -1048,7 +1099,9 @@ DEFUN ("previous-property-change", Fprevious_property_change,
        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.
+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.
 
@@ -1078,14 +1131,15 @@ back past position LIMIT; return LIMIT if nothing is found until LIMIT.  */)
         && (NILP (limit)
             || (previous->position + LENGTH (previous) > XFASTINT (limit))))
     previous = previous_interval (previous);
-  if (NULL_INTERVAL_P (previous))
-    return 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));
+  if (NULL_INTERVAL_P (previous)
+      || (previous->position + LENGTH (previous)
+         <= (INTEGERP (limit)
+             ? XFASTINT (limit)
+             : (STRINGP (object) ? 0 : BUF_BEGV (XBUFFER (object))))))
+    return limit;
+  else
+    return make_number (previous->position + LENGTH (previous));
 }
 
 DEFUN ("previous-single-property-change", Fprevious_single_property_change,
@@ -1093,7 +1147,9 @@ DEFUN ("previous-single-property-change", Fprevious_single_property_change,
        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.
+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.
@@ -1128,14 +1184,15 @@ back past position LIMIT; return LIMIT if nothing is found until LIMIT.  */)
         && (NILP (limit)
             || (previous->position + LENGTH (previous) > XFASTINT (limit))))
     previous = previous_interval (previous);
-  if (NULL_INTERVAL_P (previous))
-    return 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));
+  if (NULL_INTERVAL_P (previous)
+      || (previous->position + LENGTH (previous)
+         <= (INTEGERP (limit)
+             ? XFASTINT (limit)
+             : (STRINGP (object) ? 0 : BUF_BEGV (XBUFFER (object))))))
+    return limit;
+  else
+    return make_number (previous->position + LENGTH (previous));
 }
 \f
 /* Callers note, this can GC when OBJECT is a buffer (or nil).  */
@@ -1144,9 +1201,10 @@ DEFUN ("add-text-properties", Fadd_text_properties,
        Sadd_text_properties, 3, 4, 0,
        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.
+specifying the property values to add.  If the optional fourth 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.
 Return t if any property value actually changed, nil otherwise.  */)
      (start, end, properties, object)
      Lisp_Object start, end, properties, object;
@@ -1196,7 +1254,7 @@ Return t if any property value actually changed, nil otherwise.  */)
     }
 
   if (BUFFERP (object))
-    modify_region (XBUFFER (object), XINT (start), XINT (end));
+    modify_region (XBUFFER (object), XINT (start), XINT (end), 1);
 
   /* We are at the beginning of interval I, with LEN chars to scan.  */
   for (;;)
@@ -1253,8 +1311,9 @@ DEFUN ("put-text-property", Fput_text_property,
        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.  */)
+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.  */)
      (start, end, property, value, object)
      Lisp_Object start, end, property, value, object;
 {
@@ -1268,9 +1327,9 @@ DEFUN ("set-text-properties", Fset_text_properties,
        Sset_text_properties, 3, 4, 0,
        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 the optional fourth 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.
 If PROPERTIES is nil, the effect is to remove all properties from
 the designated part of OBJECT.  */)
      (start, end, properties, object)
@@ -1284,8 +1343,8 @@ the designated part of OBJECT.  */)
    properties PROPERTIES.  OBJECT is the buffer or string containing
    the text.  OBJECT nil means use the current buffer.
    SIGNAL_AFTER_CHANGE_P nil means don't signal after changes.  Value
-   is non-nil if properties were replaced; it is nil if there weren't
-   any properties to replace.  */
+   is nil if the function _detected_ that it did not replace any
+   properties, non-nil otherwise.  */
 
 Lisp_Object
 set_text_properties (start, end, properties, object, signal_after_change_p)
@@ -1306,12 +1365,12 @@ set_text_properties (start, end, properties, object, signal_after_change_p)
      get rid of its intervals.  */
   if (NILP (properties) && STRINGP (object)
       && XFASTINT (start) == 0
-      && XFASTINT (end) == XSTRING (object)->size)
+      && XFASTINT (end) == SCHARS (object))
     {
-      if (! XSTRING (object)->intervals)
-       return Qt;
+      if (! STRING_INTERVALS (object))
+       return Qnil;
 
-      XSTRING (object)->intervals = 0;
+      STRING_SET_INTERVALS (object, NULL_INTERVAL);
       return Qt;
     }
 
@@ -1335,7 +1394,7 @@ set_text_properties (start, end, properties, object, signal_after_change_p)
     }
 
   if (BUFFERP (object))
-    modify_region (XBUFFER (object), XINT (start), XINT (end));
+    modify_region (XBUFFER (object), XINT (start), XINT (end), 1);
 
   set_text_properties_1 (start, end, properties, object, i);
 
@@ -1438,9 +1497,12 @@ DEFUN ("remove-text-properties", Fremove_text_properties,
 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.  */)
+If the optional fourth 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.
+Return t if any property was actually removed, nil otherwise.
+
+Use set-text-properties if you want to remove all text properties.  */)
      (start, end, properties, object)
      Lisp_Object start, end, properties, object;
 {
@@ -1480,7 +1542,7 @@ Return t if any property was actually removed, nil otherwise.  */)
     }
 
   if (BUFFERP (object))
-    modify_region (XBUFFER (object), XINT (start), XINT (end));
+    modify_region (XBUFFER (object), XINT (start), XINT (end), 1);
 
   /* We are at the beginning of an interval, with len to scan */
   for (;;)
@@ -1523,8 +1585,9 @@ 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.
+If the optional fourth 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.
 Return t if any property was actually removed, nil otherwise.  */)
      (start, end, list_of_properties, object)
      Lisp_Object start, end, list_of_properties, object;
@@ -1566,10 +1629,12 @@ Return t if any property was actually removed, nil otherwise.  */)
        }
     }
 
-  if (BUFFERP (object))
-    modify_region (XBUFFER (object), XINT (start), XINT (end));
-
-  /* We are at the beginning of an interval, with len to scan */
+  /* We are at the beginning of an interval, with len to scan.
+     The flag `modified' records if changes have been made.
+     When object is a buffer, we must call modify_region before changes are
+     made and signal_after_change when we are done.
+     We call modify_region before calling remove_properties iff modified == 0,
+     and we call signal_after_change before returning iff modified != 0. */
   for (;;)
     {
       if (i == 0)
@@ -1578,10 +1643,20 @@ Return t if any property was actually removed, nil otherwise.  */)
       if (LENGTH (i) >= len)
        {
          if (! interval_has_some_properties_list (properties, i))
-           return modified ? Qt : Qnil;
+           if (modified)
+             {
+               if (BUFFERP (object))
+                 signal_after_change (XINT (start), XINT (end) - XINT (start),
+                                      XINT (end) - XINT (start));
+               return Qt;
+             }
+           else
+             return Qnil;
 
          if (LENGTH (i) == len)
            {
+             if (!modified && BUFFERP (object))
+               modify_region (XBUFFER (object), XINT (start), XINT (end), 1);
              remove_properties (Qnil, properties, i, object);
              if (BUFFERP (object))
                signal_after_change (XINT (start), XINT (end) - XINT (start),
@@ -1593,6 +1668,8 @@ Return t if any property was actually removed, nil otherwise.  */)
          unchanged = i;
          i = split_interval_left (i, len);
          copy_properties (unchanged, i);
+         if (!modified && BUFFERP (object))
+           modify_region (XBUFFER (object), XINT (start), XINT (end), 1);
          remove_properties (Qnil, properties, i, object);
          if (BUFFERP (object))
            signal_after_change (XINT (start), XINT (end) - XINT (start),
@@ -1600,8 +1677,14 @@ Return t if any property was actually removed, nil otherwise.  */)
          return Qt;
        }
 
+      if (interval_has_some_properties_list (properties, i))
+       {
+         if (!modified && BUFFERP (object))
+           modify_region (XBUFFER (object), XINT (start), XINT (end), 1);
+         remove_properties (Qnil, properties, i, object);
+         modified = 1;
+       }
       len -= LENGTH (i);
-      modified += remove_properties (Qnil, properties, i, object);
       i = next_interval (i);
     }
 }
@@ -1611,8 +1694,9 @@ DEFUN ("text-property-any", Ftext_property_any,
        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.  */)
+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.  */)
      (start, end, property, value, object)
      Lisp_Object start, end, property, value, object;
 {
@@ -1647,8 +1731,9 @@ DEFUN ("text-property-not-all", Ftext_property_not_all,
        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.  */)
+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.  */)
      (start, end, property, value, object)
      Lisp_Object start, end, property, value, object;
 {
@@ -1682,23 +1767,26 @@ containing the text.  */)
 /* 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.  */
+   the char before POS, and 0 if from neither.
+   BUFFER can be either a buffer or nil (meaning current buffer).  */
 
 int
-text_property_stickiness (prop, pos)
-     Lisp_Object prop;
-     Lisp_Object pos;
+text_property_stickiness (prop, pos, buffer)
+     Lisp_Object prop, pos, buffer;
 {
   Lisp_Object prev_pos, front_sticky;
   int is_rear_sticky = 1, is_front_sticky = 0; /* defaults */
 
-  if (XINT (pos) > BEGV)
+  if (NILP (buffer))
+    XSETBUFFER (buffer, current_buffer);
+
+  if (XINT (pos) > BUF_BEGV (XBUFFER (buffer)))
     /* 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);
+      rear_non_sticky = Fget_text_property (prev_pos, Qrear_nonsticky, buffer);
 
       if (!NILP (CONSP (rear_non_sticky)
                 ? Fmemq (prop, rear_non_sticky)
@@ -1706,9 +1794,13 @@ text_property_stickiness (prop, pos)
        /* PROP is rear-non-sticky.  */
        is_rear_sticky = 0;
     }
+  else
+    return 0;
 
   /* Consider following character.  */
-  front_sticky = Fget_text_property (pos, Qfront_sticky, Qnil);
+  /* This signals an arg-out-of-range error if pos is outside the
+     buffer's accessible range.  */
+  front_sticky = Fget_text_property (pos, Qfront_sticky, buffer);
 
   if (EQ (front_sticky, Qt)
       || (CONSP (front_sticky)
@@ -1728,7 +1820,8 @@ text_property_stickiness (prop, pos)
      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)))
+  if (XINT (pos) == BUF_BEGV (XBUFFER (buffer))
+      || NILP (Fget_text_property (prev_pos, prop, buffer)))
     return 1;
   else
     return -1;
@@ -1852,23 +1945,23 @@ text_property_list (object, start, end, prop)
   Lisp_Object result;
 
   result = Qnil;
-  
+
   i = validate_interval_range (object, &start, &end, soft);
   if (!NULL_INTERVAL_P (i))
     {
       int s = XINT (start);
       int e = XINT (end);
-      
+
       while (s < e)
        {
          int interval_end, len;
          Lisp_Object plist;
-         
+
          interval_end = i->position + LENGTH (i);
          if (interval_end > e)
            interval_end = e;
          len = interval_end - s;
-         
+
          plist = i->plist;
 
          if (!NILP (prop))
@@ -1884,14 +1977,14 @@ text_property_list (object, start, end, prop)
                                   Fcons (make_number (s + len),
                                          Fcons (plist, Qnil))),
                            result);
-         
+
          i = next_interval (i);
          if (NULL_INTERVAL_P (i))
            break;
          s = i->position;
        }
     }
-  
+
   return result;
 }
 
@@ -1908,18 +2001,18 @@ add_text_properties_from_list (object, list, delta)
 {
   struct gcpro gcpro1, gcpro2;
   int modified_p = 0;
-  
+
   GCPRO2 (list, object);
-  
+
   for (; CONSP (list); list = XCDR (list))
     {
       Lisp_Object item, start, end, plist, tem;
-      
+
       item = XCAR (list);
       start = make_number (XINT (XCAR (item)) + XINT (delta));
       end = make_number (XINT (XCAR (XCDR (item))) + XINT (delta));
       plist = XCAR (XCDR (XCDR (item)));
-      
+
       tem = Fadd_text_properties (start, end, plist, object);
       if (!NILP (tem))
        modified_p = 1;
@@ -1942,7 +2035,7 @@ extend_property_ranges (list, old_end, new_end)
   for (; CONSP (list); list = XCDR (list))
     {
       Lisp_Object item, end;
-      
+
       item = XCAR (list);
       end = XCAR (XCDR (item));
 
@@ -2040,7 +2133,7 @@ verify_interval_modification (buf, start, end)
              if (! NULL_INTERVAL_P (i))
                {
                  after = textget (i->plist, Qread_only);
-                 
+
                  /* If interval I is read-only and read-only is
                     front-sticky, inhibit insertion.
                     Check for read-only as well as category.  */
@@ -2053,14 +2146,14 @@ verify_interval_modification (buf, start, end)
                      if (TMEM (Qread_only, tem)
                          || (NILP (Fplist_get (i->plist, Qread_only))
                              && TMEM (Qcategory, tem)))
-                       text_read_only ();
+                       text_read_only (after);
                    }
                }
 
              if (! NULL_INTERVAL_P (prev))
                {
                  before = textget (prev->plist, Qread_only);
-                 
+
                  /* If interval PREV is read-only and read-only isn't
                     rear-nonsticky, inhibit insertion.
                     Check for read-only as well as category.  */
@@ -2073,14 +2166,14 @@ verify_interval_modification (buf, start, end)
                      if (! TMEM (Qread_only, tem)
                          && (! NILP (Fplist_get (prev->plist,Qread_only))
                              || ! TMEM (Qcategory, tem)))
-                       text_read_only ();
+                       text_read_only (before);
                    }
                }
            }
          else if (! NULL_INTERVAL_P (i))
            {
              after = textget (i->plist, Qread_only);
-                 
+
              /* If interval I is read-only and read-only is
                 front-sticky, inhibit insertion.
                 Check for read-only as well as category.  */
@@ -2092,13 +2185,13 @@ verify_interval_modification (buf, start, end)
                  if (TMEM (Qread_only, tem)
                      || (NILP (Fplist_get (i->plist, Qread_only))
                          && TMEM (Qcategory, tem)))
-                   text_read_only ();
+                   text_read_only (after);
 
                  tem = textget (prev->plist, Qrear_nonsticky);
                  if (! TMEM (Qread_only, tem)
                      && (! NILP (Fplist_get (prev->plist, Qread_only))
                          || ! TMEM (Qcategory, tem)))
-                   text_read_only ();
+                   text_read_only (after);
                }
            }
        }
@@ -2120,7 +2213,7 @@ verify_interval_modification (buf, start, end)
       do
        {
          if (! INTERVAL_WRITABLE_P (i))
-           text_read_only ();
+           text_read_only (textget (i->plist, Qread_only));
 
          if (!inhibit_modification_hooks)
            {
@@ -2201,14 +2294,16 @@ 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;
+  /* Text property `syntax-table' should be nonsticky by default.  */
+  Vtext_property_default_nonsticky
+    = Fcons (Fcons (intern ("syntax-table"), Qt), Qnil);
 
   staticpro (&interval_insert_behind_hooks);
   staticpro (&interval_insert_in_front_hooks);
   interval_insert_behind_hooks = Qnil;
   interval_insert_in_front_hooks = Qnil;
 
-              
+
   /* Common attributes one might give text */
 
   staticpro (&Qforeground);
@@ -2252,6 +2347,7 @@ rear-nonsticky properties of the character overrides NONSTICKINESS.  */);
   defsubr (&Stext_properties_at);
   defsubr (&Sget_text_property);
   defsubr (&Sget_char_property);
+  defsubr (&Sget_char_property_and_overlay);
   defsubr (&Snext_char_property_change);
   defsubr (&Sprevious_char_property_change);
   defsubr (&Snext_single_char_property_change);
@@ -2271,3 +2367,5 @@ rear-nonsticky properties of the character overrides NONSTICKINESS.  */);
 /*  defsubr (&Scopy_text_properties); */
 }
 
+/* arch-tag: 454cdde8-5f86-4faa-a078-101e3625d479
+   (do not change this comment) */