changeset 6321:363a2f8c9e97

[project @ 2007-02-16 20:26:23 by dbateman]
author dbateman
date Fri, 16 Feb 2007 20:27:46 +0000
parents 6338017166e4
children 723a32c8ee10
files liboctave/ChangeLog liboctave/lo-sysdep.cc liboctave/lo-sysdep.h liboctave/oct-syscalls.cc liboctave/oct-syscalls.h scripts/ChangeLog src/ChangeLog src/syscalls.cc
diffstat 8 files changed, 367 insertions(+), 14 deletions(-) [+]
line wrap: on
line diff
--- a/liboctave/ChangeLog	Fri Feb 16 20:26:11 2007 +0000
+++ b/liboctave/ChangeLog	Fri Feb 16 20:27:46 2007 +0000
@@ -1,3 +1,11 @@
+2007-02-16  Michael Goffioul  <michael.goffioul@swing.be>
+
+	* lo-sysdep.cc (octave_popen2): New function to simulate popen2 on
+	windows platform.
+	* lo-sysdep.h (octave_popen2): Declare it.
+	* oct-syscalls.cc (octave_syscalls::popen2): New function.
+	* oct-syscalls.h (octave_syscalls::popen2): Declare it.
+
 2007-02-14  John W. Eaton  <jwe@octave.org>
 
 	* kpse.cc (expand_elt): Omit special treatment for //.
--- a/liboctave/lo-sysdep.cc	Fri Feb 16 20:26:11 2007 +0000
+++ b/liboctave/lo-sysdep.cc	Fri Feb 16 20:27:46 2007 +0000
@@ -27,6 +27,7 @@
 
 #include <iostream>
 #include <string>
+#include <vector>
 
 #ifdef HAVE_UNISTD_H
 #ifdef HAVE_SYS_TYPES_H
@@ -35,10 +36,15 @@
 #include <unistd.h>
 #endif
 
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
 #include "file-ops.h"
 #include "lo-error.h"
 #include "pathlen.h"
 #include "lo-sysdep.h"
+#include "str-vec.h"
 
 std::string
 octave_getcwd (void)
@@ -99,7 +105,70 @@
 #endif
 }
 
-#if defined (_MSC_VER)
+#if defined (__WIN32__) && ! defined (__CYGWIN__)
+
+pid_t
+octave_popen2 (const std::string& cmd, const string_vector& args, bool sync_mode,
+    int *fildes, std::string& msg)
+{
+  pid_t pid;
+  PROCESS_INFORMATION pi;
+  STARTUPINFO si;
+  std::string command = "\"" + cmd + "\"";
+  HANDLE hProcess = GetCurrentProcess(), childRead, childWrite, parentRead, parentWrite;
+  DWORD pipeMode;
+
+  ZeroMemory (&pi, sizeof (pi));
+  ZeroMemory (&si, sizeof (si));
+  si.cb = sizeof (si);
+
+  if (! CreatePipe (&childRead, &parentWrite, 0, 0) ||
+      ! DuplicateHandle (hProcess, childRead, hProcess, &childRead, 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE))
+    {
+      msg = "popen2: pipe creation failed";
+      return -1;
+    }
+  if (! CreatePipe (&parentRead, &childWrite, 0, 0) ||
+      ! DuplicateHandle (hProcess, childWrite, hProcess, &childWrite, 0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE))
+    {
+      msg = "popen2: pipe creation failed";
+      return -1;
+    }
+  if (! sync_mode)
+    {
+      pipeMode = PIPE_NOWAIT;
+      SetNamedPipeHandleState (parentRead, &pipeMode, 0, 0);
+      SetNamedPipeHandleState (parentWrite, &pipeMode, 0, 0);
+    }
+  fildes[1] = _open_osfhandle (reinterpret_cast<long> (parentRead), _O_RDONLY | _O_BINARY);
+  fildes[0] = _open_osfhandle (reinterpret_cast<long> (parentWrite), _O_WRONLY | _O_BINARY);
+  si.dwFlags |= STARTF_USESTDHANDLES;
+  si.hStdInput = childRead;
+  si.hStdOutput = childWrite;
+
+  // Ignore first arg as it is the command
+  for (int k=1; k<args.length(); k++)
+    command += " \"" + args[k] + "\"";
+  OCTAVE_LOCAL_BUFFER (char, c_command, command.length () + 1);
+  strcpy (c_command, command.c_str ());
+  if (! CreateProcess (0, c_command, 0, 0, TRUE, 0, 0, 0, &si, &pi))
+    {
+      msg = "popen2: process creation failed";
+      return -1;
+    }
+  pid = pi.dwProcessId;
+
+  CloseHandle (childRead);
+  CloseHandle (childWrite);
+  CloseHandle (pi.hProcess);
+  CloseHandle (pi.hThread);
+
+  return pid;
+}
+
+#endif
+
+#if defined (_MSC_VER) && ! defined (HAVE_DIRENT_H)
 
 // FIXME -- it would probably be better to adapt the versions of
 // opendir, readdir, and closedir from Emacs as they appear to be more
