Mercurial > hg > xemacs-beta
diff src/event-stream.c @ 853:2b6fa2618f76
[xemacs-hg @ 2002-05-28 08:44:22 by ben]
merge my stderr-proc ws
make-docfile.c: Fix places where we forget to check for EOF.
code-init.el: Don't use CRLF conversion by default on process output. CMD.EXE and
friends work both ways but Cygwin programs don't like the CRs.
code-process.el, multicast.el, process.el: Removed.
Improvements to call-process-internal:
-- allows a buffer to be specified for input and stderr output
-- use it on all systems
-- implement C-g as documented
-- clean up and comment
call-process-region uses new call-process facilities; no temp file.
remove duplicate funs in process.el.
comment exactly how coding systems work and fix various problems.
open-multicast-group now does similar coding-system frobbing to
open-network-stream.
dumped-lisp.el, faces.el, msw-faces.el: Fix some hidden errors due to code not being defined at the right time.
xemacs.mak: Add -DSTRICT.
================================================================
ALLOW SEPARATION OF STDOUT AND STDERR IN PROCESSES
================================================================
Standard output and standard error can be processed separately in
a process. Each can have its own buffer, its own mark in that buffer,
and its filter function. You can specify a separate buffer for stderr
in `start-process' to get things started, or use the new primitives:
set-process-stderr-buffer
process-stderr-buffer
process-stderr-mark
set-process-stderr-filter
process-stderr-filter
Also, process-send-region takes a 4th optional arg, a buffer.
Currently always uses a pipe() under Unix to read the error output.
(#### Would a PTY be better?)
sysdep.h, sysproc.h, unexfreebsd.c, unexsunos4.c, nt.c, emacs.c, callproc.c, symsinit.h, sysdep.c, Makefile.in.in, process-unix.c: Delete callproc.c. Move child_setup() to process-unix.c.
wait_for_termination() now only needed on a few really old systems.
console-msw.h, event-Xt.c, event-msw.c, event-stream.c, event-tty.c, event-unixoid.c, events.h, process-nt.c, process-unix.c, process.c, process.h, procimpl.h: Rewrite the process methods to handle a separate channel for
error input. Create Lstreams for reading in the error channel.
Many process methods need change. In general the changes are
fairly clear as they involve duplicating what's used for reading
the normal stdout and changing for stderr -- although tedious,
as such changes are required throughout the entire process code.
Rewrote the code that reads process output to do two loops, one
for stdout and one for stderr.
gpmevent.c, tooltalk.c: set_process_filter takes an argument for stderr.
================================================================
NEW ERROR-TRAPPING MECHANISM
================================================================
Totally rewrite error trapping code to be unified and support more
features. Basic function is call_trapping_problems(), which lets
you specify, by means of flags, what sorts of problems you want
trapped. these can include
-- quit
-- errors
-- throws past the function
-- creation of "display objects" (e.g. buffers)
-- deletion of already-existing "display objects" (e.g. buffers)
-- modification of already-existing buffers
-- entering the debugger
-- gc
-- errors->warnings (ala suspended errors)
etc. All other error funs rewritten in terms of this one.
Various older mechanisms removed or rewritten.
window.c, insdel.c, console.c, buffer.c, device.c, frame.c: When creating a display object, added call to
note_object_created(), for use with trapping_problems mechanism.
When deleting, call check_allowed_operation() and note_object
deleted().
The trapping-problems code records the objects created since the
call-trapping-problems began. Those objects can be deleted, but
none others (i.e. previously existing ones).
bytecode.c, cmdloop.c: internal_catch takes another arg.
eval.c: Add long comments describing the "five lists" used to maintain
state (backtrace, gcpro, specbind, etc.) in the Lisp engine.
backtrace.h, eval.c: Implement trapping-problems mechanism, eliminate old mechanisms or
redo in terms of new one.
frame.c, gutter.c: Flush out the concept of "critical display section", defined by
the in_display() var. Use an internal_bind() to get it reset,
rather than just doing it at end, because there may be a non-local
exit.
event-msw.c, event-stream.c, console-msw.h, device.c, dialog-msw.c, frame.c, frame.h, intl.c, toolbar.c, menubar-msw.c, redisplay.c, alloc.c, menubar-x.c: Make use of new trapping-errors stuff and rewrite code based on
old mechanisms.
glyphs-widget.c, redisplay.h: Protect calling Lisp in redisplay.
insdel.c: Protect hooks against deleting existing buffers.
frame-msw.c: Use EQ, not EQUAL in hash tables whose keys are just numbers.
Otherwise we run into stickiness in redisplay because
internal_equal() can QUIT.
================================================================
SIGNAL, C-G CHANGES
================================================================
Here we change the way that C-g interacts with event reading. The
idea is that a C-g occurring while we're reading a user event
should be read as C-g, but elsewhere should be a QUIT. The former
code did all sorts of bizarreness -- requiring that no QUIT occurs
anywhere in event-reading code (impossible to enforce given the
stuff called or Lisp code invoked), and having some weird system
involving enqueue/dequeue of a C-g and interaction with Vquit_flag
-- and it didn't work.
Now, we simply enclose all code where we want C-g read as an event
with {begin/end}_dont_check_for_quit(). This completely turns off
the mechanism that checks (and may remove or alter) C-g in the
read-ahead queues, so we just get the C-g normal.
Signal.c documents this very carefully.
cmdloop.c: Correct use of dont_check_for_quit to new scheme, remove old
out-of-date comments.
event-stream.c: Fix C-g handling to actually work.
device-x.c: Disable quit checking when err out.
signal.c: Cleanup. Add large descriptive comment.
process-unix.c, process-nt.c, sysdep.c: Use QUIT instead of REALLY_QUIT.
It's not necessary to use REALLY_QUIT and just confuses the issue.
lisp.h: Comment quit handlers.
================================================================
CONS CHANGES
================================================================
free_cons() now takes a Lisp_Object not the result of XCONS().
car and cdr have been renamed so that they don't get used directly;
go through XCAR(), XCDR() instead.
alloc.c, dired.c, editfns.c, emodules.c, fns.c, glyphs-msw.c, glyphs-x.c, glyphs.c, keymap.c, minibuf.c, search.c, eval.c, lread.c, lisp.h: Correct free_cons calling convention: now takes Lisp_Object,
not Lisp_Cons
chartab.c: Eliminate direct use of ->car, ->cdr, should be black box.
callint.c: Rewrote using EXTERNAL_LIST_LOOP to avoid use of Lisp_Cons.
================================================================
USE INTERNAL-BIND-*
================================================================
eval.c: Cleanups of these funs.
alloc.c, fileio.c, undo.c, specifier.c, text.c, profile.c, lread.c, redisplay.c, menubar-x.c, macros.c: Rewrote to use internal_bind_int() and internal_bind_lisp_object()
in place of whatever varied and cumbersome mechanisms were
formerly there.
================================================================
SPECBIND SANITY
================================================================
backtrace.h: - Improved comments
backtrace.h, bytecode.c, eval.c: Add new mechanism check_specbind_stack_sanity() for sanity
checking code each time the catchlist or specbind stack change.
Removed older prototype of same mechanism.
================================================================
MISC
================================================================
lisp.h, insdel.c, window.c, device.c, console.c, buffer.c: Fleshed out authorship.
device-msw.c: Correct bad Unicode-ization.
print.c: Be more careful when not initialized or in fatal error handling.
search.c: Eliminate running_asynch_code, an FSF holdover.
alloc.c: Added comments about gc-cons-threshold.
dialog-x.c: Use begin_gc_forbidden() around code to build up a widget value
tree, like in menubar-x.c.
gui.c: Use Qunbound not Qnil as the default for
gethash.
lisp-disunion.h, lisp-union.h: Added warnings on use of VOID_TO_LISP().
lisp.h: Use ERROR_CHECK_STRUCTURES to turn on
ERROR_CHECK_TRAPPING_PROBLEMS and ERROR_CHECK_TYPECHECK
lisp.h: Add assert_with_message.
lisp.h: Add macros for gcproing entire arrays. (You could do this before
but it required manual twiddling the gcpro structure.)
lisp.h: Add prototypes for new functions defined elsewhere.
author | ben |
---|---|
date | Tue, 28 May 2002 08:45:36 +0000 |
parents | e7ee5f8bde58 |
children | 804517e16990 |
line wrap: on
line diff
--- a/src/event-stream.c Sat May 25 01:55:30 2002 +0000 +++ b/src/event-stream.c Tue May 28 08:45:36 2002 +0000 @@ -520,7 +520,7 @@ return 0; } -void +static void event_stream_next_event (Lisp_Event *event) { Lisp_Object event_obj; @@ -529,11 +529,20 @@ event_obj = wrap_event (event); zero_event (event); - /* If C-g was pressed, treat it as a character to be read. - Note that if C-g was pressed while we were blocking, - the SIGINT signal handler will be called. It will - set Vquit_flag and write a byte on our "fake pipe", - which will unblock us. */ + /* SIGINT occurs when C-g was pressed on a TTY. (SIGINT might have + been sent manually by the user, but we don't care; we treat it + the same.) + + The SIGINT signal handler sets Vquit_flag as well as sigint_happened + and write a byte on our "fake pipe", which unblocks us when we are + waiting for an event. */ + + /* If SIGINT was received after we disabled quit checking (because + we want to read C-g's as characters), but before we got a chance + to start reading, notice it now and treat it as a character to be + read. If above callers wanted this to be QUIT, they can + determine this by comparing the event against quit-char. */ + if (maybe_read_quit_event (event)) { DEBUG_PRINT_EMACS_EVENT ("SIGINT", event_obj); @@ -547,6 +556,14 @@ event_stream->next_event_cb (event); emacs_is_blocking = 0; + /* Now check to see if C-g was pressed while we were blocking. + We treat it as an event, just like above. */ + if (maybe_read_quit_event (event)) + { + DEBUG_PRINT_EMACS_EVENT ("SIGINT", event_obj); + return; + } + #ifdef DEBUG_XEMACS /* timeout events have more info set later, so print the event out in next_event_internal(). */ @@ -621,41 +638,90 @@ } void -event_stream_select_process (Lisp_Process *proc) +event_stream_select_process (Lisp_Process *proc, int doin, int doerr) { + int cur_in, cur_err; + check_event_stream_ok (EVENT_STREAM_PROCESS); - if (!get_process_selected_p (proc)) + + cur_in = get_process_selected_p (proc, 0); + if (cur_in) + doin = 0; + + if (!process_has_separate_stderr (wrap_process (proc))) { - event_stream->select_process_cb (proc); - set_process_selected_p (proc, 1); + doerr = 0; + cur_err = 0; + } + else + { + cur_err = get_process_selected_p (proc, 1); + if (cur_err) + doerr = 0; + } + + if (doin || doerr) + { + event_stream->select_process_cb (proc, doin, doerr); + set_process_selected_p (proc, cur_in || doin, cur_err || doerr); } } void -event_stream_unselect_process (Lisp_Process *proc) +event_stream_unselect_process (Lisp_Process *proc, int doin, int doerr) { + int cur_in, cur_err; + check_event_stream_ok (EVENT_STREAM_PROCESS); - if (get_process_selected_p (proc)) + + cur_in = get_process_selected_p (proc, 0); + if (!cur_in) + doin = 0; + + if (!process_has_separate_stderr (wrap_process (proc))) { - event_stream->unselect_process_cb (proc); - set_process_selected_p (proc, 0); + doerr = 0; + cur_err = 0; + } + else + { + cur_err = get_process_selected_p (proc, 1); + if (!cur_err) + doerr = 0; + } + + if (doin || doerr) + { + event_stream->unselect_process_cb (proc, doin, doerr); + set_process_selected_p (proc, cur_in && !doin, cur_err && !doerr); } } -USID -event_stream_create_stream_pair (void *inhandle, void *outhandle, - Lisp_Object *instream, Lisp_Object *outstream, int flags) +void +event_stream_create_io_streams (void *inhandle, void *outhandle, + void *errhandle, Lisp_Object *instream, + Lisp_Object *outstream, + Lisp_Object *errstream, + USID *in_usid, + USID *err_usid, + int flags) { check_event_stream_ok (EVENT_STREAM_PROCESS); - return event_stream->create_stream_pair_cb - (inhandle, outhandle, instream, outstream, flags); + event_stream->create_io_streams_cb + (inhandle, outhandle, errhandle, instream, outstream, errstream, + in_usid, err_usid, flags); } -USID -event_stream_delete_stream_pair (Lisp_Object instream, Lisp_Object outstream) +void +event_stream_delete_io_streams (Lisp_Object instream, + Lisp_Object outstream, + Lisp_Object errstream, + USID *in_usid, + USID *err_usid) { check_event_stream_ok (EVENT_STREAM_PROCESS); - return event_stream->delete_stream_pair_cb (instream, outstream); + event_stream->delete_io_streams_cb (instream, outstream, errstream, + in_usid, err_usid); } void @@ -734,9 +800,11 @@ /* This function can GC */ double echo_keystrokes; struct frame *f = selected_frame (); + int depth = begin_dont_check_for_quit (); + /* Message turns off echoing unless more keystrokes turn it on again. */ if (echo_area_active (f) && !EQ (Qcommand, echo_area_status (f))) - return; + goto done; if (INTP (Vecho_keystrokes) || FLOATP (Vecho_keystrokes)) echo_keystrokes = extract_float (Vecho_keystrokes); @@ -752,11 +820,9 @@ { if (!no_snooze) { - /* #### C-g here will cause QUIT. Setting dont_check_for_quit - doesn't work. See check_quit. */ if (NILP (Fsit_for (Vecho_keystrokes, Qnil))) /* input came in, so don't echo. */ - return; + goto done; } echo_area_message (f, command_builder->echo_buf, Qnil, 0, @@ -765,6 +831,10 @@ strlen ((char *) command_builder->echo_buf), Qcommand); } + + done: + Vquit_flag = Qnil; /* see begin_dont_check_for_quit() */ + unbind_to (depth); } static void @@ -1548,19 +1618,10 @@ return dequeue_event (&command_event_queue, &command_event_queue_tail); } -/* put the event on the typeahead queue, unless - the event is the quit char, in which case the `QUIT' - which will occur on the next trip through this loop is - all the processing we should do - leaving it on the queue - would cause the quit to be processed twice. - */ static void enqueue_command_event_1 (Lisp_Object event_to_copy) { - /* do not call check_quit() here. Vquit_flag was set in - next_event_internal. */ - if (NILP (Vquit_flag)) - enqueue_command_event (Fcopy_event (event_to_copy, Qnil)); + enqueue_command_event (Fcopy_event (event_to_copy, Qnil)); } void @@ -1969,12 +2030,23 @@ /* the number of keyboard characters read. callint.c wants this. */ Charcount num_input_chars; +/* Read an event from the window system (or tty). If ALLOW_QUEUED is + non-zero, read from the command-event queue first. + + If C-g was pressed, this function will attempt to QUIT. If you want + to read C-g as an event, wrap this function with a call to + begin_dont_check_for_quit(), and set Vquit_flag to Qnil just before + you unbind. In this case, TARGET_EVENT will contain a C-g. + + Note that even if you are interested in C-g doing QUIT, a caller of you + might not be. +*/ + static void next_event_internal (Lisp_Object target_event, int allow_queued) { struct gcpro gcpro1; - /* QUIT; This is incorrect - the caller must do this because some - callers (ie, Fnext_event()) do not want to QUIT. */ + QUIT; assert (NILP (XEVENT_NEXT (target_event))); @@ -2017,35 +2089,29 @@ DEBUG_PRINT_EMACS_EVENT ("real, timeout", target_event); } - /* If we read a ^G, then set quit-flag but do not discard the ^G. - The callers of next_event_internal() will do one of two things: - - -- set Vquit_flag to Qnil. (next-event does this.) This will - cause the ^G to be treated as a normal keystroke. - -- not change Vquit_flag but attempt to enqueue the ^G, at - which point it will be discarded. The next time QUIT is - called, it will notice that Vquit_flag was set. - + /* If we read a ^G, then set quit-flag and try to QUIT. + This may be blocked (see above). */ if (e->event_type == key_press_event && event_matches_key_specifier_p (e, make_char (CONSOLE_QUIT_CHAR (XCONSOLE (EVENT_CHANNEL (e)))))) { Vquit_flag = Qt; + QUIT; } } UNGCPRO; } -static void +void run_pre_idle_hook (void) { if (!NILP (Vpre_idle_hook) && !detect_input_pending ()) - safe_run_hook_trapping_errors + safe_run_hook_trapping_problems ("Error in `pre-idle-hook' (setting hook to nil)", - Qpre_idle_hook, 1); + Qpre_idle_hook, INHIBIT_EXISTING_PERMANENT_DISPLAY_OBJECT_DELETION); } static void push_this_command_keys (Lisp_Object event); @@ -2108,10 +2174,11 @@ XCOMMAND_BUILDER (con->command_builder); int store_this_key = 0; struct gcpro gcpro1; + int depth; GCPRO1 (event); - /* DO NOT do QUIT anywhere within this function or the functions it calls. - We want to read the ^G as an event. */ + + depth = begin_dont_check_for_quit (); #ifdef LWLIB_MENUBARS_LUCID /* @@ -2174,7 +2241,7 @@ if (!EVENTP (e) || !command_event_p (e)) signal_error_1 (Qwrong_type_argument, list3 (Qcommand_event_p, e, Qunread_command_events)); - redisplay (); + redisplay_no_pre_idle_hook (); if (!EQ (e, event)) Fcopy_event (e, event); DEBUG_PRINT_EMACS_EVENT ("unread-command-events", event); @@ -2194,7 +2261,7 @@ } if (!EQ (e, event)) Fcopy_event (e, event); - redisplay (); + redisplay_no_pre_idle_hook (); DEBUG_PRINT_EMACS_EVENT ("unread-command-event", event); } @@ -2206,7 +2273,7 @@ { if (!NILP (Vexecuting_macro)) { - redisplay (); + redisplay_no_pre_idle_hook (); pop_kbd_macro_event (event); /* This throws past us at end-of-macro. */ store_this_key = 1; @@ -2217,15 +2284,18 @@ recent-keys. */ else { - run_pre_idle_hook (); redisplay (); next_event_internal (event, 1); - Vquit_flag = Qnil; /* Read C-g as an event. */ store_this_key = 1; } } + /* temporarily reenable quit checking here, because arbitrary lisp + is executed */ + Vquit_flag = Qnil; /* see begin_dont_check_for_quit() */ + unbind_to (depth); status_notify (); /* Notice process change */ + depth = begin_dont_check_for_quit (); /* Since we can free the most stuff here * (since this is typically called from @@ -2258,7 +2328,12 @@ break; } + /* temporarily reenable quit checking here, because we could get stuck */ + Vquit_flag = Qnil; /* see begin_dont_check_for_quit() */ + unbind_to (depth); maybe_do_auto_save (); + depth = begin_dont_check_for_quit (); + num_input_chars++; STORE_AND_EXECUTE_KEY: if (store_this_key) @@ -2326,18 +2401,26 @@ store_kbd_macro_event (event); } } - /* If this is the help char and there is a help form, then execute the - help form and swallow this character. This is the only place where - calling Fnext_event() can cause arbitrary lisp code to run. Note - that execute_help_form() calls Fnext_command_event(), which calls - this function, as well as Fdispatch_event. - */ + /* If this is the help char and there is a help form, then execute + the help form and swallow this character. Note that + execute_help_form() calls Fnext_command_event(), which calls this + function, as well as Fdispatch_event. */ if (!NILP (Vhelp_form) && event_matches_key_specifier_p (XEVENT (event), Vhelp_char)) - execute_help_form (command_builder, event); + { + /* temporarily reenable quit checking here, because we could get stuck */ + Vquit_flag = Qnil; /* see begin_dont_check_for_quit() */ + unbind_to (depth); + execute_help_form (command_builder, event); + depth = begin_dont_check_for_quit (); + } RETURN: + Vquit_flag = Qnil; /* see begin_dont_check_for_quit() */ + unbind_to (depth); + UNGCPRO; + return event; } @@ -2370,9 +2453,11 @@ /* This function can GC */ struct gcpro gcpro1; GCPRO1 (event); + maybe_echo_keys (XCOMMAND_BUILDER (XCONSOLE (Vselected_console)-> command_builder), 0); /* #### This sucks bigtime */ + for (;;) { event = Fnext_event (event, prompt); @@ -2409,15 +2494,12 @@ while (event_stream_event_pending_p (0)) { - QUIT; /* next_event_internal() does not QUIT. */ - /* We're a generator of the command_event_queue, so we can't be a consumer as well. Also, we have no reason to consult the command_event_queue; there are only user and eval-events there, and we'd just have to put them back anyway. */ next_event_internal (event, 0); /* blocks */ - /* See the comment in accept-process-output about Vquit_flag */ if (XEVENT_TYPE (event) == magic_event || XEVENT_TYPE (event) == timeout_event || XEVENT_TYPE (event) == process_event || @@ -2457,16 +2539,14 @@ */ Lisp_Object event = Fmake_event (Qnil, Qnil); Lisp_Object head = Qnil, tail = Qnil; - Lisp_Object oiq = Vinhibit_quit; - struct gcpro gcpro1, gcpro2; + struct gcpro gcpro1; /* #### not correct here with Vselected_console? Should discard-input take a console argument, or maybe map over all consoles? */ struct console *con = XCONSOLE (Vselected_console); /* next_event_internal() can cause arbitrary Lisp code to be evalled */ - GCPRO2 (event, oiq); - Vinhibit_quit = Qt; + GCPRO1 (event); /* If a macro was being defined then we have to mark the modeline has changed to ensure that it gets updated correctly. */ if (!NILP (con->defining_kbd_macro)) @@ -2477,19 +2557,27 @@ while (!NILP (command_event_queue) || event_stream_event_pending_p (1)) { + /* We want to ignore C-g's along with all other keypresses. */ + int depth = begin_dont_check_for_quit (); /* This will take stuff off the command_event_queue, or read it from the event_stream, but it will not block. */ next_event_internal (event, 1); - Vquit_flag = Qnil; /* Treat C-g as a user event (ignore it). - It is vitally important that we reset - Vquit_flag here. Otherwise, if we're - reading from a TTY console, - maybe_read_quit_event() will notice - that C-g has been set and send us - another C-g. That will cause us - to get right back here, and read - another C-g, ad infinitum ... */ + /* The following comment used to be here: + + [[Treat C-g as a user event (ignore it). It is vitally + important that we reset Vquit_flag here. Otherwise, if we're + reading from a TTY console, maybe_read_quit_event() will + notice that C-g has been set and send us another C-g. That + will cause us to get right back here, and read another C-g, + ad infinitum ...]] + + but I don't think this is correct; maybe_read_quit_event() + checks and resets sigint_happened. It shouldn't matter if we + reset here or outside of the while loop. --ben */ + Vquit_flag = Qnil; /* see begin_dont_check_for_quit() */ + + unbind_to (depth); /* If the event is a user event, ignore it. */ if (!command_event_p (event)) @@ -2525,7 +2613,6 @@ Fdeallocate_event (event); UNGCPRO; - Vinhibit_quit = oiq; return Qnil; } @@ -2648,16 +2735,7 @@ continue; /* Don't call next_event_internal */ } - QUIT; /* next_event_internal() does not QUIT, so check for ^G - before reading output from the process - this makes it - less likely that the filter will actually be aborted. - */ - next_event_internal (event, 0); - /* If C-g was pressed while we were waiting, Vquit_flag got - set and next_event_internal() also returns C-g. When - we enqueue the C-g below, it will get discarded. The - next time through, QUIT will be called and will signal a quit. */ switch (XEVENT_TYPE (event)) { case process_event: @@ -2694,6 +2772,9 @@ unbind_to_1 (count, timeout_enabled ? make_int (timeout_id) : Qnil); Fdeallocate_event (event); + + status_notify (); + UNGCPRO; current_buffer = old_buffer; return result; @@ -2730,16 +2811,11 @@ if (!event_stream_wakeup_pending_p (id, 0)) goto DONE_LABEL; - QUIT; /* next_event_internal() does not QUIT, so check for ^G - before reading output from the process - this makes it - less likely that the filter will actually be aborted. - */ /* We're a generator of the command_event_queue, so we can't be a consumer as well. We don't care about command and eval-events anyway. */ next_event_internal (event, 0); /* blocks */ - /* See the comment in accept-process-output about Vquit_flag */ switch (XEVENT_TYPE (event)) { case timeout_event: @@ -2808,13 +2884,10 @@ return Qnil; /* Recursive call from a filter function or timeout handler. */ - if (!NILP(recursive_sit_for)) + if (!NILP (recursive_sit_for)) { if (!event_stream_event_pending_p (1) && NILP (nodisplay)) - { - run_pre_idle_hook (); redisplay (); - } return Qnil; } @@ -2843,10 +2916,7 @@ /* If there is no user input pending, then redisplay. */ if (!event_stream_event_pending_p (1) && NILP (nodisplay)) - { - run_pre_idle_hook (); redisplay (); - } /* If our timeout has arrived, we move along. */ if (!event_stream_wakeup_pending_p (id, 0)) @@ -2855,24 +2925,14 @@ goto DONE_LABEL; } - QUIT; /* next_event_internal() does not QUIT, so check for ^G - before reading output from the process - this makes it - less likely that the filter will actually be aborted. - */ /* We're a generator of the command_event_queue, so we can't be a consumer as well. In fact, we know there's nothing on the command_event_queue that we didn't just put there. */ next_event_internal (event, 0); /* blocks */ - /* See the comment in accept-process-output about Vquit_flag */ if (command_event_p (event)) { - QUIT; /* If the command was C-g check it here - so that we abort out of the sit-for, - not the next command. sleep-for and - accept-process-output continue looping - so they check QUIT again implicitly.*/ result = Qnil; goto DONE_LABEL; } @@ -2927,15 +2987,12 @@ while (!(*predicate) (predicate_arg)) { - QUIT; /* next_event_internal() does not QUIT. */ - /* We're a generator of the command_event_queue, so we can't be a consumer as well. Also, we have no reason to consult the command_event_queue; there are only user and eval-events there, and we'd just have to put them back anyway. */ next_event_internal (event, 0); - /* See the comment in accept-process-output about Vquit_flag */ if (command_event_p (event) || (XEVENT_TYPE (event) == eval_event) || (XEVENT_TYPE (event) == magic_eval_event)) @@ -2989,85 +3046,79 @@ { Lisp_Object p = XEVENT (event)->event.process.process; Charcount readstatus; - - assert (PROCESSP (p)); - while ((readstatus = read_process_output (p)) > 0) - ; - if (readstatus > 0) - ; /* this clauses never gets executed but allows the #ifdefs - to work cleanly. */ + int iter; + + assert (PROCESSP (p)); + for (iter = 0; iter < 2; iter++) + { + if (iter == 1 && !process_has_separate_stderr (p)) + break; + while ((readstatus = read_process_output (p, iter)) > 0) + ; + if (readstatus > 0) + ; /* this clauses never gets executed but + allows the #ifdefs to work cleanly. */ #ifdef EWOULDBLOCK - else if (readstatus == -1 && errno == EWOULDBLOCK) - ; + else if (readstatus == -1 && errno == EWOULDBLOCK) + ; #endif /* EWOULDBLOCK */ #ifdef EAGAIN - else if (readstatus == -1 && errno == EAGAIN) - ; + else if (readstatus == -1 && errno == EAGAIN) + ; #endif /* EAGAIN */ - else if ((readstatus == 0 && - /* Note that we cannot distinguish between no input - available now and a closed pipe. - With luck, a closed pipe will be accompanied by - subprocess termination and SIGCHLD. */ - (!network_connection_p (p) || - /* - When connected to ToolTalk (i.e. - connected_via_filedesc_p()), it's not possible to - reliably determine whether there is a message - waiting for ToolTalk to receive. ToolTalk expects - to have tt_message_receive() called exactly once - every time the file descriptor becomes active, so - the filter function forces this by returning 0. - Emacs must not interpret this as a closed pipe. */ - connected_via_filedesc_p (XPROCESS (p)))) - - /* On some OSs with ptys, when the process on one end of - a pty exits, the other end gets an error reading with - errno = EIO instead of getting an EOF (0 bytes read). - Therefore, if we get an error reading and errno = - EIO, just continue, because the child process has - exited and should clean itself up soon (e.g. when we - get a SIGCHLD). */ + else if ((readstatus == 0 && + /* Note that we cannot distinguish between no input + available now and a closed pipe. + With luck, a closed pipe will be accompanied by + subprocess termination and SIGCHLD. */ + (!network_connection_p (p) || + /* + When connected to ToolTalk (i.e. + connected_via_filedesc_p()), it's not possible to + reliably determine whether there is a message + waiting for ToolTalk to receive. ToolTalk expects + to have tt_message_receive() called exactly once + every time the file descriptor becomes active, so + the filter function forces this by returning 0. + Emacs must not interpret this as a closed pipe. */ + connected_via_filedesc_p (XPROCESS (p)))) + + /* On some OSs with ptys, when the process on one end of + a pty exits, the other end gets an error reading with + errno = EIO instead of getting an EOF (0 bytes read). + Therefore, if we get an error reading and errno = + EIO, just continue, because the child process has + exited and should clean itself up soon (e.g. when we + get a SIGCHLD). */ #ifdef EIO - || (readstatus == -1 && errno == EIO) + || (readstatus == -1 && errno == EIO) #endif - ) - { - /* Currently, we rely on SIGCHLD to indicate that the - process has terminated. Unfortunately, on some systems - the SIGCHLD gets missed some of the time. So we put an - additional check in status_notify() to see whether a - process has terminated. We must tell status_notify() - to enable that check, and we do so now. */ - kick_status_notify (); + ) + { + /* Currently, we rely on SIGCHLD to indicate that the + process has terminated. Unfortunately, on some systems + the SIGCHLD gets missed some of the time. So we put an + additional check in status_notify() to see whether a + process has terminated. We must tell status_notify() + to enable that check, and we do so now. */ + kick_status_notify (); + } + + /* We must call status_notify here to allow the + event_stream->unselect_process_cb to be run if appropriate. + Otherwise, dead fds may be selected for, and we will get a + continuous stream of process events for them. Since we don't + return until all process events have been flushed, we would + get stuck here, processing events on a process whose status + was 'exit. Call this after dispatch-event, or the fds will + have been closed before we read the last data from them. + It's safe for the filter to signal an error because + status_notify() will be called on return to top-level. + */ + status_notify (); + return; } - else - { - /* Deactivate network connection */ - Lisp_Object status = Fprocess_status (p); - if (EQ (status, Qopen) - /* In case somebody changes the theory of whether to - return open as opposed to run for network connection - "processes"... */ - || EQ (status, Qrun)) - update_process_status (p, Qexit, 256, 0); - deactivate_process (p); - } - - /* We must call status_notify here to allow the - event_stream->unselect_process_cb to be run if appropriate. - Otherwise, dead fds may be selected for, and we will get a - continuous stream of process events for them. Since we don't - return until all process events have been flushed, we would - get stuck here, processing events on a process whose status - was 'exit. Call this after dispatch-event, or the fds will - have been closed before we read the last data from them. - It's safe for the filter to signal an error because - status_notify() will be called on return to top-level. - */ - status_notify (); - return; } case timeout_event: @@ -3860,6 +3911,8 @@ else maybe_echo_keys (command_builder, 0); } + /* #### i don't trust this at all. --ben */ +#if 0 else if (!NILP (Vquit_flag)) { Lisp_Object quit_event = Fmake_event (Qnil, Qnil); @@ -3874,6 +3927,7 @@ enqueue_command_event (quit_event); Vquit_flag = Qnil; } +#endif } else if (!NILP (leaf)) { @@ -4095,9 +4149,9 @@ last_point_position = BUF_PT (current_buffer); last_point_position_buffer = wrap_buffer (current_buffer); /* This function can GC */ - safe_run_hook_trapping_errors + safe_run_hook_trapping_problems ("Error in `pre-command-hook' (setting hook to nil)", - Qpre_command_hook, 1); + Qpre_command_hook, INHIBIT_EXISTING_PERMANENT_DISPLAY_OBJECT_DELETION); /* This is a kludge, but necessary; see simple.el */ call0 (Qhandle_pre_motion_command); @@ -4140,9 +4194,38 @@ else zmacs_update_region (); - safe_run_hook_trapping_errors + safe_run_hook_trapping_problems ("Error in `post-command-hook' (setting hook to nil)", - Qpost_command_hook, 1); + Qpost_command_hook, INHIBIT_EXISTING_PERMANENT_DISPLAY_OBJECT_DELETION); + +#if 0 /* FSF Emacs crap */ + if (!NILP (Vdeferred_action_list)) + call0 (Vdeferred_action_function); + + if (NILP (Vunread_command_events) + && NILP (Vexecuting_macro) + && !NILP (Vpost_command_idle_hook) + && !NILP (Fsit_for (make_float ((double) post_command_idle_delay + / 1000000), Qnil))) + safe_run_hook_trapping_problems + ("Error in `post-command-idle-hook' (setting hook to nil)", + Qpost_command_idle_hook, + INHIBIT_EXISTING_PERMANENT_DISPLAY_OBJECT_DELETION); +#endif /* FSF Emacs crap */ + +#if 0 /* FSF Emacs */ + if (!NILP (current_buffer->mark_active)) + { + if (!NILP (Vdeactivate_mark) && !NILP (Vtransient_mark_mode)) + { + current_buffer->mark_active = Qnil; + run_hook (intern ("deactivate-mark-hook")); + } + else if (current_buffer != prev_buffer || + BUF_MODIFF (current_buffer) != prev_modiff) + run_hook (intern ("activate-mark-hook")); + } +#endif /* FSF Emacs */ /* #### Kludge!!! This is necessary to make sure that things are properly positioned even if post-command-hook moves point. @@ -4447,8 +4530,6 @@ if (NILP (continue_echo)) reset_this_command_keys (wrap_console (con), 1); - specbind (Qinhibit_quit, Qt); - if (!NILP (dont_downcase_last)) specbind (Qretry_undefined_key_binding_unshifted, Qnil); @@ -4475,7 +4556,6 @@ } } - Vquit_flag = Qnil; /* In case we read a ^G; do not call check_quit() here */ Fdeallocate_event (event); RETURN_UNGCPRO (unbind_to_1 (speccount, result)); } @@ -4727,7 +4807,7 @@ Function or functions to run before every command. This may examine the `this-command' variable to find out what command is about to be run, or may change it to cause a different command to run. -Function on this hook must be careful to avoid signalling errors! +Errors while running the hook are caught and turned into warnings. */ ); Vpre_command_hook = Qnil; @@ -4743,8 +4823,8 @@ This occurs whenever it is going to block, waiting for an event. This generally happens as a result of a call to `next-event', `next-command-event', `sit-for', `sleep-for', `accept-process-output', -or `x-get-selection'. -Errors running the hook are caught and ignored. +or `get-selection'. Errors while running the hook are caught and +turned into warnings. */ ); Vpre_idle_hook = Qnil; @@ -5063,6 +5143,8 @@ /* +#### this comment is at least 8 years old and some may no longer apply. + useful testcases for v18/v19 compatibility: (defun foo ()