changeset 862:278c743f1578

[xemacs-hg @ 2002-06-03 12:23:49 by ben] process fixes process.el: Create new process-synchronize-point to avoid dynamic binding problems. Fix editing bogosity in setting process sentinels. process.c: Don't invalidate the process marker after the process has died to make point synchronization in `call-process-internal' possible.
author ben
date Mon, 03 Jun 2002 12:24:14 +0000
parents 9a116d92c011
children 42375619fa45
files lisp/ChangeLog lisp/process.el src/ChangeLog src/process.c
diffstat 4 files changed, 135 insertions(+), 120 deletions(-) [+]
line wrap: on
line diff
--- a/lisp/ChangeLog	Mon Jun 03 10:10:12 2002 +0000
+++ b/lisp/ChangeLog	Mon Jun 03 12:24:14 2002 +0000
@@ -1,3 +1,12 @@
+2002-06-03  Ben Wing  <ben@xemacs.org> and
+            Michael Sperber [Mr. Preprocessor]  <sperber@informatik.uni-tuebingen.de>
+
+	* process.el:
+	* process.el (process-synchronize-point): New.
+	* process.el (call-process-internal):
+	Create new process-synchronize-point to avoid dynamic binding
+	problems.  Fix editing bogosity in setting process sentinels.
+
 2002-05-28  Katsumi Yamaoka  <yamaoka@jpl.org>
 
 	* obsolete.el (find-non-ascii-charset-region): Revert the function
