Fix inaccuracy in a comment.
[bpt/emacs.git] / src / textprop.c
index 9499b53..2b45448 100644 (file)
@@ -60,7 +60,7 @@ Lisp_Object Qinvisible, Qintangible, Qmouse_face;
 static Lisp_Object Qread_only;
 Lisp_Object Qminibuffer_prompt;
 
-/* Sticky properties */
+/* Sticky properties */
 Lisp_Object Qfront_sticky, Qrear_nonsticky;
 
 /* If o1 is a cons whose cdr is a cons, return non-zero and set o2 to
@@ -125,9 +125,10 @@ modify_region (Lisp_Object buffer, Lisp_Object start, Lisp_Object end)
 #define hard 1
 
 INTERVAL
-validate_interval_range (Lisp_Object object, Lisp_Object *begin, Lisp_Object *end, int force)
+validate_interval_range (Lisp_Object object, Lisp_Object *begin,
+                        Lisp_Object *end, bool force)
 {
-  register INTERVAL i;
+  INTERVAL i;
   ptrdiff_t searchpos;
 
   CHECK_STRING_OR_BUFFER (object);
@@ -1131,6 +1132,7 @@ Return t if any property value actually changed, nil otherwise.  */)
   ptrdiff_t s, len;
   bool modified = 0;
   struct gcpro gcpro1;
+  bool first_time = 1;
 
   properties = validate_plist (properties);
   if (NILP (properties))
@@ -1139,6 +1141,7 @@ Return t if any property value actually changed, nil otherwise.  */)
   if (NILP (object))
     XSETBUFFER (object, current_buffer);
 
+ retry:
   i = validate_interval_range (object, &start, &end, hard);
   if (!i)
     return Qnil;
@@ -1174,8 +1177,25 @@ Return t if any property value actually changed, nil otherwise.  */)
       copy_properties (unchanged, i);
     }
 
-  if (BUFFERP (object))
-    modify_region (object, start, end);
+  if (BUFFERP (object) && first_time)
+    {
+      ptrdiff_t prev_total_length = TOTAL_LENGTH (i);
+      ptrdiff_t prev_pos = i->position;
+
+      modify_region (object, start, end);
+      /* If someone called us recursively as a side effect of
+        modify_region, and changed the intervals behind our back
+        (could happen if lock_file, called by prepare_to_modify_buffer,
+        triggers redisplay, and that calls add-text-properties again
+        in the same buffer), we cannot continue with I, because its
+        data changed.  So we restart the interval analysis anew.  */
+      if (TOTAL_LENGTH (i) != prev_total_length
+         || i->position != prev_pos)
+       {
+         first_time = 0;
+         goto retry;
+       }
+    }
 
   /* We are at the beginning of interval I, with LEN chars to scan.  */
   for (;;)
@@ -1427,10 +1447,12 @@ Use `set-text-properties' if you want to remove all text properties.  */)
   INTERVAL i, unchanged;
   ptrdiff_t s, len;
   bool modified = 0;
+  bool first_time = 1;
 
   if (NILP (object))
     XSETBUFFER (object, current_buffer);
 
+ retry:
   i = validate_interval_range (object, &start, &end, soft);
   if (!i)
     return Qnil;
@@ -1462,8 +1484,25 @@ Use `set-text-properties' if you want to remove all text properties.  */)
       copy_properties (unchanged, i);
     }
 
-  if (BUFFERP (object))
-    modify_region (object, start, end);
+  if (BUFFERP (object) && first_time)
+    {
+      ptrdiff_t prev_total_length = TOTAL_LENGTH (i);
+      ptrdiff_t prev_pos = i->position;
+
+      modify_region (object, start, end);
+      /* If someone called us recursively as a side effect of
+        modify_region, and changed the intervals behind our back
+        (could happen if lock_file, called by prepare_to_modify_buffer,
+        triggers redisplay, and that calls add-text-properties again
+        in the same buffer), we cannot continue with I, because its
+        data changed.  So we restart the interval analysis anew.  */
+      if (TOTAL_LENGTH (i) != prev_total_length
+         || i->position != prev_pos)
+       {
+         first_time = 0;
+         goto retry;
+       }
+    }
 
   /* We are at the beginning of an interval, with len to scan */
   for (;;)