--- a/liboctave/lo-sysdep.h	Fri Feb 16 20:26:11 2007 +0000
+++ b/liboctave/lo-sysdep.h	Fri Feb 16 20:27:46 2007 +0000
@@ -27,6 +27,7 @@
 #include <string>
 
 #include "lo-ieee.h"
+class string_vector;
 
 extern std::string octave_getcwd (void);
 
@@ -36,7 +37,12 @@
 extern int gethostname (char *, int);
 #endif
 
-#if defined (_MSC_VER)
+#if defined (__WIN32__) && ! defined (__CYGWIN__)
+extern pid_t octave_popen2 (const std::string&, const string_vector&,
+    bool, int *, std::string&);
+#endif
+
+#if defined (_MSC_VER) && ! defined (HAVE_DIRENT_H)
 
 // FIXME -- it would probably be better to adapt the versions of
 // opendir, readdir, and closedir from Emacs as they appear to be more
--- a/liboctave/oct-syscalls.cc	Fri Feb 16 20:26:11 2007 +0000
+++ b/liboctave/oct-syscalls.cc	Fri Feb 16 20:27:46 2007 +0000
@@ -47,6 +47,7 @@
 #include <signal.h>
 
 #include "lo-utils.h"
+#include "lo-sysdep.h"
 #include "oct-syscalls.h"
 #include "str-vec.h"
 
@@ -356,6 +357,100 @@
   return status;
 }
 
