- New powerful internal error-trapping API for support of running Lisp
  code within critical sections (e.g  within redisplay, for example
  BIDI display time reordering and general char->font mapping)

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
/* call_trapping_problems():

   This is equivalent to (*fun) (arg), except that various conditions
   can be trapped or inhibited, according to FLAGS.

   If FLAGS does not contain NO_INHIBIT_ERRORS, when an error occurs,
   the error is caught and a warning is issued, specifying the
   specific error that occurred and a backtrace.  In that case,
   WARNING_STRING should be given, and will be printed at the
   beginning of the error to indicate where the error occurred.

   If FLAGS does not contain NO_INHIBIT_THROWS, all attempts to
   `throw' out of the function being called are trapped, and a warning
   issued. (Again, WARNING_STRING should be given.)

   (If FLAGS contains INHIBIT_WARNING_ISSUE, no warnings are issued;
   this applies to recursive invocations of call_trapping_problems, too.)

   Note: If neither of NO_INHIBIT_THROWS or NO_INHIBIT_ERRORS is
   given, you are *guaranteed* that there will be no non-local exits
   out of this function.

   If FLAGS contains INHIBIT_QUIT, QUIT using C-g is inhibited.  (This
   is *rarely* a good idea.  Unless you use NO_INHIBIT_ERRORS, QUIT is
   automatically caught as well, and treated as an error; you can
   check for this using EQ (problems->error_conditions, Qquit).

   If FLAGS contains INHIBIT_GC, garbage collection is inhibited.
   This is useful for Lisp called within redisplay or inside of the
   QUIT macro (where GC is generally not expected), for example.

   If FLAGS contains INHIBIT_EXISTING_PERMANENT_DISPLAY_OBJECT_DELETION,
   Lisp code is not allowed to delete any window, buffers, frames, devices,
   or consoles that were already in existence at the time this function
   was called. (However, it's perfectly legal for code to create a new
   buffer and then delete it.)

   #### It might be useful to have a flag that inhibits deletion of a
   specific permanent display object and everything it's attached to
   (e.g. a window, and the buffer, frame, device, and console it's
   attached to.)

   If FLAGS contains INHIBIT_EXISTING_BUFFER_TEXT_MODIFICATION, Lisp
   code is not allowed to modify the text of any buffers that were
   already in existence at the time this function was called.
   (However, it's perfectly legal for code to create a new buffer and
   then modify its text.)

       [These last two flags are implemented using global variables
       Vdeletable_permanent_display_objects and Vmodifiable_buffers,
       which keep track of a list of all buffers or permanent display
       objects created since the last time one of these flags was set.
       The code that deletes buffers, etc. and modifies buffers checks

       (1) if the corresponding flag is set (through the global variable
       inhibit_flags or its accessor function get_inhibit_flags()), and

       (2) if the object to be modified or deleted is not in the
       appropriate list.

       If so, it signals an error.

       Recursive calls to call_trapping_problems() are allowed.  In
       the case of the two flags mentioned above, the current values
       of the global variables are stored in an unwind-protect, and
       they're reset to nil.]

   If FLAGS contains INHIBIT_ENTERING_DEBUGGER, the debugger will not
   be entered if an error occurs inside the Lisp code being called,
   even when the user has requested an error.  In such case, a warning
   is issued stating that access to the debugger is denied, unless
   INHIBIT_WARNING_ISSUE has also been supplied.  This is useful when
   calling Lisp code inside redisplay, in menu callbacks, etc. because
   in such cases either the display is in an inconsistent state or
   doing window operations is explicitly forbidden by the OS, and the
   debugger would cause visual changes on the screen and might create
   another frame.

   If FLAGS contains INHIBIT_ANY_CHANGE_AFFECTING_REDISPLAY, no
   changes of any sort to extents, faces, glyphs, buffer text,
   specifiers relating to display, other variables relating to
   display, splitting, deleting, or resizing windows or frames,
   deleting buffers, windows, frames, devices, or consoles, etc. is
   allowed.  This is for things called absolutely in the middle of
   redisplay, which expects things to be *exactly* the same after the
   call as before.  This isn't completely implemented and needs to be
   thought out some more to determine exactly what its semantics are.
   For the moment, turning on this flag also turns on

        INHIBIT_EXISTING_PERMANENT_DISPLAY_OBJECT_DELETION
        INHIBIT_EXISTING_BUFFER_TEXT_MODIFICATION
        INHIBIT_ENTERING_DEBUGGER
        INHIBIT_WARNING_ISSUE
        INHIBIT_GC

   #### The following five flags are defined, but unimplemented:

   #define INHIBIT_EXISTING_CODING_SYSTEM_DELETION (1<<6)
   #define INHIBIT_EXISTING_CHARSET_DELETION (1<<7)
   #define INHIBIT_PERMANENT_DISPLAY_OBJECT_CREATION (1<<8)
   #define INHIBIT_CODING_SYSTEM_CREATION (1<<9)
   #define INHIBIT_CHARSET_CREATION (1<<10)

   If PROBLEM is non-zero, it should be a pointer to a structure into
   which exact information about any occurring problems (either an
   error or an attempted throw past this boundary).

   If a problem occurred and aborted operation (error, quit, or
   invalid throw), Qunbound is returned.  Otherwise the return value
   from the call to (*fun) (arg) is returned.  */

struct call_trapping_problems
{
  Lisp_Object catchtag;
  Lisp_Object error_conditions;
  Lisp_Object data;
  Lisp_Object backtrace;
  Lisp_Object warning_class;

