emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Redirecting standard output


From: Lars Magne Ingebrigtsen
Subject: Re: Redirecting standard output
Date: Thu, 21 Apr 2011 16:25:13 +0200
User-agent: Gnus/5.110016 (No Gnus v0.16) Emacs/24.0.50 (gnu/linux)

Here's a quick stab at it.  There's some cargo-cult programming in
there, and I have to go over the error cases again to make sure there's
no FD leaks, but it'll probably look something like the patch included.

Usage is:

(call-process "echo" nil '(:file "/tmp/hello") nil "thing")

or

(call-process "echo" nil '((:file "/tmp/hello") "/tmp/error") nil "thing")

So with this, `call-process' can do all the combinations of
STDERR/STDOUT to file/buffers, except that you can't put STDERR in one
buffer and STDOUT in a different buffer.

But you can get STDERR in a buffer by itself, and STDOUT in a file, so
it's progress of a kind...

=== modified file 'src/callproc.c'
*** src/callproc.c      2011-04-14 19:34:42 +0000
--- src/callproc.c      2011-04-21 14:17:44 +0000
***************
*** 96,101 ****
--- 96,103 ----
  /* Nonzero if this is termination due to exit.  */
  static int call_process_exited;
  
+ static Lisp_Object Qcallproc_file_symbol;
+ 
  static Lisp_Object Fgetenv_internal (Lisp_Object, Lisp_Object);
  
  static Lisp_Object
***************
*** 196,205 ****
--- 198,209 ----
    /* File to use for stderr in the child.
       t means use same as standard output.  */
    Lisp_Object error_file;
+   Lisp_Object output_file = Qnil;
  #ifdef MSDOS  /* Demacs 1.1.1 91/10/16 HIRANO Satoshi */
    char *outf, *tempfile;
    int outfilefd;
  #endif
+   int fd_output = 0;
    struct coding_system process_coding; /* coding-system of process output */
    struct coding_system argument_coding;       /* coding-system of arguments */
    /* Set to the return value of Ffind_operation_coding_system.  */
***************
*** 275,281 ****
  
        /* If BUFFER is a list, its meaning is
         (BUFFER-FOR-STDOUT FILE-FOR-STDERR).  */
!       if (CONSP (buffer))
        {
          if (CONSP (XCDR (buffer)))
            {
--- 279,286 ----
  
        /* If BUFFER is a list, its meaning is
         (BUFFER-FOR-STDOUT FILE-FOR-STDERR).  */
!       if (CONSP (buffer) &&
!         ! EQ (Qcallproc_file_symbol, XCAR (buffer)))
        {
          if (CONSP (XCDR (buffer)))
            {
***************
*** 291,296 ****
--- 296,312 ----
          buffer = XCAR (buffer);
        }
  
+       /* If the buffer is (still) a list, it might be a (:file "file") spec. 
*/
+       if (CONSP (buffer) &&
+         CONSP (XCDR (buffer)) &&
+         EQ (Qcallproc_file_symbol, XCAR (buffer)))
+       {
+         output_file = Fexpand_file_name (XCAR (XCDR (buffer)),
+                                          BVAR (current_buffer, directory));
+         CHECK_STRING (output_file);
+         buffer = Qnil;
+       }
+ 
        if (!(EQ (buffer, Qnil)
            || EQ (buffer, Qt)
            || INTEGERP (buffer)))
***************
*** 318,328 ****
       protected by the caller, so all we really have to worry about is
       buffer.  */
    {
!     struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
  
      current_dir = BVAR (current_buffer, directory);
  
!     GCPRO4 (infile, buffer, current_dir, error_file);
  
      current_dir = Funhandled_file_name_directory (current_dir);
      if (NILP (current_dir))
--- 334,344 ----
       protected by the caller, so all we really have to worry about is
       buffer.  */
    {
!     struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
  
      current_dir = BVAR (current_buffer, directory);
  
!     GCPRO5 (infile, buffer, current_dir, error_file, output_file);
  
      current_dir = Funhandled_file_name_directory (current_dir);
      if (NILP (current_dir))
***************
*** 342,347 ****
--- 358,365 ----
        current_dir = ENCODE_FILE (current_dir);
      if (STRINGP (error_file) && STRING_MULTIBYTE (error_file))
        error_file = ENCODE_FILE (error_file);
+     if (STRINGP (output_file) && STRING_MULTIBYTE (output_file))
+       output_file = ENCODE_FILE (output_file);
      UNGCPRO;
    }
  
***************
*** 353,358 ****
--- 371,394 ----
        infile = DECODE_FILE (infile);
        report_file_error ("Opening process input file", Fcons (infile, Qnil));
      }
+ 
+   if (STRINGP (output_file))
+     {
+ #ifdef DOS_NT
+       fd_output = emacs_open (SSDATA (output_file),
+                             O_WRONLY | O_TRUNC | O_CREAT | O_TEXT,
+                             S_IREAD | S_IWRITE);
+ #else  /* not DOS_NT */
+       fd_output = creat (SSDATA (output_file), 0666);
+ #endif /* not DOS_NT */
+       if (fd_output < 0)
+       {
+            output_file = DECODE_FILE (output_file);
+            report_file_error ("Opening process output file",
+          Fcons (output_file, Qnil));
+         }
+     }
+ 
    /* Search for program; barf if not found.  */
    {
      struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
***************
*** 413,425 ****
    strcat (tempfile, "detmp.XXX");
    mktemp (tempfile);
  
!   outfilefd = creat (tempfile, S_IREAD | S_IWRITE);
!   if (outfilefd < 0)
      {
        emacs_close (filefd);
        report_file_error ("Opening process output file",
!                        Fcons (build_string (tempfile), Qnil));
      }
    fd[0] = filefd;
    fd[1] = outfilefd;
  #endif /* MSDOS */
--- 449,467 ----
    strcat (tempfile, "detmp.XXX");
    mktemp (tempfile);
  
!   /* If we're redirecting STDOUT to a file, this is already opened. */
!   if (fd_output == 0)
      {
+       outfilefd = creat (tempfile, S_IREAD | S_IWRITE);
+       if (outfilefd < 0)
+       {
        emacs_close (filefd);
        report_file_error ("Opening process output file",
!       Fcons (build_string (tempfile), Qnil));
!         }
      }
+   else
+       outfilefd = fd_output;
    fd[0] = filefd;
    fd[1] = outfilefd;
  #endif /* MSDOS */
***************
*** 450,455 ****
--- 492,499 ----
      struct sigaction sigpipe_action;
  #endif
  
+     if (fd_output > 0)
+       fd1 = fd_output;
  #if 0  /* Some systems don't have sigblock.  */
      mask = sigblock (sigmask (SIGCHLD));
  #endif
***************
*** 1554,1559 ****
--- 1598,1606 ----
  #endif
    staticpro (&Vtemp_file_name_pattern);
  
+   Qcallproc_file_symbol = intern_c_string (":file");
+   staticpro (&Qcallproc_file_symbol);
+ 
    DEFVAR_LISP ("shell-file-name", Vshell_file_name,
               doc: /* *File name to load inferior shells from.
  Initialized from the SHELL environment variable, or to a system-dependent

(Note!  Not thoroughly tested.  I'll go through all the possibilities
now...)

-- 
(domestic pets only, the antidote for overdose, milk.)
  bloggy blog http://lars.ingebrigtsen.no/

reply via email to

[Prev in Thread] Current Thread [Next in Thread]