+pid_t
+octave_syscalls::popen2 (const std::string& cmd, const string_vector& args,
+    bool sync_mode, int *fildes)
+{
+  std::string msg;
+  bool interactive = false;
+  return popen2 (cmd, args, sync_mode, fildes, msg, interactive);
+}
+
+pid_t
+octave_syscalls::popen2 (const std::string& cmd, const string_vector& args,
+    bool sync_mode, int *fildes, std::string& msg)
+{
+  bool interactive = false;
+  return popen2 (cmd, args, sync_mode, fildes, msg, interactive);
+}
+
+pid_t
+octave_syscalls::popen2 (const std::string& cmd, const string_vector& args,
+    bool sync_mode, int *fildes, std::string& msg, bool &interactive)
+{
+#if defined (__WIN32__) && ! defined (__CYGWIN__)
+  return ::octave_popen2 (cmd, args, sync_mode, fildes, msg);
+#else
+  pid_t pid;
+  int child_stdin[2], child_stdout[2];
+
+  if (pipe (child_stdin, msg) == 0)
+    {
+      if (pipe (child_stdout, msg) == 0)
+        {
+          pid = fork (msg);
+          if (pid < 0)
+            msg = "popen2: process creation failed -- " + msg;
+          else if (pid == 0)
+            {
+	      std::string child_msg;
+
+	      interactive = false;
+
+              // Child process
+              ::close (child_stdin[1]);
+              ::close (child_stdout[0]);
+
+              if (dup2 (child_stdin[0], STDIN_FILENO) >= 0)
+                {
+                  ::close (child_stdin[0]);
+                  if (dup2 (child_stdout[1], STDOUT_FILENO) >= 0)
+                    {
+                      ::close (child_stdout[1]);
+                      if (execvp (cmd, args, child_msg) < 0)
+                        child_msg = "popen2 (child): unable to start process -- " + child_msg;
+                    }
+                  else
+                    child_msg = "popen2 (child): file handle duplication failed -- " + child_msg;
+                }
+              else
+                child_msg = "popen2 (child): file handle duplication failed -- " + child_msg;
+	      
+	      (*current_liboctave_error_handler)(child_msg.c_str());
+	      
+	      exit(0);
+            }
+          else
+            {
+              // Parent process
+              ::close (child_stdin[0]);
+              ::close (child_stdout[1]);
+#if defined (F_SETFL) && defined (O_NONBLOCK)
+              if (! sync_mode && fcntl (child_stdout[0], F_SETFL, O_NONBLOCK, msg) < 0)
+                msg = "popen2: error setting file mode -- " + msg;
+              else
+#endif
+                {
+                  fildes[0] = child_stdin [1];
+                  fildes[1] = child_stdout [0];
+                  return pid;
+                }
+            }
+          ::close (child_stdout[0]);
+          ::close (child_stdout[1]);
+        }
+      else
+        msg = "popen2: pipe creation failed -- " + msg;
+      ::close (child_stdin[0]);
+      ::close (child_stdin[1]);
+    }
+  else
+    msg = "popen2: pipe creation failed -- " + msg;
+
+  return -1;
+#endif
+}
+
 /*
 ;;; Local Variables: ***
 ;;; mode: C++ ***
--- a/liboctave/oct-syscalls.h	Fri Feb 16 20:26:11 2007 +0000
+++ b/liboctave/oct-syscalls.h	Fri Feb 16 20:27:46 2007 +0000
@@ -67,6 +67,10 @@
 
   static int kill (pid_t, int);
   static int kill (pid_t, int, std::string&);
+
+  static pid_t popen2 (const std::string&, const string_vector&, bool, int *);
+  static pid_t popen2 (const std::string&, const string_vector&, bool, int *, std::string&);
+  static pid_t popen2 (const std::string&, const string_vector&, bool, int *, std::string&, bool &interactive);
 };
 
 #endif
--- a/scripts/ChangeLog	Fri Feb 16 20:26:11 2007 +0000
+++ b/scripts/ChangeLog	Fri Feb 16 20:27:46 2007 +0000
@@ -1,3 +1,7 @@
+2007-02-16  Michael Goffioul  <michael.goffioul@swing.be>
+
+	* miscellaneous/popen2.m: Remove as replaced with builtin.
+
 2007-02-16  Muthiah Annamalai  <muthuspost@gmail.com>
 
 	* specfun/nchoosek.m: Check nargin.
--- a/src/ChangeLog	Fri Feb 16 20:26:11 2007 +0000
+++ b/src/ChangeLog	Fri Feb 16 20:27:46 2007 +0000
@@ -1,3 +1,9 @@
+2007-02-16  Michael Goffioul  <michael.goffioul@swing.be>
+
+	* syscalls.cc (Fpopen2): New function.
+	(pipe): Modify to return input and output file descriptor
+	seperately rather than in a list.
+	
 2007-02-16  John W. Eaton  <jwe@octave.org>
 
 	* input.cc (interactive_input): New arg, DEBUG.  Don't call
--- a/src/syscalls.cc	Fri Feb 16 20:26:11 2007 +0000
+++ b/src/syscalls.cc	Fri Feb 16 20:27:46 2007 +0000
@@ -60,6 +60,7 @@
 #include "sysdep.h"
 #include "utils.h"
 #include "variables.h"
+#include "input.h"
 
 static Octave_map
 mk_stat_map (const file_stat& fs)
@@ -220,6 +221,168 @@
   return retval;
 }
 
+DEFUN (popen2, args, ,
+ "-*- texinfo -*-\n\
+@deftypefn {Function File} {[@var{in}, @var{out}, @var{pid}] =} popen2 (@var{command}, @var{args})\n\
+Start a subprocess with two-way communication.  The name of the process\n\
+is given by @var{command}, and @var{args} is an array of strings\n\
+containing options for the command.  The file identifiers for the input\n\
+and output streams of the subprocess are returned in @var{in} and\n\
+@var{out}.  If execution of the command is successful, @var{pid}\n\
+contains the process ID of the subprocess.  Otherwise, @var{pid} is\n\
+@minus{}1.\n\
+\n\
+For example,\n\
+\n\
+@example\n\
+@group\n\
+[in, out, pid] = popen2 (\"sort\", \"-nr\");\n\
+fputs (in, \"these\\nare\\nsome\\nstrings\\n\");\n\
+fclose (in);\n\
+EAGAIN = errno (\"EAGAIN\");\n\
+done = false;\n\
+do\n\
+  s = fgets (out);\n\
+  if (ischar (s))\n\
+    fputs (stdout, s);\n\
+  elseif (errno () == EAGAIN)\n\
+    sleep (0.1);\n\
+    fclear (out);\n\
+  else\n\
+    done = true;\n\
+  endif\n\
+until (done)\n\
+fclose (out);\n\
+     @print{} are\n\
+     @print{} some\n\
+     @print{} strings\n\
+     @print{} these\n\
+@end group\n\
+@end example\n\
+@end deftypefn")
+{
+  octave_value_list retval;
+
+  retval(2) = -1;
+  retval(1) = Matrix ();
+  retval(0) = Matrix ();
+
+  int nargin = args.length ();
+
+  if (nargin >= 1 && nargin <= 3)
+    {
+      std::string exec_file = args(0).string_value();
+
+      if (! error_state)
+        {
+	  string_vector arg_list;
+
+	  if (nargin >= 2)
+	    {
+	      string_vector tmp = args(1).all_strings ();
+
+	      if (! error_state)
+		{
+		  int len = tmp.length ();
+
+		  arg_list.resize (len + 1);
+
+		  arg_list[0] = exec_file;
+
+		  for (int i = 0; i < len; i++)
+		    arg_list[i+1] = tmp[i];
+		}
+	      else
+		error ("popen2: arguments must be character strings");
+	    }
+	  else
+	    {
+	      arg_list.resize (1);
+
+	      arg_list[0] = exec_file;
+	    }
+
+          if (! error_state)
+            {
+              bool sync_mode = (nargin == 3 ? args(2).bool_value() : false);
+
+              if (! error_state)
+                {
+                  int fildes[2];
+                  std::string msg;
+                  pid_t pid;
+
+                  pid = octave_syscalls::popen2 (exec_file, arg_list, sync_mode, fildes, msg, interactive);
+                  if (pid >= 0)
+                    {
+                      FILE *ifile = fdopen (fildes[1], "r");
+                      FILE *ofile = fdopen (fildes[0], "w");
+
+                      std::string nm;
+
+                      octave_stream is = octave_stdiostream::create (nm, ifile,
+                          std::ios::in);
+
+                      octave_stream os = octave_stdiostream::create (nm, ofile,
+                          std::ios::out);
+
+                      Cell file_ids (1, 2);
+
+                      retval(0) = octave_stream_list::insert (os);
+                      retval(1) = octave_stream_list::insert (is);
+					  retval(2) = pid;
+                    }
+				  else
+                    error (msg.c_str ());
+                }
+            }
+          else
+            error ("popen2: arguments must be character strings");
+        }
+      else
+        error ("popen2: first argument must be a string");
+    }
+  else
+    print_usage ();
+
+  return retval;
+}
+
+/*
+
+%!test
+%!  if (isunix())
+%!    [in, out, pid] = popen2 ("sort", "-nr");
+%!    EAGAIN = errno ("EAGAIN");
+%!  else
+%!    [in, out, pid] = popen2 ("sort", "/R", 1);
+%!    EAGAIN = errno ("EINVAL");
+%!  endif
+%!  fputs (in, "these\nare\nsome\nstrings\n");
+%!  fclose (in);
+%!  done = false;
+%!  str = {};
+%!  idx = 0;
+%!  do
+%!     if (!isunix())
+%!       errno (0);
+%!     endif
+%!     s = fgets (out);
+%!     if (ischar (s))
+%!       idx++;
+%!       str{idx} = s;
+%!     elseif (errno () == EAGAIN)
+%!       sleep (0.1);
+%!       fclear (out);
+%!     else
+%!       done = true;
+%!     endif
+%!   until (done)
+%!  fclose (out);
+%!  assert(str,{"these\n","strings\n","some\n","are\n"})
+
+*/
+
 DEFUN (fcntl, args, ,
  "-*- texinfo -*-\n\
 @deftypefn {Built-in Function} {[@var{err}, @var{msg}] =} fcntl (@var{fid}, @var{request}, @var{arg})\n\
@@ -644,9 +807,9 @@
 
 DEFUN (pipe, args, ,
   "-*- texinfo -*-\n\
-@deftypefn {Built-in Function} {[@var{file_ids}, @var{err}, @var{msg}] =} pipe ()\n\
-Create a pipe and return the vector @var{file_ids}, which corresponding\n\
-to the reading and writing ends of the pipe.\n\
+@deftypefn {Built-in Function} {[@var{read_fd}, @var{write_fd}, @var{err}, @var{msg}] =} pipe ()\n\
+Create a pipe and return the reading and writing ends of the pipe\n\
+into @var{read_fd} and @var{write_fd} respectively.\n\
 \n\
 If successful, @var{err} is 0 and @var{msg} is an empty string.\n\
 Otherwise, @var{err} is nonzero and @var{msg} contains a\n\
@@ -655,9 +818,10 @@
 {
   octave_value_list retval;
 
-  retval(2) = std::string ();
+  retval(3) = std::string ();
+  retval(2) = -1;
   retval(1) = -1;
-  retval(0) = Matrix ();
+  retval(0) = -1;
 
   int nargin = args.length ();
 
@@ -670,7 +834,7 @@
       int status = octave_syscalls::pipe (fid, msg);
 
       if (status < 0)
-	retval(2) = msg;
+	retval(3) = msg;
       else
 	{
 	  FILE *ifile = fdopen (fid[0], "r");
@@ -684,13 +848,10 @@
 	  octave_stream os = octave_stdiostream::create (nm, ofile,
 							 std::ios::out);
 
-	  octave_value_list file_ids;
+	  retval(1) = octave_stream_list::insert (os);
+	  retval(0) = octave_stream_list::insert (is);
 
-	  file_ids(1) = octave_stream_list::insert (os);
-	  file_ids(0) = octave_stream_list::insert (is);
-
-	  retval(1) = status;
-          retval(0) = octave_value (file_ids);
+	  retval(2) = status;
 	}
     }
   else