# HG changeset patch # User dbateman # Date 1171657666 0 # Node ID 363a2f8c9e979240ff7470ef624f2c47ada3c765 # Parent 6338017166e4548da7c296c0e990976b2d596d8a [project @ 2007-02-16 20:26:23 by dbateman] diff -r 6338017166e4 -r 363a2f8c9e97 liboctave/ChangeLog --- 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 + + * 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 * kpse.cc (expand_elt): Omit special treatment for //. diff -r 6338017166e4 -r 363a2f8c9e97 liboctave/lo-sysdep.cc --- 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 #include +#include #ifdef HAVE_UNISTD_H #ifdef HAVE_SYS_TYPES_H @@ -35,10 +36,15 @@ #include #endif +#ifdef HAVE_FCNTL_H +#include +#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 (parentRead), _O_RDONLY | _O_BINARY); + fildes[0] = _open_osfhandle (reinterpret_cast (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 #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 diff -r 6338017166e4 -r 363a2f8c9e97 liboctave/oct-syscalls.cc --- 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 #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++ *** diff -r 6338017166e4 -r 363a2f8c9e97 liboctave/oct-syscalls.h --- 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 diff -r 6338017166e4 -r 363a2f8c9e97 scripts/ChangeLog --- 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 + + * miscellaneous/popen2.m: Remove as replaced with builtin. + 2007-02-16 Muthiah Annamalai * specfun/nchoosek.m: Check nargin. diff -r 6338017166e4 -r 363a2f8c9e97 src/ChangeLog --- 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 + + * 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 * input.cc (interactive_input): New arg, DEBUG. Don't call diff -r 6338017166e4 -r 363a2f8c9e97 src/syscalls.cc --- 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