  const char *warning_string;
  Lisp_Object (*fun) (void *);
  void *arg;
};

Lisp_Object
call_trapping_problems (Lisp_Object warning_class,
                        const char *warning_string,
                        int flags,
                        struct call_trapping_problems_result *problem,
                        Lisp_Object (*fun) (void *),
                        void *arg)

#define NO_INHIBIT_ERRORS (1<<0)
#define NO_INHIBIT_THROWS (1<<1)
#define INTERNAL_INHIBIT_ERRORS (1<<0)
#define INTERNAL_INHIBIT_THROWS (1<<1)
#define INHIBIT_WARNING_ISSUE (1<<2)
#define INHIBIT_QUIT (1<<3)
#define INHIBIT_GC (1<<4)
#define INHIBIT_EXISTING_PERMANENT_DISPLAY_OBJECT_DELETION (1<<5)
#define INHIBIT_EXISTING_CODING_SYSTEM_DELETION (1<<6)
#define INHIBIT_EXISTING_CHARSET_DELETION (1<<7)
#define INHIBIT_PERMANENT_DISPLAY_OBJECT_CREATION (1<<8)
#define INHIBIT_CODING_SYSTEM_CREATION (1<<9)
#define INHIBIT_CHARSET_CREATION (1<<10)
#define INHIBIT_EXISTING_BUFFER_TEXT_MODIFICATION (1<<11)
#define INHIBIT_ANY_CHANGE_AFFECTING_REDISPLAY (1<<12)
#define INHIBIT_ENTERING_DEBUGGER (1<<13)

enum check_allowed_operation
{
  OPERATION_DELETE_OBJECT,
  OPERATION_CREATE_OBJECT,
  OPERATION_MODIFY_BUFFER_TEXT,
  OPERATION_MODIFY_OBJECT_PROPERTY,
};

/* Buffers, frames, windows, devices, and consoles created since most
   recent active
   call_trapping_problems (INHIBIT_EXISTING_PERMANENT_DISPLAY_OBJECT_DELETION).
*/
Lisp_Object Vdeletable_permanent_display_objects;

/* Buffers created since most recent active
   call_trapping_problems (INHIBIT_EXISTING_BUFFER_TEXT_MODIFICATION). */
Lisp_Object Vmodifiable_buffers;

int get_inhibit_flags (void);
void check_allowed_operation (int what, Lisp_Object obj, Lisp_Object prop);
void note_object_created (Lisp_Object obj);
void note_object_deleted (Lisp_Object obj);
Lisp_Object call_with_condition_handler (Lisp_Object (*handler) (Lisp_Object,
                                                                 Lisp_Object,
                                                                 Lisp_Object),
                                         Lisp_Object handler_arg,
                                         Lisp_Object (*fun) (Lisp_Object),
                                         Lisp_Object arg);
Lisp_Object call_trapping_problems (Lisp_Object warning_class,
                                    const char *warning_string,
                                    int flags,
                                    struct call_trapping_problems_result
                                    *problem,
                                    Lisp_Object (*fun) (void *),
                                    void *arg);
Lisp_Object va_call_trapping_problems (Lisp_Object warning_class,
                                       const char *warning_string,
                                       int flags,
                                       struct call_trapping_problems_result
                                       *problem,
                                       lisp_fn_t fun, int nargs, ...);
Lisp_Object call0_trapping_problems (const char *, Lisp_Object, int);
Lisp_Object call1_trapping_problems (const char *, Lisp_Object, Lisp_Object,
                                   int);
Lisp_Object call2_trapping_problems (const char *, Lisp_Object, Lisp_Object,
                                   Lisp_Object, int);
Lisp_Object call3_trapping_problems (const char *, Lisp_Object, Lisp_Object,
                                   Lisp_Object, Lisp_Object, int);
Lisp_Object call4_trapping_problems (const char *, Lisp_Object, Lisp_Object,
                                   Lisp_Object, Lisp_Object, Lisp_Object,
                                   int);
Lisp_Object call5_trapping_problems (const char *, Lisp_Object, Lisp_Object,
                                   Lisp_Object, Lisp_Object, Lisp_Object,
                                   Lisp_Object, int);
Lisp_Object eval_in_buffer_trapping_problems (const char *, struct buffer *,
                                            Lisp_Object, int);
Lisp_Object run_hook_trapping_problems (const char *, Lisp_Object, int);
Lisp_Object safe_run_hook_trapping_problems (const char *, Lisp_Object, int);
Lisp_Object run_hook_with_args_in_buffer_trapping_problems (const char
                                                            *warning_string,
                                                            struct buffer
                                                            *buf, int nargs,
                                                            Lisp_Object *args,
                                                            enum
                                                            run_hooks_condition
                                                            cond, int flags);
Lisp_Object run_hook_with_args_trapping_problems (const char *warning_string,
                                                  int nargs,
                                                  Lisp_Object *args,
                                                  enum run_hooks_condition
                                                  cond,
                                                  int flags);
Lisp_Object va_run_hook_with_args_trapping_problems (const char
                                                     *warning_string,
                                                     Lisp_Object hook_var,
                                                     int nargs, ...);
Lisp_Object va_run_hook_with_args_in_buffer_trapping_problems (const char
                                                               *warning_string,
                                                               struct buffer
                                                               *buf,
                                                               Lisp_Object
                                                               hook_var,
                                                               int nargs, ...);
Lisp_Object call_with_suspended_errors (lisp_fn_t, volatile Lisp_Object,
                                        Lisp_Object,
                                        Error_behavior, int, ...);