+/* ------------------------------- */
+/* report_extent_modification() */
+/* ------------------------------- */
+struct report_extent_modification_closure {
+ Lisp_Object buffer;
+ Bufpos start, end;
+ int afterp;
+ int speccount;
+};
+
+static Lisp_Object
+report_extent_modification_restore (Lisp_Object buffer)
+{
+ if (current_buffer != XBUFFER (buffer))
+ Fset_buffer (buffer);
+ return Qnil;
+}
+
+static int
+report_extent_modification_mapper (EXTENT extent, void *arg)
+{
+ struct report_extent_modification_closure *closure =
+ (struct report_extent_modification_closure *)arg;
+ Lisp_Object exobj, startobj, endobj;
+ Lisp_Object hook = (closure->afterp
+ ? extent_after_change_functions (extent)
+ : extent_before_change_functions (extent));
+ if (NILP (hook))
+ return 0;
+
+ XSETEXTENT (exobj, extent);
+ XSETINT (startobj, closure->start);
+ XSETINT (endobj, closure->end);
+
+ /* Now that we are sure to call elisp, set up an unwind-protect so
+ inside_change_hook gets restored in case we throw. Also record
+ the current buffer, in case we change it. Do the recording only
+ once.
+
+ One confusing thing here is that our caller never actually calls
+ unbind_to (closure.speccount, Qnil). This is because
+ map_extents_bytind() unbinds before, and with a smaller
+ speccount. The additional unbind_to() in
+ report_extent_modification() would cause XEmacs to abort. */
+ if (closure->speccount == -1)
+ {
+ closure->speccount = specpdl_depth ();
+ record_unwind_protect (report_extent_modification_restore,
+ Fcurrent_buffer ());
+ }
+
+ /* The functions will expect closure->buffer to be the current
+ buffer, so change it if it isn't. */
+ if (current_buffer != XBUFFER (closure->buffer))
+ Fset_buffer (closure->buffer);
+
+ /* #### It's a shame that we can't use any of the existing run_hook*
+ functions here. This is so because all of them work with
+ symbols, to be able to retrieve default values of local hooks.
+ <sigh>
+
+ #### Idea: we could set up a dummy symbol, and call the hook
+ functions on *that*. */
+
+ if (!CONSP (hook) || EQ (XCAR (hook), Qlambda))
+ call3 (hook, exobj, startobj, endobj);
+ else
+ {
+ Lisp_Object tail;
+ EXTERNAL_LIST_LOOP (tail, hook)
+ /* #### Shouldn't this perform the same Fset_buffer() check as
+ above? */
+ call3 (XCAR (tail), exobj, startobj, endobj);
+ }
+ return 0;
+}
+
+void
+report_extent_modification (Lisp_Object buffer, Bufpos start, Bufpos end,
+ int afterp)
+{
+ struct report_extent_modification_closure closure;
+
+ closure.buffer = buffer;
+ closure.start = start;
+ closure.end = end;
+ closure.afterp = afterp;
+ closure.speccount = -1;
+
+ map_extents (start, end, report_extent_modification_mapper, (void *)&closure,
+ buffer, NULL, ME_MIGHT_CALL_ELISP);
+}
+