--- a/lisp/process.el	Mon Jun 03 10:10:12 2002 +0000
+++ b/lisp/process.el	Mon Jun 03 12:24:14 2002 +0000
@@ -75,6 +75,29 @@
   (start-process name buffer shell-file-name shell-command-switch
 		 (mapconcat #'identity args " ")))
 
+(defun process-synchronize-point (proc)
+  "Set the point(s) in buffer and stderr-buffer according to the process mark."
+  ;; We need this because the documentation says to insert *BEFORE* point,
+  ;; but we end up inserting after because only the process mark moves
+  ;; forward, not point.  We synchronize after every place output might
+  ;; happen, in sentinels, and in an unwind-protect, to make *SURE* that
+  ;; point is correct. (We could do this more easily and perhaps more
+  ;; safely using a process filter, but that would create a LOT of garbage
+  ;; since all the data would get sent in strings.) We make this a separate
+  ;; function, not an flet, due to dynamic binding problems -- the flet may
+  ;; not still be in scope when the sentinel is called.
+  (let ((pb (process-buffer proc))
+	(pm (process-mark proc)))
+    (if (and pb (buffer-live-p pb) (marker-buffer pm))
+	(goto-char pm pb))
+    (if (process-has-separate-stderr-p proc)
+	(let ((pseb (process-stderr-buffer proc))
+	      (psem (process-stderr-mark proc)))
+	  (if (and pseb (not (eq pb pseb))
+		   (buffer-live-p pseb)
+		   (marker-buffer psem))
+	      (goto-char psem pseb))))))
+
 (defun call-process-internal (program &optional infile buffer display
 				      &rest args)
   "Internal function to call PROGRAM synchronously in separate process.
@@ -186,128 +209,106 @@
 		(set-marker (process-mark proc) (point buffer) buffer))
 	    (if errbuf
 		(set-marker (process-stderr-mark proc) (point errbuf) errbuf))
-	    ;; bind a function to set the point(s) in buffer and
-	    ;; stderr-buffer.  this is because the documentation says to
-	    ;; insert *BEFORE* point, but we end up inserting after because
-	    ;; only the process mark moves forward, not point.  we
-	    ;; synchronize after every place output might happen, in
-	    ;; sentinels, and in an unwind-protect, to make *SURE* that
-	    ;; point is correct. (We could do this more easily and perhaps
-	    ;; more safely using a process filter, but that would create a
-	    ;; LOT of garbage since all the data would get sent in
-	    ;; strings.)
-	    (flet ((synchronize-point (proc)
-		     (let ((pb (process-buffer proc))
-			   (pm (process-mark proc)))
-		       (if (and pb (buffer-live-p pb) (marker-buffer pm))
-			   (goto-char pm pb))
-		       (if (process-has-separate-stderr-p proc)
-			   (let ((pseb (process-stderr-buffer proc))
-				 (psem (process-stderr-mark proc)))
-			     (if (and pseb (not (eq pb pseb))
-				      (buffer-live-p pseb)
-				      (marker-buffer psem))
-				 (goto-char psem pseb)))))))
 	      ;; now do I/O, very carefully!  the unwind-protect makes sure
 	      ;; to clear out the sentinel, since it does a `throw', which
 	      ;; would have no catch (or writes to a file -- we only want
 	      ;; this on normal exit)
-	      (unwind-protect
-		  ;; if not NO-WAIT, set a sentinel to return the exit
-		  ;; status.  it will throw to this catch so we can exit
-		  ;; properly.
-		  (catch 'call-process-done
-		    (set-process-sentinel
-		     proc
-		     (if no-wait
-			 ;; we're trying really really hard to emulate
-			 ;; the old call-process, which would save the
-			 ;; stderr to a file even if discarding output.  so
-			 ;; we set a sentinel to save the output when
-			 ;; we finish.
-			 ;;
-			 ;; #### not clear if we should be doing this.
-			 ;;
-			 ;; NOTE NOTE NOTE: Due to the total bogosity of
-			 ;; dynamic scoping, and the lack of closures, we
-			 ;; have to be careful how we write the first
-			 ;; sentinel below since it may be executed after
-			 ;; this function has returned -- thus we fake a
-			 ;; closure. (This doesn't apply to the second one,
-			 ;; which only gets executed within the
-			 ;; unwind-protect.)
-			 (if (and errbuf stderr)
-			     (set-process-sentinel
-			      proc
-			      `(lambda (proc status)
-				 (set-process-sentinel proc nil)
-				 (synchronize-point proc)
-				 (with-current-buffer ,errbuf
-				   (write-region-internal
-				    1 (1+ (buffer-size))
-				    ,stderr
-				    nil 'major-rms-kludge-city nil
-				    coding-system-for-write))
-				 (kill-buffer ,errbuf))))
-		       ;; normal sentinel: maybe write out stderr and return
-		       ;; status.
-		       #'(lambda (proc status)
-			   (synchronize-point proc)
-			   (when (and errbuf stderr)
-			     (with-current-buffer errbuf
-			       (write-region-internal
-				1 (1+ (buffer-size)) stderr
-				nil 'major-rms-kludge-city nil
-				coding-system-for-write)))
-			   (cond ((eq 'exit (process-status proc))
-				  (set-process-sentinel proc nil)
-				  (throw 'call-process-done
-					 (process-exit-status proc)))
-				 ((eq 'signal (process-status proc))
-				  (set-process-sentinel proc nil)
-				  (throw 'call-process-done status))))))
-		    (if (not no-wait)
-			;; we're waiting.  send the input and loop forever,
-			;; handling process output and maybe redisplaying.
-			;; exit happens through the sentinel or C-g.  if
-			;; C-g, send SIGINT the first time, EOF if not
-			;; already done so (might make the process exit),
-			;; and keep waiting.  Another C-g will exit the
-			;; whole function, and the unwind-protect will
-			;; kill the process. (Hence the documented semantics
-			;; of SIGINT/SIGKILL.)
-			(let (eof-sent)
-			  (condition-case nil
-			      (progn
-				(when inbuf
-				  (process-send-region proc start end inbuf))
-				(process-send-eof proc)
-				(setq eof-sent t)
-				(while t
-				  (accept-process-output proc)
-				  (synchronize-point proc)
-				  (if display (sit-for 0))))
-			    (quit
-			     (process-send-signal 'SIGINT proc)
-			     (unless eof-sent
-			       (process-send-eof proc))
-			     (while t
-			       (accept-process-output proc)
-			       (synchronize-point proc)
-			       (if display (sit-for 0))))))
-		      ;; discard and no wait: send the input, set PROC
-		      ;; and ERRBUF to nil so that the unwind-protect
-		      ;; forms don't erase the sentinel, kill the process,
-		      ;; or kill ERRBUF (the sentinel does that), and exit.
-		      (when inbuf
-			(process-send-region proc start end inbuf))
-		      (process-send-eof proc)
-		      (setq errbuf nil)
-		      (setq proc nil)))
-		;; inner unwind-protect, once we're ready to do I/O.
-		(when proc
-		  (set-process-sentinel proc nil)
-		  (synchronize-point proc))))))
+	    (unwind-protect
+		;; if not NO-WAIT, set a sentinel to return the exit
+		;; status.  it will throw to this catch so we can exit
+		;; properly.
+		(catch 'call-process-done
+		  (set-process-sentinel
+		   proc
+		   (cond
+		    ((and no-wait errbuf stderr)
+		     ;; we're trying really really hard to emulate
+		     ;; the old call-process, which would save the
+		     ;; stderr to a file even if discarding output.  so
+		     ;; we set a sentinel to save the output when
+		     ;; we finish.
+		     ;;
+		     ;; #### not clear if we should be doing this.
+		     ;;
+		     ;; NOTE NOTE NOTE: Due to the total bogosity of
+		     ;; dynamic scoping, and the lack of closures, we
+		     ;; have to be careful how we write the first
+		     ;; sentinel below since it may be executed after
+		     ;; this function has returned -- thus we fake a
+		     ;; closure. (This doesn't apply to the second one,
+		     ;; which only gets executed within the
+		     ;; unwind-protect.)
+		     `(lambda (proc status)
+			(set-process-sentinel proc nil)
+			(process-synchronize-point proc)
+			(with-current-buffer ,errbuf
+			  (write-region-internal
+			   1 (1+ (buffer-size))
+			   ,stderr
+			   nil 'major-rms-kludge-city nil
+			   coding-system-for-write))
+			(kill-buffer ,errbuf)))
+		    (no-wait nil)
+		    (t
+		     ;; normal sentinel: maybe write out stderr and return
+		     ;; status.
+		     #'(lambda (proc status)
+			 (process-synchronize-point proc)
+			 (when (and errbuf stderr)
+			   (with-current-buffer errbuf
+			     (write-region-internal
+			      1 (1+ (buffer-size)) stderr
+			      nil 'major-rms-kludge-city nil
+			      coding-system-for-write)))
+			 (cond ((eq 'exit (process-status proc))
+				(set-process-sentinel proc nil)
+				(throw 'call-process-done
+				       (process-exit-status proc)))
+			       ((eq 'signal (process-status proc))
+				(set-process-sentinel proc nil)
+				(throw 'call-process-done status)))))))
+		  (if (not no-wait)
+		      ;; we're waiting.  send the input and loop forever,
+		      ;; handling process output and maybe redisplaying.
+		      ;; exit happens through the sentinel or C-g.  if
+		      ;; C-g, send SIGINT the first time, EOF if not
+		      ;; already done so (might make the process exit),
+		      ;; and keep waiting.  Another C-g will exit the
+		      ;; whole function, and the unwind-protect will
+		      ;; kill the process. (Hence the documented semantics
+		      ;; of SIGINT/SIGKILL.)
+		      (let (eof-sent)
+			(condition-case nil
+			    (progn
+			      (when inbuf
+				(process-send-region proc start end inbuf))
+			      (process-send-eof proc)
+			      (setq eof-sent t)
+			      (while t
+				(accept-process-output proc)
+				(process-synchronize-point proc)
+				(if display (sit-for 0))))
+			  (quit
+			   (process-send-signal 'SIGINT proc)
+			   (unless eof-sent
+			     (process-send-eof proc))
+			   (while t
+			     (accept-process-output proc)
+			     (process-synchronize-point proc)
+			     (if display (sit-for 0))))))
+		    ;; discard and no wait: send the input, set PROC
+		    ;; and ERRBUF to nil so that the unwind-protect
+		    ;; forms don't erase the sentinel, kill the process,
+		    ;; or kill ERRBUF (the sentinel does that), and exit.
+		    (when inbuf
+		      (process-send-region proc start end inbuf))
+		    (process-send-eof proc)
+		    (setq errbuf nil)
+		    (setq proc nil)))
+	      ;; inner unwind-protect, once we're ready to do I/O.
+	      (when proc
+		(set-process-sentinel proc nil)
+		(process-synchronize-point proc)))))
       ;; outer unwind-protect forms, to make sure we always clean up.
       (if (and inbuf kill-inbuf) (kill-buffer inbuf))
       (if (and errbuf kill-errbuf) (kill-buffer errbuf))
--- a/src/ChangeLog	Mon Jun 03 10:10:12 2002 +0000
+++ b/src/ChangeLog	Mon Jun 03 12:24:14 2002 +0000
@@ -1,3 +1,9 @@
+2002-06-02  Michael Sperber [Mr. Preprocessor]  <sperber@informatik.uni-tuebingen.de>
+
+	* process.c (remove_process): Don't invalidate the process marker
+	after the process has died to make point synchronization in
+	`call-process-internal' possible.
+
 2002-06-01  Ben Wing  <ben@xemacs.org>
 
 	* buffer.c (init_initial_directory):
--- a/src/process.c	Mon Jun 03 10:10:12 2002 +0000
+++ b/src/process.c	Mon Jun 03 12:24:14 2002 +0000
@@ -2161,7 +2161,6 @@
 remove_process (Lisp_Object process)
 {
   Vprocess_list = delq_no_quit (process, Vprocess_list);
-  Fset_marker (XPROCESS (process)->mark, Qnil, Qnil);
 
   deactivate_process (process);
 }
@@ -2652,7 +2651,7 @@
 #ifdef PROCESS_IO_BLOCKING
   DEFVAR_LISP ("network-stream-blocking-port-list", &network_stream_blocking_port_list /*
 List of port numbers or port names to set a blocking I/O mode with connection.
-Nil value means to set a default(non-blocking) I/O mode.
+Nil value means to set a default (non-blocking) I/O mode.
 The value takes effect when `open-network-stream-internal' is called.
 */ );
   network_stream_blocking_port_list = Qnil;