|
Boost-Commit : |
Subject: [Boost-commit] svn:boost r50409 - in sandbox/process: . boost boost/process boost/process/detail libs libs/process libs/process/doc libs/process/example libs/process/test
From: boris_at_[hidden]
Date: 2008-12-29 18:16:19
Author: bschaeling
Date: 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
New Revision: 50409
URL: http://svn.boost.org/trac/boost/changeset/50409
Log:
Initial checkin of Boost.Process
Added:
sandbox/process/
sandbox/process/boost/
sandbox/process/boost/process/
sandbox/process/boost/process.hpp (contents, props changed)
sandbox/process/boost/process/child.hpp (contents, props changed)
sandbox/process/boost/process/config.hpp (contents, props changed)
sandbox/process/boost/process/context.hpp (contents, props changed)
sandbox/process/boost/process/detail/
sandbox/process/boost/process/detail/file_handle.hpp (contents, props changed)
sandbox/process/boost/process/detail/pipe.hpp (contents, props changed)
sandbox/process/boost/process/detail/posix_ops.hpp (contents, props changed)
sandbox/process/boost/process/detail/stream_info.hpp (contents, props changed)
sandbox/process/boost/process/detail/systembuf.hpp (contents, props changed)
sandbox/process/boost/process/detail/win32_ops.hpp (contents, props changed)
sandbox/process/boost/process/environment.hpp (contents, props changed)
sandbox/process/boost/process/operations.hpp (contents, props changed)
sandbox/process/boost/process/pistream.hpp (contents, props changed)
sandbox/process/boost/process/posix_child.hpp (contents, props changed)
sandbox/process/boost/process/posix_context.hpp (contents, props changed)
sandbox/process/boost/process/posix_operations.hpp (contents, props changed)
sandbox/process/boost/process/posix_status.hpp (contents, props changed)
sandbox/process/boost/process/postream.hpp (contents, props changed)
sandbox/process/boost/process/process.hpp (contents, props changed)
sandbox/process/boost/process/self.hpp (contents, props changed)
sandbox/process/boost/process/status.hpp (contents, props changed)
sandbox/process/boost/process/stream_behavior.hpp (contents, props changed)
sandbox/process/boost/process/win32_child.hpp (contents, props changed)
sandbox/process/boost/process/win32_context.hpp (contents, props changed)
sandbox/process/boost/process/win32_operations.hpp (contents, props changed)
sandbox/process/libs/
sandbox/process/libs/process/
sandbox/process/libs/process/doc/
sandbox/process/libs/process/doc/Jamfile.v2 (contents, props changed)
sandbox/process/libs/process/doc/acknowledgements.xml (contents, props changed)
sandbox/process/libs/process/doc/concepts.xml (contents, props changed)
sandbox/process/libs/process/doc/design.png (contents, props changed)
sandbox/process/libs/process/doc/design.xml (contents, props changed)
sandbox/process/libs/process/doc/introduction.xml (contents, props changed)
sandbox/process/libs/process/doc/nonportable_usage.xml (contents, props changed)
sandbox/process/libs/process/doc/platforms.xml (contents, props changed)
sandbox/process/libs/process/doc/portability.xml (contents, props changed)
sandbox/process/libs/process/doc/position.xml (contents, props changed)
sandbox/process/libs/process/doc/process.xml (contents, props changed)
sandbox/process/libs/process/doc/tutorials.xml (contents, props changed)
sandbox/process/libs/process/example/
sandbox/process/libs/process/example/async_io.cpp (contents, props changed)
sandbox/process/libs/process/example/current_environment.cpp (contents, props changed)
sandbox/process/libs/process/example/empty_environment.cpp (contents, props changed)
sandbox/process/libs/process/example/modified_environment.cpp (contents, props changed)
sandbox/process/libs/process/example/pipeline.cpp (contents, props changed)
sandbox/process/libs/process/example/posix_communication.cpp (contents, props changed)
sandbox/process/libs/process/example/posix_status.cpp (contents, props changed)
sandbox/process/libs/process/example/read_from_child.cpp (contents, props changed)
sandbox/process/libs/process/example/start_child.cpp (contents, props changed)
sandbox/process/libs/process/example/wait_for_child.cpp (contents, props changed)
sandbox/process/libs/process/example/win32_child.cpp (contents, props changed)
sandbox/process/libs/process/example/win32_startup.cpp (contents, props changed)
sandbox/process/libs/process/test/
sandbox/process/libs/process/test/Jamfile.v2 (contents, props changed)
sandbox/process/libs/process/test/arguments_test.cpp (contents, props changed)
sandbox/process/libs/process/test/child_base_test.hpp (contents, props changed)
sandbox/process/libs/process/test/child_test.cpp (contents, props changed)
sandbox/process/libs/process/test/detail_file_handle_test.cpp (contents, props changed)
sandbox/process/libs/process/test/detail_pipe_test.cpp (contents, props changed)
sandbox/process/libs/process/test/detail_systembuf_test.cpp (contents, props changed)
sandbox/process/libs/process/test/environment_test.cpp (contents, props changed)
sandbox/process/libs/process/test/executable_test.cpp (contents, props changed)
sandbox/process/libs/process/test/helpers.cpp (contents, props changed)
sandbox/process/libs/process/test/include_child_test.cpp (contents, props changed)
sandbox/process/libs/process/test/include_context_test.cpp (contents, props changed)
sandbox/process/libs/process/test/include_detail_file_handle_test.cpp (contents, props changed)
sandbox/process/libs/process/test/include_detail_pipe_test.cpp (contents, props changed)
sandbox/process/libs/process/test/include_detail_posix_ops_test.cpp (contents, props changed)
sandbox/process/libs/process/test/include_detail_systembuf_test.cpp (contents, props changed)
sandbox/process/libs/process/test/include_detail_win32_ops_test.cpp (contents, props changed)
sandbox/process/libs/process/test/include_environment_test.cpp (contents, props changed)
sandbox/process/libs/process/test/include_operations_test.cpp (contents, props changed)
sandbox/process/libs/process/test/include_pistream_test.cpp (contents, props changed)
sandbox/process/libs/process/test/include_posix_child_test.cpp (contents, props changed)
sandbox/process/libs/process/test/include_posix_context_test.cpp (contents, props changed)
sandbox/process/libs/process/test/include_posix_operations_test.cpp (contents, props changed)
sandbox/process/libs/process/test/include_posix_status_test.cpp (contents, props changed)
sandbox/process/libs/process/test/include_postream_test.cpp (contents, props changed)
sandbox/process/libs/process/test/include_process_test.cpp (contents, props changed)
sandbox/process/libs/process/test/include_self_test.cpp (contents, props changed)
sandbox/process/libs/process/test/include_status_test.cpp (contents, props changed)
sandbox/process/libs/process/test/include_stream_behavior_test.cpp (contents, props changed)
sandbox/process/libs/process/test/include_top_test.cpp (contents, props changed)
sandbox/process/libs/process/test/include_top_test_and_main.cpp (contents, props changed)
sandbox/process/libs/process/test/include_win32_child_test.cpp (contents, props changed)
sandbox/process/libs/process/test/include_win32_context_test.cpp (contents, props changed)
sandbox/process/libs/process/test/include_win32_operations_test.cpp (contents, props changed)
sandbox/process/libs/process/test/launch_base_test.hpp (contents, props changed)
sandbox/process/libs/process/test/launch_test.cpp (contents, props changed)
sandbox/process/libs/process/test/misc.hpp (contents, props changed)
sandbox/process/libs/process/test/pipeline_test.cpp (contents, props changed)
sandbox/process/libs/process/test/pistream_test.cpp (contents, props changed)
sandbox/process/libs/process/test/posix_child_test.cpp (contents, props changed)
sandbox/process/libs/process/test/posix_launch_test.cpp (contents, props changed)
sandbox/process/libs/process/test/posix_status_test.cpp (contents, props changed)
sandbox/process/libs/process/test/postream_test.cpp (contents, props changed)
sandbox/process/libs/process/test/process_base_test.hpp (contents, props changed)
sandbox/process/libs/process/test/process_test.cpp (contents, props changed)
sandbox/process/libs/process/test/self_test.cpp (contents, props changed)
sandbox/process/libs/process/test/shell_test.cpp (contents, props changed)
sandbox/process/libs/process/test/status_base_test.hpp (contents, props changed)
sandbox/process/libs/process/test/status_test.cpp (contents, props changed)
sandbox/process/libs/process/test/stream_behavior_test.cpp (contents, props changed)
sandbox/process/libs/process/test/win32_child_test.cpp (contents, props changed)
sandbox/process/libs/process/test/win32_launch_test.cpp (contents, props changed)
Added: sandbox/process/boost/process.hpp
==============================================================================
--- (empty file)
+++ sandbox/process/boost/process.hpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,50 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+/**
+ * \file boost/process.hpp
+ *
+ * Convenience header that includes all other Boost.Process public header
+ * files. It is important to note that those headers that are specific to
+ * a given platform are only included if the library is being used in that
+ * same platform.
+ */
+
+#ifndef BOOST_PROCESS_HPP
+#define BOOST_PROCESS_HPP
+
+#include <boost/process/config.hpp>
+
+#if defined(BOOST_POSIX_API)
+# include <boost/process/posix_child.hpp>
+# include <boost/process/posix_context.hpp>
+# include <boost/process/posix_operations.hpp>
+# include <boost/process/posix_status.hpp>
+#elif defined(BOOST_WINDOWS_API)
+# include <boost/process/win32_child.hpp>
+# include <boost/process/win32_context.hpp>
+# include <boost/process/win32_operations.hpp>
+#else
+# error "Unsupported platform."
+#endif
+
+#include <boost/process/child.hpp>
+#include <boost/process/context.hpp>
+#include <boost/process/environment.hpp>
+#include <boost/process/operations.hpp>
+#include <boost/process/pistream.hpp>
+#include <boost/process/postream.hpp>
+#include <boost/process/process.hpp>
+#include <boost/process/self.hpp>
+#include <boost/process/status.hpp>
+#include <boost/process/stream_behavior.hpp>
+
+#endif
Added: sandbox/process/boost/process/child.hpp
==============================================================================
--- (empty file)
+++ sandbox/process/boost/process/child.hpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,200 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+/**
+ * \file boost/process/child.hpp
+ *
+ * Includes the declaration of the child class.
+ */
+
+#ifndef BOOST_PROCESS_CHILD_HPP
+#define BOOST_PROCESS_CHILD_HPP
+
+#include <boost/process/config.hpp>
+
+#if defined(BOOST_POSIX_API)
+# include <sys/types.h>
+# include <sys/wait.h>
+# include <cerrno>
+#elif defined(BOOST_WINDOWS_API)
+# include <windows.h>
+#else
+# error "Unsupported platform."
+#endif
+
+#include <boost/process/process.hpp>
+#include <boost/process/pistream.hpp>
+#include <boost/process/postream.hpp>
+#include <boost/process/status.hpp>
+#include <boost/process/detail/file_handle.hpp>
+#include <boost/system/system_error.hpp>
+#include <boost/throw_exception.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/assert.hpp>
+#include <vector>
+
+namespace boost {
+namespace process {
+
+/**
+ * Generic implementation of the Child concept.
+ *
+ * The child class implements the Child concept in an operating system
+ * agnostic way.
+ */
+class child : public process
+{
+public:
+ /**
+ * Gets a reference to the child's standard input stream.
+ *
+ * Returns a reference to a postream object that represents the
+ * standard input communication channel with the child process.
+ */
+ postream &get_stdin() const
+ {
+ BOOST_ASSERT(stdin_);
+
+ return *stdin_;
+ }
+
+ /**
+ * Gets a reference to the child's standard output stream.
+ *
+ * Returns a reference to a pistream object that represents the
+ * standard output communication channel with the child process.
+ */
+ pistream &get_stdout() const
+ {
+ BOOST_ASSERT(stdout_);
+
+ return *stdout_;
+ }
+
+ /**
+ * Gets a reference to the child's standard error stream.
+ *
+ * Returns a reference to a pistream object that represents the
+ * standard error communication channel with the child process.
+ */
+ pistream &get_stderr() const
+ {
+ BOOST_ASSERT(stderr_);
+
+ return *stderr_;
+ }
+
+ /**
+ * Blocks and waits for the child process to terminate.
+ *
+ * Returns a status object that represents the child process'
+ * finalization condition. The child process object ceases to be
+ * valid after this call.
+ *
+ * \remark Blocking remarks: This call blocks if the child
+ * process has not finalized execution and waits until
+ * it terminates.
+ */
+ status wait()
+ {
+#if defined(BOOST_POSIX_API)
+ int s;
+ if (::waitpid(get_id(), &s, 0) == -1)
+ boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::child::wait: waitpid(2) failed"));
+ return status(s);
+#elif defined(BOOST_WINDOWS_API)
+ ::WaitForSingleObject(process_handle_.get(), INFINITE);
+ DWORD code;
+ if (!::GetExitCodeProcess(process_handle_.get(), &code))
+ boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::child::wait: GetExitCodeProcess failed"));
+ return status(code);
+#endif
+ }
+
+ /**
+ * Creates a new child object that represents the just spawned child
+ * process \a id.
+ *
+ * The \a fhstdin, \a fhstdout and \a fhstderr file handles represent
+ * the parent's handles used to communicate with the corresponding
+ * data streams. They needn't be valid but their availability must
+ * match the redirections configured by the launcher that spawned this
+ * process.
+ *
+ * The \a fhprocess handle represents a handle to the child process.
+ * It is only used on Windows as the implementation of wait() needs a
+ * process handle.
+ */
+ child(id_type id, detail::file_handle fhstdin, detail::file_handle fhstdout, detail::file_handle fhstderr, detail::file_handle fhprocess = detail::file_handle())
+ : process(id)
+#if defined(BOOST_WINDOWS_API)
+ , process_handle_(fhprocess.release(), ::CloseHandle)
+#endif
+ {
+ if (fhstdin.valid())
+ stdin_.reset(new postream(fhstdin));
+ if (fhstdout.valid())
+ stdout_.reset(new pistream(fhstdout));
+ if (fhstderr.valid())
+ stderr_.reset(new pistream(fhstderr));
+ }
+
+private:
+ /**
+ * The standard input stream attached to the child process.
+ *
+ * This postream object holds the communication channel with the
+ * child's process standard input. It is stored in a pointer because
+ * this field is only valid when the user requested to redirect this
+ * data stream.
+ */
+ boost::shared_ptr<postream> stdin_;
+
+ /**
+ * The standard output stream attached to the child process.
+ *
+ * This postream object holds the communication channel with the
+ * child's process standard output. It is stored in a pointer because
+ * this field is only valid when the user requested to redirect this
+ * data stream.
+ */
+ boost::shared_ptr<pistream> stdout_;
+
+ /**
+ * The standard error stream attached to the child process.
+ *
+ * This postream object holds the communication channel with the
+ * child's process standard error. It is stored in a pointer because
+ * this field is only valid when the user requested to redirect this
+ * data stream.
+ */
+ boost::shared_ptr<pistream> stderr_;
+
+#if defined(BOOST_WINDOWS_API)
+ /**
+ * Process handle owned by RAII object.
+ */
+ boost::shared_ptr<void> process_handle_;
+#endif
+};
+
+/**
+ * Collection of child objects.
+ *
+ * This convenience type represents a collection of child objects backed
+ * by a vector.
+ */
+typedef std::vector<child> children;
+
+}
+}
+
+#endif
Added: sandbox/process/boost/process/config.hpp
==============================================================================
--- (empty file)
+++ sandbox/process/boost/process/config.hpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,41 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+/**
+ * \file boost/process/config.hpp
+ *
+ * Defines macros that are used by the library's code to determine the
+ * operating system it is running under and the features it supports.
+ */
+
+#ifndef BOOST_PROCESS_CONFIG_HPP
+#define BOOST_PROCESS_CONFIG_HPP
+
+#include <boost/config.hpp>
+#include <boost/system/config.hpp>
+
+#if defined(BOOST_POSIX_API) || defined(BOOST_PROCESS_DOXYGEN)
+# if !defined(BOOST_PROCESS_POSIX_PATH_MAX)
+/**
+ * The macro BOOST_PROCESS_POSIX_PATH_MAX is set to a positive integer
+ * value which specifies the system's maximal supported path length.
+ * By default it is set to 259. You should set the macro to PATH_MAX
+ * which should be defined in limits.h provided by your operating system
+ * if you experience problems when instantiating a context. The
+ * constructor of basic_work_directory_context tries to find out
+ * dynamically the maximal supported path length but uses
+ * BOOST_PROCESS_POSIX_PATH_MAX if it fails.
+ */
+# define BOOST_PROCESS_POSIX_PATH_MAX 259
+# endif
+#endif
+
+#endif
Added: sandbox/process/boost/process/context.hpp
==============================================================================
--- (empty file)
+++ sandbox/process/boost/process/context.hpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,209 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+/**
+ * \file boost/process/context.hpp
+ *
+ * Includes the declaration of the context class and several accessory
+ * base classes.
+ */
+
+#ifndef BOOST_PROCESS_CONTEXT_HPP
+#define BOOST_PROCESS_CONTEXT_HPP
+
+#include <boost/process/config.hpp>
+
+#if defined(BOOST_POSIX_API)
+# include <boost/scoped_array.hpp>
+# include <cerrno>
+# include <unistd.h>
+#elif defined(BOOST_WINDOWS_API)
+# include <windows.h>
+#else
+# error "Unsupported platform."
+#endif
+
+#include <boost/process/environment.hpp>
+#include <boost/process/stream_behavior.hpp>
+#include <boost/system/system_error.hpp>
+#include <boost/throw_exception.hpp>
+#include <boost/assert.hpp>
+#include <string>
+#include <vector>
+
+namespace boost {
+namespace process {
+
+/**
+ * Base context class that defines the child's work directory.
+ *
+ * Base context class that defines the necessary fields to configure a
+ * child's work directory. This class is useless on its own because no
+ * function in the library will accept it as a valid Context
+ * implementation.
+ */
+template <class Path>
+class basic_work_directory_context
+{
+public:
+ /**
+ * Constructs a new work directory context.
+ *
+ * Constructs a new work directory context making the work directory
+ * described by the new object point to the caller's current working
+ * directory.
+ */
+ basic_work_directory_context()
+ {
+#if defined(BOOST_POSIX_API)
+ errno = 0;
+ long size = ::pathconf(".", _PC_PATH_MAX);
+ if (size == -1 && errno)
+ boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::basic_work_directory_context::basic_work_directory_context: pathconf(2) failed"));
+ else if (size == -1)
+ size = BOOST_PROCESS_POSIX_PATH_MAX;
+ boost::scoped_array<char> cwd(new char[size]);
+ if (!::getcwd(cwd.get(), size))
+ boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::basic_work_directory_context::basic_work_directory_context: getcwd(2) failed"));
+ work_directory = cwd.get();
+#elif defined(BOOST_WINDOWS_API)
+ char cwd[MAX_PATH];
+ if (!::GetCurrentDirectoryA(sizeof(cwd), cwd))
+ boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::basic_work_directory_context::basic_work_directory_context: GetCurrentDirectory failed"));
+ work_directory = cwd;
+#endif
+ BOOST_ASSERT(!work_directory.empty());
+ }
+
+ /**
+ * The process' initial work directory.
+ *
+ * The work directory is the directory in which the process starts
+ * execution.
+ */
+ Path work_directory;
+};
+
+/**
+ * Base context class that defines the child's environment.
+ *
+ * Base context class that defines the necessary fields to configure a
+ * child's environment variables. This class is useless on its own
+ * because no function in the library will accept it as a valid Context
+ * implementation.
+ */
+class environment_context
+{
+public:
+ /**
+ * The process' environment.
+ *
+ * Contains the list of environment variables, alongside with their
+ * values, that will be passed to the spawned child process.
+ */
+ boost::process::environment environment;
+};
+
+/**
+ * Process startup execution context.
+ *
+ * The context class groups all the parameters needed to configure a
+ * process' environment during its creation.
+ */
+template <class Path>
+class basic_context : public basic_work_directory_context<Path>, public environment_context
+{
+public:
+ /**
+ * Child's stdin behavior.
+ */
+ stream_behavior stdin_behavior;
+
+ /**
+ * Child's stdout behavior.
+ */
+ stream_behavior stdout_behavior;
+
+ /**
+ * Child's stderr behavior.
+ */
+ stream_behavior stderr_behavior;
+};
+
+typedef basic_context<std::string> context;
+
+/**
+ * Represents a child process in a pipeline.
+ *
+ * This convenience class is a triplet that holds all the data required
+ * to spawn a new child process in a pipeline.
+ */
+template <class Executable, class Arguments, class Context>
+class basic_pipeline_entry
+{
+public:
+ /**
+ * The executable to launch.
+ */
+ Executable executable;
+
+ /**
+ * The set of arguments to pass to the executable.
+ */
+ Arguments arguments;
+
+ /**
+ * The child's execution context.
+ */
+ Context context;
+
+ /**
+ * The type of the Executable concept used in this template
+ * instantiation.
+ */
+ typedef Executable executable_type;
+
+ /**
+ * The type of the Arguments concept used in this template
+ * instantiation.
+ */
+ typedef Arguments arguments_type;
+
+ /**
+ * The type of the Context concept used in this template
+ * instantiation.
+ */
+ typedef Context context_type;
+
+ /**
+ * Constructs a new pipeline_entry object.
+ *
+ * Given the executable, set of arguments and execution triplet,
+ * constructs a new pipeline_entry object that holds the three
+ * values.
+ */
+ basic_pipeline_entry(const Executable &exe, const Arguments &args, const Context &ctx)
+ : executable(exe),
+ arguments(args),
+ context(ctx)
+ {
+ }
+};
+
+/**
+ * Default instantiation of basic_pipeline_entry.
+ */
+typedef basic_pipeline_entry<std::string, std::vector<std::string>, context> pipeline_entry;
+
+}
+}
+
+#endif
Added: sandbox/process/boost/process/detail/file_handle.hpp
==============================================================================
--- (empty file)
+++ sandbox/process/boost/process/detail/file_handle.hpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,406 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+/**
+ * \file boost/process/detail/file_handle.hpp
+ *
+ * Includes the declaration of the file_handle class. This file is for
+ * internal usage only and must not be included by the library user.
+ */
+
+#ifndef BOOST_PROCESS_DETAIL_FILE_HANDLE_HPP
+#define BOOST_PROCESS_DETAIL_FILE_HANDLE_HPP
+
+#include <boost/process/config.hpp>
+
+#if defined(BOOST_POSIX_API)
+# include <cerrno>
+# include <unistd.h>
+#elif defined(BOOST_WINDOWS_API)
+# include <windows.h>
+#else
+# error "Unsupported platform."
+#endif
+
+#include <boost/assert.hpp>
+#include <boost/system/system_error.hpp>
+#include <boost/throw_exception.hpp>
+
+namespace boost {
+namespace process {
+namespace detail {
+
+/**
+ * Simple RAII model for system file handles.
+ *
+ * The \a file_handle class is a simple RAII model for native system file
+ * handles. This class wraps one of such handles grabbing its ownership,
+ * and automaticaly closes it upon destruction. It is basically used
+ * inside the library to avoid leaking open file handles, shall an
+ * unexpected execution trace occur.
+ *
+ * A \a file_handle object can be copied but doing so invalidates the
+ * source object. There can only be a single valid \a file_handle object
+ * for a given system file handle. This is similar to std::auto_ptr's
+ * semantics.
+ *
+ * This class also provides some convenience methods to issue special file
+ * operations under their respective platforms.
+ */
+class file_handle
+{
+public:
+#if defined(BOOST_PROCESS_DOXYGEN)
+ /**
+ * Opaque name for the native handle type.
+ *
+ * Each operating system identifies file handles using a specific type.
+ * The \a handle_type type is used to transparently refer to file
+ * handles regarless of the operating system in which this class is
+ * used.
+ *
+ * If this class is used on a POSIX system, \a NativeSystemHandle is
+ * an integer type while it is a \a HANDLE on a Windows system.
+ */
+ typedef NativeSystemHandle handle_type;
+#elif defined(BOOST_POSIX_API)
+ typedef int handle_type;
+#elif defined(BOOST_WINDOWS_API)
+ typedef HANDLE handle_type;
+#endif
+
+ /**
+ * Constructs an invalid file handle.
+ *
+ * This constructor creates a new \a file_handle object that represents
+ * an invalid file handle. An invalid file handle can be copied but
+ * cannot be manipulated in any way (except checking for its validity).
+ *
+ * \see valid()
+ */
+ file_handle()
+ : handle_(invalid_value())
+ {
+ }
+
+ /**
+ * Constructs a new file handle from a native file handle.
+ *
+ * This constructor creates a new \a file_handle object that takes
+ * ownership of the given \a h native file handle. The user must not
+ * close \a h on his own during the lifetime of the new object.
+ * Ownership can be reclaimed using release().
+ *
+ * \pre The native file handle must be valid; a close operation must
+ * succeed on it.
+ * \see release()
+ */
+ file_handle(handle_type h)
+ : handle_(h)
+ {
+ BOOST_ASSERT(handle_ != invalid_value());
+ }
+
+ /**
+ * Copy constructor; invalidates the source handle.
+ *
+ * This copy constructor creates a new file handle from a given one.
+ * Ownership of the native file handle is transferred to the new
+ * object, effectively invalidating the source file handle. This
+ * avoids having two live \a file_handle objects referring to the
+ * same native file handle. The source file handle needs not be
+ * valid in the name of simplicity.
+ *
+ * \post The source file handle is invalid.
+ * \post The new file handle owns the source's native file handle.
+ */
+ file_handle(const file_handle &fh)
+ : handle_(fh.handle_)
+ {
+ fh.handle_ = invalid_value();
+ }
+
+ /**
+ * Releases resources if the handle is valid.
+ *
+ * If the file handle is valid, the destructor closes it.
+ *
+ * \see valid()
+ */
+ ~file_handle()
+ {
+ if (valid())
+ close();
+ }
+
+ /**
+ * Assignment operator; invalidates the source handle.
+ *
+ * This assignment operator transfers ownership of the RHS file
+ * handle to the LHS one, effectively invalidating the source file
+ * handle. This avoids having two live \a file_handle objects
+ * referring to the same native file handle. The source file
+ * handle needs not be valid in the name of simplicity.
+ *
+ * \post The RHS file handle is invalid.
+ * \post The LHS file handle owns RHS' native file handle.
+ * \return A reference to the LHS file handle.
+ */
+ file_handle &operator=(const file_handle &fh)
+ {
+ handle_ = fh.handle_;
+ fh.handle_ = invalid_value();
+ return *this;
+ }
+
+ /**
+ * Checks whether the file handle is valid or not.
+ *
+ * Returns a boolean indicating whether the file handle is valid or
+ * not. If the file handle is invalid, no other methods can be
+ * executed other than the destructor.
+ *
+ * \return true if the file handle is valid; false otherwise.
+ */
+ bool valid() const
+ {
+ return handle_ != invalid_value();
+ }
+
+ /**
+ * Closes the file handle.
+ *
+ * Explicitly closes the file handle, which must be valid. Upon
+ * exit, the handle is not valid any more.
+ *
+ * \pre The file handle is valid.
+ * \post The file handle is invalid.
+ * \post The native file handle is closed.
+ */
+ void close()
+ {
+ BOOST_ASSERT(valid());
+
+#if defined(BOOST_POSIX_API)
+ ::close(handle_);
+#elif defined(BOOST_WINDOWS_API)
+ ::CloseHandle(handle_);
+#endif
+
+ handle_ = invalid_value();
+ }
+
+ /**
+ * Reclaims ownership of the native file handle.
+ *
+ * Explicitly reclaims ownership of the native file handle contained
+ * in the \a file_handle object, returning the native file handle.
+ * The caller is responsible of closing it later on.
+ *
+ * \pre The file handle is valid.
+ * \post The file handle is invalid.
+ * \return The native file handle.
+ */
+ handle_type release()
+ {
+ BOOST_ASSERT(valid());
+
+ handle_type h = handle_;
+ handle_ = invalid_value();
+ return h;
+ }
+
+ /**
+ * Gets the native file handle.
+ *
+ * Returns the native file handle for the \a file_handle object.
+ * The caller can issue any operation on it except closing it.
+ * If closing is required, release() shall be used.
+ *
+ * \pre The file handle is valid.
+ * \post The file handle is valid.
+ * \return The native file handle.
+ */
+ handle_type get() const
+ {
+ BOOST_ASSERT(valid());
+
+ return handle_;
+ }
+
+#if defined(BOOST_POSIX_API) || defined(BOOST_PROCESS_DOXYGEN)
+ /**
+ * Changes the native file handle to the given one.
+ *
+ * Given a new native file handle \a h, this operation assigns this
+ * handle to the current object, closing its old native file handle.
+ * In other words, it first calls dup2() to remap the old handle to
+ * the new one and then closes the old handle.
+ *
+ * If \a h is open, it is automatically closed by dup2().
+ *
+ * This operation is only available in POSIX systems.
+ *
+ * \pre The file handle is valid.
+ * \pre The native file handle \a h is valid; i.e., it must be
+ * closeable.
+ * \post The file handle's native file handle is \a h.
+ * \throw boost::system::system_error If the internal remapping
+ * operation fails.
+ */
+ void posix_remap(handle_type h)
+ {
+ BOOST_ASSERT(valid());
+
+ if (::dup2(handle_, h) == -1)
+ boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::file_handle::posix_remap: dup2(2) failed"));
+
+ if (::close(handle_) == -1)
+ {
+ ::close(h);
+ boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::file_handle::posix_remap: close(2) failed"));
+ }
+
+ handle_ = h;
+ }
+
+ /**
+ * Duplicates an open native file handle.
+ *
+ * Given a native file handle \a h1, this routine duplicates it so
+ * that it ends up being identified by the native file handle \a h2
+ * and returns a new \a file_handle owning \a h2.
+ *
+ * This operation is only available in POSIX systems.
+ *
+ * \pre The native file handle \a h1 is open.
+ * \pre The native file handle \a h2 is valid (non-negative).
+ * \post The native file handle \a h1 is closed.
+ * \post The native file handle \a h2 is the same as the old \a h1
+ * from the operating system's point of view.
+ * \return A new \a file_handle object that owns \a h2.
+ * \throw boost::system::system_error If dup2() fails.
+ */
+ static file_handle posix_dup(int h1, int h2)
+ {
+ if (::dup2(h1, h2) == -1)
+ boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::file_handle::posix_dup: dup2(2) failed"));
+
+ return file_handle(h2);
+ }
+#endif
+
+#if defined(BOOST_WINDOWS_API) || defined(BOOST_PROCESS_DOXYGEN)
+ /**
+ * Duplicates the \a h native file handle.
+ *
+ * Given a native file handle \a h, this routine constructs a new
+ * \a file_handle object that owns a new duplicate of \a h. The
+ * duplicate's inheritable flag is set to the value of \a inheritable.
+ *
+ * This operation is only available in Windows systems.
+ *
+ * \pre The native file handle \a h is valid.
+ * \return A file handle owning a duplicate of \a h.
+ * \throw boost::system::system_error If DuplicateHandle() fails.
+ */
+ static file_handle win32_dup(HANDLE h, bool inheritable)
+ {
+ HANDLE h2;
+ if (!::DuplicateHandle(::GetCurrentProcess(), h, ::GetCurrentProcess(), &h2, 0, inheritable ? TRUE : FALSE, DUPLICATE_SAME_ACCESS))
+ boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::detail::file_handle::win32_dup: DuplicateHandle failed"));
+
+ return file_handle(h2);
+ }
+
+ /**
+ * Creates a new duplicate of a standard file handle.
+ *
+ * Constructs a new \a file_handle object that owns a duplicate of a
+ * standard file handle. The \a d parameter specifies which standard
+ * file handle to duplicate and can be one of \a STD_INPUT_HANDLE,
+ * \a STD_OUTPUT_HANDLE or \a STD_ERROR_HANDLE. The duplicate's
+ * inheritable flag is set to the value of \a inheritable.
+ *
+ * This operation is only available in Windows systems.
+ *
+ * \pre \a d refers to one of the standard handles as described above.
+ * \return A file handle owning a duplicate of the standard handle
+ * referred to by \a d.
+ * \throw boost::system::system_error If GetStdHandle() or
+ * DuplicateHandle() fails.
+ */
+ static file_handle win32_std(DWORD d, bool inheritable)
+ {
+ BOOST_ASSERT(d == STD_INPUT_HANDLE || d == STD_OUTPUT_HANDLE || d == STD_ERROR_HANDLE);
+
+ HANDLE h = ::GetStdHandle(d);
+ if (h == INVALID_HANDLE_VALUE)
+ boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::detail::file_handle::win32_std: GetStdHandle failed"));
+
+ return win32_dup(h, inheritable);
+ }
+
+ /**
+ * Changes the file handle's inheritable flag.
+ *
+ * Changes the file handle's inheritable flag to \a i. It is not
+ * necessary for the file handle's flag to be different than \a i.
+ *
+ * This operation is only available in Windows systems.
+ *
+ * \pre The file handle is valid.
+ * \post The native file handle's inheritable flag is set to \a i.
+ * \throw boost::system::system_error If the property change fails.
+ */
+ void win32_set_inheritable(bool i)
+ {
+ BOOST_ASSERT(valid());
+
+ if (!::SetHandleInformation(handle_, HANDLE_FLAG_INHERIT, i ? HANDLE_FLAG_INHERIT : 0))
+ boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::detail::file_handle::win32_set_inheritable: SetHandleInformation failed"));
+ }
+#endif
+
+private:
+ /**
+ * Internal handle value.
+ *
+ * This variable holds the native handle value for the file handle
+ * hold by this object. It is interesting to note that this needs
+ * to be mutable because the copy constructor and the assignment
+ * operator invalidate the source object.
+ */
+ mutable handle_type handle_;
+
+ /**
+ * Constant function representing an invalid handle value.
+ *
+ * Returns the platform-specific handle value that represents an
+ * invalid handle. This is a constant function rather than a regular
+ * constant because, in the latter case, we cannot define it under
+ * Windows due to the value being of a complex type.
+ */
+ static const handle_type invalid_value()
+ {
+#if defined(BOOST_POSIX_API)
+ return -1;
+#elif defined(BOOST_WINDOWS_API)
+ return INVALID_HANDLE_VALUE;
+#endif
+ }
+};
+
+}
+}
+}
+
+#endif
Added: sandbox/process/boost/process/detail/pipe.hpp
==============================================================================
--- (empty file)
+++ sandbox/process/boost/process/detail/pipe.hpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,187 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+/**
+ * \file boost/process/detail/pipe.hpp
+ *
+ * Includes the declaration of the pipe class. This file is for
+ * internal usage only and must not be included by the library user.
+ */
+
+#ifndef BOOST_PROCESS_DETAIL_PIPE_HPP
+#define BOOST_PROCESS_DETAIL_PIPE_HPP
+
+#include <boost/process/config.hpp>
+
+#if defined(BOOST_POSIX_API)
+# include <unistd.h>
+# include <cerrno>
+#elif defined(BOOST_WINDOWS_API)
+# if defined(BOOST_PROCESS_WINDOWS_USE_NAMED_PIPE)
+# include <boost/lexical_cast.hpp>
+# include <string>
+# endif
+# include <windows.h>
+#else
+# error "Unsupported platform."
+#endif
+
+#include <boost/process/detail/file_handle.hpp>
+#include <boost/system/system_error.hpp>
+#include <boost/throw_exception.hpp>
+
+namespace boost {
+namespace process {
+namespace detail {
+
+/**
+ * Simple RAII model for anonymous pipes.
+ *
+ * The pipe class is a simple RAII model for anonymous pipes. It
+ * provides a portable constructor that allocates a new %pipe and creates
+ * a pipe object that owns the two file handles associated to it: the
+ * read end and the write end.
+ *
+ * These handles can be retrieved for modification according to
+ * file_handle semantics. Optionally, their ownership can be transferred
+ * to external \a file_handle objects which comes handy when the two
+ * ends need to be used in different places (i.e. after a POSIX fork()
+ * system call).
+ *
+ * Pipes can be copied following the same semantics as file handles.
+ * In other words, copying a %pipe object invalidates the source one.
+ *
+ * \see file_handle
+ */
+class pipe
+{
+public:
+ /**
+ * Creates a new %pipe.
+ *
+ * The default pipe constructor allocates a new anonymous %pipe
+ * and assigns its ownership to the created pipe object. On Windows
+ * when the macro BOOST_PROCESS_WINDOWS_USE_NAMED_PIPE is defined
+ * a named pipe is created. This is required if asynchronous I/O
+ * should be used as asynchronous I/O is only supported by named
+ * pipes on Windows.
+ *
+ * \throw boost::system::system_error If the anonymous %pipe
+ * creation fails.
+ */
+ pipe()
+ {
+ file_handle::handle_type hs[2];
+
+#if defined(BOOST_POSIX_API)
+ if (::pipe(hs) == -1)
+ boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::pipe::pipe: pipe(2) failed"));
+#elif defined(BOOST_WINDOWS_API)
+ SECURITY_ATTRIBUTES sa;
+ ZeroMemory(&sa, sizeof(sa));
+ sa.nLength = sizeof(sa);
+ sa.lpSecurityDescriptor = NULL;
+ sa.bInheritHandle = FALSE;
+
+# if defined(BOOST_PROCESS_WINDOWS_USE_NAMED_PIPE)
+ static unsigned int nextid = 0;
+ std::string pipe = "\\\\.\\pipe\\boost_process_" + boost::lexical_cast<std::string>(::GetCurrentProcessId()) + "_" + boost::lexical_cast<std::string>(nextid++);
+ hs[0] = ::CreateNamedPipeA(pipe.c_str(), PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED, 0, 1, 8192, 8192, 0, &sa);
+ if (hs[0] == INVALID_HANDLE_VALUE)
+ boost::throw_exception(boost::system::system_error(::GetLastError(), boost::system::system_category, "boost::process::detail::pipe::pipe: CreateNamedPipe failed"));
+ hs[1] = ::CreateFileA(pipe.c_str(), GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
+ if (hs[1] == INVALID_HANDLE_VALUE)
+ boost::throw_exception(boost::system::system_error(::GetLastError(), boost::system::system_category, "boost::process::detail::pipe::pipe: CreateFile failed"));
+
+ OVERLAPPED overlapped;
+ ZeroMemory(&overlapped, sizeof(overlapped));
+ overlapped.hEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
+ if (!overlapped.hEvent)
+ boost::throw_exception(boost::system::system_error(::GetLastError(), boost::system::system_category, "boost::process::detail::pipe::pipe: CreateEvent failed"));
+ BOOL b = ::ConnectNamedPipe(hs[0], &overlapped);
+ if (!b)
+ {
+ if (::GetLastError() == ERROR_IO_PENDING)
+ {
+ if (::WaitForSingleObject(overlapped.hEvent, INFINITE) == WAIT_FAILED)
+ {
+ ::CloseHandle(overlapped.hEvent);
+ boost::throw_exception(boost::system::system_error(::GetLastError(), boost::system::system_category, "boost::process::detail::pipe::pipe: WaitForSingleObject failed"));
+ }
+ }
+ else if (::GetLastError() != ERROR_PIPE_CONNECTED)
+ {
+ ::CloseHandle(overlapped.hEvent);
+ boost::throw_exception(boost::system::system_error(::GetLastError(), boost::system::system_category, "boost::process::detail::pipe::pipe: ConnectNamedPipe failed"));
+ }
+ }
+ ::CloseHandle(overlapped.hEvent);
+# else
+ if (!::CreatePipe(&hs[0], &hs[1], &sa, 0))
+ boost::throw_exception(boost::system::system_error(::GetLastError(), boost::system::system_category, "boost::process::detail::pipe::pipe: CreatePipe failed"));
+# endif
+#endif
+
+ read_end_ = file_handle(hs[0]);
+ write_end_ = file_handle(hs[1]);
+ }
+
+ /**
+ * Returns the %pipe's read end file handle.
+ *
+ * Obtains a reference to the %pipe's read end file handle. Care
+ * should be taken to not duplicate the returned object if ownership
+ * shall remain to the %pipe.
+ *
+ * Duplicating the returned object invalidates its corresponding file
+ * handle in the %pipe.
+ *
+ * \return A reference to the %pipe's read end file handle.
+ */
+ file_handle &rend()
+ {
+ return read_end_;
+ }
+
+ /**
+ * Returns the %pipe's write end file handle.
+ *
+ * Obtains a reference to the %pipe's write end file handle. Care
+ * should be taken to not duplicate the returned object if ownership
+ * shall remain to the %pipe.
+ *
+ * Duplicating the returned object invalidates its corresponding file
+ * handle in the %pipe.
+ *
+ * \return A reference to the %pipe's write end file handle.
+ */
+ file_handle &wend()
+ {
+ return write_end_;
+ }
+
+private:
+ /**
+ * The %pipe's read end file handle.
+ */
+ file_handle read_end_;
+
+ /**
+ * The %pipe's write end file handle.
+ */
+ file_handle write_end_;
+};
+
+}
+}
+}
+
+#endif
Added: sandbox/process/boost/process/detail/posix_ops.hpp
==============================================================================
--- (empty file)
+++ sandbox/process/boost/process/detail/posix_ops.hpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,495 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+/**
+ * \file boost/process/detail/posix_ops.hpp
+ *
+ * Provides some convenience functions to start processes under POSIX
+ * operating systems.
+ */
+
+#ifndef BOOST_PROCESS_DETAIL_POSIX_OPS_HPP
+#define BOOST_PROCESS_DETAIL_POSIX_OPS_HPP
+
+#include <boost/process/environment.hpp>
+#include <boost/process/detail/file_handle.hpp>
+#include <boost/process/detail/pipe.hpp>
+#include <boost/process/detail/stream_info.hpp>
+#include <boost/scoped_array.hpp>
+#include <boost/assert.hpp>
+#include <boost/system/system_error.hpp>
+#include <boost/throw_exception.hpp>
+#include <map>
+#include <utility>
+#include <string>
+#include <cerrno>
+#include <cstdlib>
+#include <cstring>
+#include <fcntl.h>
+#include <unistd.h>
+
+namespace boost {
+namespace process {
+namespace detail {
+
+/**
+ * Converts the command line to an array of C strings.
+ *
+ * Converts the command line's list of arguments to the format expected
+ * by the \a argv parameter in the POSIX execve() system call.
+ *
+ * This operation is only available on POSIX systems.
+ *
+ * \return The first argument of the pair is an integer that indicates
+ * how many strings are stored in the second argument. The
+ * second argument is a NULL-terminated, dynamically allocated
+ * array of dynamically allocated strings holding the arguments
+ * to the executable. The caller is responsible of freeing them.
+ */
+template <class Arguments>
+inline std::pair<std::size_t, char**> collection_to_posix_argv(const Arguments &args)
+{
+ std::size_t nargs = args.size();
+ BOOST_ASSERT(nargs > 0);
+
+ char **argv = new char*[nargs + 1];
+ typename Arguments::size_type i = 0;
+ for (typename Arguments::const_iterator it = args.begin(); it != args.end(); ++it)
+ {
+ argv[i] = new char[it->size() + 1];
+ std::strncpy(argv[i], it->c_str(), it->size() + 1);
+ ++i;
+ }
+ argv[nargs] = 0;
+
+ return std::pair<std::size_t, char**>(nargs, argv);
+}
+
+/**
+ * Converts an environment to a char** table as used by execve().
+ *
+ * Converts the environment's contents to the format used by the
+ * execve() system call. The returned char** array is allocated
+ * in dynamic memory; the caller must free it when not used any
+ * more. Each entry is also allocated in dynamic memory and is a
+ * NULL-terminated string of the form var=value; these must also be
+ * released by the caller.
+ *
+ * \return A dynamically allocated char** array that represents
+ * the environment's content. Each array entry is a
+ * NULL-terminated string of the form var=value.
+ */
+inline char **environment_to_envp(const environment &env)
+{
+ char **envp = new char*[env.size() + 1];
+
+ environment::size_type i = 0;
+ for (environment::const_iterator it = env.begin(); it != env.end(); ++it)
+ {
+ std::string s = it->first + "=" + it->second;
+ envp[i] = new char[s.size() + 1];
+ std::strncpy(envp[i], s.c_str(), s.size() + 1);
+ ++i;
+ }
+ envp[i] = 0;
+
+ return envp;
+}
+
+/**
+ * Holds a mapping between native file descriptors and their corresponding
+ * pipes to set up communication between the parent and the %child process.
+ */
+typedef std::map<int, stream_info> info_map;
+
+/**
+ * Helper class to configure a POSIX %child.
+ *
+ * This helper class is used to hold all the attributes that configure a
+ * new POSIX %child process and to centralize all the actions needed to
+ * make them effective.
+ *
+ * All its fields are public for simplicity. It is only intended for
+ * internal use and it is heavily coupled with the Context
+ * implementations.
+ */
+struct posix_setup
+{
+ /**
+ * The work directory.
+ *
+ * This string specifies the directory in which the %child process
+ * starts execution. It cannot be empty.
+ */
+ std::string work_directory;
+
+ /**
+ * The chroot directory, if any.
+ *
+ * Specifies the directory in which the %child process is chrooted
+ * before execution. Empty if this feature is not desired.
+ */
+ std::string chroot;
+
+ /**
+ * The user credentials.
+ *
+ * UID that specifies the user credentials to use to run the %child
+ * process. Defaults to the current UID.
+ */
+ uid_t uid;
+
+ /**
+ * The effective user credentials.
+ *
+ * EUID that specifies the effective user credentials to use to run
+ * the %child process. Defaults to the current EUID.
+ */
+ uid_t euid;
+
+ /**
+ * The group credentials.
+ *
+ * GID that specifies the group credentials to use to run the %child
+ * process. Defaults to the current GID.
+ */
+ gid_t gid;
+
+ /**
+ * The effective group credentials.
+ *
+ * EGID that specifies the effective group credentials to use to run
+ * the %child process. Defaults to the current EGID.
+ */
+ gid_t egid;
+
+ /**
+ * Creates a new properties set.
+ *
+ * Creates a new object that has sensible default values for all the
+ * properties.
+ */
+ posix_setup()
+ : uid(::getuid()),
+ euid(::geteuid()),
+ gid(::getgid()),
+ egid(::getegid())
+ {
+ }
+
+ /**
+ * Sets up the execution environment.
+ *
+ * Modifies the current execution environment (that of the %child) so
+ * that the properties become effective.
+ *
+ * \throw boost::system::system_error If any error ocurred during
+ * environment configuration. The child process should abort
+ * execution if this happens because its start conditions
+ * cannot be met.
+ */
+ void operator()() const
+ {
+ if (!chroot.empty() && ::chroot(chroot.c_str()) == -1)
+ boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::posix_setup: chroot(2) failed"));
+
+ if (gid != ::getgid() && ::setgid(gid) == -1)
+ boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::posix_setup: setgid(2) failed"));
+
+ if (egid != ::getegid() && ::setegid(egid) == -1)
+ boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::posix_setup: setegid(2) failed"));
+
+ if (uid != ::getuid() && ::setuid(uid) == -1)
+ boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::posix_setup: setuid(2) failed"));
+
+ if (euid != ::geteuid() && ::seteuid(euid) == -1)
+ boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::posix_setup: seteuid(2) failed"));
+
+ BOOST_ASSERT(!work_directory.empty());
+ if (::chdir(work_directory.c_str()) == -1)
+ boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::posix_setup: chdir(2) failed"));
+ }
+};
+
+/**
+ * Configures child process' input streams.
+ *
+ * Sets up the current process' input streams to behave according to the
+ * information in the \a info map. \a closeflags is modified to reflect
+ * those descriptors that should not be closed because they where modified
+ * by the function.
+ *
+ * Modifies the current execution environment, so this should only be run
+ * on the child process after the fork(2) has happened.
+ *
+ * \throw boost::system::system_error If any error occurs during the
+ * configuration.
+ */
+inline void setup_input(info_map &info, bool *closeflags, int maxdescs)
+{
+ for (info_map::iterator it = info.begin(); it != info.end(); ++it)
+ {
+ int d = it->first;
+ stream_info &si = it->second;
+
+ BOOST_ASSERT(d < maxdescs);
+ closeflags[d] = false;
+
+ switch (si.type_)
+ {
+ case stream_info::use_file:
+ {
+ int fd = ::open(si.file_.c_str(), O_RDONLY);
+ if (fd == -1)
+ boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::setup_input: open(2) of " + si.file_ + " failed"));
+ if (fd != d)
+ {
+ file_handle h(fd);
+ h.posix_remap(d);
+ h.release();
+ }
+ break;
+ }
+ case stream_info::use_handle:
+ {
+ if (si.handle_.get() != d)
+ si.handle_.posix_remap(d);
+ break;
+ }
+ case stream_info::use_pipe:
+ {
+ si.pipe_->wend().close();
+ if (d != si.pipe_->rend().get())
+ si.pipe_->rend().posix_remap(d);
+ break;
+ }
+ default:
+ {
+ BOOST_ASSERT(si.type_ == stream_info::inherit);
+ break;
+ }
+ }
+ }
+}
+
+/**
+ * Configures child process' output streams.
+ *
+ * Sets up the current process' output streams to behave according to the
+ * information in the \a info map. \a closeflags is modified to reflect
+ * those descriptors that should not be closed because they where
+ * modified by the function.
+ *
+ * Modifies the current execution environment, so this should only be run
+ * on the child process after the fork(2) has happened.
+ *
+ * \throw boost::system::system_error If any error occurs during the
+ * configuration.
+ */
+inline void setup_output(info_map &info, bool *closeflags, int maxdescs)
+{
+ for (info_map::iterator it = info.begin(); it != info.end(); ++it)
+ {
+ int d = it->first;
+ stream_info &si = it->second;
+
+ BOOST_ASSERT(d < maxdescs);
+ closeflags[d] = false;
+
+ switch (si.type_)
+ {
+ case stream_info::redirect:
+ {
+ break;
+ }
+ case stream_info::use_file:
+ {
+ int fd = ::open(si.file_.c_str(), O_WRONLY);
+ if (fd == -1)
+ boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::setup_output: open(2) of " + si.file_ + " failed"));
+ if (fd != d)
+ {
+ file_handle h(fd);
+ h.posix_remap(d);
+ h.release();
+ }
+ break;
+ }
+ case stream_info::use_handle:
+ {
+ if (si.handle_.get() != d)
+ si.handle_.posix_remap(d);
+ break;
+ }
+ case stream_info::use_pipe:
+ {
+ si.pipe_->rend().close();
+ if (d != si.pipe_->wend().get())
+ si.pipe_->wend().posix_remap(d);
+ break;
+ }
+ default:
+ {
+ BOOST_ASSERT(si.type_ == stream_info::inherit);
+ break;
+ }
+ }
+ }
+
+ for (info_map::const_iterator it = info.begin(); it != info.end(); ++it)
+ {
+ int d = it->first;
+ const stream_info &si = it->second;
+
+ if (si.type_ == stream_info::redirect)
+ file_handle::posix_dup(si.desc_to_, d).release();
+ }
+}
+
+/**
+ * Starts a new child process in a POSIX operating system.
+ *
+ * This helper functions is provided to simplify the Context's task when
+ * it comes to starting up a new process in a POSIX operating system.
+ * The function hides all the details of the fork/exec pair of calls as
+ * well as all the setup of communication pipes and execution environment.
+ *
+ * \param exe The executable to spawn the child process.
+ * \param args The arguments for the executable.
+ * \param env The environment variables that the new child process
+ * receives.
+ * \param infoin A map describing all input file descriptors to be
+ * redirected.
+ * \param infoout A map describing all output file descriptors to be
+ * redirected.
+ * \param setup A helper object used to configure the child's execution
+ * environment.
+ * \return The new process' PID. The caller is responsible of creating
+ * an appropriate Child representation for it.
+ */
+template <class Executable, class Arguments>
+inline pid_t posix_start(const Executable &exe, const Arguments &args, const environment &env, info_map &infoin, info_map &infoout, const posix_setup &setup)
+{
+ pid_t pid = ::fork();
+ if (pid == -1)
+ boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::posix_start: fork(2) failed"));
+ else if (pid == 0)
+ {
+#if defined(F_MAXFD)
+ int maxdescs = ::fcntl(-1, F_MAXFD, 0);
+ if (maxdescs == -1)
+ maxdescs = ::sysconf(_SC_OPEN_MAX);
+#else
+ int maxdescs = ::sysconf(_SC_OPEN_MAX);
+#endif
+ if (maxdescs == -1)
+ maxdescs = 1024;
+ try
+ {
+ boost::scoped_array<bool> closeflags(new bool[maxdescs]);
+ for (int i = 0; i < maxdescs; ++i)
+ closeflags[i] = true;
+
+ setup_input(infoin, closeflags.get(), maxdescs);
+ setup_output(infoout, closeflags.get(), maxdescs);
+
+ for (int i = 0; i < maxdescs; ++i)
+ {
+ if (closeflags[i])
+ ::close(i);
+ }
+
+ setup();
+ }
+ catch (const boost::system::system_error &e)
+ {
+ ::write(STDERR_FILENO, e.what(), std::strlen(e.what()));
+ ::write(STDERR_FILENO, "\n", 1);
+ std::exit(EXIT_FAILURE);
+ }
+
+ std::pair<std::size_t, char**> argcv = collection_to_posix_argv(args);
+ char **envp = environment_to_envp(env);
+
+ ::execve(exe.c_str(), argcv.second, envp);
+ boost::system::system_error e(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::posix_start: execve(2) failed");
+
+ for (std::size_t i = 0; i < argcv.first; ++i)
+ delete[] argcv.second[i];
+ delete[] argcv.second;
+
+ for (std::size_t i = 0; i < env.size(); ++i)
+ delete[] envp[i];
+ delete[] envp;
+
+ ::write(STDERR_FILENO, e.what(), std::strlen(e.what()));
+ ::write(STDERR_FILENO, "\n", 1);
+ std::exit(EXIT_FAILURE);
+ }
+
+ BOOST_ASSERT(pid > 0);
+
+ for (info_map::iterator it = infoin.begin(); it != infoin.end(); ++it)
+ {
+ stream_info &si = it->second;
+ if (si.type_ == stream_info::use_pipe)
+ si.pipe_->rend().close();
+ }
+
+ for (info_map::iterator it = infoout.begin(); it != infoout.end(); ++it)
+ {
+ stream_info &si = it->second;
+ if (si.type_ == stream_info::use_pipe)
+ si.pipe_->wend().close();
+ }
+
+ return pid;
+}
+
+/**
+ * Locates a communication pipe and returns one of its endpoints.
+ *
+ * Given a \a info map, and a file descriptor \a desc, searches for its
+ * communicataion pipe in the map and returns one of its endpoints as
+ * indicated by the \a out flag. This is intended to be used by a
+ * parent process after a fork(2) call.
+ *
+ * \pre If the info map contains the given descriptor, it is configured
+ * to use a pipe.
+ * \post The info map does not contain the given descriptor.
+ * \return If the file descriptor is found in the map, returns the pipe's
+ * read end if out is true; otherwise its write end. If the
+ * descriptor is not found returns an invalid file handle.
+ */
+inline file_handle posix_info_locate_pipe(info_map &info, int desc, bool out)
+{
+ file_handle fh;
+
+ info_map::iterator it = info.find(desc);
+ if (it != info.end())
+ {
+ stream_info &si = it->second;
+ if (si.type_ == stream_info::use_pipe)
+ {
+ fh = out ? si.pipe_->rend().release() : si.pipe_->wend().release();
+ BOOST_ASSERT(fh.valid());
+ }
+ info.erase(it);
+ }
+
+ return fh;
+}
+
+}
+}
+}
+
+#endif
Added: sandbox/process/boost/process/detail/stream_info.hpp
==============================================================================
--- (empty file)
+++ sandbox/process/boost/process/detail/stream_info.hpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,176 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+/**
+ * \file boost/process/detail/stream_info.hpp
+ *
+ * Provides the definition of the stream_info structure.
+ */
+
+#ifndef BOOST_PROCESS_DETAIL_STREAM_INFO_HPP
+#define BOOST_PROCESS_DETAIL_STREAM_INFO_HPP
+
+#include <boost/process/config.hpp>
+
+#if defined(BOOST_POSIX_API)
+# include <unistd.h>
+#elif defined(BOOST_WINDOWS_API)
+#else
+# error "Unsupported platform."
+#endif
+
+#include <boost/process/stream_behavior.hpp>
+#include <boost/process/detail/file_handle.hpp>
+#include <boost/process/detail/pipe.hpp>
+#include <boost/optional.hpp>
+#include <boost/assert.hpp>
+#include <string>
+
+namespace boost {
+namespace process {
+namespace detail {
+
+/**
+ * Configuration data for a file descriptor.
+ *
+ * This convenience structure provides a compact way to pass information
+ * around on how to configure a file descriptor. It is a lower-level
+ * representation of stream_behavior, as it can hold the same information
+ * but in a way that can be used by the underlying operating system.
+ */
+struct stream_info
+{
+ /**
+ * Supported stream types.
+ */
+ enum type
+ {
+ /**
+ * Matches stream_behavior::close.
+ */
+ close,
+
+ /**
+ * Matches stream_behavior::inherit.
+ */
+ inherit,
+
+ /**
+ * Matches stream_behavior::redirect_to_stdout and
+ * stream_behavior::posix_redirect.
+ */
+ redirect,
+
+ /**
+ * Matches stream_behavior::silence.
+ */
+ use_file,
+
+ /**
+ * TODO: Matches nothing yet ...
+ */
+ use_handle,
+
+ /**
+ * Matches stream_behavior::capture.
+ */
+ use_pipe
+ };
+
+ /**
+ * Stream type.
+ */
+ type type_;
+
+ /**
+ * Descriptor to use when stream type is set to \a redirect.
+ */
+ int desc_to_;
+
+ /**
+ * File to use when stream type is set to \a use_file.
+ */
+ std::string file_;
+
+ /**
+ * Handle to use when stream type is set to \a use_handle.
+ */
+ file_handle handle_;
+
+ /**
+ * Pipe to use when stream type is set to \a use_pipe.
+ */
+ boost::optional<pipe> pipe_;
+
+ /**
+ * Constructs a new stream_info object.
+ */
+ stream_info(const stream_behavior &sb, bool out)
+ {
+ switch (sb.type_)
+ {
+ case stream_behavior::close:
+ {
+ type_ = close;
+ break;
+ }
+ case stream_behavior::inherit:
+ {
+ type_ = inherit;
+ break;
+ }
+ case stream_behavior::redirect_to_stdout:
+ {
+ type_ = redirect;
+#if defined(BOOST_POSIX_API)
+ desc_to_ = STDOUT_FILENO;
+#elif defined(BOOST_WINDOWS_API)
+ desc_to_ = 1;
+#endif
+ break;
+ }
+#if defined(BOOST_POSIX_API)
+ case stream_behavior::posix_redirect:
+ {
+ type_ = redirect;
+ desc_to_ = sb.desc_to_;
+ break;
+ }
+#endif
+ case stream_behavior::silence:
+ {
+ type_ = use_file;
+#if defined(BOOST_POSIX_API)
+ file_ = out ? "/dev/null" : "/dev/zero";
+#elif defined(BOOST_WINDOWS_API)
+ file_ = "NUL";
+#endif
+ break;
+ }
+ case stream_behavior::capture:
+ {
+ type_ = use_pipe;
+ pipe_ = pipe();
+ break;
+ }
+ default:
+ {
+ BOOST_ASSERT(false);
+ }
+ }
+ }
+};
+
+}
+}
+}
+
+#endif
Added: sandbox/process/boost/process/detail/systembuf.hpp
==============================================================================
--- (empty file)
+++ sandbox/process/boost/process/detail/systembuf.hpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,231 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+/**
+ * \file boost/process/detail/systembuf.hpp
+ *
+ * Includes the declaration of the systembuf class. This file is for
+ * internal usage only and must not be included by the library user.
+ */
+
+#ifndef BOOST_PROCESS_DETAIL_SYSTEMBUF_HPP
+#define BOOST_PROCESS_DETAIL_SYSTEMBUF_HPP
+
+#include <boost/process/config.hpp>
+
+#if defined(BOOST_POSIX_API)
+# include <sys/types.h>
+# include <unistd.h>
+#elif defined(BOOST_WINDOWS_API)
+# include <windows.h>
+#else
+# error "Unsupported platform."
+#endif
+
+#include <boost/noncopyable.hpp>
+#include <boost/scoped_array.hpp>
+#include <boost/assert.hpp>
+#include <streambuf>
+#include <cstddef>
+
+namespace boost {
+namespace process {
+
+class postream;
+
+namespace detail {
+
+/**
+ * std::streambuf implementation for system file handles.
+ *
+ * systembuf provides a std::streambuf implementation for system file
+ * handles. Contrarywise to file_handle, this class does \b not take
+ * ownership of the native file handle; this should be taken care of
+ * somewhere else.
+ *
+ * This class follows the expected semantics of a std::streambuf object.
+ * However, it is not copyable to avoid introducing inconsistences with
+ * the on-disk file and the in-memory buffers.
+ */
+class systembuf : public std::streambuf, public boost::noncopyable
+{
+ friend class ::boost::process::postream;
+
+public:
+#if defined(BOOST_PROCESS_DOXYGEN)
+ /**
+ * Opaque name for the native handle type.
+ */
+ typedef NativeHandleType handle_type;
+#elif defined(BOOST_POSIX_API)
+ typedef int handle_type;
+#elif defined(BOOST_WINDOWS_API)
+ typedef HANDLE handle_type;
+#endif
+
+ /**
+ * Constructs a new systembuf for the given file handle.
+ *
+ * This constructor creates a new systembuf object that reads or
+ * writes data from/to the \a h native file handle. This handle
+ * is \b not owned by the created systembuf object; the code
+ * should take care of it externally.
+ *
+ * This class buffers input and output; the buffer size may be
+ * tuned through the \a bufsize parameter, which defaults to 8192
+ * bytes.
+ *
+ * \see pistream and postream
+ */
+ explicit systembuf(handle_type h, std::size_t bufsize = 8192)
+ : handle_(h),
+ bufsize_(bufsize),
+ read_buf_(new char[bufsize]),
+ write_buf_(new char[bufsize])
+ {
+#if defined(BOOST_POSIX_API)
+ BOOST_ASSERT(handle_ >= 0);
+#elif defined(BOOST_WINDOWS_API)
+ BOOST_ASSERT(handle_ != INVALID_HANDLE_VALUE);
+#endif
+ BOOST_ASSERT(bufsize_ > 0);
+
+ setp(write_buf_.get(), write_buf_.get() + bufsize_);
+ }
+
+protected:
+ /**
+ * Reads new data from the native file handle.
+ *
+ * This operation is called by input methods when there is no more
+ * data in the input buffer. The function fills the buffer with new
+ * data, if available.
+ *
+ * \pre All input positions are exhausted (gptr() >= egptr()).
+ * \post The input buffer has new data, if available.
+ * \returns traits_type::eof() if a read error occurrs or there are
+ * no more data to be read. Otherwise returns
+ * traits_type::to_int_type(*gptr()).
+ */
+ virtual int_type underflow()
+ {
+ BOOST_ASSERT(gptr() >= egptr());
+
+ bool ok;
+#if defined(BOOST_POSIX_API)
+ ssize_t cnt = ::read(handle_, read_buf_.get(), bufsize_);
+ ok = (cnt != -1 && cnt != 0);
+#elif defined(BOOST_WINDOWS_API)
+ DWORD cnt;
+ BOOL res = ::ReadFile(handle_, read_buf_.get(), bufsize_, &cnt, NULL);
+ ok = (res && cnt > 0);
+#endif
+
+ if (!ok)
+ return traits_type::eof();
+ else
+ {
+ setg(read_buf_.get(), read_buf_.get(), read_buf_.get() + cnt);
+ return traits_type::to_int_type(*gptr());
+ }
+ }
+
+ /**
+ * Makes room in the write buffer for additional data.
+ *
+ * This operation is called by output methods when there is no more
+ * space in the output buffer to hold a new element. The function
+ * first flushes the buffer's contents to disk and then clears it to
+ * leave room for more characters. The given \a c character is
+ * stored at the beginning of the new space.
+ *
+ * \pre All output positions are exhausted (pptr() >= epptr()).
+ * \post The output buffer has more space if no errors occurred
+ * during the write to disk.
+ * \post *(pptr() - 1) is \a c.
+ * \returns traits_type::eof() if a write error occurrs. Otherwise
+ * returns traits_type::not_eof(c).
+ */
+ virtual int_type overflow(int c)
+ {
+ BOOST_ASSERT(pptr() >= epptr());
+
+ if (sync() == -1)
+ return traits_type::eof();
+
+ if (!traits_type::eq_int_type(c, traits_type::eof()))
+ {
+ traits_type::assign(*pptr(), c);
+ pbump(1);
+ }
+
+ return traits_type::not_eof(c);
+ }
+
+ /**
+ * Flushes the output buffer to disk.
+ *
+ * Synchronizes the systembuf buffers with the contents of the file
+ * associated to this object through the native file handle. The
+ * output buffer is flushed to disk and cleared to leave new room
+ * for more data.
+ *
+ * \returns 0 on success, -1 if an error occurred.
+ */
+ virtual int sync()
+ {
+#if defined(BOOST_POSIX_API)
+ ssize_t cnt = pptr() - pbase();
+#elif defined(BOOST_WINDOWS_API)
+ long cnt = pptr() - pbase();
+#endif
+
+ bool ok;
+#if defined(BOOST_POSIX_API)
+ ok = ::write(handle_, pbase(), cnt) == cnt;
+#elif defined(BOOST_WINDOWS_API)
+ DWORD rcnt;
+ BOOL res = ::WriteFile(handle_, pbase(), cnt, &rcnt, NULL);
+ ok = (res && static_cast<long>(rcnt) == cnt);
+#endif
+
+ if (ok)
+ pbump(-cnt);
+ return ok ? 0 : -1;
+ }
+
+private:
+ /**
+ * Native file handle used by the systembuf object.
+ */
+ handle_type handle_;
+
+ /**
+ * Internal buffer size used during read and write operations.
+ */
+ std::size_t bufsize_;
+
+ /**
+ * Internal buffer used during read operations.
+ */
+ boost::scoped_array<char> read_buf_;
+
+ /**
+ * Internal buffer used during write operations.
+ */
+ boost::scoped_array<char> write_buf_;
+};
+
+}
+}
+}
+
+#endif
Added: sandbox/process/boost/process/detail/win32_ops.hpp
==============================================================================
--- (empty file)
+++ sandbox/process/boost/process/detail/win32_ops.hpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,355 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+/**
+ * \file boost/process/detail/win32_ops.hpp
+ *
+ * Provides some convenience functions to start processes under
+ * Windows-compatible operating systems.
+ */
+
+#ifndef BOOST_PROCESS_DETAIL_WIN32_OPS_HPP
+#define BOOST_PROCESS_DETAIL_WIN32_OPS_HPP
+
+#include <boost/process/environment.hpp>
+#include <boost/process/detail/file_handle.hpp>
+#include <boost/process/detail/pipe.hpp>
+#include <boost/process/detail/stream_info.hpp>
+#include <boost/scoped_ptr.hpp>
+#include <boost/shared_array.hpp>
+#include <boost/scoped_array.hpp>
+#include <boost/assert.hpp>
+#include <boost/system/system_error.hpp>
+#include <boost/throw_exception.hpp>
+#include <vector>
+#include <string>
+#include <cstddef>
+#include <string.h>
+#include <windows.h>
+
+namespace boost {
+namespace process {
+namespace detail {
+
+/**
+ * Converts the command line to a plain string. Converts the command line's
+ * list of arguments to the format expected by the \a lpCommandLine parameter
+ * in the CreateProcess() system call.
+ *
+ * This operation is only available on Windows systems.
+ *
+ * \return A dynamically allocated string holding the command line
+ * to be passed to the executable. It is returned in a
+ * shared_array object to ensure its release at some point.
+ */
+template <class Arguments>
+inline boost::shared_array<char> collection_to_win32_cmdline(const Arguments &args)
+{
+ typedef std::vector<std::string> arguments_t;
+ arguments_t args2;
+ typename Arguments::size_type i = 0;
+ std::size_t size = 0;
+ for (typename Arguments::const_iterator it = args.begin(); it != args.end(); ++it)
+ {
+ std::string arg = *it;
+
+ std::string::size_type pos = 0;
+ while ( (pos = arg.find('"', pos)) != std::string::npos)
+ {
+ arg.replace(pos, 1, "\\\"");
+ pos += 2;
+ }
+
+ if (arg.find(' ') != std::string::npos)
+ arg = '\"' + arg + '\"';
+
+ if (i++ != args.size() - 1)
+ arg += ' ';
+
+ args2.push_back(arg);
+ size += arg.size() + 1;
+ }
+
+ boost::shared_array<char> cmdline(new char[size]);
+ cmdline.get()[0] = '\0';
+ for (arguments_t::size_type i = 0; i < args.size(); ++i)
+#if defined(__CYGWIN__)
+ ::strncat(cmdline.get(), args2[i].c_str(), args2[i].size());
+#else
+ ::strcat_s(cmdline.get(), size, args2[i].c_str());
+#endif
+
+ return cmdline;
+}
+
+/**
+ * Converts an environment to a string used by CreateProcess().
+ *
+ * Converts the environment's contents to the format used by the
+ * CreateProcess() system call. The returned char* string is
+ * allocated in dynamic memory; the caller must free it when not
+ * used any more. This is enforced by the use of a shared pointer.
+ *
+ * \return A dynamically allocated char* string that represents
+ * the environment's content. This string is of the form
+ * var1=value1\\0var2=value2\\0\\0.
+ */
+inline boost::shared_array<char> environment_to_win32_strings(const environment &env)
+{
+ boost::shared_array<char> envp;
+
+ if (env.empty())
+ {
+ envp.reset(new char[2]);
+ ::ZeroMemory(envp.get(), 2);
+ }
+ else
+ {
+ std::string s;
+ for (environment::const_iterator it = env.begin(); it != env.end(); ++it)
+ {
+ s += it->first + "=" + it->second;
+ s.push_back(0);
+ }
+
+ envp.reset(new char[s.size() + 1]);
+#if defined(__CYGWIN__)
+ ::memcpy(envp.get(), s.c_str(), s.size() + 1);
+#else
+ ::memcpy_s(envp.get(), s.size() + 1, s.c_str(), s.size() + 1);
+#endif
+ }
+
+ return envp;
+}
+
+/**
+ * Helper class to configure a Win32 %child.
+ *
+ * This helper class is used to hold all the attributes that configure a
+ * new Win32 %child process.
+ *
+ * All its fields are public for simplicity. It is only intended for
+ * internal use and it is heavily coupled with the Context
+ * implementations.
+ */
+struct win32_setup
+{
+ /**
+ * The work directory.
+ *
+ * This string specifies the directory in which the %child process
+ * starts execution. It cannot be empty.
+ */
+ std::string work_directory;
+
+ /**
+ * The process startup properties.
+ *
+ * This Win32-specific object holds a list of properties that describe
+ * how the new process should be started. The \a STARTF_USESTDHANDLES
+ * flag should not be set in it because it is automatically configured
+ * by win32_start().
+ */
+ STARTUPINFOA *startupinfo;
+};
+
+/**
+ * Starts a new child process in a Win32 operating system.
+ *
+ * This helper functions is provided to simplify the Context's task when
+ * it comes to starting up a new process in a Win32 operating system.
+ *
+ * \param exe The executable to spawn the child process.
+ * \param args The arguments for the executable.
+ * \param env The environment variables that the new child process
+ * receives.
+ * \param infoin Information that describes stdin's behavior.
+ * \param infoout Information that describes stdout's behavior.
+ * \param infoerr Information that describes stderr's behavior.
+ * \param setup A helper object holding extra child information.
+ * \return The new process' information as returned by the CreateProcess()
+ * system call. The caller is responsible of creating an
+ * appropriate Child representation for it.
+ * \pre \a setup.startupinfo_ cannot have the \a STARTF_USESTDHANDLES set
+ * in the \a dwFlags field.
+ */
+template <class Executable, class Arguments>
+inline PROCESS_INFORMATION win32_start(const Executable &exe, const Arguments &args, const environment &env, stream_info &infoin, stream_info &infoout, stream_info &infoerr, const win32_setup &setup)
+{
+ file_handle chin, chout, cherr;
+
+ BOOST_ASSERT(setup.startupinfo->cb >= sizeof(STARTUPINFOA));
+ BOOST_ASSERT(!(setup.startupinfo->dwFlags & STARTF_USESTDHANDLES));
+
+ boost::scoped_ptr<STARTUPINFOA> si(new STARTUPINFOA);
+ ::CopyMemory(si.get(), setup.startupinfo, sizeof(*setup.startupinfo));
+ si->dwFlags |= STARTF_USESTDHANDLES;
+
+ switch (infoin.type_)
+ {
+ case stream_info::close:
+ {
+ break;
+ }
+ case stream_info::inherit:
+ {
+ chin = file_handle::win32_std(STD_INPUT_HANDLE, true);
+ break;
+ }
+ case stream_info::use_file:
+ {
+ HANDLE h = ::CreateFileA(infoin.file_.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (h == INVALID_HANDLE_VALUE)
+ boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::detail::win32_start: CreateFile failed"));
+ chin = file_handle(h);
+ break;
+ }
+ case stream_info::use_handle:
+ {
+ chin = infoin.handle_;
+ chin.win32_set_inheritable(true);
+ break;
+ }
+ case stream_info::use_pipe:
+ {
+ infoin.pipe_->rend().win32_set_inheritable(true);
+ chin = infoin.pipe_->rend();
+ break;
+ }
+ default:
+ {
+ BOOST_ASSERT(false);
+ break;
+ }
+ }
+
+ si->hStdInput = chin.valid() ? chin.get() : INVALID_HANDLE_VALUE;
+
+ switch (infoout.type_)
+ {
+ case stream_info::close:
+ {
+ break;
+ }
+ case stream_info::inherit:
+ {
+ chout = file_handle::win32_std(STD_OUTPUT_HANDLE, true);
+ break;
+ }
+ case stream_info::use_file:
+ {
+ HANDLE h = ::CreateFileA(infoout.file_.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (h == INVALID_HANDLE_VALUE)
+ boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::detail::win32_start: CreateFile failed"));
+ chout = file_handle(h);
+ break;
+ }
+ case stream_info::use_handle:
+ {
+ chout = infoout.handle_;
+ chout.win32_set_inheritable(true);
+ break;
+ }
+ case stream_info::use_pipe:
+ {
+ infoout.pipe_->wend().win32_set_inheritable(true);
+ chout = infoout.pipe_->wend();
+ break;
+ }
+ default:
+ {
+ BOOST_ASSERT(false);
+ break;
+ }
+ }
+
+ si->hStdOutput = chout.valid() ? chout.get() : INVALID_HANDLE_VALUE;
+
+ switch (infoerr.type_)
+ {
+ case stream_info::close:
+ {
+ break;
+ }
+ case stream_info::inherit:
+ {
+ cherr = file_handle::win32_std(STD_ERROR_HANDLE, true);
+ break;
+ }
+ case stream_info::redirect:
+ {
+ BOOST_ASSERT(infoerr.desc_to_ == 1);
+ BOOST_ASSERT(chout.valid());
+ cherr = file_handle::win32_dup(chout.get(), true);
+ break;
+ }
+ case stream_info::use_file:
+ {
+ HANDLE h = ::CreateFileA(infoerr.file_.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (h == INVALID_HANDLE_VALUE)
+ boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::detail::win32_start: CreateFile failed"));
+ cherr = file_handle(h);
+ break;
+ }
+ case stream_info::use_handle:
+ {
+ cherr = infoerr.handle_;
+ cherr.win32_set_inheritable(true);
+ break;
+ }
+ case stream_info::use_pipe:
+ {
+ infoerr.pipe_->wend().win32_set_inheritable(true);
+ cherr = infoerr.pipe_->wend();
+ break;
+ }
+ default:
+ {
+ BOOST_ASSERT(false);
+ break;
+ }
+ }
+
+ si->hStdError = cherr.valid() ? cherr.get() : INVALID_HANDLE_VALUE;
+
+ PROCESS_INFORMATION pi;
+ ::ZeroMemory(&pi, sizeof(pi));
+
+ boost::shared_array<char> cmdline = collection_to_win32_cmdline(args);
+
+ boost::scoped_array<char> executable(new char[exe.size() + 1]);
+#if defined(__CYGWIN__)
+ ::strcpy(executable.get(), exe.c_str());
+#else
+ ::strcpy_s(executable.get(), exe.size() + 1, exe.c_str());
+#endif
+
+ boost::scoped_array<char> workdir(new char[setup.work_directory.size() + 1]);
+#if defined(__CYGWIN__)
+ ::strcpy(workdir.get(), setup.work_directory.c_str());
+#else
+ ::strcpy_s(workdir.get(), setup.work_directory.size() + 1, setup.work_directory.c_str());
+#endif
+
+ boost::shared_array<char> envstrs = environment_to_win32_strings(env);
+
+ if (!::CreateProcessA(executable.get(), cmdline.get(), NULL, NULL, TRUE, 0, envstrs.get(), workdir.get(), si.get(), &pi))
+ boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::detail::win32_start: CreateProcess failed"));
+
+ return pi;
+}
+
+}
+}
+}
+
+#endif
Added: sandbox/process/boost/process/environment.hpp
==============================================================================
--- (empty file)
+++ sandbox/process/boost/process/environment.hpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,50 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+/**
+ * \file boost/process/environment.hpp
+ *
+ * Includes the declaration of the environment class.
+ */
+
+#ifndef BOOST_PROCESS_ENVIRONMENT_HPP
+#define BOOST_PROCESS_ENVIRONMENT_HPP
+
+#include <string>
+#include <map>
+
+namespace boost {
+namespace process {
+
+/**
+ * Representation of a process' environment variables.
+ *
+ * The environment is a map that stablishes an unidirectional
+ * association between variable names and their values and is
+ * represented by a string to string map.
+ *
+ * Variables may be defined to the empty string. Be aware that doing so
+ * is not portable: POSIX systems will treat such variables as being
+ * defined to the empty value, but Windows systems are not able to
+ * distinguish them from undefined variables.
+ *
+ * Neither POSIX nor Windows systems support a variable with no name.
+ *
+ * It is worthy to note that the environment is sorted alphabetically.
+ * This is provided for-free by the map container used to implement this
+ * type, and this behavior is required by Windows systems.
+ */
+typedef std::map<std::string, std::string> environment;
+
+}
+}
+
+#endif
Added: sandbox/process/boost/process/operations.hpp
==============================================================================
--- (empty file)
+++ sandbox/process/boost/process/operations.hpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,583 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+/**
+ * \file boost/process/operations.hpp
+ *
+ * Provides miscellaneous free functions.
+ */
+
+#ifndef BOOST_PROCESS_OPERATIONS_HPP
+#define BOOST_PROCESS_OPERATIONS_HPP
+
+#include <boost/process/config.hpp>
+
+#if defined(BOOST_POSIX_API)
+# include <boost/process/detail/posix_ops.hpp>
+# include <stdlib.h>
+# include <unistd.h>
+# if defined(__CYGWIN__)
+# include <boost/scoped_array.hpp>
+# include <sys/cygwin.h>
+# endif
+#elif defined(BOOST_WINDOWS_API)
+# include <boost/process/detail/win32_ops.hpp>
+# include <boost/algorithm/string/predicate.hpp>
+# include <windows.h>
+#else
+# error "Unsupported platform."
+#endif
+
+#include <boost/process/child.hpp>
+#include <boost/process/stream_behavior.hpp>
+#include <boost/process/status.hpp>
+#include <boost/process/detail/file_handle.hpp>
+#include <boost/process/detail/pipe.hpp>
+#include <boost/process/detail/stream_info.hpp>
+#include <boost/filesystem/path.hpp>
+#include <boost/algorithm/string/predicate.hpp>
+#include <boost/system/system_error.hpp>
+#include <boost/throw_exception.hpp>
+#include <boost/scoped_array.hpp>
+#include <boost/assert.hpp>
+#include <string>
+#include <vector>
+#include <stdexcept>
+#include <cstddef>
+
+namespace boost {
+namespace process {
+
+/**
+ * Locates the executable program \a file in all the directory components
+ * specified in \a path. If \a path is empty, the value of the PATH
+ * environment variable is used.
+ *
+ * The path variable is interpreted following the same conventions used
+ * to parse the PATH environment variable in the underlying platform.
+ *
+ * \throw boost::filesystem::filesystem_error If the file cannot be found
+ * in the path.
+ */
+inline std::string find_executable_in_path(const std::string &file, std::string path = "")
+{
+#if defined(BOOST_POSIX_API)
+ BOOST_ASSERT(file.find('/') == std::string::npos);
+#elif defined(BOOST_WINDOWS_API)
+ BOOST_ASSERT(file.find_first_of("\\/") == std::string::npos);
+#endif
+
+ std::string result;
+
+#if defined(BOOST_POSIX_API)
+ if (path.empty())
+ {
+ const char *envpath = ::getenv("PATH");
+ if (!envpath)
+ boost::throw_exception(boost::filesystem::filesystem_error("boost::process::find_executable_in_path: retrieving PATH failed", file, boost::system::errc::make_error_code(boost::system::errc::no_such_file_or_directory)));
+
+ path = envpath;
+ }
+ BOOST_ASSERT(!path.empty());
+
+#if defined(__CYGWIN__)
+ if (!::cygwin_posix_path_list_p(path.c_str()))
+ {
+ int size = ::cygwin_win32_to_posix_path_list_buf_size(path.c_str());
+ boost::scoped_array<char> cygpath(new char[size]);
+ ::cygwin_win32_to_posix_path_list(path.c_str(), cygpath.get());
+ path = cygpath.get();
+ }
+#endif
+
+ std::string::size_type pos1 = 0, pos2;
+ do
+ {
+ pos2 = path.find(':', pos1);
+ std::string dir = (pos2 != std::string::npos) ? path.substr(pos1, pos2 - pos1) : path.substr(pos1);
+ std::string f = dir + (boost::algorithm::ends_with(dir, "/") ? "" : "/") + file;
+ if (!::access(f.c_str(), X_OK))
+ result = f;
+ pos1 = pos2 + 1;
+ } while (pos2 != std::string::npos && result.empty());
+#elif defined(BOOST_WINDOWS_API)
+ const char *exts[] = { "", ".exe", ".com", ".bat", NULL };
+ const char **ext = exts;
+ while (*ext)
+ {
+ char buf[MAX_PATH];
+ char *dummy;
+ DWORD size = ::SearchPathA(path.empty() ? NULL : path.c_str(), file.c_str(), *ext, MAX_PATH, buf, &dummy);
+ BOOST_ASSERT(size < MAX_PATH);
+ if (size > 0)
+ {
+ result = buf;
+ break;
+ }
+ ++ext;
+ }
+#endif
+
+ if (result.empty())
+ boost::throw_exception(boost::filesystem::filesystem_error("boost::process::find_executable_in_path: file not found", file, boost::system::errc::make_error_code(boost::system::errc::no_such_file_or_directory)));
+
+ return result;
+}
+
+/**
+ * Extracts the program name from a given executable.
+ *
+ * \return The program name. On Windows the program name
+ * is returned without a file extension.
+ */
+inline std::string executable_to_progname(const std::string &exe)
+{
+ std::string::size_type begin = 0;
+ std::string::size_type end = std::string::npos;
+
+#if defined(BOOST_POSIX_API)
+ std::string::size_type slash = exe.rfind('/');
+#elif defined(BOOST_WINDOWS_API)
+ std::string::size_type slash = exe.find_last_of("/\\");
+#endif
+ if (slash != std::string::npos)
+ begin = slash + 1;
+
+#if defined(BOOST_WINDOWS_API)
+ if (exe.size() > 4 &&
+ (boost::algorithm::iends_with(exe, ".exe") || boost::algorithm::iends_with(exe, ".com") || boost::algorithm::iends_with(exe, ".bat")))
+ end = exe.size() - 4;
+#endif
+
+ return exe.substr(begin, end - begin);
+}
+
+/**
+ * Starts a new child process.
+ *
+ * Launches a new process based on the binary image specified by the
+ * executable, the set of arguments to be passed to it and several
+ * parameters that describe the execution context.
+ *
+ * \remark Blocking remarks: This function may block if the device
+ * holding the executable blocks when loading the image. This might
+ * happen if, e.g., the binary is being loaded from a network share.
+ *
+ * \return A handle to the new child process.
+ */
+template <class Executable, class Arguments, class Context>
+inline child launch(const Executable &exe, const Arguments &args, const Context &ctx)
+{
+ detail::file_handle fhstdin, fhstdout, fhstderr;
+
+ BOOST_ASSERT(!args.empty());
+ BOOST_ASSERT(!ctx.work_directory.empty());
+
+#if defined(BOOST_POSIX_API)
+ detail::info_map infoin, infoout;
+
+ if (ctx.stdin_behavior.get_type() != stream_behavior::close)
+ {
+ detail::stream_info si = detail::stream_info(ctx.stdin_behavior, false);
+ infoin.insert(detail::info_map::value_type(STDIN_FILENO, si));
+ }
+
+ if (ctx.stdout_behavior.get_type() != stream_behavior::close)
+ {
+ detail::stream_info si = detail::stream_info(ctx.stdout_behavior, true);
+ infoout.insert(detail::info_map::value_type(STDOUT_FILENO, si));
+ }
+
+ if (ctx.stderr_behavior.get_type() != stream_behavior::close)
+ {
+ detail::stream_info si = detail::stream_info(ctx.stderr_behavior, true);
+ infoout.insert(detail::info_map::value_type(STDERR_FILENO, si));
+ }
+
+ detail::posix_setup s;
+ s.work_directory = ctx.work_directory;
+
+ child::id_type pid = detail::posix_start(exe, args, ctx.environment, infoin, infoout, s);
+
+ if (ctx.stdin_behavior.get_type() == stream_behavior::capture)
+ {
+ fhstdin = detail::posix_info_locate_pipe(infoin, STDIN_FILENO, false);
+ BOOST_ASSERT(fhstdin.valid());
+ }
+
+ if (ctx.stdout_behavior.get_type() == stream_behavior::capture)
+ {
+ fhstdout = detail::posix_info_locate_pipe(infoout, STDOUT_FILENO, true);
+ BOOST_ASSERT(fhstdout.valid());
+ }
+
+ if (ctx.stderr_behavior.get_type() == stream_behavior::capture)
+ {
+ fhstderr = detail::posix_info_locate_pipe(infoout, STDERR_FILENO, true);
+ BOOST_ASSERT(fhstderr.valid());
+ }
+
+ return child(pid, fhstdin, fhstdout, fhstderr);
+#elif defined(BOOST_WINDOWS_API)
+ detail::stream_info behin = detail::stream_info(ctx.stdin_behavior, false);
+ if (behin.type_ == detail::stream_info::use_pipe)
+ fhstdin = behin.pipe_->wend();
+ detail::stream_info behout = detail::stream_info(ctx.stdout_behavior, true);
+ if (behout.type_ == detail::stream_info::use_pipe)
+ fhstdout = behout.pipe_->rend();
+ detail::stream_info beherr = detail::stream_info(ctx.stderr_behavior, true);
+ if (beherr.type_ == detail::stream_info::use_pipe)
+ fhstderr = beherr.pipe_->rend();
+
+ STARTUPINFOA si;
+ ::ZeroMemory(&si, sizeof(si));
+ si.cb = sizeof(si);
+
+ detail::win32_setup s;
+ s.work_directory = ctx.work_directory;
+ s.startupinfo = &si;
+
+ PROCESS_INFORMATION pi = detail::win32_start(exe, args, ctx.environment, behin, behout, beherr, s);
+
+ if (!::CloseHandle(pi.hThread))
+ boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::launch: CloseHandle failed"));
+
+ return child(pi.dwProcessId, fhstdin, fhstdout, fhstderr, detail::file_handle(pi.hProcess));
+#endif
+}
+
+/**
+ * Launches a shell-based command.
+ *
+ * Executes the given command through the default system shell. The
+ * command is subject to pattern expansion, redirection and pipelining.
+ * The shell is launched as described by the parameters in the execution
+ * context.
+ *
+ * This function behaves similarly to the system(3) system call. In a
+ * POSIX system, the command is fed to /bin/sh whereas under a Windows
+ * system, it is fed to cmd.exe. It is difficult to write portable
+ * commands as the first parameter, but this function comes in handy in
+ * multiple situations.
+ */
+template <class Context>
+inline child launch_shell(const std::string &command, const Context &ctx)
+{
+ std::string exe;
+ std::vector<std::string> args;
+
+#if defined(BOOST_POSIX_API)
+ exe = "/bin/sh";
+ args.push_back("sh");
+ args.push_back("-c");
+ args.push_back(command);
+#elif defined(BOOST_WINDOWS_API)
+ char sysdir[MAX_PATH];
+ UINT size = ::GetSystemDirectoryA(sysdir, sizeof(sysdir));
+ if (!size)
+ boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::launch_shell: GetWindowsDirectory failed"));
+ BOOST_ASSERT(size < MAX_PATH);
+
+ exe = std::string(sysdir) + (sysdir[size - 1] != '\\' ? "\\cmd.exe" : "cmd.exe");
+ args.push_back("cmd");
+ args.push_back("/c");
+ args.push_back(command);
+#endif
+
+ return launch(exe, args, ctx);
+}
+
+/**
+ * Launches a pipelined set of child processes.
+ *
+ * Given a collection of pipeline_entry objects describing how to launch
+ * a set of child processes, spawns them all and connects their inputs and
+ * outputs in a way that permits pipelined communication.
+ *
+ * \pre Let 1..N be the processes in the collection: the input behavior of
+ * the 2..N processes must be set to close_stream().
+ * \pre Let 1..N be the processes in the collection: the output behavior of
+ * the 1..N-1 processes must be set to close_stream().
+ * \remark Blocking remarks: This function may block if the device holding
+ * the executable of one of the entries blocks when loading the
+ * image. This might happen if, e.g., the binary is being loaded
+ * from a network share.
+ * \return A set of Child objects that represent all the processes spawned
+ * by this call. You should use wait_children() to wait for their
+ * termination.
+ */
+template <class Entries>
+inline children launch_pipeline(const Entries &entries)
+{
+ BOOST_ASSERT(entries.size() >= 2);
+
+ children cs;
+ detail::file_handle fhinvalid;
+
+ boost::scoped_array<detail::pipe> pipes(new detail::pipe[entries.size() - 1]);
+
+#if defined(BOOST_POSIX_API)
+ {
+ typename Entries::size_type i = 0;
+ const typename Entries::value_type::context_type &ctx = entries[i].context;
+
+ detail::info_map infoin, infoout;
+
+ if (ctx.stdin_behavior.get_type() != stream_behavior::close)
+ {
+ detail::stream_info si = detail::stream_info(ctx.stdin_behavior, false);
+ infoin.insert(detail::info_map::value_type(STDIN_FILENO, si));
+ }
+
+ BOOST_ASSERT(ctx.stdout_behavior.get_type() == stream_behavior::close);
+ detail::stream_info si2(close_stream(), true);
+ si2.type_ = detail::stream_info::use_handle;
+ si2.handle_ = pipes[i].wend().release();
+ infoout.insert(detail::info_map::value_type(STDOUT_FILENO, si2));
+
+ if (ctx.stderr_behavior.get_type() != stream_behavior::close)
+ {
+ detail::stream_info si = detail::stream_info(ctx.stderr_behavior, true);
+ infoout.insert(detail::info_map::value_type(STDERR_FILENO, si));
+ }
+
+ detail::posix_setup s;
+ s.work_directory = ctx.work_directory;
+
+ pid_t pid = detail::posix_start(entries[i].executable, entries[i].arguments, ctx.environment, infoin, infoout, s);
+
+ detail::file_handle fhstdin;
+
+ if (ctx.stdin_behavior.get_type() == stream_behavior::capture)
+ {
+ fhstdin = detail::posix_info_locate_pipe(infoin, STDIN_FILENO, false);
+ BOOST_ASSERT(fhstdin.valid());
+ }
+
+ cs.push_back(child(pid, fhstdin, fhinvalid, fhinvalid));
+ }
+
+ for (typename Entries::size_type i = 1; i < entries.size() - 1; ++i)
+ {
+ const typename Entries::value_type::context_type &ctx = entries[i].context;
+ detail::info_map infoin, infoout;
+
+ BOOST_ASSERT(ctx.stdin_behavior.get_type() == stream_behavior::close);
+ detail::stream_info si1(close_stream(), false);
+ si1.type_ = detail::stream_info::use_handle;
+ si1.handle_ = pipes[i - 1].rend().release();
+ infoin.insert(detail::info_map::value_type(STDIN_FILENO, si1));
+
+ BOOST_ASSERT(ctx.stdout_behavior.get_type() == stream_behavior::close);
+ detail::stream_info si2(close_stream(), true);
+ si2.type_ = detail::stream_info::use_handle;
+ si2.handle_ = pipes[i].wend().release();
+ infoout.insert(detail::info_map::value_type(STDOUT_FILENO, si2));
+
+ if (ctx.stderr_behavior.get_type() != stream_behavior::close)
+ {
+ detail::stream_info si = detail::stream_info(ctx.stderr_behavior, true);
+ infoout.insert(detail::info_map::value_type(STDERR_FILENO, si));
+ }
+
+ detail::posix_setup s;
+ s.work_directory = ctx.work_directory;
+
+ pid_t pid = detail::posix_start(entries[i].executable, entries[i].arguments, ctx.environment, infoin, infoout, s);
+
+ cs.push_back(child(pid, fhinvalid, fhinvalid, fhinvalid));
+ }
+
+ {
+ typename Entries::size_type i = entries.size() - 1;
+ const typename Entries::value_type::context_type &ctx = entries[i].context;
+
+ detail::info_map infoin, infoout;
+
+ BOOST_ASSERT(ctx.stdin_behavior.get_type() == stream_behavior::close);
+ detail::stream_info si1(close_stream(), false);
+ si1.type_ = detail::stream_info::use_handle;
+ si1.handle_ = pipes[i - 1].rend().release();
+ infoin.insert(detail::info_map::value_type(STDIN_FILENO, si1));
+
+ if (ctx.stdout_behavior.get_type() != stream_behavior::close)
+ {
+ detail::stream_info si = detail::stream_info(ctx.stdout_behavior, true);
+ infoout.insert(detail::info_map::value_type(STDOUT_FILENO, si));
+ }
+
+ if (ctx.stderr_behavior.get_type() != stream_behavior::close)
+ {
+ detail::stream_info si = detail::stream_info(ctx.stderr_behavior, true);
+ infoout.insert(detail::info_map::value_type(STDERR_FILENO, si));
+ }
+
+ detail::posix_setup s;
+ s.work_directory = ctx.work_directory;
+
+ pid_t pid = detail::posix_start(entries[i].executable, entries[i].arguments, ctx.environment, infoin, infoout, s);
+
+ detail::file_handle fhstdout, fhstderr;
+
+ if (ctx.stdout_behavior.get_type() == stream_behavior::capture)
+ {
+ fhstdout = detail::posix_info_locate_pipe(infoout, STDOUT_FILENO, true);
+ BOOST_ASSERT(fhstdout.valid());
+ }
+
+ if (ctx.stderr_behavior.get_type() == stream_behavior::capture)
+ {
+ fhstderr = detail::posix_info_locate_pipe(infoout, STDERR_FILENO, true);
+ BOOST_ASSERT(fhstderr.valid());
+ }
+
+ cs.push_back(child(pid, fhinvalid, fhstdout, fhstderr));
+ }
+#elif defined(BOOST_WINDOWS_API)
+ STARTUPINFO si;
+ detail::win32_setup s;
+ s.startupinfo = &si;
+
+ {
+ typename Entries::size_type i = 0;
+ const typename Entries::value_type::context_type &ctx = entries[i].context;
+
+ detail::stream_info sii = detail::stream_info(ctx.stdin_behavior, false);
+ detail::file_handle fhstdin;
+ if (sii.type_ == detail::stream_info::use_pipe)
+ fhstdin = sii.pipe_->wend();
+
+ BOOST_ASSERT(ctx.stdout_behavior.get_type() == stream_behavior::close);
+ detail::stream_info sio(close_stream(), true);
+ sio.type_ = detail::stream_info::use_handle;
+ sio.handle_ = pipes[i].wend().release();
+
+ detail::stream_info sie(ctx.stderr_behavior, true);
+
+ s.work_directory = ctx.work_directory;
+
+ ::ZeroMemory(&si, sizeof(si));
+ si.cb = sizeof(si);
+ PROCESS_INFORMATION pi = detail::win32_start(entries[i].executable, entries[i].arguments, ctx.environment, sii, sio, sie, s);
+
+ if (!::CloseHandle(pi.hThread))
+ boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::launch_pipeline: CloseHandle failed"));
+
+ cs.push_back(child(pi.dwProcessId, fhstdin, fhinvalid, fhinvalid, detail::file_handle(pi.hProcess)));
+ }
+
+ for (typename Entries::size_type i = 1; i < entries.size() - 1; ++i)
+ {
+ const typename Entries::value_type::context_type &ctx = entries[i].context;
+
+ BOOST_ASSERT(ctx.stdin_behavior.get_type() == stream_behavior::close);
+ detail::stream_info sii(close_stream(), false);
+ sii.type_ = detail::stream_info::use_handle;
+ sii.handle_ = pipes[i - 1].rend().release();
+
+ detail::stream_info sio(close_stream(), true);
+ sio.type_ = detail::stream_info::use_handle;
+ sio.handle_ = pipes[i].wend().release();
+
+ detail::stream_info sie(ctx.stderr_behavior, true);
+
+ s.work_directory = ctx.work_directory;
+
+ ::ZeroMemory(&si, sizeof(si));
+ si.cb = sizeof(si);
+ PROCESS_INFORMATION pi = detail::win32_start(entries[i].executable, entries[i].arguments, ctx.environment, sii, sio, sie, s);
+
+ if (!::CloseHandle(pi.hThread))
+ boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::launch_pipeline: CloseHandle failed"));
+
+ cs.push_back(child(pi.dwProcessId, fhinvalid, fhinvalid, fhinvalid, detail::file_handle(pi.hProcess)));
+ }
+
+ {
+ typename Entries::size_type i = entries.size() - 1;
+ const typename Entries::value_type::context_type &ctx = entries[i].context;
+
+ BOOST_ASSERT(ctx.stdin_behavior.get_type() == stream_behavior::close);
+ detail::stream_info sii(close_stream(), false);
+ sii.type_ = detail::stream_info::use_handle;
+ sii.handle_ = pipes[i - 1].rend().release();
+
+ detail::file_handle fhstdout, fhstderr;
+
+ detail::stream_info sio(ctx.stdout_behavior, true);
+ if (sio.type_ == detail::stream_info::use_pipe)
+ fhstdout = sio.pipe_->rend();
+ detail::stream_info sie(ctx.stderr_behavior, true);
+ if (sie.type_ == detail::stream_info::use_pipe)
+ fhstderr = sie.pipe_->rend();
+
+ s.work_directory = ctx.work_directory;
+
+ ::ZeroMemory(&si, sizeof(si));
+ si.cb = sizeof(si);
+ PROCESS_INFORMATION pi = detail::win32_start(entries[i].executable, entries[i].arguments, ctx.environment, sii, sio, sie, s);
+
+ if (!::CloseHandle(pi.hThread))
+ boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::launch_pipeline: CloseHandle failed"));
+
+ cs.push_back(child(pi.dwProcessId, fhinvalid, fhstdout, fhstderr, detail::file_handle(pi.hProcess)));
+ }
+#endif
+
+ return cs;
+}
+
+/**
+ * Waits for a collection of children to terminate.
+ *
+ * Given a collection of Child objects (such as std::vector<child> or
+ * the convenience children type), waits for the termination of all of
+ * them.
+ *
+ * \remark Blocking remarks: This call blocks if any of the children
+ * processes in the collection has not finalized execution and
+ * waits until it terminates.
+ *
+ * \return The exit status of the first process that returns an error
+ * code or, if all of them executed correctly, the exit status
+ * of the last process in the collection.
+ */
+template <class Children>
+inline status wait_children(Children &cs)
+{
+ BOOST_ASSERT(cs.size() >= 2);
+
+ typename Children::iterator it = cs.begin();
+ while (it != cs.end())
+ {
+ const status s = it->wait();
+ ++it;
+ if (it == cs.end())
+ return s;
+ else if (!s.exited() || s.exit_status() != EXIT_SUCCESS)
+ {
+ while (it != cs.end())
+ {
+ it->wait();
+ ++it;
+ }
+ return s;
+ }
+ }
+
+ BOOST_ASSERT(false);
+ return cs.begin()->wait();
+}
+
+}
+}
+
+#endif
Added: sandbox/process/boost/process/pistream.hpp
==============================================================================
--- (empty file)
+++ sandbox/process/boost/process/pistream.hpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,116 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+/**
+ * \file boost/process/pistream.hpp
+ *
+ * Includes the declaration of the pistream class.
+ */
+
+#ifndef BOOST_PROCESS_PISTREAM_HPP
+#define BOOST_PROCESS_PISTREAM_HPP
+
+#include <boost/process/detail/file_handle.hpp>
+#include <boost/process/detail/systembuf.hpp>
+#include <boost/noncopyable.hpp>
+#include <istream>
+
+namespace boost {
+namespace process {
+
+/**
+ * Child process' output stream.
+ *
+ * The pistream class represents an output communication channel with the
+ * child process. The child process writes data to this stream and the
+ * parent process can read it through the pistream object. In other
+ * words, from the child's point of view, the communication channel is an
+ * output one, but from the parent's point of view it is an input one;
+ * hence the confusing pistream name.
+ *
+ * pistream objects cannot be copied because they own the file handle
+ * they use to communicate with the child and because they buffer data
+ * that flows through the communication channel.
+ *
+ * A pistream object behaves as a std::istream stream in all senses.
+ * The class is only provided because it must provide a method to let
+ * the caller explicitly close the communication channel.
+ *
+ * \remark Blocking remarks: Functions that read data from this
+ * stream can block if the associated file handle blocks during
+ * the read. As this class is used to communicate with child
+ * processes through anonymous pipes, the most typical blocking
+ * condition happens when the child has no more data to send to
+ * the pipe's system buffer. When this happens, the buffer
+ * eventually empties and the system blocks until the writer
+ * generates some data.
+ */
+class pistream : public std::istream, public boost::noncopyable
+{
+public:
+ /**
+ * Creates a new process' output stream.
+ *
+ * Given a file handle, this constructor creates a new pistream
+ * object that owns the given file handle \a fh. Ownership of
+ * \a fh is transferred to the created pistream object.
+ *
+ * \pre \a fh is valid.
+ * \post \a fh is invalid.
+ * \post The new pistream object owns \a fh.
+ */
+ explicit pistream(detail::file_handle &fh)
+ : std::istream(0),
+ handle_(fh),
+ systembuf_(handle_.get())
+ {
+ rdbuf(&systembuf_);
+ }
+
+ /**
+ * Returns the file handle managed by this stream.
+ *
+ * The file handle must not be copied. Copying invalidates
+ * the source file handle making the pistream unusable.
+ */
+ detail::file_handle &handle()
+ {
+ return handle_;
+ }
+
+ /**
+ * Closes the file handle managed by this stream.
+ *
+ * Explicitly closes the file handle managed by this stream. This
+ * function can be used by the user to tell the child process it's
+ * not willing to receive more data.
+ */
+ void close()
+ {
+ handle_.close();
+ }
+
+private:
+ /**
+ * The file handle managed by this stream.
+ */
+ detail::file_handle handle_;
+
+ /**
+ * The systembuf object used to manage this stream's data.
+ */
+ detail::systembuf systembuf_;
+};
+
+}
+}
+
+#endif
Added: sandbox/process/boost/process/posix_child.hpp
==============================================================================
--- (empty file)
+++ sandbox/process/boost/process/posix_child.hpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,178 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+/**
+ * \file boost/process/posix_child.hpp
+ *
+ * Includes the declaration of the posix_child class.
+ */
+
+#ifndef BOOST_PROCESS_POSIX_CHILD_HPP
+#define BOOST_PROCESS_POSIX_CHILD_HPP
+
+#include <boost/process/child.hpp>
+#include <boost/process/pistream.hpp>
+#include <boost/process/postream.hpp>
+#include <boost/process/detail/pipe.hpp>
+#include <boost/process/detail/posix_ops.hpp>
+#include <boost/process/detail/stream_info.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/assert.hpp>
+#include <map>
+#include <unistd.h>
+
+namespace boost {
+namespace process {
+
+/**
+ * POSIX implementation of the Child concept.
+ *
+ * The posix_child class implements the Child concept in a POSIX
+ * operating system.
+ *
+ * A POSIX child differs from a regular child (represented by a
+ * child object) in that it supports more than three communication
+ * channels with its parent. These channels are identified by regular
+ * file descriptors (integers).
+ *
+ * This class is built on top of the generic child so as to allow its
+ * trivial adoption. When a program is changed to use the POSIX-specific
+ * context (posix_context), it will most certainly need to migrate its
+ * use of the child class to posix_child. Doing so is only a matter of
+ * redefining the appropriate object and later using the required extra
+ * features: there should be no need to modify the existing code (e.g.
+ * method calls) in any other way.
+ */
+class posix_child : public child
+{
+public:
+ /**
+ * Gets a reference to the child's input stream \a desc.
+ *
+ * Returns a reference to a postream object that represents one of
+ * the multiple input communication channels with the child process.
+ * The channel is identified by \a desc as seen from the child's
+ * point of view. The parent can use the returned stream to send
+ * data to the child.
+ *
+ * Giving this function the STDIN_FILENO constant (defined in
+ * unistd.h) is a synonym for the get_stdin() call inherited from
+ * child.
+ */
+ postream &get_input(int desc) const
+ {
+ if (desc == STDIN_FILENO)
+ return posix_child::get_stdin();
+ else
+ {
+ input_map_t::const_iterator it = input_map_.find(desc);
+ BOOST_ASSERT(it != input_map_.end());
+ return *it->second;
+ }
+ }
+
+ /**
+ * Gets a reference to the child's output stream \a desc.
+ *
+ * Returns a reference to a pistream object that represents one of
+ * the multiple output communication channels with the child process.
+ * The channel is identified by \a desc as seen from the child's
+ * point of view. The parent can use the returned stream to retrieve
+ * data from the child.
+ *
+ * Giving this function the STDOUT_FILENO or STDERR_FILENO constants
+ * (both defined in unistd.h) are synonyms for the get_stdout() and
+ * get_stderr() calls inherited from child, respectively.
+ */
+ pistream &get_output(int desc) const
+ {
+ if (desc == STDOUT_FILENO)
+ return posix_child::get_stdout();
+ else if (desc == STDERR_FILENO)
+ return posix_child::get_stderr();
+ else
+ {
+ output_map_t::const_iterator it = output_map_.find(desc);
+ BOOST_ASSERT(it != output_map_.end());
+ return *it->second;
+ }
+ }
+
+ /**
+ * Constructs a new POSIX child object representing a just
+ * spawned child process.
+ *
+ * Creates a new child object that represents the just spawned process
+ * \a id.
+ *
+ * The \a infoin and \a infoout maps contain the pipes used to handle
+ * the redirections of the child process; at the moment, no other
+ * stream_info types are supported. If the launcher was asked to
+ * redirect any of the three standard flows, their pipes must be
+ * present in these maps.
+ */
+ posix_child(id_type id, detail::info_map &infoin, detail::info_map &infoout)
+ : child(id,
+ detail::posix_info_locate_pipe(infoin, STDIN_FILENO, false),
+ detail::posix_info_locate_pipe(infoout, STDOUT_FILENO, true),
+ detail::posix_info_locate_pipe(infoout, STDERR_FILENO, true))
+ {
+ for (detail::info_map::iterator it = infoin.begin(); it != infoin.end(); ++it)
+ {
+ detail::stream_info &si = it->second;
+ if (si.type_ == detail::stream_info::use_pipe)
+ {
+ BOOST_ASSERT(si.pipe_->wend().valid());
+ boost::shared_ptr<postream> st(new postream(si.pipe_->wend()));
+ input_map_.insert(input_map_t::value_type(it->first, st));
+ }
+ }
+
+ for (detail::info_map::iterator it = infoout.begin(); it != infoout.end(); ++it)
+ {
+ detail::stream_info &si = it->second;
+ if (si.type_ == detail::stream_info::use_pipe)
+ {
+ BOOST_ASSERT(si.pipe_->rend().valid());
+ boost::shared_ptr<pistream> st(new pistream(si.pipe_->rend()));
+ output_map_.insert(output_map_t::value_type(it->first, st));
+ }
+ }
+ }
+
+private:
+ /**
+ * Maps child's file descriptors to postream objects.
+ */
+ typedef std::map<int, boost::shared_ptr<postream> > input_map_t;
+
+ /**
+ * Contains all relationships between child's input file
+ * descriptors and their corresponding postream objects.
+ */
+ input_map_t input_map_;
+
+ /**
+ * Maps child's file descriptors to pistream objects.
+ */
+ typedef std::map<int, boost::shared_ptr<pistream> > output_map_t;
+
+ /**
+ * Contains all relationships between child's output file
+ * descriptors and their corresponding pistream objects.
+ */
+ output_map_t output_map_;
+};
+
+}
+}
+
+#endif
Added: sandbox/process/boost/process/posix_context.hpp
==============================================================================
--- (empty file)
+++ sandbox/process/boost/process/posix_context.hpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,118 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+/**
+ * \file boost/process/posix_context.hpp
+ *
+ * Includes the declaration of the posix_context class.
+ */
+
+#ifndef BOOST_PROCESS_POSIX_CONTEXT_HPP
+#define BOOST_PROCESS_POSIX_CONTEXT_HPP
+
+#include <boost/process/context.hpp>
+#include <boost/process/stream_behavior.hpp>
+#include <map>
+#include <string>
+#include <unistd.h>
+
+namespace boost {
+namespace process {
+
+/**
+ * Holds a mapping between native file descriptors and their corresponding
+ * pipes to set up communication between the parent and the %child process.
+ */
+typedef std::map<int, stream_behavior> behavior_map;
+
+template <class Path>
+class posix_basic_context : public basic_work_directory_context<Path>, public environment_context
+{
+public:
+ /**
+ * Constructs a new POSIX-specific context.
+ *
+ * Constructs a new context. It is configured as follows:
+ * * All communcation channels with the child process are closed.
+ * * There are no channel mergings.
+ * * The initial work directory of the child processes is set to the
+ * current working directory.
+ * * The environment variables table is empty.
+ * * The credentials are the same as those of the current process.
+ */
+ posix_basic_context()
+ : uid(::getuid()),
+ euid(::geteuid()),
+ gid(::getgid()),
+ egid(::getegid())
+ {
+ }
+
+ /**
+ * List of input streams that will be redirected.
+ */
+ behavior_map input_behavior;
+
+ /**
+ * List of output streams that will be redirected.
+ */
+ behavior_map output_behavior;
+
+ /**
+ * The user credentials.
+ *
+ * UID that specifies the user credentials to use to run the %child
+ * process. Defaults to the current UID.
+ */
+ uid_t uid;
+
+ /**
+ * The effective user credentials.
+ *
+ * EUID that specifies the effective user credentials to use to run
+ * the %child process. Defaults to the current EUID.
+ */
+ uid_t euid;
+
+ /**
+ * The group credentials.
+ *
+ * GID that specifies the group credentials to use to run the %child
+ * process. Defaults to the current GID.
+ */
+ gid_t gid;
+
+ /**
+ * The effective group credentials.
+ *
+ * EGID that specifies the effective group credentials to use to run
+ * the %child process. Defaults to the current EGID.
+ */
+ gid_t egid;
+
+ /**
+ * The chroot directory, if any.
+ *
+ * Specifies the directory in which the %child process is chrooted
+ * before execution. Empty if this feature is not desired.
+ */
+ Path chroot;
+};
+
+/**
+ * Default instantiation of posix_basic_context.
+ */
+typedef posix_basic_context<std::string> posix_context;
+
+}
+}
+
+#endif
Added: sandbox/process/boost/process/posix_operations.hpp
==============================================================================
--- (empty file)
+++ sandbox/process/boost/process/posix_operations.hpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,81 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+/**
+ * \file boost/process/posix_operations.hpp
+ *
+ * Provides miscellaneous free functions specific to POSIX operating
+ * systems.
+ */
+
+#ifndef BOOST_PROCESS_POSIX_OPERATIONS_HPP
+#define BOOST_PROCESS_POSIX_OPERATIONS_HPP
+
+#include <boost/process/posix_child.hpp>
+#include <boost/process/posix_context.hpp>
+#include <boost/process/stream_behavior.hpp>
+#include <boost/process/detail/stream_info.hpp>
+#include <boost/process/detail/posix_ops.hpp>
+#include <sys/types.h>
+
+namespace boost {
+namespace process {
+
+/**
+ * Starts a new child process.
+ *
+ * Given an executable and the set of arguments passed to it, starts
+ * a new process with all the parameters configured in the context.
+ * The context can be reused afterwards to launch other different
+ * processes.
+ *
+ * \return A handle to the new child process.
+ */
+template <class Executable, class Arguments, class Posix_Context>
+inline posix_child posix_launch(const Executable &exe, const Arguments &args, const Posix_Context &ctx)
+{
+ detail::info_map input_info;
+ for (behavior_map::const_iterator it = ctx.input_behavior.begin(); it != ctx.input_behavior.end(); ++it)
+ {
+ if (it->second.get_type() != stream_behavior::close)
+ {
+ detail::stream_info si = detail::stream_info(it->second, false);
+ input_info.insert(detail::info_map::value_type(it->first, si));
+ }
+ }
+
+ detail::info_map output_info;
+ for (behavior_map::const_iterator it = ctx.output_behavior.begin(); it != ctx.output_behavior.end(); ++it)
+ {
+ if (it->second.get_type() != stream_behavior::close)
+ {
+ detail::stream_info si = detail::stream_info(it->second, true);
+ output_info.insert(detail::info_map::value_type(it->first, si));
+ }
+ }
+
+ detail::posix_setup s;
+ s.work_directory = ctx.work_directory;
+ s.uid = ctx.uid;
+ s.euid = ctx.euid;
+ s.gid = ctx.gid;
+ s.egid = ctx.egid;
+ s.chroot = ctx.chroot;
+
+ pid_t pid = detail::posix_start(exe, args, ctx.environment, input_info, output_info, s);
+
+ return posix_child(pid, input_info, output_info);
+}
+
+}
+}
+
+#endif
Added: sandbox/process/boost/process/posix_status.hpp
==============================================================================
--- (empty file)
+++ sandbox/process/boost/process/posix_status.hpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,124 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+/**
+ * \file boost/process/posix_status.hpp
+ *
+ * Includes the declaration of the posix_status class.
+ */
+
+#ifndef BOOST_PROCESS_POSIX_STATUS_HPP
+#define BOOST_PROCESS_POSIX_STATUS_HPP
+
+#include <boost/process/config.hpp>
+
+#if defined(BOOST_POSIX_API)
+# include <sys/wait.h>
+#elif defined(BOOST_WINDOWS_API)
+#else
+# error "Unsupported platform."
+#endif
+
+#include <boost/process/status.hpp>
+#include <boost/assert.hpp>
+
+namespace boost {
+namespace process {
+
+/**
+ * Status returned by a finalized %child process on a POSIX system.
+ *
+ * This class represents the %status returned by a child process after it
+ * has terminated. It contains some methods not available in the status
+ * class that provide information only available in POSIX systems.
+ */
+class posix_status : public status
+{
+public:
+ /**
+ * Creates a posix_status object from an existing status object.
+ *
+ * Creates a new status object representing the exit status of a
+ * child process. The construction is done based on an existing
+ * status object which already contains all the available
+ * information: this class only provides controlled access to it.
+ */
+ posix_status(const status &s)
+ : status(s)
+ {
+ }
+
+ /**
+ * Returns whether the process exited due to an external
+ * signal.
+ */
+ bool signaled() const
+ {
+ return WIFSIGNALED(flags_);
+ }
+
+ /**
+ * If signaled, returns the terminating signal code.
+ *
+ * If the process was signaled, returns the terminating signal code.
+ *
+ * \pre signaled() is true.
+ */
+ int term_signal() const
+ {
+ BOOST_ASSERT(signaled());
+
+ return WTERMSIG(flags_);
+ }
+
+ /**
+ * If signaled, returns whether the process dumped core.
+ *
+ * If the process was signaled, returns whether the process
+ * produced a core dump.
+ *
+ * \pre signaled() is true.
+ */
+ bool dumped_core() const
+ {
+ BOOST_ASSERT(signaled());
+
+ return WCOREDUMP(flags_);
+ }
+
+ /**
+ * Returns whether the process was stopped by an external
+ * signal.
+ */
+ bool stopped() const
+ {
+ return WIFSTOPPED(flags_);
+ }
+
+ /**
+ * If stopped, returns the stop signal code.
+ *
+ * If the process was stopped, returns the stop signal code.
+ *
+ * \pre stopped() is true.
+ */
+ int stop_signal() const
+ {
+ BOOST_ASSERT(stopped());
+
+ return WSTOPSIG(flags_);
+ }
+};
+
+}
+}
+
+#endif
Added: sandbox/process/boost/process/postream.hpp
==============================================================================
--- (empty file)
+++ sandbox/process/boost/process/postream.hpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,117 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+/**
+ * \file boost/process/postream.hpp
+ *
+ * Includes the declaration of the postream class.
+ */
+
+#ifndef BOOST_PROCESS_POSTREAM_HPP
+#define BOOST_PROCESS_POSTREAM_HPP
+
+#include <boost/process/detail/file_handle.hpp>
+#include <boost/process/detail/systembuf.hpp>
+#include <boost/noncopyable.hpp>
+#include <ostream>
+
+namespace boost {
+namespace process {
+
+/**
+ * Child process' input stream.
+ *
+ * The postream class represents an input communication channel with the
+ * child process. The child process reads data from this stream and the
+ * parent process can write to it through the postream object. In other
+ * words, from the child's point of view, the communication channel is an
+ * input one, but from the parent's point of view it is an output one;
+ * hence the confusing postream name.
+ *
+ * postream objects cannot be copied because they own the file handle
+ * they use to communicate with the child and because they buffer data
+ * that flows through the communication channel.
+ *
+ * A postream object behaves as a std::ostream stream in all senses.
+ * The class is only provided because it must provide a method to let
+ * the caller explicitly close the communication channel.
+ *
+ * \remark Blocking remarks: Functions that write data to this
+ * stream can block if the associated file handle blocks during
+ * the write. As this class is used to communicate with child
+ * processes through anonymous pipes, the most typical blocking
+ * condition happens when the child is not processing the data
+ * in the pipe's system buffer. When this happens, the buffer
+ * eventually fills up and the system blocks until the reader
+ * consumes some data, leaving some new room.
+ */
+class postream : public std::ostream, public boost::noncopyable
+{
+public:
+ /**
+ * Creates a new process' input stream.
+ *
+ * Given a file handle, this constructor creates a new postream
+ * object that owns the given file handle \a fh. Ownership of
+ * \a fh is transferred to the created postream object.
+ *
+ * \pre \a fh is valid.
+ * \post \a fh is invalid.
+ * \post The new postream object owns \a fh.
+ */
+ explicit postream(detail::file_handle &fh)
+ : std::ostream(0),
+ handle_(fh),
+ systembuf_(handle_.get())
+ {
+ rdbuf(&systembuf_);
+ }
+
+ /**
+ * Returns the file handle managed by this stream.
+ *
+ * The file handle must not be copied. Copying invalidates
+ * the source file handle making the postream unusable.
+ */
+ detail::file_handle &handle()
+ {
+ return handle_;
+ }
+
+ /**
+ * Closes the file handle managed by this stream.
+ *
+ * Explicitly closes the file handle managed by this stream. This
+ * function can be used by the user to tell the child process there
+ * is no more data to send.
+ */
+ void close()
+ {
+ systembuf_.sync();
+ handle_.close();
+ }
+
+private:
+ /**
+ * The file handle managed by this stream.
+ */
+ detail::file_handle handle_;
+
+ /**
+ * The systembuf object used to manage this stream's data.
+ */
+ detail::systembuf systembuf_;
+};
+
+}
+}
+
+#endif
Added: sandbox/process/boost/process/process.hpp
==============================================================================
--- (empty file)
+++ sandbox/process/boost/process/process.hpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,130 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+/**
+ * \file boost/process/process.hpp
+ *
+ * Includes the declaration of the process class.
+ */
+
+#ifndef BOOST_PROCESS_PROCESS_HPP
+#define BOOST_PROCESS_PROCESS_HPP
+
+#include <boost/process/config.hpp>
+
+#if defined(BOOST_POSIX_API)
+# include <cerrno>
+# include <signal.h>
+#elif defined(BOOST_WINDOWS_API)
+# include <cstdlib>
+# include <windows.h>
+#else
+# error "Unsupported platform."
+#endif
+
+#include <boost/system/system_error.hpp>
+#include <boost/throw_exception.hpp>
+
+namespace boost {
+namespace process {
+
+/**
+ * Generic implementation of the Process concept.
+ *
+ * The process class implements the Process concept in an operating system
+ * agnostic way.
+ */
+class process
+{
+public:
+#if defined(BOOST_PROCESS_DOXYGEN)
+ /**
+ * Opaque name for the native process' identifier type.
+ *
+ * Each operating system identifies processes using a specific type.
+ * The \a id_type type is used to transparently refer to a process
+ * regardless of the operating system in which this class is used.
+ *
+ * This type is guaranteed to be an integral type on all supported
+ * platforms.
+ */
+ typedef NativeProcessId id_type;
+#elif defined(BOOST_POSIX_API)
+ typedef pid_t id_type;
+#elif defined(BOOST_WINDOWS_API)
+ typedef DWORD id_type;
+#endif
+
+ /**
+ * Constructs a new process object.
+ *
+ * Creates a new process object that represents a running process
+ * within the system.
+ */
+ process(id_type id)
+ : id_(id)
+ {
+ }
+
+ /**
+ * Returns the process' identifier.
+ */
+ id_type get_id() const
+ {
+ return id_;
+ }
+
+ /**
+ * Terminates the process execution.
+ *
+ * Forces the termination of the process execution. Some platforms
+ * allow processes to ignore some external termination notifications
+ * or to capture them for a proper exit cleanup. You can set the
+ * \a force flag to true in them to force their termination regardless
+ * of any exit handler.
+ *
+ * After this call, accessing this object can be dangerous because the
+ * process identifier may have been reused by a different process. It
+ * might still be valid, though, if the process has refused to die.
+ *
+ * \throw boost::system::system_error If the system call used to
+ * terminate the process fails.
+ */
+ void terminate(bool force = false) const
+ {
+#if defined(BOOST_POSIX_API)
+ if (::kill(id_, force ? SIGKILL : SIGTERM) == -1)
+ boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::process::terminate: kill(2) failed"));
+#elif defined(BOOST_WINDOWS_API)
+ HANDLE h = ::OpenProcess(PROCESS_TERMINATE, FALSE, id_);
+ if (h == NULL)
+ boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::process::terminate: OpenProcess failed"));
+ if (!::TerminateProcess(h, EXIT_FAILURE))
+ {
+ ::CloseHandle(h);
+ boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::process::terminate: TerminateProcess failed"));
+ }
+ if (!::CloseHandle(h))
+ boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::process::terminate: CloseHandle failed"));
+#endif
+ }
+
+private:
+ /**
+ * The process' identifier.
+ */
+ id_type id_;
+};
+
+}
+}
+
+#endif
Added: sandbox/process/boost/process/self.hpp
==============================================================================
--- (empty file)
+++ sandbox/process/boost/process/self.hpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,134 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+/**
+ * \file boost/process/self.hpp
+ *
+ * Includes the declaration of the self class.
+ */
+
+#ifndef BOOST_PROCESS_SELF_HPP
+#define BOOST_PROCESS_SELF_HPP
+
+#include <boost/process/config.hpp>
+
+#if defined(BOOST_POSIX_API)
+# include <unistd.h>
+#elif defined(BOOST_WINDOWS_API)
+# include <windows.h>
+#else
+# error "Unsupported platform."
+#endif
+
+#include <boost/process/process.hpp>
+#include <boost/process/environment.hpp>
+#include <boost/system/system_error.hpp>
+#include <boost/throw_exception.hpp>
+#include <boost/noncopyable.hpp>
+#include <string>
+
+#if defined(BOOST_POSIX_API)
+extern "C"
+{
+ extern char **environ;
+}
+#endif
+
+namespace boost {
+namespace process {
+
+/**
+ * Generic implementation of the Process concept.
+ *
+ * The self singleton provides access to the current process.
+ */
+class self : public process, boost::noncopyable
+{
+public:
+ /**
+ * Returns the self instance representing the caller's process.
+ */
+ static self &get_instance()
+ {
+ static self *instance = 0;
+ if (!instance)
+ instance = new self;
+ return *instance;
+ }
+
+ /**
+ * Returns the current environment.
+ *
+ * Returns the current process' environment variables. Modifying the
+ * returned object has no effect on the current environment.
+ */
+ static environment get_environment()
+ {
+ environment e;
+
+#if defined(BOOST_POSIX_API)
+ char **env = ::environ;
+ while (*env)
+ {
+ std::string s = *env;
+ std::string::size_type pos = s.find('=');
+ e.insert(boost::process::environment::value_type(s.substr(0, pos), s.substr(pos + 1)));
+ ++env;
+ }
+#elif defined(BOOST_WINDOWS_API)
+#ifdef GetEnvironmentStrings
+#undef GetEnvironmentStrings
+#endif
+ char *environ = ::GetEnvironmentStrings();
+ if (!environ)
+ boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::self::get_environment: GetEnvironmentStrings failed"));
+ try
+ {
+ char *env = environ;
+ while (*env)
+ {
+ std::string s = env;
+ std::string::size_type pos = s.find('=');
+ e.insert(boost::process::environment::value_type(s.substr(0, pos), s.substr(pos + 1)));
+ env += s.size() + 1;
+ }
+ }
+ catch (...)
+ {
+ ::FreeEnvironmentStringsA(environ);
+ throw;
+ }
+ ::FreeEnvironmentStringsA(environ);
+#endif
+
+ return e;
+ }
+
+private:
+ /**
+ * Constructs a new self object.
+ *
+ * Creates a new self object that represents the current process.
+ */
+ self() :
+#if defined(BOOST_POSIX_API)
+ process(::getpid())
+#elif defined(BOOST_WINDOWS_API)
+ process(::GetCurrentProcessId())
+#endif
+ {
+ }
+};
+
+}
+}
+
+#endif
Added: sandbox/process/boost/process/status.hpp
==============================================================================
--- (empty file)
+++ sandbox/process/boost/process/status.hpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,105 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+/**
+ * \file boost/process/status.hpp
+ *
+ * Includes the declaration of the status class.
+ */
+
+#ifndef BOOST_PROCESS_STATUS_HPP
+#define BOOST_PROCESS_STATUS_HPP
+
+#include <boost/process/config.hpp>
+
+#if defined(BOOST_POSIX_API)
+# include <sys/wait.h>
+#elif defined(BOOST_WINDOWS_API)
+#else
+# error "Unsupported platform."
+#endif
+
+#include <boost/assert.hpp>
+
+namespace boost {
+namespace process {
+
+class child;
+
+/**
+ * Status returned by a finalized %child process.
+ *
+ * This class represents the %status returned by a child process after it
+ * has terminated. It only provides that information available under all
+ * supported platforms.
+ *
+ * \see posix_status
+ */
+class status
+{
+ friend class child;
+
+public:
+ /**
+ * Returns whether the process exited gracefully or not.
+ */
+ bool exited() const
+ {
+#if defined(BOOST_POSIX_API)
+ return WIFEXITED(flags_);
+#elif defined(BOOST_WINDOWS_API)
+ return true;
+#endif
+ }
+
+ /**
+ * If exited, returns the exit code.
+ *
+ * If the process exited, returns the exit code it returned.
+ *
+ * \pre exited() is true.
+ */
+ int exit_status() const
+ {
+ BOOST_ASSERT(exited());
+#if defined(BOOST_POSIX_API)
+ return WEXITSTATUS(flags_);
+#elif defined(BOOST_WINDOWS_API)
+ return flags_;
+#endif
+ }
+
+protected:
+ /**
+ * Creates a status object based on exit information.
+ *
+ * Creates a new status object representing the exit status of a
+ * child process.
+ *
+ * \param flags In a POSIX system this parameter contains the
+ * flags returned by the ::waitpid() call. In a
+ * Windows system it contains the exit code only.
+ */
+ status(int flags)
+ : flags_(flags)
+ {
+ }
+
+ /**
+ * OS-specific codification of exit status.
+ */
+ int flags_;
+};
+
+}
+}
+
+#endif
Added: sandbox/process/boost/process/stream_behavior.hpp
==============================================================================
--- (empty file)
+++ sandbox/process/boost/process/stream_behavior.hpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,234 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+/**
+ * \file boost/process/stream_behavior.hpp
+ *
+ * Includes the declaration of the stream_behavior class and associated
+ * free functions.
+ */
+
+#ifndef BOOST_PROCESS_STREAM_BEHAVIOR_HPP
+#define BOOST_PROCESS_STREAM_BEHAVIOR_HPP
+
+#include <boost/process/config.hpp>
+
+namespace boost {
+namespace process {
+
+namespace detail {
+ struct stream_info;
+}
+
+/**
+ * Describes the possible states for a communication stream.
+ */
+class stream_behavior
+{
+public:
+ friend struct detail::stream_info;
+ friend stream_behavior capture_stream();
+ friend stream_behavior close_stream();
+ friend stream_behavior inherit_stream();
+ friend stream_behavior redirect_stream_to_stdout();
+ friend stream_behavior silence_stream();
+#if defined(BOOST_POSIX_API) || defined(BOOST_PROCESS_DOXYGEN)
+ friend stream_behavior posix_redirect_stream(int to);
+#endif
+
+ /**
+ * Describes the possible states for a communication stream.
+ */
+ enum type
+ {
+ /**
+ * The child's stream is connected to the parent by using an
+ * anonymous pipe so that they can send and receive data to/from
+ * each other.
+ */
+ capture,
+
+ /**
+ * The child's stream is closed upon startup so that it will not
+ * have any access to it.
+ */
+ close,
+
+ /**
+ * The child's stream is connected to the same stream used by the
+ * parent. In other words, the corresponding parent's stream is
+ * inherited.
+ */
+ inherit,
+
+ /**
+ * The child's stream is connected to child's standard output.
+ * This is typically used when configuring the standard error
+ * stream.
+ */
+ redirect_to_stdout,
+
+ /**
+ * The child's stream is redirected to a null device so that its
+ * input is always zero or its output is lost, depending on
+ * whether the stream is an input or an output one. It is
+ * important to notice that this is different from close because
+ * the child is still able to write data. If we closed, e.g.
+ * stdout, the child might not work at all!
+ */
+ silence,
+
+#if defined(BOOST_POSIX_API) || defined(BOOST_PROCESS_DOXYGEN)
+ /**
+ * The child redirects the stream's output to the provided file
+ * descriptor. This is a generalization of the portable
+ * redirect_to_stdout behavior.
+ */
+ posix_redirect
+#endif
+ };
+
+ /**
+ * Constructs a new stream behavior of type close.
+ *
+ * The public constructor creates a new stream behavior that defaults
+ * to the close behavior. In general, you will want to use the
+ * available free functions to construct a stream behavior (including
+ * the close one).
+ */
+ stream_behavior()
+ : type_(stream_behavior::close)
+ {
+ }
+
+ /**
+ * Returns this stream's behavior type.
+ */
+ type get_type() const
+ {
+ return type_;
+ }
+
+private:
+ /**
+ * Constructs a new stream behavior of type \a t.
+ *
+ * Constructs a new stream behavior of type \a t. It is the
+ * responsibility of the caller to fill in any other attributes
+ * required by the specified type, if any.
+ */
+ stream_behavior(type t)
+ : type_(t)
+ {
+ }
+
+ /**
+ * This stream's behavior type.
+ */
+ type type_;
+
+#if defined(BOOST_POSIX_API) || defined(BOOST_PROCESS_DOXYGEN)
+ /**
+ * File descriptor the stream is redirected to.
+ */
+ int desc_to_;
+#endif
+};
+
+/**
+ * Creates a new stream_behavior of type stream_behavior::capture.
+ *
+ * Creates a new stream_behavior of type stream_behavior::capture,
+ * meaning that the child's stream is connected to the parent by using an
+ * anonymous pipe so that they can send and receive data to/from each
+ * other.
+ */
+inline stream_behavior capture_stream()
+{
+ return stream_behavior(stream_behavior::capture);
+}
+
+/**
+ * Creates a new stream_behavior of type stream_behavior::close.
+ *
+ * Creates a new stream_behavior of type stream_behavior::close,
+ * meaning that the child's stream is closed upon startup so that it
+ * will not have any access to it.
+ */
+inline stream_behavior close_stream()
+{
+ return stream_behavior(stream_behavior::close);
+}
+
+/**
+ * Creates a new stream_behavior of type stream_behavior::inherit.
+ *
+ * Creates a new stream_behavior of type stream_behavior::inherit,
+ * meaning that the child's stream is connected to the same stream used
+ * by the parent. In other words, the corresponding parent's stream is
+ * inherited.
+ */
+inline stream_behavior inherit_stream()
+{
+ return stream_behavior(stream_behavior::inherit);
+}
+
+/**
+ * Creates a new stream_behavior of type
+ * stream_behavior::redirect_to_stdout.
+ *
+ * Creates a new stream_behavior of type
+ * stream_behavior::redirect_to_stdout, meaning that the child's stream is
+ * connected to child's standard output. This is typically used when
+ * configuring the standard error stream.
+ */
+inline stream_behavior redirect_stream_to_stdout()
+{
+ return stream_behavior(stream_behavior::redirect_to_stdout);
+}
+
+/**
+ * Creates a new stream_behavior of type stream_behavior::silence.
+ *
+ * Creates a new stream_behavior of type stream_behavior::silence,
+ * meaning that the child's stream is redirected to a null device so that
+ * its input is always zero or its output is lost, depending on whether
+ * the stream is an input or an output one. It is important to notice
+ * that this is different from close because the child is still able to
+ * write data. If we closed, e.g. stdout, the child might not work at
+ * all!
+ */
+inline stream_behavior silence_stream()
+{
+ return stream_behavior(stream_behavior::silence);
+}
+
+#if defined(BOOST_POSIX_API) || defined(BOOST_PROCESS_DOXYGEN)
+/**
+ * Creates a new stream_behavior of type stream_behavior::posix_redirect.
+ *
+ * Creates a new stream_behavior of type stream_behavior::posix_redirect,
+ * meaning that the child's stream is redirected to the \a to child's
+ * file descriptor. This is a generalization of the portable
+ * redirect_stream_to_stdout() behavior.
+ */
+inline stream_behavior posix_redirect_stream(int to)
+{
+ stream_behavior sb(stream_behavior::posix_redirect);
+ sb.desc_to_ = to;
+ return sb;
+}
+#endif
+
+}
+}
+
+#endif
Added: sandbox/process/boost/process/win32_child.hpp
==============================================================================
--- (empty file)
+++ sandbox/process/boost/process/win32_child.hpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,128 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+/**
+ * \file boost/process/win32_child.hpp
+ *
+ * Includes the declaration of the win32_child class.
+ */
+
+#ifndef BOOST_PROCESS_WIN32_CHILD_HPP
+#define BOOST_PROCESS_WIN32_CHILD_HPP
+
+#include <boost/process/child.hpp>
+#include <boost/process/detail/file_handle.hpp>
+#include <windows.h>
+
+namespace boost {
+namespace process {
+
+/**
+ * Windows implementation of the Child concept.
+ *
+ * The win32_child class implements the Child concept in a Windows
+ * operating system.
+ *
+ * A Windows child differs from a regular %child (represented by a
+ * child object) in that it holds additional information about a process.
+ * Aside from the standard handle, it also includes a handle to the
+ * process' main thread, together with identifiers to both entities.
+ *
+ * This class is built on top of the generic child so as to allow its
+ * trivial adoption. When a program is changed to use the
+ * Windows-specific context (win32_context), it will most certainly need
+ * to migrate its use of the child class to win32_child. Doing so is only
+ * a matter of redefining the appropriate object and later using the
+ * required extra features: there should be no need to modify the existing
+ * code (e.g. method calls) in any other way.
+ */
+class win32_child : public child
+{
+public:
+ /**
+ * Constructs a new Windows child object representing a just
+ * spawned %child process.
+ *
+ * Creates a new %child object that represents the process described by
+ * the \a pi structure.
+ *
+ * The \a fhstdin, \a fhstdout and \a fhstderr parameters hold the
+ * communication streams used to interact with the %child process if
+ * the launcher configured redirections. See the parent class'
+ * constructor for more details on these.
+ *
+ * \see child
+ */
+ win32_child(const PROCESS_INFORMATION &pi, detail::file_handle fhstdin, detail::file_handle fhstdout, detail::file_handle fhstderr)
+ : child(pi.dwProcessId, fhstdin, fhstdout, fhstderr, pi.hProcess),
+ process_information_(pi),
+ thread_handle_(process_information_.hThread)
+ {
+ }
+
+ /**
+ * Returns the process handle.
+ *
+ * Returns a process-specific handle that can be used to access the
+ * process. This is the value of the \a hProcess field in the
+ * PROCESS_INFORMATION structure returned by CreateProcess().
+ *
+ * \see get_id()
+ */
+ HANDLE get_handle() const
+ {
+ return process_information_.hProcess;
+ }
+
+ /**
+ * Returns the primary thread's handle.
+ *
+ * Returns a handle to the primary thread of the new process. This is
+ * the value of the \a hThread field in the PROCESS_INFORMATION
+ * structure returned by CreateProcess().
+ *
+ * \see get_primary_thread_id()
+ */
+ HANDLE get_primary_thread_handle() const
+ {
+ return process_information_.hThread;
+ }
+
+ /**
+ * Returns the primary thread's identifier.
+ *
+ * Returns a system-wide value that identifies the process's primary
+ * thread. This is the value of the \a dwThreadId field in the
+ * PROCESS_INFORMATION structure returned by CreateProcess().
+ *
+ * \see get_primary_thread_handle()
+ */
+ DWORD get_primary_thread_id() const
+ {
+ return process_information_.dwThreadId;
+ }
+
+private:
+ /**
+ * Windows-specific process information.
+ */
+ PROCESS_INFORMATION process_information_;
+
+ /**
+ * Thread handle owned by RAII object.
+ */
+ detail::file_handle thread_handle_;
+};
+
+}
+}
+
+#endif
Added: sandbox/process/boost/process/win32_context.hpp
==============================================================================
--- (empty file)
+++ sandbox/process/boost/process/win32_context.hpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,61 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+/**
+ * \file boost/process/win_32context.hpp
+ *
+ * Includes the declaration of the win32_context class.
+ */
+
+#ifndef BOOST_PROCESS_WIN32_CONTEXT_HPP
+#define BOOST_PROCESS_WIN32_CONTEXT_HPP
+
+#include <boost/process/context.hpp>
+#include <string>
+#include <windows.h>
+
+namespace boost {
+namespace process {
+
+/**
+ * Generic implementation of the Context concept.
+ *
+ * The context class implements the Context concept in an operating
+ * system agnostic way; it allows spawning new child processes using
+ * a single and common interface across different systems.
+ */
+template <class String>
+class win32_basic_context : public basic_context<String>
+{
+public:
+ /**
+ * Initializes the Win32-specific process startup information with NULL.
+ */
+ win32_basic_context()
+ : startupinfo(NULL)
+ {
+ }
+
+ /**
+ * Win32-specific process startup information.
+ */
+ STARTUPINFOA *startupinfo;
+};
+
+/**
+ * Default instantiation of win32_basic_context.
+ */
+typedef win32_basic_context<std::string> win32_context;
+
+}
+}
+
+#endif
Added: sandbox/process/boost/process/win32_operations.hpp
==============================================================================
--- (empty file)
+++ sandbox/process/boost/process/win32_operations.hpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,77 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+/**
+ * \file boost/process/win32_operations.hpp
+ *
+ * Provides miscellaneous free functions specific to Windows operating
+ * systems.
+ */
+
+#ifndef BOOST_PROCESS_WIN32_OPERATIONS_HPP
+#define BOOST_PROCESS_WIN32_OPERATIONS_HPP
+
+#include <boost/process/win32_child.hpp>
+#include <boost/process/detail/file_handle.hpp>
+#include <boost/process/detail/stream_info.hpp>
+#include <boost/process/detail/win32_ops.hpp>
+#include <windows.h>
+
+namespace boost {
+namespace process {
+
+/**
+ * Starts a new child process.
+ *
+ * Given an executable and the set of arguments passed to it, starts
+ * a new process with all the parameters configured in the context.
+ * The context can be reused afterwards to launch other different
+ * processes.
+ *
+ * \return A handle to the new child process.
+ */
+template <class Executable, class Arguments, class Win32_Context>
+inline win32_child win32_launch(const Executable &exe, const Arguments &args, const Win32_Context &ctx)
+{
+ detail::file_handle fhstdin, fhstdout, fhstderr;
+
+ detail::stream_info behin = detail::stream_info(ctx.stdin_behavior, false);
+ if (behin.type_ == detail::stream_info::use_pipe)
+ fhstdin = behin.pipe_->wend();
+ detail::stream_info behout = detail::stream_info(ctx.stdout_behavior, true);
+ if (behout.type_ == detail::stream_info::use_pipe)
+ fhstdout = behout.pipe_->rend();
+ detail::stream_info beherr = detail::stream_info(ctx.stderr_behavior, true);
+ if (beherr.type_ == detail::stream_info::use_pipe)
+ fhstderr = beherr.pipe_->rend();
+
+ detail::win32_setup s;
+ s.work_directory = ctx.work_directory;
+
+ STARTUPINFOA si;
+ if (!ctx.startupinfo)
+ {
+ ::ZeroMemory(&si, sizeof(si));
+ si.cb = sizeof(si);
+ s.startupinfo = &si;
+ }
+ else
+ s.startupinfo = ctx.startupinfo;
+
+ PROCESS_INFORMATION pi = detail::win32_start(exe, args, ctx.environment, behin, behout, beherr, s);
+
+ return win32_child(pi, fhstdin, fhstdout, fhstderr);
+}
+
+}
+}
+
+#endif
Added: sandbox/process/libs/process/doc/Jamfile.v2
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/doc/Jamfile.v2 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,15 @@
+#
+# Boost.Process
+# ~~~~~~~~~~~~~
+#
+# Copyright (c) 2006, 2007 Julio M. Merino Vidal
+# Copyright (c) 2008 Boris Schaeling
+#
+# Distributed under the Boost Software License, Version 1.0. (See accompanying
+# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+#
+
+project boost/doc ;
+import boostbook : boostbook ;
+
+boostbook process-doc : process.xml ;
Added: sandbox/process/libs/process/doc/acknowledgements.xml
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/doc/acknowledgements.xml 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN" "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd">
+<section id="process.acknowledgments">
+ <title>Acknowledgements</title>
+ <para>This library was designed by <ulink url="http://julipedia.blogspot.com/">Julio M. Merino Vidal</ulink> during the <ulink url="http://code.google.com/soc/">Google Summer of Code</ulink> 2006 program under the supervision of <ulink url="http://www.boost.org/people/jeff_garland.html">Jeff Garland</ulink>.</para>
+ <para>The latest snapshot of Boost.Process <ulink url="http://julipedia.blogspot.com/">Julio M. Merino Vidal</ulink> had worked on was checked into the sandbox in 2007.</para>
+ <para>In 2008 the library was picked up by <ulink url="http://www.highscore.de/">Boris Schaeling</ulink> to tidy up the code, fix various bugs, add minor improvements and update the documentation.</para>
+</section>
Added: sandbox/process/libs/process/doc/concepts.xml
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/doc/concepts.xml 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN" "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd">
+<section id="process.concepts" xmlns:xi="http://www.w3.org/2001/XInclude">
+ <title>Concepts</title>
+ <para>The following sections describe the basic concepts behind Boost.Process. They are first slightly introduced based on the operating system concepts behind them and are later specified as concepts to be used in templates.</para>
+ <section id="process.concepts.executable">
+ <title>Executable</title>
+ <para>An executable is a file which can be executed by the operating system. The file can contain machine code or be a script which is automatically executed by a script host.</para>
+ <para>The Executable concept is used to refer to an executable. It is a filename which can include a path (either absolute or relative). If the filename doesn't include a path the executable is expected to be in the current working directory (relative to the <link linkend="process.concepts.context">Context</link> which is another concept explained below).</para>
+ <para>There is no class in Boost.Process to implement the Executable concept. As the executable is a filename only it is simply stored in a <classname>std::string</classname>. It might be possible to generalize the library further to make it possible for library users to use other string classes. Currently it is the safest bet to use a <classname>std::string</classname> though.</para>
+ </section>
+ <section xml:id="process.concepts.arguments">
+ <title>Arguments</title>
+ <para>Arguments are the parameters passed to an executable when invoked. In C++ they can be accessed via a <type>char*[]</type> parameter of <function>main</function> which is often called <varname>argv</varname>.</para>
+ <para>This concept is not represented by a class either. The library user is expected to use a collection whose items are strings, eg. <type>std::vector<std::string></type>. While the library user is free to choose any collection from the STL the items' type must be <type>std::string</type>. The library is not as much generalized yet as if it is likely to work with other string types.</para>
+ </section>
+ <section xml:id="process.concepts.context">
+ <title>Context</title>
+ <para>A context defines additional data next to the executable and arguments a child process should be spawned with. This includes for example the work directory and environment variables. There are also platform-specific features supported. On POSIX systems security credentials can be set for example.</para>
+ <para>A generic context is implemented as <classname alt="boost::process::context">context</classname>. There are two platform-specific context classes <classname alt="boost::process::posix_context">posix_context</classname> and <classname alt="boost::process::win32_context">win32_context</classname> to provide access to platform-specific features.</para>
+ </section>
+ <section xml:id="process.concepts.process">
+ <title>Process</title>
+ <para>A process is the execution context of a program, represented internally by the operating system through multiple objects in its internal tables. Any reference to a process always mentions a running application in the system; it has to be clear that it cannot refer to an on-disk program that has not yet started execution.</para>
+ <para>Processes are internally organized by the operating system as a tree. Each process (except for the one at the tree's root) has a parent and can have multiple children. A parent process owns its children and therefore has full control over their execution.</para>
+ <para>There are two possible states for a child process:</para>
+ <itemizedlist>
+ <listitem>
+ <para>Active: the process is alive. It may either be running or sleeping, but it has not finalized execution.</para>
+ </listitem>
+ <listitem>
+ <para>Zombie: the process finished execution and is waiting for its parent to collect its status. This may happen due to unexpected and expected termination conditions.</para>
+ </listitem>
+ </itemizedlist>
+ <para>While there is a <classname alt="boost::process::process">process</classname> class library users typically deal with objects of type <classname alt="boost::process::child">child</classname> (a class derived from <classname alt="boost::process::process">process</classname>). If platform-specific features should be used child objects of type <classname alt="boost::process::posix_child">posix_child</classname> and <classname alt="boost::process::win32_child">win32_child</classname> can be created.</para>
+ <para>The class <classname alt="boost::process::self">self</classname> (which is also derived from <classname alt="boost::process::process">process</classname>) can be used to access the current process.</para>
+ </section>
+ <section xml:id="process.concepts.status">
+ <title>Exit status</title>
+ <para>Upon termination, a process reports information to its parent describing why it finalized. This information is known as the exit status and includes the reason behind termination (regular exit, crash, external signal, etc.) together with details describing it.</para>
+ <para>Exit status can only be gathered from zombie processes; that is, child processes that stopped execution and are waiting for its parent to collect it. When the information is collected, the zombie process ceases to exist from the system tables, invalidating the Process object that represented it.</para>
+ <para>The Status concept is used to represent a process' exit status.</para>
+ <para>This concept is implemented by the <classname alt="boost::process::status">status</classname> class. On POSIX systems additional features are available via the <classname alt="boost::process::posix_status">posix_status</classname> class.</para>
+ </section>
+ <section xml:id="process.concepts.handle">
+ <title>Handle</title>
+ <para>A handle is an operating system entity that identifies one of its objects, such as a file or a process. Handles are used by user space programs to tell the operating system the object they are referring to.</para>
+ <para>Given the low-level interactions of Boost.Process with the operating system, the library lets the user access these handles, should he need them to call operating system services directly.</para>
+ <para>It is important to note that handles are object-specific. An operating system may use different data types to identify each of its objects. For example, POSIX systems refer to files through an <type>int</type> value while processes are referred to by <type>pid_t</type> values. Contrarywise, Windows uses a single <type>HANDLE</type> type to describe any object. Therefore, Boost.Process abstracts these handles in each class where it makes sense using types named <type>handle_type</type>.</para>
+ </section>
+</section>
Added: sandbox/process/libs/process/doc/design.png
==============================================================================
Binary file. No diff available.
Added: sandbox/process/libs/process/doc/design.xml
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/doc/design.xml 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN" "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd">
+<section id="process.design">
+ <title>Design overview</title>
+ <para>Boost.Process is a rather small library to make it as simple as possible for developers to create, control and communicate with processes. For a better idea how the library's structure looks like the following diagram has been created.</para>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="design.png"/>
+ </imageobject>
+ </mediaobject>
+ <para>The most important classes are <classname alt="boost::process::context">context</classname> and <classname alt="boost::process::child">child</classname>: They implement the <link linkend="process.concepts.context">Context</link> and <link linkend="process.concepts.process">Process</link> concepts Boost.Process is built on. While <link linkend="process.concepts.context">Context</link> is used to setup the overall context the new process will run in, <link linkend="process.concepts.process">Process</link> describes any process. Currently it's only possible to access children via <classname alt="boost::process::child">child</classname> and the current process via <classname alt="boost::process::self">self</classname>. As of today there is no way to access other processes.</para>
+ <para>In order to communicate with a child <classname alt="boost::process::pistream">pistream</classname> and <classname alt="boost::process::postream">postream</classname> are used. They can be accessed via <classname alt="boost::process::child">child</classname> and represent input and output streams. By default all streams are closed when a child is started. The context has to be configured appropriately to redirect streams if a parent should be able to communicate with a child.</para>
+ <para>A process can wait for a child to terminate. When it is terminated <classname alt="boost::process::status">status</classname> enables the process to fetch the exit code of the child.</para>
+ <para>If more than one child should be created and the children should be connected with each other <classname alt="boost::process::pipeline_entry">pipeline_entry</classname> is used to specify the context of every child in the pipeline. As a pipeline consists of more than one process <classname alt="boost::process::children">children</classname> is used to manage the entire pipeline. It's then for example not possible to communicate via <classname alt="boost::process::pistream">pistream</classname> and <classname alt="boost::process::postream">postream</classname> with each and every child in the pipeline but only with the first and last child (as the children in the pipeline communicate with each other).</para>
+ <para>As Boost.Process is platform-independent by default only those features are supported which are available on all platforms. As POSIX and Windows platforms support more features additional classes are provided in case platform-specific features should be used.</para>
+ <section id="process.design.steps">
+ <title>Creating, controlling and communicating with a child</title>
+ <para>There are basically four steps when a child is spawned:</para>
+ <itemizedlist>
+ <listitem>
+ <para>Before a process can be created <classname alt="boost::process::context">context</classname> (in <filename class="headerfile">boost/process/context.hpp</filename>) must be setup. This includes specifying what should happen with the input, output and error streams (eg. if they should be closed or redirected) and how the environment table which contains environment variables should look like. The classes <classname alt="boost::process::posix_context">posix_context</classname> (in <filename class="headerfile">boost/process/posix_context.hpp</filename>) and <classname alt="boost::process::win32_context">win32_context</classname> (in <filename class="headerfile">boost/process/win32_context.hpp</filename>) support additional options which are only available on the respective platforms (eg. setting the <ulink url="http://www.opengroup.org/onlinepubs/000095399/functions/setuid.html">uid</ulink> on POSIX platforms or passing a <ulink url="http://msdn.microsoft.com/en-us/library/ms686331(VS.85).aspx">ST
ARTUPINFO</ulink> object on Windows platforms).</para>
+ </listitem>
+ <listitem>
+ <para>After a context has been created it is passed to a function which starts the process and returns <classname alt="boost::process::child">child</classname>. The header file <filename class="headerfile">boost/process/operations.hpp</filename> provides the template function <function alt="boost::process::launch">launch</function> which requires the caller to pass the name of the executable (typically <classname>std::string</classname>), a set of arguments (typically <classname>std::vector<std::string></classname> and the <classname alt="boost::process::context">context</classname> object. The template functions <function alt="boost::process::win32_launch">win32_launch</function> (in <filename class="headerfile">boost/process/win32_operations.hpp</filename>) and <function alt="boost::process::posix_launch">posix_launch</function> (in <filename class="headerfile">boost/process/posix_operations.hpp</filename>) must be called if the classes <classname alt="boost::process::posix_context">posix_co
ntext</classname> and <classname alt="boost::process::win32_context">win32_context</classname> have been used to setup a context. While <function alt="boost::process::launch">launch</function> returns a <classname alt="boost::process::child">child</classname> object, <function alt="boost::process::posix_launch">posix_launch</function> returns a <classname alt="boost::process::posix_child">posix_child</classname> object (in <filename class="headerfile">boost/process/posix_child.hpp</filename>) and <function alt="boost::process::win32_launch">win32_launch</function> a <classname alt="boost::process::win32_child">win32_child</classname> object (in <filename class="headerfile">boost/process/win32_child.hpp</filename>).</para>
+ </listitem>
+ <listitem>
+ <para>If the context has been setup to redirect streams it is possible to access the child's input, output and error streams. The library provides two classes <classname alt="boost::process::pistream">pistream</classname> (in <filename class="headerfile">boost/process/pistream.hpp</filename>) and <classname alt="boost::process::postream">postream</classname> (in <filename class="headerfile">boost/process/postream.hpp</filename>) which are derived from <classname>std::istream</classname> respectively <classname>std::ostream</classname> and thus behave like standard C++ streams. They can be used to write to the child's input stream and to read from the child's output and error streams (always assuming that the context has been setup in a way that these streams are redirected). Of course it's not required to communicate with a child at all - this step is optional.</para>
+ </listitem>
+ <listitem>
+ <para>After having created a context, started a process and possibly communicated with the child it's possible to wait for the child to terminate, terminate the child explicitly or just forget about the child. If a process waits for the child to terminate and the child terminates a <classname alt="boost::process::status">status</classname> object (in <filename class="headerfile">boost/process/status.hpp</filename>) is returned which enables a process to check the exit code of the child (eg. if it returned EXIT_SUCCESS or EXIT_FAILURE). On POSIX platforms <classname alt="boost::process::posix_child">posix_child</classname> returns a <classname alt="boost::process::posix_status">posix_status</classname> object (in <filename class="headerfile">boost/process/posix_status.hpp</filename>) to check for example if the child dumped core.</para>
+ </listitem>
+ </itemizedlist>
+ </section>
+ <section id="process.design.io">
+ <title>Support for blocking and asynchronous I/O</title>
+ <para>When <classname alt="boost::process::pistream">pistream</classname> and <classname alt="boost::process::postream">postream</classname> objects are used to communicate with a child all read/write operations are blocking just like with any other standard C++ stream. If for example a process reads from a child and the child doesn't write data the read operation blocks until new data is written by the child.</para>
+ <para>While there is no support for asynchronous I/O in <classname alt="boost::process::pistream">pistream</classname> and <classname alt="boost::process::postream">postream</classname> the underlying handle can be fetched and passed to <classname>boost::asio::posix::stream_descriptor</classname> respectively <classname>boost::asio::windows::stream_handle</classname> which are provided by <libraryname alt="Asio">Boost.Asio</libraryname>. On Windows platforms it is required to define BOOST_PROCESS_WINDOWS_USE_NAMED_PIPE as on Windows anonymous pipes which are used by default to redirect streams between processes don't support asynchronous I/O.</para>
+ <para>For details check the <link linkend="process.tutorials">tutorials</link> for an example how to use asynchronous I/O with Boost.Asio.</para>
+ </section>
+</section>
Added: sandbox/process/libs/process/doc/introduction.xml
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/doc/introduction.xml 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN" "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd">
+<section id="process.introduction" xmlns:xi="http://www.w3.org/2001/XInclude">
+ <title>Introduction</title>
+ <section id="process.introduction.overview">
+ <title>Overview</title>
+ <para>Boost.Process provides a flexible framework for the C++ programming language to manage running programs, also known as processes. It empowers C++ developers to do what Java developers can do with java.lang.Runtime/java.lang.Process and .NET developers can do with System.Diagnostics.Process. Among other functionality, this includes the ability to manage the execution context of the currently running process, the ability to spawn new child processes, and a way to communicate with them using standard C++ streams and asynchronous I/O.</para>
+ <para>The library is designed in a way to transparently abstract all process management details to the user, allowing for painless development of cross-platform applications. However, as such abstractions often restrict what the developer can do, the framework allows direct access to operating system specific functionality - obviously losing the portability features of the library.</para>
+ </section>
+ <section id="process.introduction.features">
+ <title>Features</title>
+ <para>This section contains a summary of the most important features provided by the library.</para>
+ <section>
+ <title>Process management</title>
+ <para>Boost.Process' long-term goal is to provide a portable abstraction layer over the operating system that allows the programmer to manage any running process, not only those spawned by it. Due to the complexity in offering such an interface, the library currently focuses on child process management alone.</para>
+ <para>As an exception, it also allows access to the caller's process because this is easy to expose, helps in providing a more modular interface and is a very useful feature.</para>
+ </section>
+ <section>
+ <title>Child process management</title>
+ <para>Boost.Process' most important feature is the ability to painlessly launch external applications, control them during their lifetime and set up communication channels between them and their parent. Traditionally, this has been a boring and hard task in C and C++ because there are many details to take into account: create the new process, launch the external binary, set up anonymous pipes to communicate with it, wait for its termination, inspect its exit status, etc.</para>
+ <para>To make things worse, each major operating system has its own process model and API to manage child processes. Writing an application that deals with both is time consuming and in most cases drives away the developer from his original goal - not related at all to interacting with the underlying operating system. Therefore, Boost.Process provides an abstraction to handle all these details on behalf of the developer.</para>
+ </section>
+ <section>
+ <title>Input/output redirction</title>
+ <para>An application launching a child process typically wants to communicate with it by means of data transfers. This Inter-Process Communication (IPC) happens at the level of file handles and typically involves the standard input (stdin), the standard output (stdout) and the standard error output (stderr). If the operating system supports it (e.g. Unix), other unnamed data streams can be redirected.</para>
+ <para>In order to properly integrate with the C++ standard library, this IPC is morphed into standard C++ streams making interaction with child processes a piece of cake. Each of these streams can be configured based on many predefined modes, which allow you to simply ignore a stream, collect it for further processing or redirect it to another stream (be it a program, a file or a low-level file handle).</para>
+ </section>
+ <section>
+ <title>Different operation modes</title>
+ <para>Boost.Process allows a process to be managed in several different operation modes; these are described below:</para>
+ <itemizedlist>
+ <listitem>
+ <para>Asynchronous operation: The child process is spawned and the parent process continues execution. This is the most common operation mode because the parent will typically need to manage the data generated by its child as soon as it is available. At any point, the parent process can decide to synchronize with its child, effectively waiting for its termination.</para>
+ </listitem>
+ <listitem>
+ <para>Synchronous operation: In this scenario, the parent process blocks until its newly spawned children finishes execution. This can be useful in those cases where the parent does not directly receive data generated from its child (e.g. because it is redirected to a file on disk).</para>
+ </listitem>
+ <listitem>
+ <para>Disconnected operation: The parent process forgets about the existence of its child process, which can continue to exist even when the parent dies.</para>
+ </listitem>
+ </itemizedlist>
+ </section>
+ <section>
+ <title>Pipeline management</title>
+ <para>A pipeline is a unidimensional and unidirectional chain of interconnected processes in which the output of one of them is connected to the input of the following. The programmer can then feed data to this pipeline through the first process' input channel and fetch the results through the last process' output channel.</para>
+ <para>The library provides the necessary functionality to model pipelines and handle them.</para>
+ </section>
+ </section>
+ <section id="process.introduction.non_functional_requirements">
+ <title>Non-functional requirements</title>
+ <section>
+ <title>Portability</title>
+ <para>Boost.Process is constructed with portability in mind. Both the POSIX process management model and the Windows one are taken into account in the library and are supported by its API. More details are available in the <link linkend="process.platforms">Platforms and compilers</link> chapter.</para>
+ <para>To achieve this goal, the library provides a common and system-agnostic API that lets the developer manage processes without ever knowing the operating system the code is running on. However, it is a fact that each operating system provides specific and useful features that are not portable to others; these must not be banned to developers if they need them. Therefore, the library provides a way to access these features that is clearly separated from the cross-platform API to avoid introducing portability bugs by mistake.</para>
+ </section>
+ <section>
+ <title>Modularity</title>
+ <para>Boost.Process is modelled around a set of abstract concepts that are implemented in the form of C++ templates and classes. This allows the developer to replace any part of the library with custom implementations as long as they match the requirements of each concept, useful when he may need extreme performance or highly OS-specific functionality not provided by the standard classes.</para>
+ </section>
+ <section>
+ <title>Testability</title>
+ <para>The library comes with a very complete set of regression tests to ensure that it behaves according to its specifications. These tests try to be as complete as possible and are an excellent tool to verify that the library works correctly on a platform where it has not been tested before.</para>
+ <para>Although the library was not developed following the Test Driven Development (TDD) methodology, it is still interesting to have as much automated tests as possible. Whenever a bug is found or a new functionality is added, a new test must be introduced to ensure that no regressions appear and that the fixed/new code works as expected.</para>
+ </section>
+ <section>
+ <title>Efficiency</title>
+ <para>The library is implemented with efficiency in mind although this is not a primary goal of its development. Improvements to efficiency are of course welcome but are a second class item in front of the other goals. However, it is understandable that efficiency can be a very important feature for some developers. Therefore the programmer is allowed to replace parts of the framework with custom implementations to improve the areas that may not be efficient enough.</para>
+ </section>
+ </section>
+</section>
Added: sandbox/process/libs/process/doc/nonportable_usage.xml
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/doc/nonportable_usage.xml 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,163 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN" "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd">
+<section id="process.nonportable_usage" xmlns:xi="http://www.w3.org/2001/XInclude">
+ <title>Platform-specific usage</title>
+ <para>The <link linkend="process.usage">usage chapter</link> focused on explaining all features provided by Boost.Process that are available under all <link linkend="process.platforms.supported_platforms">supported platforms</link>. However, those features may be too limited when portability across different platforms is not a determining factor; in such cases, you will want to access the full power of the underlying operating system to manage processes. Boost.Process lets you do so through specialized classes - even if they are not enough for your use case, you can always design your own.</para>
+ <para>This chapter describes all platform-specific features available in Boost.Process. Keep in mind that using them will lower your application's portability.</para>
+ <section xml:id="process.nonportable_usage.posix">
+ <title>The POSIX platform</title>
+ <section>
+ <title>Interprocess communication</title>
+ <para>As we saw <link linkend="process.usage">earlier</link> in the usage chapter, all platforms supported by Boost.Process provide three communication channels to each process. Although these are enough in almost all use cases, some applications can take advantage of more data flows. For example, they may support multiple input streams so that external processes can feed in different types of data, or emit messages through more than two output streams to clearly separate their purpose.</para>
+ <para>The POSIX platform allows the configuration of more than three communication channels thanks to the way <function>fork</function> works: any file descriptor can be used to connect two different processes through an anonymous pipe. Boost.Process can take advantage of such feature and configure more than three data flows by using the specialized <classname alt="boost::process::posix_launcher">posix_launcher</classname> and <classname alt="boost::process::posix_child">posix_child</classname> classes, both based on the generic implementations.</para>
+ <para>Before continuing, it is interesting to remember that POSIX systems identify communication channels with plain integers because they are regular file descriptors. The three standard communication channels are typically attached to fixed file descriptors and the <filename class="headerfile">cstdlib</filename> standard header provides constants to refer to them; these constants shall be used instead of the integer values to achieve maximum portability and clarity.</para>
+ <table>
+ <caption>Standard channels on POSIX operating systems</caption>
+ <thead>
+ <tr>
+ <td>Channel</td>
+ <td>Symbolic constant</td>
+ <td>Typical value</td>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>Standard input</td>
+ <td>STDIN_FILENO</td>
+ <td>0</td>
+ </tr>
+ <tr>
+ <td>Standard output</td>
+ <td>STDOUT_FILENO</td>
+ <td>1</td>
+ </tr>
+ <tr>
+ <td>Standard error</td>
+ <td>STDERR_FILENO</td>
+ <td>2</td>
+ </tr>
+ </tbody>
+ </table>
+ <para>The POSIX context class <classname alt="boost::process::posix_context">posix_context</classname> provides two additional properties that allow the user to add and specify the behavior of non-standard file descriptors; these are <varname>input_behavior</varname> and <varname>output_behavior</varname>. The former is used to configure a child's input streams and the latter output ones.</para>
+ <para>Once the streams are configured and the child process is running, the caller accesses the child's streams as it did with the generic child. However, non-standard streams are only available through two additional methods: <methodname alt="boost::process::posix_child::get_input">get_input</methodname> and <methodname alt="boost::process::posix_child::get_output">get_output</methodname>.</para>
+ <para>These methods can be seen as general cases of those provided by the generic child. The following table illustrates the equivalences:</para>
+ <table>
+ <caption>POSIX child specific methods and equivalent portable methods</caption>
+ <thead>
+ <tr>
+ <td>Portable method</td>
+ <td>Equivalent to</td>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td><code>boost::process::child::get_stdin()</code></td>
+ <td><code>boost::process::posix_child::get_input(STDIN_FILENO)</code></td>
+ </tr>
+ <tr>
+ <td><code>boost::process::child::get_stdout()</code></td>
+ <td><code>boost::process::posix_child::get_output(STDOUT_FILENO)</code></td>
+ </tr>
+ <tr>
+ <td><code>boost::process::child::get_stderr()</code></td>
+ <td><code>boost::process::posix_child::get_output(STDERR_FILENO)</code></td>
+ </tr>
+ </tbody>
+ </table>
+ <para>The following example program illustrates the use of these functions. It uses the D-BUS daemon application because it allows to print useful information to two non-standard streams (3 and 4 in the code below). The example utility captures these messages and provides them to the user:</para>
+ <programlisting><xi:include href="../example/posix_communication.cpp" parse="text"/></programlisting>
+ </section>
+ <section>
+ <title>Process credentials</title>
+ <para>Processes under POSIX operating systems carry several properties that describe their security credentials. All of these can be configured through the POSIX context prior startup of a new process, as seen in the following table:</para>
+ <table>
+ <caption>How to retrieve process credentials on POSIX operating systems</caption>
+ <thead>
+ <tr>
+ <td>Concept</td>
+ <td>Abbreviation</td>
+ <td>POSIX launcher method</td>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>Real and effective user IDs</td>
+ <td>UID</td>
+ <td><methodname alt="boost::process::posix_launcher::set_uid">set_uid</methodname></td>
+ </tr>
+ <tr>
+ <td>Effective user ID</td>
+ <td>EUID</td>
+ <td><methodname alt="boost::process::posix_launcher::set_euid">set_euid</methodname></td>
+ </tr>
+ <tr>
+ <td>Real and effective group IDs</td>
+ <td>GID</td>
+ <td><methodname alt="boost::process::posix_launcher::set_gid">set_gid</methodname></td>
+ </tr>
+ <tr>
+ <td>Effective group ID</td>
+ <td>EGID</td>
+ <td><methodname alt="boost::process::posix_launcher::set_egid">set_egid</methodname></td>
+ </tr>
+ </tbody>
+ </table>
+ <para>Note that changing the security credentials of a process is a privileged operation generally restricted to the super user. For more information you should see your operating system's documentation on the <function>setuid</function>, <function>seteuid</function>, <function>setgid</function> and <function>setegid</function> system calls.</para>
+ </section>
+ <section>
+ <title>Root directory change</title>
+ <para>Every process in a POSIX system has a root directory, used to resolve paths aside from the current working directory. This root directory is used to restrict processes to view only a part of the global file system: the process is not allowed to see the real file system's root directory; instead it sees the specified root directory as if it really was the file system's root. See the <function>chroot</function> system call documentation for more details.</para>
+ <para>The specialized <classname alt="boost::process::posix_context">posix_context</classname> supports changing the root directory of a new process, always assuming that sufficient privileges are available (i.e. the caller must be the super user). This is done through the <varname alt="boost::process::posix_context::chroot">chroot</varname> property.</para>
+ </section>
+ <section>
+ <title>Process termination</title>
+ <para>The POSIX's <function>wait</function> family of system calls returns a lot of information about the status of a finalized process, not only the exit status code provided on a normal exit. This information includes additional termination reasons such as if the process dumped a core file, if it exited due an external signal, etc.</para>
+ <para>The information described above can be queried through the <classname alt="boost::process::posix_status">posix_status</classname> class. This is built on top of the regular status class and includes additional methods to query all additional details. It can be used anywhere a <classname alt="boost::process::status">status</classname> object is created thanks to its conversion constructor.</para>
+ <programlisting><xi:include href="../example/posix_status.cpp" parse="text"/></programlisting>
+ </section>
+ </section>
+ <section xml:id="process.nonportable_usage.windows">
+ <title>The Windows platforms</title>
+ <section>
+ <title>Startup information</title>
+ <para>The Windows <function>CreateProcess</function> system call receives a <type>STARTUPINFO</type> object that contains multiple details on how to configure the new process. Among these are the handles for the three standard communication channels (internally set up by the library), hints to set up the application's main window, etc.</para>
+ <para>The Windows-specific context <classname alt="boost::process::win32_context">win32_context</classname> provides mechanisms to provide some of this platform-specific information to the new process. The property <varname alt="boost::process::win32_context::startupinfo">startupinfo</varname> can receive a pointer to an already initialized <type>STARTUPINFO</type> object that is later passed to the <function>CreateProcess</function> call. If no such object is provided, the context behaves as <classname alt="boost::process::context">context</classname>.</para>
+ <para>The example below demonstrates this feature. It relies on features provided by Windows operating systems to start a GUI process with hints on how to create the main window. The example passes the suggested window position as well as size and then waits until the new process terminates.</para>
+ <programlisting><xi:include href="../example/win32_startup.cpp" parse="text"/></programlisting>
+ </section>
+ <section>
+ <title>Process information</title>
+ <para>The Windows <function>CreateProcess</function> system call starts a new process and returns a handle and an identifier for both the application's process and its main thread. Due to portability restrictions, the generic child implementation does not allow access to this information but, fortunately, the Windows-speficic child does. The class <classname alt="boost::process::win32_child">win32_child</classname> provides access to the information returned by the <function>CreateProcess</function> system call as described below:</para>
+ <table>
+ <caption>How to retrieve process information on Windows</caption>
+ <thead>
+ <tr>
+ <td><type>PROCESS_INFORMATION</type> field</td>
+ <td>Windows child method</td>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td><varname>hProcess</varname></td>
+ <td><methodname alt="boost::process::win32_child::get_handle">get_handle</methodname></td>
+ </tr>
+ <tr>
+ <td><varname>dwProcessId</varname></td>
+ <td><methodname alt="boost::process::win32_child::get_id">get_id</methodname></td>
+ </tr>
+ <tr>
+ <td><varname>hThread</varname></td>
+ <td><methodname alt="boost::process::win32_child::get_primary_thread_handle">get_primary_thread_handle</methodname></td>
+ </tr>
+ <tr>
+ <td><varname>dwThreadId</varname></td>
+ <td><methodname alt="boost::process::win32_child::get_primary_thread_id">get_primary_thread_id</methodname></td>
+ </tr>
+ </tbody>
+ </table>
+ <para>Windows child objects can only be constructed by using the Windows-specific context <classname alt="boost::process::win32_context">win32_context</classname> even if the user does not need any of the extra features provided by that class.</para>
+ <para>The following example demonstrates how a program can retrieve all the information returned by Windows's <function>CreateProcess</function> system call; that is: the process' and primary thread's identifier and handle. It relies on the Windows-specific context and child classes to be able to access this information:</para>
+ <programlisting><xi:include href="../example/win32_child.cpp" parse="text"/></programlisting>
+ </section>
+ </section>
+</section>
Added: sandbox/process/libs/process/doc/platforms.xml
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/doc/platforms.xml 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN" "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd">
+<section id="process.platforms" xmlns:xi="http://www.w3.org/2001/XInclude">
+ <title>Platforms and compilers</title>
+ <para>This chapter describes the operating systems and compilers supported by Boost.Process. It also includes some guidelines on how to port the code to a new platform or a different Boost.Build toolset.</para>
+ <section xml:id="process.platforms.supported_platforms">
+ <title>Supported platforms</title>
+ <para>Boost.Process supports several different operating systems. Based on their programming API and process management models, they can be classified in two major platforms:</para>
+ <variablelist>
+ <varlistentry>
+ <term>POSIX systems</term>
+ <listitem>
+ <para>These systems follow the POSIX process model and use standard APIs to manage child processes. Simply put all processes are organized based on a parent/child relationship and applications start new processes by using the <function>fork</function> and <function>execve</function> pair of system calls. This separation allows the child process to perform extra operations before executing the real target. Systems in this group include all Unix-like operating systems.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Windows systems</term>
+ <listitem>
+ <para>Even though these systems support some of the POSIX system calls in the standard C Runtime library (CRT), they have a completely different process management model. Processes are spawned using a single system call known as <function>CreateProcess</function> which receives all the configuration parameters for the new child.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <para>Knowing how to classify the supported operating systems, the following table lists all operating systems known to support Boost.Process (according to the test suite):</para>
+ <table>
+ <caption>Supported operating systems</caption>
+ <thead>
+ <tr>
+ <td>Operating system name</td>
+ <td>API type</td>
+ <td>API constant</td>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>Linux 2.6</td>
+ <td>POSIX</td>
+ <td>BOOST_POSIX_API</td>
+ </tr>
+ <tr>
+ <td><ulink url="http://www.apple.com/macosx/">Mac OS X 10.4.x</ulink></td>
+ <td>POSIX</td>
+ <td>BOOST_POSIX_API</td>
+ </tr>
+ <tr>
+ <td><ulink url="http://www.netbsd.org/">NetBSD 3.x and 4.x</ulink></td>
+ <td>POSIX</td>
+ <td>BOOST_POSIX_API</td>
+ </tr>
+ <tr>
+ <td><ulink url="http://www.microsoft.com/windows/">Windows XP</ulink></td>
+ <td>Win32</td>
+ <td>BOOST_WINDOWS_API</td>
+ </tr>
+ </tbody>
+ </table>
+ <para>The third column in the table above mentions the name of a preprocessor constant defined by the header filer <filename class="headerfile">boost/process/config.hpp</filename> based on the platform type. Code using the library can use that constant to determine the platform it is running under.</para>
+ <para>Please note that the list above is not exhaustive. It is highly possible that Boost.Process works fine under other, unlisted operating systems because many of them are just variations of the above. Shall you try and use Boost.Process successfully on any other platform, please <link linkend="process.acknowledgments">tell us</link> so that it can be added to the list.</para>
+ </section>
+ <section xml:id="process.platforms.supported_compilers">
+ <title>Supported compilers</title>
+ <para>The Boost.Build compilation system abstracts compilers in what are known as toolsets. A toolset interacts with a specific compiler and linker to build the library and associated utilities (test suite, documentation and examples) in a platform-independent way, freeing the application developer from knowing the specific build details of the underlying platform.</para>
+ <para>Toolsets are specific to the operating systems they run under; e.g. the msvc toolset (Microsoft Visual C++) is not available under a GNU/Linux system. Therefore they should not be considered on their own but, for simplicity reasons, the table below lists the supported toolsets only.</para>
+ <table>
+ <caption>Supported toolsets</caption>
+ <thead>
+ <tr>
+ <td>Toolset name</td>
+ <td>Specific versions</td>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>darwin</td>
+ <td>GCC 3.3 and 4.0 as shipped with XCode 2.3</td>
+ </tr>
+ <tr>
+ <td>gcc</td>
+ <td>GCC 3.x and 4.x</td>
+ </tr>
+ <tr>
+ <td>msvc</td>
+ <td>Microsoft Visual Studio 2005/2008</td>
+ </tr>
+ </tbody>
+ </table>
+ </section>
+ <section xml:id="process.platforms.how_to_port">
+ <title>How to port to a new platform or compiler</title>
+ <para>A very important design goal of Boost.Process was to achieve maximum portability. It is certainly possible to adapt the library to new operating systems and compilers, generally with minimum efforts. However, porting to a new platform might be an extremely complex task, specially if its process management model differs from that of POSIX and Windows platforms.</para>
+ <para>Let's start with the easy task: porting to a new compiler. The library itself does not use any compiler-specific construction in its code so it should not cause problems. However, old compilers can raise errors if they do not support some of the ANSI C++ features. If this happens, the problem should be worked around in the simplest possible way.</para>
+ <para>A different issue is the test suite. The test suite builds a helper binary utility used by many other tests. These tests need to know where the helper binary is located and to do so they use some conditionals based on the toolset name. (Ideally Boost.Build could provide the real path to the code, but this feature is not available.) As you can imagine, this will surely cause problems when adopting a new toolset because it will not be recognized by the path determination machinery. In order to fix this you must adapt the <function>get_helpers_path</function> function in <filename class="headerfile">libs/process/test/misc.hpp</filename> to recognize the helper's binary location when built with the new toolset.</para>
+ <para>In order to port the library to a new operating system, you must first check that <filename class="headerfile">boost/process/config.hpp</filename> is determining the appropriate platform type for it. Once this is done, it should be a matter of running the test suite, detecting any build problems that may arise and fixing them appropriately. Remember that if the new operating system conforms to one of the supported platforms, it should behave similarly and not require big changes to the code.</para>
+ <para>In a different order of magnitude is the task to port the library to a new platform. The first step is to add a new platform constant to <filename class="headerfile">boost/process/config.hpp</filename> to identify the new platform. Once this is done, you will need to modify lots of source files to add support for it, including those in the library code, in the examples and in the test suite. Files that depend on a platform typically have the following conditional at the very beginning:</para>
+ <programlisting>#include <boost/process/config.hpp>
+
+#if defined(BOOST_POSIX_API)
+// Inclusion of POSIX-specific headers.
+#elif defined(BOOST_WINDOWS_API)
+// Inclusion of Windows-specific headers.
+#else
+# error "Unsupported platform."
+#endif
+
+// Inclusion of portable headers.</programlisting>
+ <para>It is important to note that only the first conditional in a given file carries the preprocessor error to ensure that the file is not compilable on an unsupported platform. Similarly the conditionals list all known platforms explicitly to denote that they were taken into account when writing or porting the code.</para>
+ </section>
+</section>
Added: sandbox/process/libs/process/doc/portability.xml
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/doc/portability.xml 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,137 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN" "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd">
+<section id="process.portability" xmlns:xi="http://www.w3.org/2001/XInclude">
+ <title>Portability remarks</title>
+ <para>The <link linkend="process.usage">usage chapter</link> has discussed all the portable features provided by Boost.Process and the <link linkend="process.nonportable_usage">platform-specific features chapter</link> has detailed all those that are restricted to concrete platforms. Unfortunately, there are several details you have to take into account if you want to write programs that are really portable even if you only use the features described by the former chapter.</para>
+ <section xml:id="process.portability.generic_classes">
+ <title>Generic classes</title>
+ <para>The most basic and obvious rule to develop a portable program is to stay away from all platform-specific classes. These are all prefixed with the platform's name to avoid using them by mistake. Shall you need to use them, you can still protect their usage with one of the <link linkend="process.platforms.supported_platforms">platform constants</link> and provide an appropriate fall-back alternative when they are not available.</para>
+ <para>As an example consider an application that wants to control a process' main window position. Under Windows platforms this is achieved by tweaking the <link linkend="process.nonportable_usage">startup information</link>, something that is supported only through a platform-specific class. However, this same thing is typically achieved under Unix by passing the program a <literal>-geometry</literal> flag:</para>
+ <programlisting>std::string exec = "some-application";
+
+std::vector<std::string> args;
+
+#if defined(BOOST_POSIX_API)
+args.push_back("-geometry");
+args.push_back("+100+200");
+...
+boost::process::context ctx;
+...
+boost::process::launch(exec, args, ctx);
+#elif defined(BOOST_WINDOWS_API)
+STARTUPINFO si;
+...
+si.dwX = 100;
+si.dwY = 200;
+...
+boost::process::win32_context ctx;
+ctx.startupinfo = &si;
+...
+boost::process::win32_launch(exec, args, ctx);
+#else
+# error "Unsupported platform."
+#endif </programlisting>
+ </section>
+ <section xml:id="process.portability.shell_command">
+ <title>Shell commands</title>
+ <para>The free-standing function <function alt="boost::process::launch_shell">launch_shell</function> allows the user to invoke a command which is passed verbatim to the shell. This is a delicate procedure because the Windows shell (<command>cmd.exe</command>) has very different rules than the standard POSIX shell (<command>/bin/sh</command>).</para>
+ <para>You should be aware of the following issues:</para>
+ <variablelist>
+ <varlistentry>
+ <term>Quoting issues</term>
+ <listitem>
+ <para>Each shell has its own quoting patterns when it comes to special characters. It is your responsibility to properly quote the string passed to <function alt="boost::process::launch_shell">launch_shell</function> so that there are no side effects. Special care must be taken if you are feeding the shell a user-supplied string.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Wildcard expansion</term>
+ <listitem>
+ <para>POSIX shells expand wildcards while the Windows shell does not. In the latter, the expansion is done by the application itself.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Variable expansion</term>
+ <listitem>
+ <para>Each shell has its own syntax to expand variables. E.g. Windows uses a %VAR% syntax while the POSIX shell uses ${VAR} or one of its multiple variations.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Built-in commands</term>
+ <listitem>
+ <para>Some commands are built-ins under some platforms while they are regular binaries under others. For example, POSIX's <command>ls</command> is a binary utility that resides under <filename class="directory">/bin</filename> whereas Windows' <command>dir</command> is a <command>cmd.exe</command> built-in. In the latter case the shell is required to execute the command.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </section>
+ <section xml:id="process.portability.environment">
+ <title>The environment</title>
+ <para>Environment variables are a common concept across all supported platforms and they behave very similarly. However there are some subtle differences that might cause problems:</para>
+ <variablelist>
+ <varlistentry>
+ <term>Empty variable values</term>
+ <listitem>
+ <para>Under a POSIX system, a variable can be defined and undefined regardless of its value. That is, it is perfectly legal to define a variable whose value is the empty string; in that case the application will see the variable as defined. Under Windows, however, there is no way to differentiate an empty variable from an undefined variable. To all effects, setting a variable to an empty string is the same as removing it.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Empty variable names</term>
+ <listitem>
+ <para>Neither Windows systems nor POSIX systems support an empty-named variable.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Variable length</term>
+ <listitem>
+ <para>Each operating system (even under the same platform) has a limit on the variable name's and value's length.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </section>
+ <section xml:id="process.portability.status">
+ <title>Exit status</title>
+ <para>The class <classname alt="boost::process::status">status</classname> provides a very generic interface to represent a process' exit condition. Among its members are a bunch that return booleans indicating whether an exit condition is true. The other methods are restricted to be used when their corresponding boolean exit condition holds <literal>true</literal>.</para>
+ <para>This generic interface is modelled after the POSIX exit status. Windows is much more restricted in this regard and only supports a subset of these features. There is no problem in calling the class' methods as long as the preconditions are met, but some of them make no sense under Windows. The following table describes the special cases:</para>
+ <table>
+ <caption>Platform dependency of <classname alt="boost::process::status">status</classname></caption>
+ <thead>
+ <tr>
+ <td>Method</td>
+ <td>Platform</td>
+ <td>Returns</td>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td><methodname alt="boost::process::status::exited">exited</methodname></td>
+ <td>POSIX</td>
+ <td>Whether the process exited on its own or not.</td>
+ </tr>
+ <tr>
+ <td><methodname alt="boost::process::status::exited">exited</methodname></td>
+ <td>Windows</td>
+ <td>Always <literal>true</literal>.</td>
+ </tr>
+ <tr>
+ <td><methodname alt="boost::process::status::signaled">signaled</methodname></td>
+ <td>POSIX</td>
+ <td>Whether the process exited due to an external signal or not.</td>
+ </tr>
+ <tr>
+ <td><methodname alt="boost::process::status::signaled">signaled</methodname></td>
+ <td>Windows</td>
+ <td>Always <literal>false</literal>.</td>
+ </tr>
+ <tr>
+ <td><methodname alt="boost::process::status::stopped">stopped</methodname></td>
+ <td>POSIX</td>
+ <td>Whether the process was stopped by an external signal.</td>
+ </tr>
+ <tr>
+ <td><methodname alt="boost::process::status::stopped">stopped</methodname></td>
+ <td>Windows</td>
+ <td>Always <literal>false</literal>.</td>
+ </tr>
+ </tbody>
+ </table>
+ </section>
+</section>
Added: sandbox/process/libs/process/doc/position.xml
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/doc/position.xml 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,129 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN" "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd">
+<section id="process.position" xmlns:xi="http://www.w3.org/2001/XInclude">
+ <title>Project position</title>
+ <section xml:id="process.position.history">
+ <title>History of changes</title>
+ <section>
+ <title>Version 0.3 (September 22nd, 2008)</title>
+ <itemizedlist>
+ <listitem>
+ <para>Dropped the macros <literal>BOOST_PROCESS_POSIX_API</literal> and <literal>BOOST_PROCESS_WIN32_API</literal> as Boost.System defines the macros <literal>BOOST_POSIX_API</literal> and <literal>BOOST_WINDOWS_API</literal> already.</para>
+ </listitem>
+ <listitem>
+ <para>Dropped exception class <type>boost::process::not_found_error</type> which was only thrown by <function alt="boost::process::find_executable_in_path">find_executable_in_path</function> and replaced it with <classname alt="boost::filesystem::filesystem_error">filesystem_error</classname>.</para>
+ </listitem>
+ <listitem>
+ <para>Updated and extended the documentation (e.g. added documentation to functions which were not yet documented).</para>
+ </listitem>
+ <listitem>
+ <para>Fixed various bugs including problems with code calling Unicode- or ANSI-versions of Windows API functions.</para>
+ </listitem>
+ <listitem>
+ <para>On Windows named pipes are used if the macro <literal>BOOST_PROCESS_WINDOWS_USE_NAMED_PIPE</literal> is defined. As only named pipes support asynchronous I/O on Windows this macro must be defined if Boost.Process should be used together with <libraryname alt="Asio">Boost.Asio</libraryname>.</para>
+ </listitem>
+ </itemizedlist>
+ </section>
+ <section>
+ <title>Version 0.2 (incomplete and only in the sandbox)</title>
+ <itemizedlist>
+ <listitem>
+ <para>Relicensed the code under the <ulink url="http://www.boost.org/LICENSE_1_0.txt">Boost Software License 1.0 only</ulink>. The first version was available under both this license and the MIT one only to comply with Summer of Code guidelines.</para>
+ </listitem>
+ <listitem>
+ <para>The POSIX-specific bits of a child's exit status were split from the <classname alt="status">status</classname> class into a new <classname alt="boost::process::posix_status">posix_status</classname> class.</para>
+ </listitem>
+ <listitem>
+ <para>The <classname alt="boost::process::status">status</classname> and <classname alt="boost::process::children">children</classname> constructors were made private to prevent accidental construction by the user.</para>
+ </listitem>
+ <listitem>
+ <para>Fixed duplicate symbols when linking multiple compilation units that use the library.</para>
+ </listitem>
+ <listitem>
+ <para>Fixed build with Visual C++ compilers older than 8.0 that do not provide <function>strcpy_s</function> and similar safe functions.</para>
+ </listitem>
+ <listitem>
+ <para>Removed the <type>command_line</type> class. The user now specifies the executable path and its arguments separately, using any classes he wants (such as a standard string and a STL container). This removes some black-box magic.</para>
+ </listitem>
+ <listitem>
+ <para>Decoupled the launcher classes into context classes and free launch functions. For example, the configuration bits of the old <type>launcher</type> class are now part of <classname alt="boost::process::context">context</classname> while its <code>start</code> method is now implemented as the <function>launch</function> free function. The same goes for the POSIX and Windows launchers. This was done to cleanly separate the action of launching a process from the parameters describing its properties. As a side effect, a lot of useless getters and setters are gone.</para>
+ </listitem>
+ <listitem>
+ <para>The <classname alt="boost::process::environment">environment</classname> class was refactored (much simplified) and made public because it is now exposed to the user through the new <classname alt="boost::process::context">context</classname>.</para>
+ </listitem>
+ <listitem>
+ <para>The file <filename class="headerfile">forward_decls.hpp</filename> was removed. It is not clear it was any useful, and it could be flawed in concept. Will add later on again if there really is a need for it.</para>
+ </listitem>
+ <listitem>
+ <para>The <classname alt="boost::process::stream_behavior">stream_behavior</classname> enumeration was converted to a class so that it can carry more information than a simple type. This is useful to be able to implement more complex stream behaviors. As a side effect, stream merging by the use of booleans or standalone data sets is now superseded by the new <literal>redirect_to_stdout</literal> and <literal>posix_redirect</literal> behaviors.</para>
+ </listitem>
+ <listitem>
+ <para>The <classname alt="boost::process::basic_work_directory_context">basic_work_directory_context</classname> and <classname alt="boost::process::environment_context">environment_context</classname> base classes were added. These are mainly provided to simplify the code in the final Context implementations but may also come handy to the end user in case he is working on his own Context implementation.</para>
+ </listitem>
+ <listitem>
+ <para>The <classname alt="boost::process::status">status</classname> and <classname alt="boost::process::posix_status">posix_status</classname> classes were greatly simplified. Instead of providing lots of accessor functions they now just expose some constant members. This avoids the need for several preconditions and consistency checks because the interface makes incoherent situations impossible.</para>
+ </listitem>
+ <listitem>
+ <para>The <classname alt="boost::process::pipeline">pipeline</classname> and <classname alt="boost::process::children">children</classname> classes were removed. The former was replaced by the <function>launch_pipeline</function> convenience function and the <classname alt="boost::process::pipeline_entry">pipeline_entry</classname> class. The latter was superseded by a simple typedef and a generic <function>wait_children</function> function that can be applied to any kind of collection of Child objects.</para>
+ </listitem>
+ <listitem>
+ <para>Made the processes be identified by a system-wide integer instead of a process-specific handle under Windows.</para>
+ </listitem>
+ <listitem>
+ <para>Added the <classname alt="boost::process::process">process</classname> class, an abstraction on top of <classname alt="boost::process::child">child</classname> that is able to represent any running process within the system. This was a requisite to introduce the <classname alt="boost::process::self">self</classname> class.</para>
+ </listitem>
+ <listitem>
+ <para>Added the <classname alt="boost::process::self">self</classname> class, whose instances allow access to the current process.</para>
+ </listitem>
+ <listitem>
+ <para>Added a way to force the termination of processes.</para>
+ </listitem>
+ </itemizedlist>
+ </section>
+ <section>
+ <title>Version 0.1 (August 21st, 2006)</title>
+ <para>Initial public release. This is what was presented at the end of the program under which Boost.Process was developed: <ulink url="http://code.google.com/soc/">Google Summer of Code</ulink> 2006.</para>
+ </section>
+ </section>
+ <section xml:id="process.position.pending_work">
+ <title>Pending work</title>
+ <para>This section contains a list of pending items in the library that should be addressed before it can be sent for a serious/formal review. Some of these are a simple matter of programming but others will require more consideration to decide the best way to solve them.</para>
+ <itemizedlist>
+ <listitem>
+ <para>Improve integration with <libraryname alt="Asio">Boost.Asio</libraryname> for example to permit asynchronous notification of child process termination.</para>
+ </listitem>
+ <listitem>
+ <para>Make it possible to specify a timeout when waiting for child processes to terminate.</para>
+ </listitem>
+ <listitem>
+ <para>Make <classname alt="boost::process::status">status</classname>' constructor private.</para>
+ </listitem>
+ <listitem>
+ <para>Add an interface to <classname alt="boost::process::self">self</classname> to modify the current environment.</para>
+ </listitem>
+ <listitem>
+ <para>Abstract <classname alt="boost::process::child">child</classname>'s streams so that <classname alt="boost::process::self">self</classname> can also provide a way to access the current process' standard streams.</para>
+ </listitem>
+ <listitem>
+ <para>Add a way (a <type>win32_self</type> class?) that allows the retrieval of a Windows <type>HANDLE</type> for the current process.</para>
+ </listitem>
+ <listitem>
+ <para>The <classname alt="boost::process::process">process</classname> class might conflict with the <code>process</code> namespace. I like the names as they are, but maybe one of the two should be renamed or simply put a warning in the documentation explaining where the conflicts may arise. These happen in some compilers when giving both <code>using namespace boost::process</code> and <code>using namespace boost</code>.</para>
+ </listitem>
+ </itemizedlist>
+ </section>
+ <section xml:id="process.position.documentation">
+ <title>Documentation</title>
+ <itemizedlist>
+ <listitem>
+ <para>Explain why the <type>launcher</type> class was discared in favour of the <classname alt="boost::process::context">context</classname>.</para>
+ </listitem>
+ <listitem>
+ <para>Add some diagrams to illustrate pipelines.</para>
+ </listitem>
+ <listitem>
+ <para>Add some diagrams to illustrate interprocess communication.</para>
+ </listitem>
+ </itemizedlist>
+ </section>
+</section>
Added: sandbox/process/libs/process/doc/process.xml
Added: sandbox/process/libs/process/doc/tutorials.xml
Added: sandbox/process/libs/process/example/async_io.cpp
Added: sandbox/process/libs/process/example/current_environment.cpp
Added: sandbox/process/libs/process/example/empty_environment.cpp
Added: sandbox/process/libs/process/example/modified_environment.cpp
Added: sandbox/process/libs/process/example/pipeline.cpp
Added: sandbox/process/libs/process/example/posix_communication.cpp
Added: sandbox/process/libs/process/example/posix_status.cpp
Added: sandbox/process/libs/process/example/read_from_child.cpp
Added: sandbox/process/libs/process/example/start_child.cpp
Added: sandbox/process/libs/process/example/wait_for_child.cpp
Added: sandbox/process/libs/process/example/win32_child.cpp
Added: sandbox/process/libs/process/example/win32_startup.cpp
Added: sandbox/process/libs/process/test/Jamfile.v2
Added: sandbox/process/libs/process/test/arguments_test.cpp
Added: sandbox/process/libs/process/test/child_base_test.hpp
Added: sandbox/process/libs/process/test/child_test.cpp
Added: sandbox/process/libs/process/test/detail_file_handle_test.cpp
Added: sandbox/process/libs/process/test/detail_pipe_test.cpp
Added: sandbox/process/libs/process/test/detail_systembuf_test.cpp
Added: sandbox/process/libs/process/test/environment_test.cpp
Added: sandbox/process/libs/process/test/executable_test.cpp
Added: sandbox/process/libs/process/test/helpers.cpp
Added: sandbox/process/libs/process/test/include_child_test.cpp
Added: sandbox/process/libs/process/test/include_context_test.cpp
Added: sandbox/process/libs/process/test/include_detail_file_handle_test.cpp
Added: sandbox/process/libs/process/test/include_detail_pipe_test.cpp
Added: sandbox/process/libs/process/test/include_detail_posix_ops_test.cpp
Added: sandbox/process/libs/process/test/include_detail_systembuf_test.cpp
Added: sandbox/process/libs/process/test/include_detail_win32_ops_test.cpp
Added: sandbox/process/libs/process/test/include_environment_test.cpp
Added: sandbox/process/libs/process/test/include_operations_test.cpp
Added: sandbox/process/libs/process/test/include_pistream_test.cpp
Added: sandbox/process/libs/process/test/include_posix_child_test.cpp
Added: sandbox/process/libs/process/test/include_posix_context_test.cpp
Added: sandbox/process/libs/process/test/include_posix_operations_test.cpp
Added: sandbox/process/libs/process/test/include_posix_status_test.cpp
Added: sandbox/process/libs/process/test/include_postream_test.cpp
Added: sandbox/process/libs/process/test/include_process_test.cpp
Added: sandbox/process/libs/process/test/include_self_test.cpp
Added: sandbox/process/libs/process/test/include_status_test.cpp
Added: sandbox/process/libs/process/test/include_stream_behavior_test.cpp
Added: sandbox/process/libs/process/test/include_top_test.cpp
Added: sandbox/process/libs/process/test/include_top_test_and_main.cpp
Added: sandbox/process/libs/process/test/include_win32_child_test.cpp
Added: sandbox/process/libs/process/test/include_win32_context_test.cpp
Added: sandbox/process/libs/process/test/include_win32_operations_test.cpp
Added: sandbox/process/libs/process/test/launch_base_test.hpp
Added: sandbox/process/libs/process/test/launch_test.cpp
Added: sandbox/process/libs/process/test/misc.hpp
Added: sandbox/process/libs/process/test/pipeline_test.cpp
Added: sandbox/process/libs/process/test/pistream_test.cpp
Added: sandbox/process/libs/process/test/posix_child_test.cpp
Added: sandbox/process/libs/process/test/posix_launch_test.cpp
Added: sandbox/process/libs/process/test/posix_status_test.cpp
Added: sandbox/process/libs/process/test/postream_test.cpp
Added: sandbox/process/libs/process/test/process_base_test.hpp
Added: sandbox/process/libs/process/test/process_test.cpp
Added: sandbox/process/libs/process/test/self_test.cpp
Added: sandbox/process/libs/process/test/shell_test.cpp
Added: sandbox/process/libs/process/test/status_base_test.hpp
Added: sandbox/process/libs/process/test/status_test.cpp
Added: sandbox/process/libs/process/test/stream_behavior_test.cpp
Added: sandbox/process/libs/process/test/win32_child_test.cpp
Added: sandbox/process/libs/process/test/win32_launch_test.cpp
Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/doc/process.xml 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN" "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd">
+<library name="Process" dirname="process" xmlns:xi="http://www.w3.org/2001/XInclude" id="process">
+ <libraryinfo>
+ <orgname>
+ <ulink url="http://www.boost.org/">Boost</ulink>
+ </orgname>
+ <authorgroup>
+ <author>
+ <personname>
+ <firstname>Julio M. Merino</firstname>
+ <surname>Vidal</surname>
+ </personname>
+ <uri type="weblog">http://julipedia.blogspot.com/>
+ </author>
+ <author>
+ <personname>
+ <firstname>Boris</firstname>
+ <surname>Schaeling</surname>
+ </personname>
+ <uri type="website">http://www.highscore.de/>
+ <email>boris_at_[hidden]</email>
+ </author>
+ </authorgroup>
+ <othercredit>
+ <personname>
+ <firstname>Jeff</firstname>
+ <surname>Garland</surname>
+ </personname>
+ <uri type="webpage">http://www.boost.org/people/jeff_garland.html>
+ </othercredit>
+ <copyright>
+ <year>2006</year>
+ <year>2007</year>
+ <holder>Julio M. Merino Vidal</holder>
+ </copyright>
+ <copyright>
+ <year>2008</year>
+ <holder>Boris Schaeling</holder>
+ </copyright>
+ <legalnotice>
+ <para>Use, modification and distribution is subject to the Boost Software License, Version 1.0. (See accompanying file <filename>LICENSE_1_0.txt</filename> or copy at <ulink url="http://www.boost.org/LICENSE_1_0.txt">http://www.boost.org/LICENSE_1_0.txt>)</para>
+ </legalnotice>
+ <librarypurpose>Create, control and communicate with processes</librarypurpose>
+ <librarycategory name="category:misc"/>
+ </libraryinfo>
+ <title>Boost.Process</title>
+ <section id="process.download">
+ <title>Download</title>
+ <para>Boost.Process is not (yet) an official Boost C++ library. It must be downloaded and installed separately. As Boost.Process is header-only the two directories boost and libs in the zip archive only need to be copied to your Boost directory. As Boost.Process has been tested with Boost 1.36.0 this is the minimum version supported.</para>
+ </section>
+ <xi:include href="introduction.xml"/>
+ <xi:include href="design.xml"/>
+ <xi:include href="concepts.xml"/>
+ <xi:include href="tutorials.xml"/>
+ <xi:include href="nonportable_usage.xml"/>
+ <xi:include href="platforms.xml"/>
+ <xi:include href="portability.xml"/>
+ <xi:include href="position.xml"/>
+ <xi:include href="acknowledgements.xml"/>
+</library>
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/doc/tutorials.xml 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN" "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd">
+<section id="process.tutorials" xmlns:xi="http://www.w3.org/2001/XInclude">
+ <title>Tutorials</title>
+ <section id="process.tutorials.start_child">
+ <title>Child.1 - Starting a child</title>
+ <para>The smallest program to start a child consists of specifying the executable name and the arguments, setting up the context and calling a free-standing function to launch the process.</para>
+ <programlisting><xi:include href="../example/start_child.cpp" parse="text"/></programlisting>
+ <para>The header file <filename class="headerfile">boost/process.hpp</filename> can be used to declare easily all classes and functions which are defined by Boost.Process. It simply includes all header files. Instead of including <filename class="headerfile">boost/process.hpp</filename> the program would also compile if the header files <filename class="headerfile">boost/process/context.hpp</filename>, <filename class="headerfile">boost/process/stream_behavior.hpp</filename>, <filename class="headerfile">boost/process/operations.hpp</filename> and <filename class="headerfile">boost/process/child.hpp</filename> would have been included.</para>
+ <para>In order to start a process the executable name and the arguments must be specified and a context must be setup. While the executable name is simply a <code>std::string</code> and arguments are stored in a <code>std::vector<std::string></code> the context is a class from Boost.Process. It provides three properties <varname>stdin_behavior</varname>, <varname>stdout_behavior</varname> and <varname>stderr_behavior</varname> to specify the behavior of the stdin, stdout and stderr streams. By default all streams are closed. If a child should be able to read from or write to some of these streams they need to be configured. Boost.Process provides a few helper functions - among others <function alt="boost::process::silence_stream">silence_stream</function>. With <function alt="boost::process::silence_stream">silence_stream</function> a stream is not closed but all data written to it is discarded. For the program above it means that bjam can print the version number as the stdout stream is available
. However the version number is written to a null device.</para>
+ <para>The free-standing function <function alt="boost::process::launch">launch</function> returns a <classname alt="boost::process::child">child</classname> object. If a parent does not want to communicate with a child nor wait for its termination it can simply forget about it. When the <classname alt="boost::process::child">child</classname> object goes out of scope and is destroyed the parent can not reach the child anymore. However the child may still be running and even might outlive the parent.</para>
+ </section>
+ <section id="process.tutorials.wait_for_child">
+ <title>Child.2 - Waiting for a child to terminate</title>
+ <para>When a child has been started <methodname>wait</methodname> can be called to wait for the child to terminate.</para>
+ <programlisting><xi:include href="../example/wait_for_child.cpp" parse="text"/></programlisting>
+ <para><methodname>wait</methodname> returns a <classname alt="boost::process::status">status</classname> object when the child has terminated. As long as the child is running <methodname>wait</methodname> does not return but blocks.</para>
+ <para>The returned <classname alt="boost::process::status">status</classname> object can be used to check the exit code of the child via <methodname>exit_status</methodname>. Before <methodname>exit_status</methodname> is called though the return value of <methodname>exited</methodname> should be checked to make sure the child exited gracefully. Only if <methodname>exited</methodname> returns <code>true</code> <methodname>exit_status</methodname> may be called.</para>
+ </section>
+ <section id="process.tutorials.read_from_child">
+ <title>Child.3 - Reading from a child with a standard C++ stream</title>
+ <para>Boost.Process can not only be used to start a child and wait for its termination. It also enables a parent to communicate with a child via standard C++ streams.</para>
+ <programlisting><xi:include href="../example/read_from_child.cpp" parse="text"/></programlisting>
+ <para>When a child has been started the stdin, stdout and stderr streams can be fetched by calling <methodname>get_stdin</methodname>, <methodname>get_stdout</methodname> and <methodname>get_stderr</methodname>. As all streams are closed by default it's required to change the behavior of a stream prior to starting a child! If for example the parent wants to read what the child writes to stdout the behavior of the stdout stream must be changed to <function alt="boost::process::capture_stream">capture_stream</function>. Only then the parent can access the stdout stream of the child.</para>
+ <para>While stdout is a stream the child writes data to from the parent's point of view it's an input stream. That's why <methodname>get_stdout</methodname> returns a <classname alt="boost::process::pistream">pistream</classname> object. As <classname alt="boost::process::pistream">pistream</classname> is derived from <code>std::istream</code> it behaves like any other standard C++ stream. The only additional method available in <classname alt="boost::process::pistream">pistream</classname> is <methodname>close</methodname> which can be called to close a stream and notify the child that the parent does not want to read any more data.</para>
+ <para>As <classname alt="boost::process::pistream">pistream</classname> behaves like a standard C++ stream all method calls can block. If the stream buffer is empty and the child doesn't write any data to the stream currently the parent will wait until there is new data written to the stream buffer. If it's not acceptable to block <link linkend="process.tutorials.async_io">asynchronous I/O</link> should be used.</para>
+ </section>
+ <section id="process.tutorials.async_io">
+ <title>Child.4 - Reading from a child using asynchronous I/O</title>
+ <para>While Boost.Process does not support aysynchronous I/O out of the box it provides methods to access the underlying handles of a stream which can be assigned to <libraryname alt="Asio">Boost.Asio</libraryname> objects.</para>
+ <programlisting><xi:include href="../example/async_io.cpp" parse="text"/></programlisting>
+ <para><libraryname alt="Asio">Boost.Asio</libraryname> provides the classes <classname alt="boost::asio::posix::stream_descriptor">stream_descriptor</classname> and <classname alt="boost::asio::windows::stream_handle">stream_handle</classname> to use file descriptors on POSIX platforms and HANDLEs on Windows for asynchronous I/O. By calling <methodname>handle</methodname> an object is returned with owns the underlying handle. In order to access the underlying handle and assign it to a <libraryname alt="Asio">Boost.Asio</libraryname> object <methodname>release</methodname> must be called. Ownership of the underlying handle will be transferred to the caller which means the streams won't be closed when the <classname alt="boost::process::child">child</classname> object goes out of scope.</para>
+ <para>Please note that the macro BOOST_PROCESS_WINDOWS_USE_NAMED_PIPE must be defined for asynchronous I/O to work on Windows platforms. By default streams use anonymous pipes which don't support asynchronous I/O on Windows though. By defining BOOST_PROCESS_WINDOWS_USE_NAMED_PIPE named pipes are used on Windows which support asynchronous I/O.</para>
+ <para>Once the underlying handles have been assigned to <libraryname alt="Asio">Boost.Asio</libraryname> objects asynchronous I/O works like usual. To make sure that the parent waits for the child to write data and does not terminate <methodname>wait</methodname> is called.</para>
+ </section>
+ <section id="process.tutorials.env_empty">
+ <title>Environment.1 - Starting a child with an empty environment</title>
+ <para>When a context is setup the environment table which contains environment variables for the new process can be configured. By default the environment table is empty.</para>
+ <programlisting><xi:include href="../example/empty_environment.cpp" parse="text"/></programlisting>
+ <para>The child started simply writes the environment variables to the stdout stream. As different commands have to be used on POSIX and Windows platforms the macros BOOST_POSIX_API and BOOST_WINDOWS_API are used. They are automatically available when <filename class="headerfile">boost/process.hpp</filename> is included.</para>
+ <para>On POSIX platforms the program <command>env</command> is used to print environment variables. On Windows a built-in shell command has to be used. As the built-in shell command is not a stand-alone executable the free-standing function <function alt="boost::process::launch_shell">launch_shell</function> must be called. This function starts the shell (cmd.exe on Windows) and passes the command as an argument to the shell.</para>
+ <para>When the program is run which reads the data written to stdout by the child no data is received: By default the environment table is empty.</para>
+ </section>
+ <section id="process.tutorials.env_current">
+ <title>Environment.2 - Starting a child with the current environment</title>
+ <para>If a child should see the same environment variables as the parent process the context has to be setup accordingly.</para>
+ <programlisting><xi:include href="../example/current_environment.cpp" parse="text"/></programlisting>
+ <para>By calling <function alt="boost::process::current_environment">current_environment</function> the current environment can be copied to the property <varname>environment</varname> of a context. When the program is run the very same environment variables as seen by the parent are printed.</para>
+ </section>
+ <section id="process.tutorials.env_modified">
+ <title>Environment.3 - Starting a child with a modified environment</title>
+ <para>If a child should not see some environment variables or needs other environment variables to be defined the environment table can be modified.</para>
+ <programlisting><xi:include href="../example/modified_environment.cpp" parse="text"/></programlisting>
+ <para>The property <varname>environment</varname> of the context is a typedef for <code>std::map<std::string, std::string></code>. Thus it's easy to modify the environment table and remove or insert environment variables.</para>
+ </section>
+ <section id="process.tutorials.posix_status">
+ <title>POSIX child.1 - Accessing status codes of a terminated child</title>
+ <para>While <classname alt="boost::process::status">status</classname> is typically used to check the exit status of a terminated child on POSIX platforms the class <classname alt="boost::process::posix_status">posix_status</classname> provides more methods to find out why and how a child terminated.</para>
+ <programlisting><xi:include href="../example/posix_status.cpp" parse="text"/></programlisting>
+ <para>The methods <methodname alt="boost::process::signaled">signaled</methodname> and <methodname alt="boost::process::stopped">stopped</methodname> can be called to check if the process exited due to an external signal or was stopped by an external signal. If they return <literal>true</literal> additional methods can be called to get the signal code.</para>
+ </section>
+ <section id="process.tutorials.posix_communication">
+ <title>POSIX child.2 - Using more than three communication streams</title>
+ <para>On POSIX platforms it's possible to setup more communication streams than stdin, stdout and stderr.</para>
+ <programlisting><xi:include href="../example/posix_communication.cpp" parse="text"/></programlisting>
+ <para>The class <classname alt="boost::process::posix_context">posix_context</classname> provides the properties <varname>input_behavior</varname> and <varname>output_behavior</varname> to add and configure more streams than stdin, stdout and stderr. When started those streams can be accessed by calling <methodname>get_intput</methodname> and <methodname>get_output</methodname> on <classname alt="boost::process::posix_child">posix_child</classname>.</para>
+ </section>
+ <section id="process.tutorials.win32_startup">
+ <title>Windows child.1 - Setting up a context with startup information</title>
+ <para>With <classname alt="boost::process::win32_context">win32_context</classname> it's possible to add a <ulink url="http://msdn.microsoft.com/en-us/library/ms686331(VS.85).aspx">STARTUPINFO</ulink> structure which will be used by <function alt="boost::process::win32_launch">win32_launch</function> to start a Windows process.</para>
+ <programlisting><xi:include href="../example/win32_startup.cpp" parse="text"/></programlisting>
+ <para>The <ulink url="http://msdn.microsoft.com/en-us/library/ms686331(VS.85).aspx">STARTUPINFO</ulink> structure enables developers to specify for example location and size of the main window of the new process.</para>
+ </section>
+ <section id="process.tutorials.win32_child">
+ <title>Windows child.2 - Accessing process and thread identifiers and handles</title>
+ <para>If it's required to access process and thread identifiers and handles on Windows platforms a child should be started with <function alt="boost::process::win32_launch">win32_launch</function>.</para>
+ <programlisting><xi:include href="../example/win32_child.cpp" parse="text"/></programlisting>
+ <para>The function <function alt="boost::process::win32_launch">win32_launch</function> returns a <classname alt="boost::process::win32_child">win32_child</classname> object which provides additional methods to access identifiers and handles of the child's process and primary thread.</para>
+ </section>
+ <section id="process.tutorials.pipeline">
+ <title>Pipeline.1 - Creating children and connecting their streams</title>
+ <para>The library supports creating a so-called pipeline: Children are spawned in a way that an output stream is connected to the input stream of the next child.</para>
+ <programlisting><xi:include href="../example/pipeline.cpp" parse="text"/></programlisting>
+ </section>
+</section>
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/example/async_io.cpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,84 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#if defined(__CYGWIN__)
+# define _WIN32_WINNT 0x0501
+# define __USE_W32_SOCKETS
+# undef BOOST_POSIX_API
+# define BOOST_WINDOWS_API
+#endif
+#include <boost/asio.hpp>
+#define BOOST_PROCESS_WINDOWS_USE_NAMED_PIPE
+#include <boost/process.hpp>
+#include <boost/array.hpp>
+#include <boost/bind.hpp>
+#include <string>
+#include <vector>
+#include <iostream>
+
+namespace bp = ::boost::process;
+namespace ba = ::boost::asio;
+
+ba::io_service io_service;
+boost::array<char, 4096> buffer;
+
+#if defined(BOOST_POSIX_API)
+ba::posix::stream_descriptor in(io_service);
+#elif defined(BOOST_WINDOWS_API)
+ba::windows::stream_handle in(io_service);
+#else
+# error "Unsupported platform."
+#endif
+
+bp::child start_child()
+{
+ std::string exec = "bjam.exe";
+
+ std::vector<std::string> args;
+ args.push_back("bjam.exe");
+ args.push_back("--version");
+
+ bp::context ctx;
+ ctx.stdout_behavior = bp::capture_stream();
+ ctx.environment = bp::self::get_environment();
+
+ return bp::launch(exec, args, ctx);
+}
+
+void end_read(const boost::system::error_code &ec, std::size_t bytes_transferred);
+
+void begin_read()
+{
+ in.async_read_some(boost::asio::buffer(buffer),
+ boost::bind(&end_read, ba::placeholders::error, ba::placeholders::bytes_transferred));
+}
+
+void end_read(const boost::system::error_code &ec, std::size_t bytes_transferred)
+{
+ if (!ec)
+ {
+ std::cout << std::string(buffer.data(), bytes_transferred) << std::flush;
+ begin_read();
+ }
+}
+
+int main()
+{
+ bp::child c = start_child();
+
+ bp::pistream &is = c.get_stdout();
+ in.assign(is.handle().release());
+
+ begin_read();
+ io_service.run();
+
+ c.wait();
+}
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/example/current_environment.cpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,42 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/process.hpp>
+#include <string>
+#include <vector>
+#include <iostream>
+
+namespace bp = ::boost::process;
+
+bp::child start_child(bp::context ctx)
+{
+#if defined(BOOST_POSIX_API)
+ return bp::launch(std::string("env"), std::vector<std::string>(), ctx);
+#elif defined(BOOST_WINDOWS_API)
+ return bp::launch_shell("set", ctx);
+#else
+# error "Unsupported platform."
+#endif
+}
+
+int main()
+{
+ bp::context ctx;
+ ctx.stdout_behavior = bp::capture_stream();
+ ctx.environment = bp::self::get_environment();
+
+ bp::child c = start_child(ctx);
+
+ bp::pistream &is = c.get_stdout();
+ std::string line;
+ while (std::getline(is, line))
+ std::cout << line << std::endl;
+}
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/example/empty_environment.cpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,41 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/process.hpp>
+#include <string>
+#include <vector>
+#include <iostream>
+
+namespace bp = ::boost::process;
+
+bp::child start_child(bp::context ctx)
+{
+#if defined(BOOST_POSIX_API)
+ return bp::launch(std::string("env"), std::vector<std::string>(), ctx);
+#elif defined(BOOST_WINDOWS_API)
+ return bp::launch_shell("set", ctx);
+#else
+# error "Unsupported platform."
+#endif
+}
+
+int main()
+{
+ bp::context ctx;
+ ctx.stdout_behavior = bp::capture_stream();
+
+ bp::child c = start_child(ctx);
+
+ bp::pistream &is = c.get_stdout();
+ std::string line;
+ while (std::getline(is, line))
+ std::cout << line << std::endl;
+}
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/example/modified_environment.cpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,44 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/process.hpp>
+#include <string>
+#include <vector>
+#include <iostream>
+
+namespace bp = ::boost::process;
+
+bp::child start_child(bp::context ctx)
+{
+#if defined(BOOST_POSIX_API)
+ return bp::launch(std::string("env"), std::vector<std::string>(), ctx);
+#elif defined(BOOST_WINDOWS_API)
+ return bp::launch_shell("set", ctx);
+#else
+# error "Unsupported platform."
+#endif
+}
+
+int main()
+{
+ bp::context ctx;
+ ctx.stdout_behavior = bp::capture_stream();
+ ctx.environment = bp::self::get_environment();
+ ctx.environment.erase("TMP");
+ ctx.environment.insert(bp::environment::value_type("MYNEWVAR", "VALUE"));
+
+ bp::child c = start_child(ctx);
+
+ bp::pistream &is = c.get_stdout();
+ std::string line;
+ while (std::getline(is, line))
+ std::cout << line << std::endl;
+}
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/example/pipeline.cpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,88 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/process.hpp>
+#include <string>
+#include <vector>
+#include <iostream>
+#include <fstream>
+#include <cstdlib>
+
+namespace bp = ::boost::process;
+
+bp::children start_children()
+{
+ bp::context ctxin;
+ ctxin.stdin_behavior = bp::capture_stream();
+
+ bp::context ctxout;
+ ctxout.stdout_behavior = bp::inherit_stream();
+ ctxout.stderr_behavior = bp::redirect_stream_to_stdout();
+
+ std::string exec1 = bp::find_executable_in_path("cut");
+ std::vector<std::string> args1;
+ args1.push_back("cut");
+ args1.push_back("-d ");
+ args1.push_back("-f2-5");
+
+ std::string exec2 = bp::find_executable_in_path("sed");
+ std::vector<std::string> args2;
+ args2.push_back("sed");
+ args2.push_back("s,^,line: >>>,");
+
+ std::string exec3 = bp::find_executable_in_path("sed");
+ std::vector<std::string> args3;
+ args3.push_back("sed");
+ args3.push_back("s,$,<<<,");
+
+ std::vector<bp::pipeline_entry> entries;
+ entries.push_back(bp::pipeline_entry(exec1, args1, ctxin));
+ entries.push_back(bp::pipeline_entry(exec2, args2, ctxout));
+ entries.push_back(bp::pipeline_entry(exec3, args3, ctxout));
+
+ return bp::launch_pipeline(entries);
+}
+
+int main(int argc, char *argv[])
+{
+ try
+ {
+ if (argc < 2)
+ {
+ std::cerr << "Please specify a file name" << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ std::ifstream file(argv[1]);
+ if (!file)
+ {
+ std::cerr << "Cannot open file" << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ bp::children cs = start_children();
+
+ bp::postream &os = cs.front().get_stdin();
+ std::string line;
+ while (std::getline(file, line))
+ os << line << std::endl;
+ os.close();
+
+ bp::status s = bp::wait_children(cs);
+
+ return s.exited() ? s.exit_status() : EXIT_FAILURE;
+ }
+ catch (boost::filesystem::filesystem_error &ex)
+ {
+ std::cout << ex.what() << std::endl;
+ return EXIT_FAILURE;
+ }
+}
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/example/posix_communication.cpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,75 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/process.hpp>
+#if defined(BOOST_POSIX_API)
+#include <string>
+#include <vector>
+#include <iostream>
+#include <cstdlib>
+#include <unistd.h>
+
+namespace bp = ::boost::process;
+
+bp::posix_child start_child()
+{
+ std::string exec = bp::find_executable_in_path("dbus-daemon");
+
+ std::vector<std::string> args;
+ args.push_back("dbus-daemon");
+ args.push_back("--fork");
+ args.push_back("--session");
+ args.push_back("--print-address=3");
+ args.push_back("--print-pid=4");
+
+ bp::posix_context ctx;
+ ctx.output_behavior.insert(bp::behavior_map::value_type(STDOUT_FILENO, bp::inherit_stream()));
+ ctx.output_behavior.insert(bp::behavior_map::value_type(STDERR_FILENO, bp::inherit_stream()));
+ ctx.output_behavior.insert(bp::behavior_map::value_type(3, bp::capture_stream()));
+ ctx.output_behavior.insert(bp::behavior_map::value_type(4, bp::capture_stream()));
+
+ return bp::posix_launch(exec, args, ctx);
+}
+
+int main()
+{
+ try
+ {
+ bp::posix_child c = start_child();
+
+ std::string address;
+ pid_t pid;
+ c.get_output(3) >> address;
+ c.get_output(4) >> pid;
+
+ bp::status s = c.wait();
+ if (s.exited())
+ {
+ if (s.exit_status() == EXIT_SUCCESS)
+ {
+ std::cout << "D-BUS daemon's address is: " << address << std::endl;
+ std::cout << "D-BUS daemon's PID is: " << pid << std::endl;
+ }
+ else
+ std::cout << "D-BUS daemon returned error condition: " << s.exit_status() << std::endl;
+ }
+ else
+ std::cout << "D-BUS daemon terminated abnormally" << std::endl;
+
+ return s.exited() ? s.exit_status() : EXIT_FAILURE;
+ }
+ catch (boost::filesystem::filesystem_error &ex)
+ {
+ std::cout << ex.what() << std::endl;
+ return EXIT_FAILURE;
+ }
+}
+#endif
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/example/posix_status.cpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,59 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/process.hpp>
+#if defined(BOOST_POSIX_API)
+#include <string>
+#include <vector>
+#include <iostream>
+#include <cstdlib>
+
+namespace bp = ::boost::process;
+
+bp::child start_child(std::string exec)
+{
+ std::vector<std::string> args;
+
+ bp::context ctx;
+ ctx.stdin_behavior = bp::inherit_stream();
+ ctx.stdout_behavior = bp::inherit_stream();
+ ctx.stderr_behavior = bp::inherit_stream();
+
+ return bp::launch(exec, args, ctx);
+}
+
+int main(int argc, char *argv[])
+{
+ if (argc < 2)
+ {
+ std::cerr << "Please provide a program name" << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ bp::child c = start_child(argv[1]);
+
+ bp::posix_status s = c.wait();
+ if (s.exited())
+ std::cout << "Program returned exit code " << s.exit_status() << std::endl;
+ else if (s.signaled())
+ {
+ std::cout << "Program received signal " << s.term_signal() << std::endl;
+ if (s.dumped_core())
+ std::cout << "Program also dumped core" << std::endl;
+ }
+ else if (s.stopped())
+ std::cout << "Program stopped by signal " << s.stop_signal() << std::endl;
+ else
+ std::cout << "Unknown termination reason" << std::endl;
+
+ return s.exited() ? s.exit_status() : EXIT_FAILURE;
+}
+#endif
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/example/read_from_child.cpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,41 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/process.hpp>
+#include <string>
+#include <vector>
+#include <iostream>
+
+namespace bp = ::boost::process;
+
+bp::child start_child()
+{
+ std::string exec = "bjam";
+
+ std::vector<std::string> args;
+ args.push_back("bjam");
+ args.push_back("--version");
+
+ bp::context ctx;
+ ctx.stdout_behavior = bp::capture_stream();
+
+ return bp::launch(exec, args, ctx);
+}
+
+int main()
+{
+ bp::child c = start_child();
+
+ bp::pistream &is = c.get_stdout();
+ std::string line;
+ while (std::getline(is, line))
+ std::cout << line << std::endl;
+}
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/example/start_child.cpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,30 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/process.hpp>
+#include <string>
+#include <vector>
+
+namespace bp = ::boost::process;
+
+int main()
+{
+ std::string exec = "bjam";
+
+ std::vector<std::string> args;
+ args.push_back("bjam");
+ args.push_back("--version");
+
+ bp::context ctx;
+ ctx.stdout_behavior = bp::silence_stream();
+
+ bp::child c = bp::launch(exec, args, ctx);
+}
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/example/wait_for_child.cpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,39 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/process.hpp>
+#include <string>
+#include <vector>
+
+namespace bp = ::boost::process;
+
+bp::child start_child()
+{
+ std::string exec = "bjam";
+
+ std::vector<std::string> args;
+ args.push_back("bjam");
+ args.push_back("--version");
+
+ bp::context ctx;
+ ctx.stdout_behavior = bp::silence_stream();
+
+ return bp::launch(exec, args, ctx);
+}
+
+int main()
+{
+ bp::child c = start_child();
+
+ bp::status s = c.wait();
+
+ return s.exited() ? s.exit_status() : EXIT_FAILURE;
+}
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/example/win32_child.cpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,54 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/process.hpp>
+#if defined(BOOST_WINDOWS_API)
+#include <string>
+#include <vector>
+#include <iostream>
+#include <windows.h>
+
+namespace bp = ::boost::process;
+
+bp::win32_child start_child()
+{
+ std::string exec = bp::find_executable_in_path("notepad");
+
+ std::vector<std::string> args;
+ args.push_back(bp::executable_to_progname(exec));
+
+ bp::win32_context ctx;
+ ctx.environment = bp::self::get_environment();
+
+ return bp::win32_launch(exec, args, ctx);
+}
+
+int main()
+{
+ try
+ {
+ bp::win32_child c = start_child();
+
+ std::cout << "Process handle : 0x"
+ << c.get_handle() << std::endl;
+ std::cout << "Process identifier : "
+ << c.get_id() << std::endl;
+ std::cout << "Primary thread handle : 0x"
+ << c.get_primary_thread_handle() << std::endl;
+ std::cout << "Primary thread identifier : "
+ << c.get_primary_thread_id() << std::endl;
+ }
+ catch (boost::filesystem::filesystem_error &ex)
+ {
+ std::cout << ex.what() << std::endl;
+ }
+}
+#endif
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/example/win32_startup.cpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,55 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/process.hpp>
+#if defined(BOOST_WINDOWS_API)
+#include <string>
+#include <vector>
+#include <iostream>
+#include <windows.h>
+
+namespace bp = ::boost::process;
+
+bp::win32_child start_child()
+{
+ std::string exec = bp::find_executable_in_path("notepad");
+
+ std::vector<std::string> args;
+ args.push_back(bp::executable_to_progname(exec));
+
+ STARTUPINFOA si;
+ ::ZeroMemory(&si, sizeof(si));
+ si.cb = sizeof(si);
+ si.dwFlags |= STARTF_USEPOSITION | STARTF_USESIZE;
+ si.dwX = 0;
+ si.dwY = 0;
+ si.dwXSize = 640;
+ si.dwYSize = 480;
+
+ bp::win32_context ctx;
+ ctx.startupinfo = &si;
+ ctx.environment = bp::self::get_environment();
+
+ return bp::win32_launch(exec, args, ctx);
+}
+
+int main()
+{
+ try
+ {
+ bp::win32_child c = start_child();
+ }
+ catch (boost::filesystem::filesystem_error &ex)
+ {
+ std::cout << ex.what() << std::endl;
+ }
+}
+#endif
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/test/Jamfile.v2 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,226 @@
+#
+# Boost.Process
+# ~~~~~~~~~~~~~
+#
+# Copyright (c) 2006, 2007 Julio M. Merino Vidal
+# Copyright (c) 2008 Boris Schaeling
+#
+# Distributed under the Boost Software License, Version 1.0. (See accompanying
+# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+#
+
+using testing ;
+
+if ! $(BOOST_ROOT)
+{
+ BOOST_ROOT = [ modules.peek : BOOST_ROOT ] ;
+}
+
+project :
+ : requirements
+ <include>$(BOOST_ROOT)
+ <include>../../..
+ <library>/boost/system//boost_system
+ <library>/boost/test//boost_unit_test_framework
+ <define>BOOST_ALL_NO_LIB
+ <define>BOOST_FILESYSTEM_STATIC_LINK
+ <link>static
+ ;
+
+exe helpers
+ : helpers.cpp
+ : <library>$(BOOST_ROOT)//filesystem
+ ;
+
+test-suite process :
+ [ compile include_child_test.cpp : : ]
+ [ compile include_context_test.cpp : : ]
+ [ compile include_detail_file_handle_test.cpp : : ]
+ [ compile include_detail_pipe_test.cpp : : ]
+ [ compile include_detail_posix_ops_test.cpp : : ]
+ [ compile include_detail_systembuf_test.cpp : : ]
+ [ compile include_detail_win32_ops_test.cpp : : ]
+ [ compile include_environment_test.cpp : : ]
+ [ compile include_operations_test.cpp : : ]
+ [ compile include_pistream_test.cpp : : ]
+ [ compile include_posix_child_test.cpp : : ]
+ [ compile include_posix_context_test.cpp : : ]
+ [ compile include_posix_operations_test.cpp : : ]
+ [ compile include_posix_status_test.cpp : : ]
+ [ compile include_postream_test.cpp : : ]
+ [ compile include_process_test.cpp : : ]
+ [ compile include_self_test.cpp : : ]
+ [ compile include_status_test.cpp : : ]
+ [ compile include_stream_behavior_test.cpp : : ]
+ [ compile include_top_test.cpp : : ]
+ [ compile include_win32_child_test.cpp : : ]
+ [ compile include_win32_context_test.cpp : : ]
+ [ compile include_win32_operations_test.cpp : : ]
+
+ [ run include_top_test_and_main.cpp include_top_test.cpp
+ :
+ :
+ :
+ ]
+
+ [ run arguments_test.cpp
+ :
+ :
+ : <dependency>helpers
+ <library>$(BOOST_ROOT)//unit_test_framework
+ <library>$(BOOST_ROOT)//filesystem
+ ]
+
+ [ run environment_test.cpp
+ :
+ :
+ : <library>$(BOOST_ROOT)//unit_test_framework
+ ]
+
+ [ run detail_systembuf_test.cpp
+ :
+ :
+ : <library>$(BOOST_ROOT)//unit_test_framework
+ ]
+
+ [ run detail_file_handle_test.cpp
+ :
+ :
+ : <library>$(BOOST_ROOT)//unit_test_framework
+ ]
+
+ [ run detail_pipe_test.cpp
+ :
+ :
+ : <library>$(BOOST_ROOT)//unit_test_framework
+ ]
+
+ [ run stream_behavior_test.cpp
+ :
+ :
+ : <dependency>helpers
+ <library>$(BOOST_ROOT)//unit_test_framework
+ ]
+
+ [ run executable_test.cpp
+ :
+ :
+ : <dependency>helpers
+ <library>$(BOOST_ROOT)//unit_test_framework
+ <library>$(BOOST_ROOT)//filesystem
+ ]
+
+ [ run pistream_test.cpp
+ :
+ :
+ : <library>$(BOOST_ROOT)//unit_test_framework
+ ]
+
+ [ run postream_test.cpp
+ :
+ :
+ : <library>$(BOOST_ROOT)//unit_test_framework
+ ]
+
+ [ run process_test.cpp
+ :
+ :
+ : <library>$(BOOST_ROOT)//unit_test_framework
+ <library>$(BOOST_ROOT)//filesystem
+ ]
+
+ [ run self_test.cpp
+ :
+ :
+ : <library>$(BOOST_ROOT)//unit_test_framework
+ ]
+
+ [ run child_test.cpp
+ :
+ :
+ : <library>$(BOOST_ROOT)//unit_test_framework
+ <library>$(BOOST_ROOT)//filesystem
+ ]
+
+ [ run launch_test.cpp
+ :
+ :
+ : <dependency>helpers
+ <library>$(BOOST_ROOT)//unit_test_framework
+ <library>$(BOOST_ROOT)//filesystem
+ ]
+
+ [ run shell_test.cpp
+ :
+ :
+ : <library>$(BOOST_ROOT)//unit_test_framework
+ ]
+
+ [ run status_test.cpp
+ :
+ :
+ : <dependency>helpers
+ <library>$(BOOST_ROOT)//unit_test_framework
+ <library>$(BOOST_ROOT)//filesystem
+ ]
+
+ [ run pipeline_test.cpp
+ :
+ :
+ : <dependency>helpers
+ <library>$(BOOST_ROOT)//unit_test_framework
+ <library>$(BOOST_ROOT)//filesystem
+ ]
+
+ [ run posix_child_test.cpp
+ :
+ :
+ : <library>$(BOOST_ROOT)//unit_test_framework
+ <library>$(BOOST_ROOT)//filesystem
+ ]
+
+ [ run posix_launch_test.cpp
+ :
+ :
+ : <dependency>helpers
+ <library>$(BOOST_ROOT)//unit_test_framework
+ <library>$(BOOST_ROOT)//filesystem
+ ]
+
+ [ run posix_status_test.cpp
+ :
+ :
+ : <dependency>helpers
+ <library>$(BOOST_ROOT)//unit_test_framework
+ <library>$(BOOST_ROOT)//filesystem
+ ]
+
+ [ run win32_child_test.cpp
+ :
+ :
+ : <library>$(BOOST_ROOT)//unit_test_framework
+ <library>$(BOOST_ROOT)//filesystem
+ ]
+
+ [ run win32_launch_test.cpp
+ :
+ :
+ : <dependency>helpers
+ <library>$(BOOST_ROOT)//unit_test_framework
+ <library>$(BOOST_ROOT)//filesystem
+ ]
+
+ [ compile ../example/async_io.cpp : : ]
+ [ compile ../example/current_environment.cpp : : ]
+ [ compile ../example/empty_environment.cpp : : ]
+ [ compile ../example/modified_environment.cpp : : ]
+ [ compile ../example/pipeline.cpp : : ]
+ [ compile ../example/posix_communication.cpp : : ]
+ [ compile ../example/posix_status.cpp : : ]
+ [ compile ../example/read_from_child.cpp : : ]
+ [ compile ../example/start_child.cpp : : ]
+ [ compile ../example/wait_for_child.cpp : : ]
+ [ compile ../example/win32_child.cpp : : ]
+ [ compile ../example/win32_startup.cpp : : ]
+
+ ;
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/test/arguments_test.cpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,143 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/process/config.hpp>
+
+#if defined(BOOST_POSIX_API)
+# include <boost/process/detail/posix_ops.hpp>
+# include <utility>
+# include <cstddef>
+#elif defined(BOOST_WINDOWS_API)
+# include <boost/process/detail/win32_ops.hpp>
+# include <cstring>
+#else
+# error "Unsupported platform."
+#endif
+
+#include "misc.hpp"
+#include <boost/filesystem/operations.hpp>
+#include <boost/process/child.hpp>
+#include <boost/process/context.hpp>
+#include <boost/process/self.hpp>
+#include <boost/process/operations.hpp>
+#include <boost/process/status.hpp>
+#include <boost/test/unit_test.hpp>
+#include <string>
+#include <vector>
+#include <cstdlib>
+
+namespace bfs = ::boost::filesystem;
+namespace bp = ::boost::process;
+namespace bpd = ::boost::process::detail;
+namespace but = ::boost::unit_test;
+
+static std::string get_argument(const std::string &word)
+{
+ std::vector<std::string> args;
+ args.push_back("helpers");
+ args.push_back("echo-quoted");
+ args.push_back(word);
+
+ bp::context ctx;
+ ctx.stdout_behavior = bp::capture_stream();
+ ctx.environment = bp::self::get_environment();
+
+ bp::child c = bp::launch(get_helpers_path(), args, ctx);
+ bp::pistream &is = c.get_stdout();
+
+ std::string result;
+ portable_getline(is, result);
+
+ const bp::status s = c.wait();
+ BOOST_REQUIRE(s.exited());
+ BOOST_CHECK_EQUAL(s.exit_status(), EXIT_SUCCESS);
+
+ return result;
+}
+
+static void test_quoting()
+{
+ BOOST_CHECK_EQUAL(get_argument("foo"), ">>>foo<<<");
+ BOOST_CHECK_EQUAL(get_argument("foo "), ">>>foo <<<");
+ BOOST_CHECK_EQUAL(get_argument(" foo"), ">>> foo<<<");
+ BOOST_CHECK_EQUAL(get_argument("foo bar"), ">>>foo bar<<<");
+
+ BOOST_CHECK_EQUAL(get_argument("foo\"bar"), ">>>foo\"bar<<<");
+ BOOST_CHECK_EQUAL(get_argument("foo\"bar\""), ">>>foo\"bar\"<<<");
+ BOOST_CHECK_EQUAL(get_argument("\"foo\"bar"), ">>>\"foo\"bar<<<");
+ BOOST_CHECK_EQUAL(get_argument("\"foo bar\""), ">>>\"foo bar\"<<<");
+
+ BOOST_CHECK_EQUAL(get_argument("*"), ">>>*<<<");
+ BOOST_CHECK_EQUAL(get_argument("?*"), ">>>?*<<<");
+ BOOST_CHECK_EQUAL(get_argument("[a-z]*"), ">>>[a-z]*<<<");
+}
+
+#if defined(BOOST_POSIX_API)
+static void test_collection_to_posix_argv()
+{
+ std::vector<std::string> args;
+ args.push_back("program");
+ args.push_back("arg1");
+ args.push_back("arg2");
+ args.push_back("arg3");
+
+ std::pair<std::size_t, char**> p = bpd::collection_to_posix_argv(args);
+ std::size_t argc = p.first;
+ char **argv = p.second;
+
+ BOOST_REQUIRE_EQUAL(argc, static_cast<std::size_t>(4));
+
+ BOOST_REQUIRE(std::strcmp(argv[0], "program") == 0);
+ BOOST_REQUIRE(std::strcmp(argv[1], "arg1") == 0);
+ BOOST_REQUIRE(std::strcmp(argv[2], "arg2") == 0);
+ BOOST_REQUIRE(std::strcmp(argv[3], "arg3") == 0);
+ BOOST_REQUIRE(argv[4] == NULL);
+
+ delete[] argv[0];
+ delete[] argv[1];
+ delete[] argv[2];
+ delete[] argv[3];
+ delete[] argv;
+}
+#endif
+
+#if defined(BOOST_WINDOWS_API)
+static void test_collection_to_win32_cmdline()
+{
+ std::vector<std::string> args;
+ args.push_back("program");
+ args.push_back("arg1");
+ args.push_back("arg2");
+ args.push_back("arg3");
+
+ boost::shared_array<char> cmdline =
+ bpd::collection_to_win32_cmdline(args);
+ BOOST_REQUIRE(std::strcmp(cmdline.get(),
+ "program arg1 arg2 arg3") == 0);
+}
+#endif
+
+but::test_suite *init_unit_test_suite(int argc, char *argv[])
+{
+ bfs::initial_path();
+
+ but::test_suite* test = BOOST_TEST_SUITE("arguments test suite");
+
+ test->add(BOOST_TEST_CASE(&test_quoting));
+
+#if defined(BOOST_POSIX_API)
+ test->add(BOOST_TEST_CASE(&test_collection_to_posix_argv));
+#elif defined(BOOST_WINDOWS_API)
+ test->add(BOOST_TEST_CASE(&test_collection_to_win32_cmdline));
+#endif
+
+ return test;
+}
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/test/child_base_test.hpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,111 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include "process_base_test.hpp"
+#include <boost/process/pistream.hpp>
+#include <boost/process/postream.hpp>
+#include <boost/process/detail/pipe.hpp>
+#include <boost/process/detail/file_handle.hpp>
+#include <boost/test/unit_test.hpp>
+#include <string>
+
+namespace bp = ::boost::process;
+namespace bpd = ::boost::process::detail;
+namespace but = ::boost::unit_test;
+
+namespace child_base_test {
+
+//
+// Overview
+// --------
+//
+// The functions below implement tests for the basic Child implementation.
+// In order to ensure appropriate behavior, all implementations must
+// have the same behavior in common public methods; keeping this set of
+// tests generic makes it easy to check this restriction because the tests
+// can easily be applied to any specific Child implementation.
+//
+// Factory concept
+// ---------------
+//
+// The functions in this file all rely on a Factory concept. This concept
+// provides a class whose () operator constructs a new Child instance
+// based on a process's identifier and three file handles, one for each of
+// the standard communication channels. Note that this is the most possible
+// generic construction, which should be conceptually supported by all
+// implementations.
+//
+
+template <class Child, class Factory>
+static void test_stdin()
+{
+ typename Child::id_type id = (typename Child::id_type)0;
+ bpd::pipe p;
+ bpd::file_handle fhinvalid;
+ Child c = Factory()(id, p.wend(), fhinvalid, fhinvalid);
+
+ bp::postream &os = c.get_stdin();
+ os << "test-stdin" << std::endl;
+
+ bp::pistream is(p.rend());
+ std::string word;
+ is >> word;
+ BOOST_CHECK_EQUAL(word, "test-stdin");
+}
+
+template <class Child, class Factory>
+static void test_stdout()
+{
+ typename Child::id_type id = (typename Child::id_type)0;
+ bpd::pipe p;
+ bpd::file_handle fhinvalid;
+ Child c = Factory()(id, fhinvalid, p.rend(), fhinvalid);
+
+ bp::postream os(p.wend());
+ os << "test-stdout" << std::endl;
+
+ bp::pistream &is = c.get_stdout();
+ std::string word;
+ is >> word;
+ BOOST_CHECK_EQUAL(word, "test-stdout");
+}
+
+template <class Child, class Factory>
+static void test_stderr()
+{
+ typename Child::id_type id = (typename Child::id_type)0;
+ bpd::pipe p;
+ bpd::file_handle fhinvalid;
+ Child c = Factory()(id, fhinvalid, fhinvalid, p.rend());
+
+ bp::postream os(p.wend());
+ os << "test-stderr" << std::endl;
+
+ bp::pistream &is = c.get_stderr();
+ std::string word;
+ is >> word;
+ BOOST_CHECK_EQUAL(word, "test-stderr");
+}
+
+} // namespace child_base_test
+
+template <class Child, class Factory>
+void add_tests_child_base(boost::unit_test::test_suite *ts)
+{
+ using namespace child_base_test;
+ using namespace process_base_test;
+
+ add_tests_process_base<Child, Factory>(ts);
+
+ ts->add(BOOST_TEST_CASE(&(test_stdin<Child, Factory>)));
+ ts->add(BOOST_TEST_CASE(&(test_stdout<Child, Factory>)));
+ ts->add(BOOST_TEST_CASE(&(test_stderr<Child, Factory>)));
+}
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/test/child_test.cpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,43 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include "child_base_test.hpp"
+#include <boost/process/child.hpp>
+#include <boost/test/unit_test.hpp>
+
+namespace bp = ::boost::process;
+namespace bpd = ::boost::process::detail;
+namespace but = ::boost::unit_test;
+
+class launcher
+{
+public:
+ bp::child operator()(bp::child::id_type id)
+ {
+ bpd::file_handle fhinvalid;
+ return bp::child(id, fhinvalid, fhinvalid, fhinvalid);
+ }
+
+ bp::child operator()(bp::child::id_type id, bpd::file_handle fhstdin,
+ bpd::file_handle fhstdout, bpd::file_handle fhstderr)
+ {
+ return bp::child(id, fhstdin, fhstdout, fhstderr);
+ }
+};
+
+but::test_suite *init_unit_test_suite(int argc, char *argv[])
+{
+ but::test_suite *test = BOOST_TEST_SUITE("child test suite");
+
+ add_tests_child_base<bp::child, launcher>(test);
+
+ return test;
+}
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/test/detail_file_handle_test.cpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,213 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/process/config.hpp>
+
+#if defined(BOOST_POSIX_API)
+# include <cstdlib>
+# include <cstring>
+# include <unistd.h>
+#elif defined(BOOST_WINDOWS_API)
+# include <windows.h>
+#else
+# error "Unsupported platform."
+#endif
+
+#include <boost/process/detail/file_handle.hpp>
+#include <boost/test/unit_test.hpp>
+#include <iostream>
+
+namespace bp = ::boost::process;
+namespace bpd = ::boost::process::detail;
+namespace but = ::boost::unit_test;
+
+static bpd::file_handle::handle_type get_test_handle()
+{
+#if defined(BOOST_POSIX_API)
+ return STDOUT_FILENO;
+#elif defined(BOOST_WINDOWS_API)
+ HANDLE htest = ::GetStdHandle(STD_OUTPUT_HANDLE);
+ BOOST_REQUIRE(htest != INVALID_HANDLE_VALUE);
+ return htest;
+#endif
+}
+
+static void test_construct()
+{
+ bpd::file_handle fh1;
+ BOOST_CHECK(!fh1.valid());
+
+ bpd::file_handle fh2(get_test_handle());
+ BOOST_CHECK(fh2.valid());
+ fh2.release();
+}
+
+static void test_copy()
+{
+ bpd::file_handle fh1;
+ bpd::file_handle fh2(get_test_handle());
+
+ bpd::file_handle fh3(fh2);
+ BOOST_REQUIRE(!fh2.valid());
+ BOOST_REQUIRE(fh3.valid());
+
+ fh1 = fh3;
+ BOOST_REQUIRE(!fh3.valid());
+ BOOST_REQUIRE(fh1.valid());
+
+ fh1.release();
+}
+
+static void test_get()
+{
+ bpd::file_handle fh1(get_test_handle());
+ BOOST_REQUIRE_EQUAL(fh1.get(), get_test_handle());
+}
+
+#if defined(BOOST_POSIX_API)
+static void test_posix_dup()
+{
+ int pfd[2];
+
+ BOOST_REQUIRE(::pipe(pfd) != -1);
+ bpd::file_handle rend(pfd[0]);
+ bpd::file_handle wend(pfd[1]);
+
+ BOOST_REQUIRE(rend.get() != 10);
+ BOOST_REQUIRE(wend.get() != 10);
+ bpd::file_handle fh1 = bpd::file_handle::posix_dup(wend.get(), 10);
+ BOOST_REQUIRE_EQUAL(fh1.get(), 10);
+
+ BOOST_REQUIRE(::write(wend.get(), "test-posix-dup", 14) != -1);
+ char buf1[15];
+ BOOST_REQUIRE_EQUAL(::read(rend.get(), buf1, sizeof(buf1)), 14);
+ buf1[14] = '\0';
+ BOOST_REQUIRE(std::strcmp(buf1, "test-posix-dup") == 0);
+
+ BOOST_REQUIRE(::write(fh1.get(), "test-posix-dup", 14) != -1);
+ char buf2[15];
+ BOOST_REQUIRE_EQUAL(::read(rend.get(), buf2, sizeof(buf2)), 14);
+ buf2[14] = '\0';
+ BOOST_REQUIRE(std::strcmp(buf2, "test-posix-dup") == 0);
+}
+
+static void test_posix_remap()
+{
+ int pfd[2];
+
+ BOOST_REQUIRE(::pipe(pfd) != -1);
+ bpd::file_handle rend(pfd[0]);
+ bpd::file_handle wend(pfd[1]);
+
+ BOOST_REQUIRE(rend.get() != 10);
+ BOOST_REQUIRE(wend.get() != 10);
+ wend.posix_remap(10);
+ BOOST_REQUIRE_EQUAL(wend.get(), 10);
+ BOOST_REQUIRE(::write(wend.get(), "test-posix-remap", 16) != -1);
+
+ char buf[17];
+ BOOST_REQUIRE_EQUAL(::read(rend.get(), buf, sizeof(buf)), 16);
+ buf[16] = '\0';
+ BOOST_REQUIRE(std::strcmp(buf, "test-posix-remap") == 0);
+}
+#endif
+
+#if defined(BOOST_WINDOWS_API)
+static void test_win32_dup()
+{
+ HANDLE in, out;
+ SECURITY_ATTRIBUTES sa;
+ ZeroMemory(&sa, sizeof(sa));
+ sa.nLength = sizeof(sa);
+ sa.lpSecurityDescriptor = NULL;
+ sa.bInheritHandle = FALSE;
+ BOOST_REQUIRE(::CreatePipe(&in, &out, &sa, 0) != 0);
+ bpd::file_handle rend(in);
+ bpd::file_handle wend(out);
+
+ DWORD flags, rcnt;
+ char buf[15];
+
+ bpd::file_handle out2 = bpd::file_handle::win32_dup(wend.get(), false);
+ BOOST_REQUIRE(::GetHandleInformation(out2.get(), &flags) != 0);
+ BOOST_REQUIRE(!(flags & HANDLE_FLAG_INHERIT));
+
+ bpd::file_handle out3 = bpd::file_handle::win32_dup(wend.get(), true);
+ BOOST_REQUIRE(::GetHandleInformation(out3.get(), &flags) != 0);
+ BOOST_REQUIRE(flags & HANDLE_FLAG_INHERIT);
+
+ BOOST_REQUIRE(::WriteFile(wend.get(), "test-win32-dup", 14, &rcnt,
+ NULL) != 0);
+ BOOST_REQUIRE_EQUAL(rcnt, 14);
+ BOOST_REQUIRE(::ReadFile(rend.get(), buf, sizeof(buf), &rcnt, NULL) != 0);
+ BOOST_REQUIRE_EQUAL(rcnt, 14);
+ buf[14] = '\0';
+ BOOST_REQUIRE(std::strcmp(buf, "test-win32-dup") == 0);
+
+ BOOST_REQUIRE(::WriteFile(out2.get(), "test-win32-dup", 14, &rcnt,
+ NULL) != 0);
+ BOOST_REQUIRE_EQUAL(rcnt, 14);
+ BOOST_REQUIRE(::ReadFile(rend.get(), buf, sizeof(buf), &rcnt, NULL) != 0);
+ BOOST_REQUIRE_EQUAL(rcnt, 14);
+ buf[14] = '\0';
+ BOOST_REQUIRE(std::strcmp(buf, "test-win32-dup") == 0);
+
+ BOOST_REQUIRE(::WriteFile(out3.get(), "test-win32-dup", 14, &rcnt,
+ NULL) != 0);
+ BOOST_REQUIRE_EQUAL(rcnt, 14);
+ BOOST_REQUIRE(::ReadFile(rend.get(), buf, sizeof(buf), &rcnt, NULL) != 0);
+ BOOST_REQUIRE_EQUAL(rcnt, 14);
+ buf[14] = '\0';
+ BOOST_REQUIRE(std::strcmp(buf, "test-win32-dup") == 0);
+}
+
+static void test_win32_set_inheritable()
+{
+ HANDLE in, out;
+ SECURITY_ATTRIBUTES sa;
+ ZeroMemory(&sa, sizeof(sa));
+ sa.nLength = sizeof(sa);
+ sa.lpSecurityDescriptor = NULL;
+ sa.bInheritHandle = FALSE;
+ BOOST_REQUIRE(::CreatePipe(&in, &out, &sa, 0) != 0);
+ bpd::file_handle rend(in);
+ bpd::file_handle wend(out);
+
+ DWORD flags;
+
+ bpd::file_handle out2 = bpd::file_handle::win32_dup(wend.get(), false);
+ BOOST_REQUIRE(::GetHandleInformation(out2.get(), &flags) != 0);
+ BOOST_REQUIRE(!(flags & HANDLE_FLAG_INHERIT));
+
+ bpd::file_handle out3 = bpd::file_handle::win32_dup(wend.get(), true);
+ BOOST_REQUIRE(::GetHandleInformation(out3.get(), &flags) != 0);
+ BOOST_REQUIRE(flags & HANDLE_FLAG_INHERIT);
+}
+#endif
+
+but::test_suite *init_unit_test_suite(int argc, char *argv[])
+{
+ but::test_suite *test = BOOST_TEST_SUITE("detail::file_handle test suite");
+
+ test->add(BOOST_TEST_CASE(&test_construct));
+ test->add(BOOST_TEST_CASE(&test_copy));
+ test->add(BOOST_TEST_CASE(&test_get));
+
+#if defined(BOOST_POSIX_API)
+ test->add(BOOST_TEST_CASE(&test_posix_dup));
+ test->add(BOOST_TEST_CASE(&test_posix_remap));
+#elif defined(BOOST_WINDOWS_API)
+ test->add(BOOST_TEST_CASE(&test_win32_dup));
+ test->add(BOOST_TEST_CASE(&test_win32_set_inheritable));
+#endif
+
+ return test;
+}
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/test/detail_pipe_test.cpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,97 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/process/config.hpp>
+
+#if defined(BOOST_POSIX_API)
+# include <unistd.h>
+#elif defined(BOOST_WINDOWS_API)
+#else
+# error "Unsupported platform."
+#endif
+
+#include <boost/process/detail/pipe.hpp>
+#include <boost/process/detail/systembuf.hpp>
+#include <boost/test/unit_test.hpp>
+#include <iostream>
+#include <string>
+
+namespace bp = ::boost::process;
+namespace bpd = ::boost::process::detail;
+namespace but = ::boost::unit_test;
+
+static void test_read_and_write()
+{
+ bpd::pipe p;
+ bpd::systembuf rbuf(p.rend().get());
+ bpd::systembuf wbuf(p.wend().get());
+ std::istream rend(&rbuf);
+ std::ostream wend(&wbuf);
+
+ // This assumes that the pipe's buffer is big enough to accept
+ // the data written without blocking!
+ wend << "1Test 1message" << std::endl;
+ std::string tmp;
+ rend >> tmp;
+ BOOST_CHECK_EQUAL(tmp, "1Test");
+ rend >> tmp;
+ BOOST_CHECK_EQUAL(tmp, "1message");
+}
+
+#if defined(BOOST_POSIX_API)
+static void test_remap_read()
+{
+ bpd::pipe p;
+ bpd::systembuf wbuf(p.wend().get());
+ std::ostream wend(&wbuf);
+ p.rend().posix_remap(STDIN_FILENO);
+
+ // This assumes that the pipe's buffer is big enough to accept
+ // the data written without blocking!
+ wend << "2Test 2message" << std::endl;
+ std::string tmp;
+ std::cin >> tmp;
+ BOOST_CHECK_EQUAL(tmp, "2Test");
+ std::cin >> tmp;
+ BOOST_CHECK_EQUAL(tmp, "2message");
+}
+
+static void test_remap_write()
+{
+ bpd::pipe p;
+ bpd::systembuf rbuf(p.rend().get());
+ std::istream rend(&rbuf);
+ p.wend().posix_remap(STDOUT_FILENO);
+
+ // This assumes that the pipe's buffer is big enough to accept
+ // the data written without blocking!
+ std::cout << "3Test 3message" << std::endl;
+ std::string tmp;
+ rend >> tmp;
+ BOOST_CHECK_EQUAL(tmp, "3Test");
+ rend >> tmp;
+ BOOST_CHECK_EQUAL(tmp, "3message");
+}
+#endif
+
+but::test_suite *init_unit_test_suite(int argc, char *argv[])
+{
+ but::test_suite *test = BOOST_TEST_SUITE("detail::pipe test suite");
+
+ test->add(BOOST_TEST_CASE(&test_read_and_write));
+
+#if defined(BOOST_POSIX_API)
+ test->add(BOOST_TEST_CASE(&test_remap_read));
+ test->add(BOOST_TEST_CASE(&test_remap_write));
+#endif
+
+ return test;
+}
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/test/detail_systembuf_test.cpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,157 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/process/config.hpp>
+
+#if defined(BOOST_POSIX_API)
+# include <sys/stat.h>
+# include <fcntl.h>
+# include <unistd.h>
+#elif defined(BOOST_WINDOWS_API)
+# include <windows.h>
+#else
+# error "Unsupported platform."
+#endif
+
+#include <boost/process/detail/systembuf.hpp>
+#include <boost/test/unit_test.hpp>
+#include <istream>
+#include <ostream>
+#include <fstream>
+#include <cstddef>
+
+namespace bp = ::boost::process;
+namespace bpd = ::boost::process::detail;
+namespace but = ::boost::unit_test;
+
+static void check_data(std::istream &is, std::size_t length)
+{
+ char ch = 'A', chr;
+ std::size_t cnt = 0;
+ while (is >> chr)
+ {
+ BOOST_CHECK(ch == chr);
+ if (ch == 'Z')
+ ch = 'A';
+ else
+ ++ch;
+ ++cnt;
+ }
+ BOOST_CHECK(cnt == length);
+}
+
+static void write_data(std::ostream &os, std::size_t length)
+{
+ char ch = 'A';
+ for (std::size_t i = 0; i < length; ++i)
+ {
+ os << ch;
+ if (ch == 'Z')
+ ch = 'A';
+ else
+ ++ch;
+ }
+ os.flush();
+}
+
+static void remove_file(const std::string &name)
+{
+#if defined(BOOST_WINDOWS_API)
+ ::DeleteFileA(name.c_str());
+#else
+ ::unlink(name.c_str());
+#endif
+}
+
+static void test_read(std::size_t length, std::size_t bufsize)
+{
+ std::ofstream f("test_read.txt");
+ write_data(f, length);
+ f.close();
+
+#if defined(BOOST_WINDOWS_API)
+ HANDLE hfile = ::CreateFileA("test_read.txt",
+ GENERIC_READ, 0, NULL, OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL, NULL);
+ BOOST_REQUIRE(hfile != INVALID_HANDLE_VALUE);
+ bpd::systembuf sb(hfile, bufsize);
+ std::istream is(&sb);
+ check_data(is, length);
+ ::CloseHandle(hfile);
+#else
+ int fd = ::open("test_read.txt", O_RDONLY);
+ BOOST_CHECK(fd != -1);
+ bpd::systembuf sb(fd, bufsize);
+ std::istream is(&sb);
+ check_data(is, length);
+ ::close(fd);
+#endif
+ remove_file("test_read.txt");
+}
+
+static void test_short_read()
+{
+ test_read(64, 1024);
+}
+
+static void test_long_read()
+{
+ test_read(64 * 1024, 1024);
+}
+
+static void test_write(std::size_t length, std::size_t bufsize)
+{
+#if defined(BOOST_WINDOWS_API)
+ HANDLE hfile = ::CreateFileA("test_write.txt",
+ GENERIC_WRITE, 0, NULL, CREATE_NEW,
+ FILE_ATTRIBUTE_NORMAL, NULL);
+ BOOST_REQUIRE(hfile != INVALID_HANDLE_VALUE);
+ bpd::systembuf sb(hfile, bufsize);
+ std::ostream os(&sb);
+ write_data(os, length);
+ ::CloseHandle(hfile);
+#else
+ int fd = ::open("test_write.txt", O_WRONLY | O_CREAT | O_TRUNC,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ BOOST_CHECK(fd != -1);
+ bpd::systembuf sb(fd, bufsize);
+ std::ostream os(&sb);
+ write_data(os, length);
+ ::close(fd);
+#endif
+
+ std::ifstream is("test_write.txt");
+ check_data(is, length);
+ is.close();
+ remove_file("test_write.txt");
+}
+
+static void test_short_write()
+{
+ test_write(64, 1024);
+}
+
+static void test_long_write()
+{
+ test_write(64 * 1024, 1024);
+}
+
+but::test_suite *init_unit_test_suite(int argc, char *argv[])
+{
+ but::test_suite *test = BOOST_TEST_SUITE("detail::systembuf test suite");
+
+ test->add(BOOST_TEST_CASE(&test_short_read));
+ test->add(BOOST_TEST_CASE(&test_long_read));
+ test->add(BOOST_TEST_CASE(&test_short_write));
+ test->add(BOOST_TEST_CASE(&test_long_write));
+
+ return test;
+}
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/test/environment_test.cpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,145 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/process/config.hpp>
+
+#if defined(BOOST_POSIX_API)
+# include <boost/process/detail/posix_ops.hpp>
+# include <stdlib.h>
+#elif defined(BOOST_WINDOWS_API)
+# include <boost/process/detail/win32_ops.hpp>
+# include <boost/shared_array.hpp>
+# include <cstring>
+# include <windows.h>
+#else
+# error "Unsupported platform."
+#endif
+
+#include <boost/process/environment.hpp>
+#include <boost/process/self.hpp>
+#include <boost/test/unit_test.hpp>
+
+namespace bp = ::boost::process;
+namespace bpd = ::boost::process::detail;
+namespace but = ::boost::unit_test;
+
+static void test_current()
+{
+ bp::environment env1 = bp::self::get_environment();
+ BOOST_CHECK(env1.find("THIS_SHOULD_NOT_BE_DEFINED") == env1.end());
+
+#if defined(BOOST_POSIX_API)
+ BOOST_REQUIRE(::setenv("THIS_SHOULD_BE_DEFINED", "some-value", 1) == 0);
+#elif defined(BOOST_WINDOWS_API)
+ BOOST_REQUIRE(::SetEnvironmentVariable("THIS_SHOULD_BE_DEFINED",
+ "some-value") != 0);
+#endif
+
+ bp::environment env2 = bp::self::get_environment();
+ bp::environment::const_iterator it =
+ env2.find("THIS_SHOULD_BE_DEFINED");
+ BOOST_CHECK(it != env2.end());
+ BOOST_CHECK_EQUAL(it->second, "some-value");
+}
+
+#if defined(BOOST_POSIX_API)
+static void test_envp()
+{
+ bp::environment env;
+ env.insert(bp::environment::value_type("VAR1", "value1"));
+ env.insert(bp::environment::value_type("VAR2", "value2"));
+ env.insert(bp::environment::value_type("VAR3", "value3"));
+
+ char **ep = bpd::environment_to_envp(env);
+
+ BOOST_REQUIRE(ep[0] != NULL);
+ BOOST_REQUIRE_EQUAL(std::string(ep[0]), "VAR1=value1");
+ delete[] ep[0];
+
+ BOOST_REQUIRE(ep[1] != NULL);
+ BOOST_REQUIRE_EQUAL(std::string(ep[1]), "VAR2=value2");
+ delete[] ep[1];
+
+ BOOST_REQUIRE(ep[2] != NULL);
+ BOOST_REQUIRE_EQUAL(std::string(ep[2]), "VAR3=value3");
+ delete[] ep[2];
+
+ BOOST_REQUIRE(ep[3] == NULL);
+ delete[] ep;
+}
+
+static void test_envp_unsorted()
+{
+ bp::environment env;
+ env.insert(bp::environment::value_type("VAR2", "value2"));
+ env.insert(bp::environment::value_type("VAR1", "value1"));
+
+ char **ep = bpd::environment_to_envp(env);
+
+ BOOST_REQUIRE(ep[0] != NULL);
+ BOOST_REQUIRE_EQUAL(std::string(ep[0]), "VAR1=value1");
+ delete[] ep[0];
+
+ BOOST_REQUIRE(ep[1] != NULL);
+ BOOST_REQUIRE_EQUAL(std::string(ep[1]), "VAR2=value2");
+ delete[] ep[1];
+
+ BOOST_REQUIRE(ep[2] == NULL);
+ delete[] ep;
+}
+#endif
+
+#if defined(BOOST_WINDOWS_API)
+static void test_strings()
+{
+ bp::environment env;
+ env.insert(bp::environment::value_type("VAR1", "value1"));
+ env.insert(bp::environment::value_type("VAR2", "value2"));
+ env.insert(bp::environment::value_type("VAR3", "value3"));
+
+ boost::shared_array<char> strs =
+ bpd::environment_to_win32_strings(env);
+ BOOST_REQUIRE(strs.get() != NULL);
+
+ char *expected = "VAR1=value1\0VAR2=value2\0VAR3=value3\0\0";
+ BOOST_REQUIRE(std::memcmp(strs.get(), expected, 37) == 0);
+}
+
+static void test_strings_unsorted()
+{
+ bp::environment env;
+ env.insert(bp::environment::value_type("VAR2", "value2"));
+ env.insert(bp::environment::value_type("VAR1", "value1"));
+
+ boost::shared_array<char> strs =
+ bpd::environment_to_win32_strings(env);
+ BOOST_REQUIRE(strs.get() != NULL);
+
+ char *expected = "VAR1=value1\0VAR2=value2\0\0";
+ BOOST_REQUIRE(std::memcmp(strs.get(), expected, 25) == 0);
+}
+#endif
+
+but::test_suite *init_unit_test_suite(int argc, char *argv[])
+{
+ but::test_suite *test = BOOST_TEST_SUITE("environment test suite");
+
+ test->add(BOOST_TEST_CASE(&test_current));
+#if defined(BOOST_POSIX_API)
+ test->add(BOOST_TEST_CASE(&test_envp));
+ test->add(BOOST_TEST_CASE(&test_envp_unsorted));
+#elif defined(BOOST_WINDOWS_API)
+ test->add(BOOST_TEST_CASE(&test_strings));
+ test->add(BOOST_TEST_CASE(&test_strings_unsorted));
+#endif
+
+ return test;
+}
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/test/executable_test.cpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,123 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/process/config.hpp>
+
+#if defined(BOOST_POSIX_API)
+# include <stdlib.h>
+# if defined(__CYGWIN__)
+# undef BOOST_POSIX_API
+# define BOOST_CYGWIN_PATH
+# endif
+#elif defined(BOOST_WINDOWS_API)
+# include <windows.h>
+#else
+# error "Unsupported platform."
+#endif
+
+#include "misc.hpp"
+#include <boost/process/operations.hpp>
+#include <boost/test/unit_test.hpp>
+#include <string>
+#include <stdexcept>
+
+namespace bfs = ::boost::filesystem;
+namespace bp = ::boost::process;
+namespace but = ::boost::unit_test;
+
+static void test_find_default()
+{
+ std::string helpersname = bfs::path(get_helpers_path()).leaf();
+
+ BOOST_CHECK_THROW(bp::find_executable_in_path(helpersname),
+ boost::filesystem::filesystem_error);
+}
+
+static void test_find_env()
+{
+ bfs::path orig = get_helpers_path();
+ std::string helpersdir = orig.branch_path().string();
+ std::string helpersname = orig.leaf();
+
+#if defined(BOOST_POSIX_API)
+ std::string oldpath = ::getenv("PATH");
+ try
+ {
+ ::setenv("PATH", helpersdir.c_str(), 1);
+ bfs::path found = bp::find_executable_in_path(helpersname);
+ BOOST_CHECK(bfs::equivalent(orig, found));
+ ::setenv("PATH", oldpath.c_str(), 1);
+ }
+ catch (...)
+ {
+ ::setenv("PATH", oldpath.c_str(), 1);
+ }
+#elif defined(BOOST_WINDOWS_API)
+ char oldpath[MAX_PATH];
+ BOOST_REQUIRE(::GetEnvironmentVariableA("PATH", oldpath, MAX_PATH) != 0);
+ try
+ {
+ BOOST_REQUIRE(::SetEnvironmentVariableA("PATH",
+ helpersdir.c_str()) != 0);
+ bfs::path found = bp::find_executable_in_path(helpersname);
+ BOOST_CHECK(bfs::equivalent(orig, found));
+ BOOST_REQUIRE(::SetEnvironmentVariable("PATH", oldpath) != 0);
+ }
+ catch (...)
+ {
+ BOOST_REQUIRE(::SetEnvironmentVariable("PATH", oldpath) != 0);
+ }
+#endif
+}
+
+static void test_find_param()
+{
+ bfs::path orig = get_helpers_path();
+ std::string helpersdir = orig.branch_path().string();
+ std::string helpersname = orig.leaf();
+
+ bfs::path found = bp::find_executable_in_path(helpersname, helpersdir);
+ BOOST_CHECK(bfs::equivalent(orig, found));
+}
+
+static void test_progname()
+{
+ BOOST_CHECK_EQUAL(bp::executable_to_progname("foo"), "foo");
+ BOOST_CHECK_EQUAL(bp::executable_to_progname("/foo"), "foo");
+ BOOST_CHECK_EQUAL(bp::executable_to_progname("/foo/bar"), "bar");
+ BOOST_CHECK_EQUAL(bp::executable_to_progname("///foo///bar"), "bar");
+ BOOST_CHECK_EQUAL(bp::executable_to_progname("/foo/bar/baz"), "baz");
+
+ if (bp_api_type == win32_api)
+ {
+ BOOST_CHECK_EQUAL(bp::executable_to_progname("f.exe"), "f");
+ BOOST_CHECK_EQUAL(bp::executable_to_progname("f.com"), "f");
+ BOOST_CHECK_EQUAL(bp::executable_to_progname("f.bat"), "f");
+ BOOST_CHECK_EQUAL(bp::executable_to_progname("f.bar"), "f.bar");
+ BOOST_CHECK_EQUAL(bp::executable_to_progname("f.bar.exe"), "f.bar");
+ BOOST_CHECK_EQUAL(bp::executable_to_progname("f.bar.com"), "f.bar");
+ BOOST_CHECK_EQUAL(bp::executable_to_progname("f.bar.bat"), "f.bar");
+ }
+}
+
+but::test_suite *init_unit_test_suite(int argc, char *argv[])
+{
+ bfs::initial_path();
+
+ but::test_suite *test = BOOST_TEST_SUITE("executable test suite");
+
+ test->add(BOOST_TEST_CASE(&test_find_default));
+ test->add(BOOST_TEST_CASE(&test_find_env));
+ test->add(BOOST_TEST_CASE(&test_find_param));
+ test->add(BOOST_TEST_CASE(&test_progname));
+
+ return test;
+}
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/test/helpers.cpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,279 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/process/config.hpp>
+
+#if defined(BOOST_POSIX_API)
+# include <stdlib.h>
+#elif defined(BOOST_WINDOWS_API)
+# include <windows.h>
+#else
+# error "Unsupported platform."
+#endif
+
+#include <boost/filesystem/operations.hpp>
+#include <boost/process/detail/systembuf.hpp>
+#include <iostream>
+#include <string>
+#include <cstdlib>
+
+namespace bfs = ::boost::filesystem;
+namespace bpd = ::boost::process::detail;
+
+static int h_echo_quoted(int, char*[]);
+static int h_echo_stdout(int, char*[]);
+static int h_echo_stderr(int, char*[]);
+static int h_echo_stdout_stderr(int, char*[]);
+static int h_exit_failure(int, char*[]);
+static int h_exit_success(int, char*[]);
+static int h_is_closed_stdin(int, char*[]);
+static int h_is_closed_stdout(int, char*[]);
+static int h_is_closed_stderr(int, char*[]);
+static int h_loop(int, char*[]);
+static int h_prefix(int, char*[]);
+static int h_pwd(int, char*[]);
+static int h_query_env(int, char*[]);
+static int h_stdin_to_stdout(int, char*[]);
+
+#if defined(BOOST_POSIX_API)
+static int h_posix_echo_one(int, char*[]);
+static int h_posix_echo_two(int, char*[]);
+#elif defined(BOOST_WINDOWS_API)
+static int h_win32_print_startupinfo(int, char*[]);
+#endif
+
+struct helper
+{
+ const char *name;
+ int (*entry)(int, char*[]);
+ int min_argc;
+ const char *syntax;
+} helpers[] = {
+ { "echo-quoted", h_echo_quoted, 2, "word" },
+ { "echo-stdout", h_echo_stdout, 2, "message" },
+ { "echo-stderr", h_echo_stderr, 2, "message" },
+ { "echo-stdout-stderr", h_echo_stdout_stderr, 2, "message" },
+ { "exit-failure", h_exit_failure, 1, "" },
+ { "exit-success", h_exit_success, 1, "" },
+ { "is-closed-stdin", h_is_closed_stdin, 1, "" },
+ { "is-closed-stdout", h_is_closed_stdout, 1, "" },
+ { "is-closed-stderr", h_is_closed_stderr, 1, "" },
+ { "loop", h_loop, 1, "" },
+ { "prefix", h_prefix, 2, "string" },
+ { "pwd", h_pwd, 1, "" },
+ { "query-env", h_query_env, 2, "variable" },
+ { "stdin-to-stdout", h_stdin_to_stdout, 1, "" },
+
+#if defined(BOOST_POSIX_API)
+ { "posix-echo-one", h_posix_echo_one, 3, "desc message" },
+ { "posix-echo-two", h_posix_echo_two, 4, "desc1 desc2 message" },
+#elif defined(BOOST_WINDOWS_API)
+ { "win32-print-startupinfo", h_win32_print_startupinfo, 1, "" },
+#endif
+
+ { NULL, NULL }
+};
+
+static int h_echo_quoted(int argc, char *argv[])
+{
+ std::cout << ">>>" << argv[1] << "<<<" << std::endl;
+ return EXIT_SUCCESS;
+}
+
+static int h_echo_stdout(int argc, char *argv[])
+{
+ std::cout << argv[1] << std::endl;
+ return EXIT_SUCCESS;
+}
+
+static int h_echo_stderr(int argc, char *argv[])
+{
+ std::cerr << argv[1] << std::endl;
+ return EXIT_SUCCESS;
+}
+
+static int h_echo_stdout_stderr(int argc, char *argv[])
+{
+ std::cout << "stdout " << argv[1] << std::endl;
+ std::cout.flush();
+ std::cerr << "stderr " << argv[1] << std::endl;
+ std::cerr.flush();
+ return EXIT_SUCCESS;
+}
+
+static int h_exit_failure(int argc, char *argv[])
+{
+ return EXIT_FAILURE;
+}
+
+static int h_exit_success(int argc, char *argv[])
+{
+ return EXIT_SUCCESS;
+}
+
+static int h_is_closed_stdin(int argc, char *argv[])
+{
+ std::string word;
+ std::cin >> word;
+ return std::cin.eof() ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
+static int h_is_closed_stdout(int argc, char *argv[])
+{
+ std::cout << "foo" << std::endl;
+ return std::cout.bad() ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
+static int h_is_closed_stderr(int argc, char *argv[])
+{
+ std::cerr << "foo" << std::endl;
+ return std::cerr.bad() ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
+static int h_loop(int argc, char *argv[])
+{
+ for (;;)
+ ;
+
+ return EXIT_SUCCESS;
+}
+
+static int h_prefix(int argc, char *argv[])
+{
+ std::string line;
+ while (std::getline(std::cin, line))
+ std::cout << argv[1] << line << std::endl;
+
+ return EXIT_SUCCESS;
+}
+
+static int h_pwd(int argc, char *argv[])
+{
+ std::cout << bfs::current_path().string() << std::endl;
+ return EXIT_SUCCESS;
+}
+
+static int h_query_env(int argc, char *argv[])
+{
+#if defined(BOOST_WINDOWS_API)
+ char buf[1024];
+ DWORD res = ::GetEnvironmentVariableA(argv[1], buf, sizeof(buf));
+ if (res == 0)
+ std::cout << "undefined" << std::endl;
+ else
+ {
+ std::cout << "defined" << std::endl;
+ std::cout << "'" << buf << "'" << std::endl;
+ }
+#else
+ const char *value = ::getenv(argv[1]);
+ if (value == NULL)
+ std::cout << "undefined" << std::endl;
+ else
+ {
+ std::cout << "defined" << std::endl;
+ std::cout << "'" << value << "'" << std::endl;
+ }
+#endif
+
+ return EXIT_SUCCESS;
+}
+
+static int h_stdin_to_stdout(int argc, char *argv[])
+{
+ char ch;
+ while (std::cin >> ch)
+ std::cout << ch;
+
+ return EXIT_SUCCESS;
+}
+
+#if defined(BOOST_POSIX_API)
+static int h_posix_echo_one(int argc, char *argv[])
+{
+ int desc = ::atoi(argv[1]);
+
+ bpd::systembuf buf(desc);
+ std::ostream os(&buf);
+ os << argv[2] << std::endl;
+
+ return EXIT_SUCCESS;
+}
+
+static int h_posix_echo_two(int argc, char *argv[])
+{
+ int desc1 = ::atoi(argv[1]);
+ int desc2 = ::atoi(argv[2]);
+
+ bpd::systembuf buf1(desc1);
+ std::ostream os1(&buf1);
+ os1 << argv[1] << " " << argv[3] << std::endl;
+ os1.flush();
+
+ bpd::systembuf buf2(desc2);
+ std::ostream os2(&buf2);
+ os2 << argv[2] << " " << argv[3] << std::endl;
+ os2.flush();
+
+ return EXIT_SUCCESS;
+}
+#endif
+
+#if defined(BOOST_WINDOWS_API)
+static int h_win32_print_startupinfo(int argc, char *argv[])
+{
+ STARTUPINFO si;
+ ::GetStartupInfo(&si);
+ std::cout << "dwFlags = " << si.dwFlags << std::endl;
+ std::cout << "dwX = " << si.dwX << std::endl;
+ std::cout << "dwY = " << si.dwY << std::endl;
+ std::cout << "dwXSize = " << si.dwXSize << std::endl;
+ std::cout << "dwYSize = " << si.dwYSize << std::endl;
+
+ return EXIT_SUCCESS;
+}
+#endif
+
+int main(int argc, char *argv[])
+{
+ if (argc < 2)
+ {
+ std::cerr << "helpers: Missing command" << std::endl;
+ return 128;
+ }
+
+ std::string command(argv[1]);
+ --argc;
+ ++argv;
+
+ struct helper *h = helpers;
+ while (h->name != NULL)
+ {
+ if (command == h->name)
+ {
+ int res;
+ if (argc < h->min_argc)
+ {
+ std::cerr << "helpers: Command syntax: `" << command << " "
+ << h->syntax << "'" << std::endl;
+ res = 128;
+ }
+ else
+ res = (*h->entry)(argc, argv);
+ return res;
+ }
+ ++h;
+ }
+
+ std::cerr << "helpers: Invalid command `" << command << "'"
+ << std::endl;
+ return 128;
+}
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/test/include_child_test.cpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,22 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/process/child.hpp>
+
+namespace bp = ::boost::process;
+namespace bpd = ::boost::process::detail;
+
+bp::child *test_it()
+{
+ bp::child::id_type id = static_cast<bp::child::id_type>(0);
+ bpd::file_handle fh;
+ return new bp::child(id, fh, fh, fh);
+}
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/test/include_context_test.cpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,19 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/process/context.hpp>
+
+namespace bp = ::boost::process;
+
+bp::context *test_it()
+{
+ return new bp::context();
+}
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/test/include_detail_file_handle_test.cpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,19 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/process/detail/file_handle.hpp>
+
+namespace bpd = ::boost::process::detail;
+
+bpd::file_handle *test_it()
+{
+ return new bpd::file_handle();
+}
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/test/include_detail_pipe_test.cpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,19 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/process/detail/pipe.hpp>
+
+namespace bpd = ::boost::process::detail;
+
+bpd::pipe *test_it()
+{
+ return new bpd::pipe();
+}
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/test/include_detail_posix_ops_test.cpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,16 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/process/config.hpp>
+
+#if defined(BOOST_POSIX_API)
+# include <boost/process/detail/posix_ops.hpp>
+#endif
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/test/include_detail_systembuf_test.cpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,20 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/process/detail/systembuf.hpp>
+
+namespace bpd = ::boost::process::detail;
+
+bpd::systembuf *test_it()
+{
+ bpd::systembuf::handle_type h = static_cast<bpd::systembuf::handle_type>(0);
+ return new bpd::systembuf(h);
+}
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/test/include_detail_win32_ops_test.cpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,16 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/process/config.hpp>
+
+#if defined(BOOST_WINDOWS_API)
+# include <boost/process/detail/win32_ops.hpp>
+#endif
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/test/include_environment_test.cpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,19 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/process/environment.hpp>
+
+namespace bp = ::boost::process;
+
+bp::environment *test_it()
+{
+ return new bp::environment();
+}
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/test/include_operations_test.cpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,12 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/process/operations.hpp>
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/test/include_pistream_test.cpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,21 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/process/pistream.hpp>
+
+namespace bp = ::boost::process;
+namespace bpd = ::boost::process::detail;
+
+bp::pistream *test_it()
+{
+ bpd::file_handle fh;
+ return new bp::pistream(fh);
+}
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/test/include_posix_child_test.cpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,27 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/process/config.hpp>
+
+#if defined(BOOST_POSIX_API)
+# include <boost/process/posix_child.hpp>
+
+namespace bp = ::boost::process;
+namespace bpd = ::boost::process::detail;
+
+bp::posix_child *test_it()
+{
+ bp::posix_child::id_type id = static_cast<bp::posix_child::id_type>(0);
+ bpd::info_map info;
+ return new bp::posix_child(id, info, info);
+}
+
+#endif
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/test/include_posix_context_test.cpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,24 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/process/config.hpp>
+
+#if defined(BOOST_POSIX_API)
+# include <boost/process/posix_context.hpp>
+
+namespace bp = ::boost::process;
+
+bp::posix_context *test_it()
+{
+ return new bp::posix_context();
+}
+
+#endif
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/test/include_posix_operations_test.cpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,16 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/process/config.hpp>
+
+#if defined(BOOST_POSIX_API)
+# include <boost/process/posix_operations.hpp>
+#endif
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/test/include_posix_status_test.cpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,39 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/process/config.hpp>
+
+#if defined(BOOST_POSIX_API)
+# include <boost/process/posix_status.hpp>
+
+namespace bp = ::boost::process;
+
+namespace boost {
+namespace process {
+
+class child
+{
+public:
+ static bp::posix_status *test_it()
+ {
+ return new bp::posix_status(bp::status(0));
+ }
+};
+
+}
+}
+
+bp::posix_status *test_it()
+{
+ return bp::child::test_it();
+}
+
+#endif
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/test/include_postream_test.cpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,21 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/process/postream.hpp>
+
+namespace bp = ::boost::process;
+namespace bpd = ::boost::process::detail;
+
+bp::postream *test_it()
+{
+ bpd::file_handle fh;
+ return new bp::postream(fh);
+}
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/test/include_process_test.cpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,20 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/process/process.hpp>
+
+namespace bp = ::boost::process;
+
+bp::process *test_it()
+{
+ bp::process::id_type id = static_cast<bp::process::id_type>(0);
+ return new bp::process(id);
+}
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/test/include_self_test.cpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,19 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/process/self.hpp>
+
+namespace bp = ::boost::process;
+
+bp::self *test_it()
+{
+ return &bp::self::get_instance();
+}
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/test/include_status_test.cpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,34 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/process/status.hpp>
+
+namespace bp = ::boost::process;
+
+namespace boost {
+namespace process {
+
+class child
+{
+public:
+ static bp::status *test_it()
+ {
+ return new bp::status(0);
+ }
+};
+
+}
+}
+
+bp::status *test_it()
+{
+ return bp::child::test_it();
+}
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/test/include_stream_behavior_test.cpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,20 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/process/stream_behavior.hpp>
+
+namespace bp = ::boost::process;
+
+bp::stream_behavior *test_it()
+{
+ bp::stream_behavior b = bp::close_stream();
+ return new bp::stream_behavior(b);
+}
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/test/include_top_test.cpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,12 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/process.hpp>
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/test/include_top_test_and_main.cpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,18 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/process.hpp>
+#include <cstdlib>
+
+int main()
+{
+ return EXIT_SUCCESS;
+}
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/test/include_win32_child_test.cpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,27 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/process/config.hpp>
+
+#if defined(BOOST_WINDOWS_API)
+# include <boost/process/win32_child.hpp>
+
+namespace bp = ::boost::process;
+namespace bpd = ::boost::process::detail;
+
+bp::win32_child *test_it()
+{
+ PROCESS_INFORMATION pi;
+ bpd::file_handle fh;
+ return new bp::win32_child(pi, fh, fh, fh);
+}
+
+#endif
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/test/include_win32_context_test.cpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,24 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/process/config.hpp>
+
+#if defined(BOOST_WINDOWS_API)
+# include <boost/process/win32_context.hpp>
+
+namespace bp = ::boost::process;
+
+bp::win32_context *test_it()
+{
+ return new bp::win32_context();
+}
+
+#endif
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/test/include_win32_operations_test.cpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,16 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/process/config.hpp>
+
+#if defined(BOOST_WINDOWS_API)
+# include <boost/process/win32_operations.hpp>
+#endif
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/test/launch_base_test.hpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,391 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/process/config.hpp>
+
+#if defined(BOOST_POSIX_API)
+# include <stdlib.h>
+# if defined(__CYGWIN__)
+# undef BOOST_POSIX_API
+# define BOOST_CYGWIN_PATH
+# endif
+#elif defined(BOOST_WINDOWS_API)
+# include <windows.h>
+#else
+# error "Unsupported platform."
+#endif
+
+#include "misc.hpp"
+#include <boost/process/stream_behavior.hpp>
+#include <boost/process/status.hpp>
+#include <boost/process/pistream.hpp>
+#include <boost/process/postream.hpp>
+#include <boost/process/environment.hpp>
+#include <boost/process/self.hpp>
+#include <boost/test/unit_test.hpp>
+#include <vector>
+#include <string>
+#include <utility>
+#include <cstdlib>
+
+namespace bfs = ::boost::filesystem;
+namespace bp = ::boost::process;
+
+namespace launch_base_test {
+
+//
+// Overview
+// --------
+//
+// The functions below implement tests for common launcher functionality.
+// These are used to test different implementations without duplicating
+// much code.
+//
+// Launcher concept
+// ----------------
+//
+// The functions in this file all rely on a Launcher concept. This concept
+// provides a class whose () operator starts a new process given an
+// executable, its arguments, an execution context and the redirections for
+// the standard streams, and returns a new Child object. The operator also
+// receives a boolean, defaulting to false, that indicates if the child
+// process focuses on testing stdin input. This is needed when testing
+// pipelines to properly place a dummy process in the flow.
+//
+
+template <class Launcher, class Context, class Child>
+static void test_close_stdin()
+{
+ std::vector<std::string> args;
+ args.push_back("helpers");
+ args.push_back("is-closed-stdin");
+
+ const bp::status s1 = Launcher()(args, Context(), bp::close_stream(),
+ bp::close_stream(), bp::close_stream(),
+ true).wait();
+ BOOST_REQUIRE(s1.exited());
+ BOOST_CHECK_EQUAL(s1.exit_status(), EXIT_SUCCESS);
+
+ Child c2 = Launcher()(args, Context(), bp::capture_stream(),
+ bp::close_stream(), bp::close_stream(), true);
+ c2.get_stdin() << "foo" << std::endl;
+ c2.get_stdin().close();
+ const bp::status s2 = c2.wait();
+ BOOST_REQUIRE(s2.exited());
+ BOOST_CHECK_EQUAL(s2.exit_status(), EXIT_FAILURE);
+}
+
+template <class Launcher, class Context, class Child>
+static void test_close_stdout()
+{
+ std::vector<std::string> args;
+ args.push_back("helpers");
+ args.push_back("is-closed-stdout");
+
+ const bp::status s1 = Launcher()(args, Context()).wait();
+ BOOST_REQUIRE(s1.exited());
+ BOOST_CHECK_EQUAL(s1.exit_status(), EXIT_SUCCESS);
+
+ const bp::status s2 = Launcher()(args, Context(), bp::close_stream(),
+ bp::capture_stream()).wait();
+ BOOST_REQUIRE(s2.exited());
+ BOOST_CHECK_EQUAL(s2.exit_status(), EXIT_FAILURE);
+}
+
+template <class Launcher, class Context, class Child>
+static void test_close_stderr()
+{
+ std::vector<std::string> args;
+ args.push_back("helpers");
+ args.push_back("is-closed-stderr");
+
+ const bp::status s1 = Launcher()(args, Context()).wait();
+ BOOST_REQUIRE(s1.exited());
+ BOOST_CHECK_EQUAL(s1.exit_status(), EXIT_SUCCESS);
+
+ const bp::status s2 = Launcher()(args, Context(), bp::close_stream(),
+ bp::close_stream(),
+ bp::capture_stream()).wait();
+ BOOST_REQUIRE(s2.exited());
+ BOOST_CHECK_EQUAL(s2.exit_status(), EXIT_FAILURE);
+}
+
+template <class Launcher, class Context, class Child>
+static void test_input()
+{
+ std::vector<std::string> args;
+ args.push_back("helpers");
+ args.push_back("stdin-to-stdout");
+
+ Child c = Launcher()(args, Context(), bp::capture_stream(),
+ bp::capture_stream());
+
+ bp::postream &os = c.get_stdin();
+ bp::pistream &is = c.get_stdout();
+
+ os << "message-to-process" << std::endl;
+ os.close();
+
+ std::string word;
+ is >> word;
+ BOOST_CHECK_EQUAL(word, "message-to-process");
+
+ const bp::status s = c.wait();
+ BOOST_REQUIRE(s.exited());
+ BOOST_CHECK_EQUAL(s.exit_status(), EXIT_SUCCESS);
+}
+
+template <class Launcher, class Context, class Child>
+static void test_output(bool out, const std::string &msg)
+{
+ std::vector<std::string> args;
+ args.push_back("helpers");
+ args.push_back(out ? "echo-stdout" : "echo-stderr");
+ args.push_back(msg);
+
+ Child c = Launcher()(args, Context(), bp::close_stream(),
+ out ? bp::capture_stream() : bp::close_stream(),
+ out ? bp::close_stream() : bp::capture_stream());
+
+ std::string word;
+ if (out)
+ {
+ bp::pistream &is = c.get_stdout();
+ is >> word;
+ }
+ else
+ {
+ bp::pistream &is = c.get_stderr();
+ is >> word;
+ }
+ BOOST_CHECK_EQUAL(word, msg);
+
+ const bp::status s = c.wait();
+ BOOST_REQUIRE(s.exited());
+ BOOST_CHECK_EQUAL(s.exit_status(), EXIT_SUCCESS);
+}
+
+template <class Launcher, class Context, class Child>
+static void test_stderr()
+{
+ test_output<Launcher, Context, Child>(false, "message1-stderr");
+ test_output<Launcher, Context, Child>(false, "message2-stderr");
+}
+
+template <class Launcher, class Context, class Child>
+static void test_stdout()
+{
+ test_output<Launcher, Context, Child>(true, "message1-stdout");
+ test_output<Launcher, Context, Child>(true, "message2-stdout");
+}
+
+template <class Launcher, class Context, class Child>
+static void test_redirect_err_to_out()
+{
+ std::vector<std::string> args;
+ args.push_back("helpers");
+ args.push_back("echo-stdout-stderr");
+ args.push_back("message-to-two-streams");
+
+ Child c = Launcher()(args, Context(), bp::close_stream(),
+ bp::capture_stream(),
+ bp::redirect_stream_to_stdout());
+
+ bp::pistream &is = c.get_stdout();
+ std::string word;
+ is >> word;
+ BOOST_CHECK_EQUAL(word, "stdout");
+ is >> word;
+ BOOST_CHECK_EQUAL(word, "message-to-two-streams");
+ is >> word;
+ BOOST_CHECK_EQUAL(word, "stderr");
+ is >> word;
+ BOOST_CHECK_EQUAL(word, "message-to-two-streams");
+
+ const bp::status s = c.wait();
+ BOOST_REQUIRE(s.exited());
+ BOOST_CHECK_EQUAL(s.exit_status(), EXIT_SUCCESS);
+}
+
+template <class Launcher, class Context, class Child>
+static void check_work_directory(const std::string &wdir)
+{
+ std::vector<std::string> args;
+ args.push_back("helpers");
+ args.push_back("pwd");
+
+ Context ctx;
+ if (wdir.empty())
+ BOOST_CHECK(bfs::equivalent(ctx.work_directory,
+ bfs::current_path().string()));
+ else
+ ctx.work_directory = wdir;
+ Child c = Launcher()(args, ctx, bp::close_stream(),
+ bp::capture_stream());
+
+ bp::pistream &is = c.get_stdout();
+ std::string dir;
+ portable_getline(is, dir);
+
+ const bp::status s = c.wait();
+ BOOST_REQUIRE(s.exited());
+ BOOST_REQUIRE_EQUAL(s.exit_status(), EXIT_SUCCESS);
+
+ BOOST_CHECK_EQUAL(bfs::path(dir), bfs::path(ctx.work_directory));
+}
+
+template <class Launcher, class Context, class Child>
+static void test_work_directory()
+{
+ check_work_directory<Launcher, Context, Child>("");
+
+ bfs::path wdir = bfs::current_path() / "test.dir";
+ BOOST_REQUIRE_NO_THROW(bfs::create_directory(wdir));
+ try
+ {
+ check_work_directory<Launcher, Context, Child>(wdir.string());
+ BOOST_CHECK_NO_THROW(bfs::remove_all(wdir));
+ }
+ catch (...)
+ {
+ BOOST_CHECK_NO_THROW(bfs::remove_all(wdir));
+ throw;
+ }
+}
+
+template <class Launcher, class Context, class Child>
+static std::pair<bool, std::string> get_var_value(Context &ctx, const std::string &var)
+{
+ std::vector<std::string> args;
+ args.push_back("helpers");
+ args.push_back("query-env");
+ args.push_back(var);
+
+ Child c = Launcher()(args, ctx, bp::close_stream(),
+ bp::capture_stream());
+
+ bp::pistream &is = c.get_stdout();
+ std::string status;
+ is >> status;
+ std::string gotval;
+ if (status == "defined")
+ is >> gotval;
+
+ const bp::status s = c.wait();
+ BOOST_REQUIRE(s.exited());
+ BOOST_REQUIRE_EQUAL(s.exit_status(), EXIT_SUCCESS);
+
+ return std::pair<bool, std::string>(status == "defined", gotval);
+}
+
+template <class Launcher, class Context, class Child>
+static void test_clear_environment()
+{
+ Context ctx;
+ BOOST_REQUIRE_EQUAL(ctx.environment.size(),
+ static_cast<bp::environment::size_type>(0));
+ ctx.environment = bp::self::get_environment();
+ ctx.environment.erase("TO_BE_QUERIED");
+
+#if defined(BOOST_POSIX_API)
+ BOOST_REQUIRE(::setenv("TO_BE_QUERIED", "test", 1) != -1);
+ BOOST_REQUIRE(::getenv("TO_BE_QUERIED") != 0);
+#elif defined(BOOST_WINDOWS_API)
+ BOOST_REQUIRE(::SetEnvironmentVariableA("TO_BE_QUERIED", "test") != 0);
+ char buf[5];
+ BOOST_REQUIRE(::GetEnvironmentVariableA("TO_BE_QUERIED", buf, 5) == 4);
+#endif
+
+ std::pair<bool, std::string> p =
+ get_var_value<Launcher, Context, Child>(ctx, "TO_BE_QUERIED");
+ BOOST_REQUIRE(!p.first);
+}
+
+template <class Launcher, class Context, class Child>
+static void test_unset_environment()
+{
+ std::vector<std::string> args;
+ args.push_back("helpers");
+ args.push_back("query-env");
+ args.push_back("TO_BE_UNSET");
+
+#if defined(BOOST_POSIX_API)
+ BOOST_REQUIRE(::setenv("TO_BE_UNSET", "test", 1) != -1);
+ BOOST_REQUIRE(::getenv("TO_BE_UNSET") != 0);
+#elif defined(BOOST_WINDOWS_API)
+ BOOST_REQUIRE(::SetEnvironmentVariableA("TO_BE_UNSET", "test") != 0);
+ char buf[5];
+ BOOST_REQUIRE(::GetEnvironmentVariableA("TO_BE_UNSET", buf, 5) == 4);
+#endif
+
+ Context ctx;
+ ctx.environment = bp::self::get_environment();
+ ctx.environment.erase("TO_BE_UNSET");
+ std::pair<bool, std::string> p =
+ get_var_value<Launcher, Context, Child>(ctx, "TO_BE_SET");
+ BOOST_CHECK(!p.first);
+}
+
+template <class Launcher, class Context, class Child>
+static void test_set_environment_var(const std::string &value)
+{
+ std::vector<std::string> args;
+ args.push_back("helpers");
+ args.push_back("query-env");
+ args.push_back("TO_BE_SET");
+
+#if defined(BOOST_POSIX_API)
+ ::unsetenv("TO_BE_SET");
+ BOOST_REQUIRE(::getenv("TO_BE_SET") == 0);
+#elif defined(BOOST_WINDOWS_API)
+ char buf[5];
+ BOOST_REQUIRE(::GetEnvironmentVariableA("TO_BE_SET", buf, 5) == 0 ||
+ ::SetEnvironmentVariableA("TO_BE_SET", NULL) != 0);
+ BOOST_REQUIRE(::GetEnvironmentVariableA("TO_BE_SET", buf, 5) == 0);
+#endif
+
+ Context ctx;
+ ctx.environment = bp::self::get_environment();
+ ctx.environment.insert(bp::environment::value_type("TO_BE_SET", value));
+ std::pair<bool, std::string> p =
+ get_var_value<Launcher, Context, Child>(ctx, "TO_BE_SET");
+ BOOST_CHECK(p.first);
+ BOOST_CHECK_EQUAL(p.second, "'" + value + "'");
+}
+
+template <class Launcher, class Context, class Child>
+static void test_set_environment()
+{
+ if (bp_api_type == posix_api)
+ test_set_environment_var<Launcher, Context, Child>("");
+ test_set_environment_var<Launcher, Context, Child>("some-value-1");
+ test_set_environment_var<Launcher, Context, Child>("some-value-2");
+}
+
+}
+
+template <class Launcher, class Context, class Child>
+void add_tests_launch_base(boost::unit_test::test_suite *ts)
+{
+ using namespace launch_base_test;
+
+ ts->add(BOOST_TEST_CASE(&(test_close_stdin<Launcher, Context, Child>)), 0, 10);
+ ts->add(BOOST_TEST_CASE(&(test_close_stdout<Launcher, Context, Child>)), 0, 10);
+ ts->add(BOOST_TEST_CASE(&(test_close_stderr<Launcher, Context, Child>)), 0, 10);
+ ts->add(BOOST_TEST_CASE(&(test_stdout<Launcher, Context, Child>)), 0, 10);
+ ts->add(BOOST_TEST_CASE(&(test_stderr<Launcher, Context, Child>)), 0, 10);
+ ts->add(BOOST_TEST_CASE(&(test_redirect_err_to_out<Launcher, Context, Child>)), 0, 10);
+ ts->add(BOOST_TEST_CASE(&(test_input<Launcher, Context, Child>)), 0, 10);
+ ts->add(BOOST_TEST_CASE(&(test_work_directory<Launcher, Context, Child>)), 0, 10);
+ ts->add(BOOST_TEST_CASE(&(test_clear_environment<Launcher, Context, Child>)), 0, 10);
+ ts->add(BOOST_TEST_CASE(&(test_unset_environment<Launcher, Context, Child>)), 0, 10);
+ ts->add(BOOST_TEST_CASE(&(test_set_environment<Launcher, Context, Child>)), 0, 10);
+}
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/test/launch_test.cpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,58 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include "launch_base_test.hpp"
+#include <boost/process/child.hpp>
+#include <boost/process/self.hpp>
+#include <boost/process/context.hpp>
+#include <boost/process/stream_behavior.hpp>
+#include <boost/process/operations.hpp>
+#include <boost/filesystem/operations.hpp>
+#include <boost/test/unit_test.hpp>
+#include <vector>
+#include <string>
+
+namespace bfs = ::boost::filesystem;
+namespace bp = ::boost::process;
+namespace but = ::boost::unit_test;
+
+class launcher
+{
+public:
+ bp::child operator()(const std::vector<std::string> args,
+ bp::context ctx,
+ bp::stream_behavior bstdin = bp::close_stream(),
+ bp::stream_behavior bstdout = bp::close_stream(),
+ bp::stream_behavior bstderr = bp::close_stream(),
+ bool usein = false)
+ const
+ {
+ ctx.stdin_behavior = bstdin;
+ ctx.stdout_behavior = bstdout;
+ ctx.stderr_behavior = bstderr;
+
+ if (ctx.environment.empty())
+ ctx.environment = bp::self::get_environment();
+
+ return bp::launch(get_helpers_path(), args, ctx);
+ }
+};
+
+but::test_suite *init_unit_test_suite(int argc, char *argv[])
+{
+ bfs::initial_path();
+
+ but::test_suite *test = BOOST_TEST_SUITE("launch test suite");
+
+ add_tests_launch_base<launcher, bp::context, bp::child>(test);
+
+ return test;
+}
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/test/misc.hpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,69 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/process/config.hpp>
+
+#if defined(BOOST_POSIX_API)
+# if defined(__CYGWIN__)
+# undef BOOST_POSIX_API
+# define BOOST_CYGWIN_PATH
+# endif
+#endif
+
+#include <boost/filesystem/operations.hpp>
+#include <boost/filesystem/path.hpp>
+#include <boost/test/unit_test.hpp>
+#include <string>
+#include <istream>
+
+enum bp_api_type {
+ posix_api,
+ win32_api
+}
+#if defined(BOOST_POSIX_API)
+bp_api_type = posix_api;
+#elif defined(BOOST_WINDOWS_API)
+bp_api_type = win32_api;
+#else
+# error "Unsupported platform."
+#endif
+
+inline std::string get_helpers_path()
+{
+ boost::filesystem::path hp = boost::filesystem::initial_path();
+
+#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
+ hp /= "../../../bin.v2/libs/process/test/msvc-9.0/debug/link-static/helpers.exe";
+#elif defined(sun) || defined(__sun)
+# if defined(__GNUG__)
+ hp /= "../../../bin.v2/libs/process/test/gcc-3.4.6/debug/link-static/helpers";
+# elif defined(__SUNPRO_CC)
+ hp /= "../../../bin.v2/libs/process/test/sun/debug/link-static/stdlib-sun-stlport/helpers";
+# endif
+#elif defined(__CYGWIN__)
+ hp /= "../../../bin.v2/libs/process/test/gcc-3.4.4/debug/link-static/helpers.exe";
+#elif defined(__APPLE__)
+ hp /= "../../../bin.v2/libs/process/test/darwin/debug/link-static/helpers";
+#endif
+
+ BOOST_REQUIRE_MESSAGE(boost::filesystem::exists(hp), hp.string() + " not found");
+
+ return hp.string();
+}
+
+inline std::istream &portable_getline(std::istream &is, std::string &str)
+{
+ std::getline(is, str);
+ std::string::size_type pos = str.rfind('\r');
+ if (pos != std::string::npos)
+ str.erase(pos);
+ return is;
+}
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/test/pipeline_test.cpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,238 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include "launch_base_test.hpp"
+#include <boost/process/child.hpp>
+#include <boost/process/self.hpp>
+#include <boost/process/pistream.hpp>
+#include <boost/process/postream.hpp>
+#include <boost/process/context.hpp>
+#include <boost/process/stream_behavior.hpp>
+#include <boost/process/operations.hpp>
+#include <boost/filesystem/operations.hpp>
+#include <boost/test/unit_test.hpp>
+#include <vector>
+#include <string>
+#include <cstdlib>
+
+namespace bfs = ::boost::filesystem;
+namespace bp = ::boost::process;
+namespace but = ::boost::unit_test;
+
+class children_to_child
+{
+public:
+ children_to_child(bp::children cs)
+ : cs_(cs)
+ {
+ }
+
+ bp::postream &get_stdin() const
+ {
+ return cs_.front().get_stdin();
+ }
+
+ bp::pistream &get_stdout() const
+ {
+ return cs_.back().get_stdout();
+ }
+
+ bp::pistream &get_stderr() const
+ {
+ return cs_.back().get_stderr();
+ }
+
+ const bp::status wait()
+ {
+ return wait_children(cs_);
+ }
+
+private:
+ bp::children cs_;
+};
+
+class launcher
+{
+public:
+ children_to_child operator()(const std::vector<std::string> args,
+ bp::context ctx,
+ bp::stream_behavior bstdin = bp::close_stream(),
+ bp::stream_behavior bstdout = bp::close_stream(),
+ bp::stream_behavior bstderr = bp::close_stream(),
+ bool usein = false)
+ const
+ {
+ std::vector<std::string> dummy;
+ dummy.push_back("helpers");
+ dummy.push_back("stdin-to-stdout");
+
+ if (ctx.environment.empty())
+ ctx.environment = bp::self::get_environment();
+
+ bp::context ctx1(ctx);
+ ctx1.stdin_behavior = bstdin;
+
+ bp::context ctx2(ctx);
+ ctx2.stdout_behavior = bstdout;
+ ctx2.stderr_behavior = bstderr;
+
+ std::vector<bp::pipeline_entry> entries;
+
+ if (usein)
+ {
+ entries.push_back(bp::pipeline_entry(get_helpers_path(),
+ args, ctx1));
+ entries.push_back(bp::pipeline_entry(get_helpers_path(),
+ dummy, ctx2));
+ }
+ else
+ {
+ entries.push_back(bp::pipeline_entry(get_helpers_path(),
+ dummy, ctx1));
+ entries.push_back(bp::pipeline_entry(get_helpers_path(),
+ args, ctx2));
+ }
+ return launch_pipeline(entries);
+ }
+};
+
+static void test_exit(const std::string &middle, int value)
+{
+ std::vector<std::string> args1;
+ args1.push_back("helpers");
+ args1.push_back("exit-success");
+
+ std::vector<std::string> args2;
+ args2.push_back("helpers");
+ args2.push_back(middle);
+
+ std::vector<std::string> args3;
+ args3.push_back("helpers");
+ args3.push_back("exit-success");
+
+ bp::context ctx;
+ ctx.environment = bp::self::get_environment();
+
+ std::vector<bp::pipeline_entry> entries;
+ entries.push_back(bp::pipeline_entry(get_helpers_path(), args1, ctx));
+ entries.push_back(bp::pipeline_entry(get_helpers_path(), args2, ctx));
+ entries.push_back(bp::pipeline_entry(get_helpers_path(), args3, ctx));
+ bp::children cs = bp::launch_pipeline(entries);
+
+ BOOST_REQUIRE(cs.size() == 3);
+
+ const bp::status s = bp::wait_children(cs);
+ BOOST_REQUIRE(s.exited());
+ BOOST_CHECK_EQUAL(s.exit_status(), value);
+}
+
+static void test_exit_failure()
+{
+ test_exit("exit-failure", EXIT_FAILURE);
+}
+
+static void test_exit_success()
+{
+ test_exit("exit-success", EXIT_SUCCESS);
+}
+
+static void test_simple()
+{
+ std::vector<std::string> args1;
+ args1.push_back("helpers");
+ args1.push_back("prefix");
+ args1.push_back("proc1-");
+
+ std::vector<std::string> args2;
+ args2.push_back("helpers");
+ args2.push_back("prefix");
+ args2.push_back("proc2-");
+
+ bp::context ctxin;
+ ctxin.stdin_behavior = bp::capture_stream();
+ ctxin.environment = bp::self::get_environment();
+
+ bp::context ctxout;
+ ctxout.stdout_behavior = bp::capture_stream();
+ ctxout.environment = bp::self::get_environment();
+
+ std::vector<bp::pipeline_entry> entries;
+ entries.push_back(bp::pipeline_entry(get_helpers_path(), args1, ctxin));
+ entries.push_back(bp::pipeline_entry(get_helpers_path(), args2, ctxout));
+ bp::children cs = bp::launch_pipeline(entries);
+
+ BOOST_REQUIRE(cs.size() == 2);
+
+ cs[0].get_stdin() << "message" << std::endl;
+ cs[0].get_stdin().close();
+
+ std::string word;
+ cs[1].get_stdout() >> word;
+ BOOST_CHECK_EQUAL(word, "proc2-proc1-message");
+
+ const bp::status s = bp::wait_children(cs);
+ BOOST_REQUIRE(s.exited());
+ BOOST_CHECK_EQUAL(s.exit_status(), EXIT_SUCCESS);
+}
+
+static void test_merge_first()
+{
+ std::vector<std::string> args1;
+ args1.push_back("helpers");
+ args1.push_back("echo-stdout-stderr");
+ args1.push_back("message");
+
+ std::vector<std::string> args2;
+ args2.push_back("helpers");
+ args2.push_back("prefix");
+ args2.push_back("second:");
+
+ bp::context ctxin;
+ ctxin.stderr_behavior = bp::redirect_stream_to_stdout();
+ ctxin.environment = bp::self::get_environment();
+
+ bp::context ctxout;
+ ctxout.stdout_behavior = bp::capture_stream();
+ ctxout.environment = bp::self::get_environment();
+
+ std::vector<bp::pipeline_entry> entries;
+ entries.push_back(bp::pipeline_entry(get_helpers_path(), args1, ctxin));
+ entries.push_back(bp::pipeline_entry(get_helpers_path(), args2, ctxout));
+ bp::children cs = bp::launch_pipeline(entries);
+
+ BOOST_REQUIRE(cs.size() == 2);
+
+ std::string line;
+ portable_getline(cs[1].get_stdout(), line);
+ BOOST_CHECK_EQUAL(line, "second:stdout message");
+ portable_getline(cs[1].get_stdout(), line);
+ BOOST_CHECK_EQUAL(line, "second:stderr message");
+
+ const bp::status s = bp::wait_children(cs);
+ BOOST_REQUIRE(s.exited());
+ BOOST_CHECK_EQUAL(s.exit_status(), EXIT_SUCCESS);
+}
+
+but::test_suite *init_unit_test_suite(int argc, char *argv[])
+{
+ bfs::initial_path();
+
+ but::test_suite *test = BOOST_TEST_SUITE("pipeline test suite");
+
+ add_tests_launch_base<launcher, bp::context, children_to_child>(test);
+
+ test->add(BOOST_TEST_CASE(&test_exit_success), 0, 10);
+ test->add(BOOST_TEST_CASE(&test_exit_failure), 0, 10);
+ test->add(BOOST_TEST_CASE(&test_simple), 0, 10);
+ test->add(BOOST_TEST_CASE(&test_merge_first), 0, 10);
+
+ return test;
+}
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/test/pistream_test.cpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,47 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/process/pistream.hpp>
+#include <boost/process/detail/pipe.hpp>
+#include <boost/process/detail/systembuf.hpp>
+#include <boost/test/unit_test.hpp>
+#include <ostream>
+#include <string>
+
+namespace bp = ::boost::process;
+namespace bpd = ::boost::process::detail;
+namespace but = ::boost::unit_test;
+
+static void test_it()
+{
+ bpd::pipe p;
+ bp::pistream rend(p.rend());
+ bpd::systembuf wbuf(p.wend().get());
+ std::ostream wend(&wbuf);
+
+ // This assumes that the pipe's buffer is big enough to accept
+ // the data written without blocking!
+ wend << "1Test 1message" << std::endl;
+ std::string tmp;
+ rend >> tmp;
+ BOOST_CHECK_EQUAL(tmp, "1Test");
+ rend >> tmp;
+ BOOST_CHECK_EQUAL(tmp, "1message");
+}
+
+but::test_suite *init_unit_test_suite(int argc, char *argv[])
+{
+ but::test_suite *test = BOOST_TEST_SUITE("pistream test suite");
+
+ test->add(BOOST_TEST_CASE(&test_it));
+
+ return test;
+}
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/test/posix_child_test.cpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,99 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/process/config.hpp>
+
+#if defined(BOOST_POSIX_API)
+# include "child_base_test.hpp"
+# include <boost/process/posix_child.hpp>
+# include <boost/process/stream_behavior.hpp>
+# include <boost/process/detail/posix_ops.hpp>
+# include <boost/process/detail/file_handle.hpp>
+# include <unistd.h>
+
+namespace bp = ::boost::process;
+namespace bpd = ::boost::process::detail;
+#endif
+
+#include <boost/test/unit_test.hpp>
+
+namespace but = ::boost::unit_test;
+
+#if defined(BOOST_POSIX_API)
+namespace boost {
+namespace process {
+
+class posix_launcher
+{
+public:
+ bp::posix_child operator()(bp::posix_child::id_type id)
+ {
+ bpd::info_map infoin, infoout;
+
+ return bp::posix_child(id, infoin, infoout);
+ }
+
+ bp::posix_child operator()(bp::posix_child::id_type id, bpd::file_handle fhstdin,
+ bpd::file_handle fhstdout, bpd::file_handle fhstderr)
+ {
+ bpd::info_map infoin, infoout;
+ bp::stream_behavior withpipe = bp::capture_stream();
+
+ if (fhstdin.valid())
+ {
+ bpd::stream_info si(withpipe, false);
+ si.pipe_->rend().close();
+ si.pipe_->wend() = fhstdin;
+ infoin.insert(bpd::info_map::value_type(STDIN_FILENO, si));
+ }
+
+ if (fhstdout.valid())
+ {
+ bpd::stream_info si(withpipe, true);
+ si.pipe_->wend().close();
+ si.pipe_->rend() = fhstdout;
+ infoout.insert(bpd::info_map::value_type(STDOUT_FILENO, si));
+ }
+
+ if (fhstderr.valid())
+ {
+ bpd::stream_info si(withpipe, true);
+ si.pipe_->wend().close();
+ si.pipe_->rend() = fhstderr;
+ infoout.insert(bpd::info_map::value_type(STDERR_FILENO, si));
+ }
+
+ return bp::posix_child(id, infoin, infoout);
+ }
+};
+
+}
+}
+#endif
+
+#if !defined(BOOST_POSIX_API)
+static void test_dummy()
+{
+}
+#endif
+
+but::test_suite *init_unit_test_suite(int argc, char *argv[])
+{
+ but::test_suite *test = BOOST_TEST_SUITE("posix_child test suite");
+
+#if defined(BOOST_POSIX_API)
+ add_tests_child_base<bp::posix_child, bp::posix_launcher>(test);
+#else
+ test->add(BOOST_TEST_CASE(&test_dummy));
+#endif
+
+ return test;
+}
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/test/posix_launch_test.cpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,206 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/process/config.hpp>
+
+#if defined(BOOST_POSIX_API)
+# include "launch_base_test.hpp"
+# include <boost/process/child.hpp>
+# include <boost/process/self.hpp>
+# include <boost/process/posix_child.hpp>
+# include <boost/process/posix_context.hpp>
+# include <boost/process/posix_operations.hpp>
+# include <boost/process/stream_behavior.hpp>
+# include <boost/process/pistream.hpp>
+# include <boost/process/postream.hpp>
+# include <boost/process/status.hpp>
+# include <boost/format.hpp>
+# include <vector>
+# include <string>
+# include <cstdlib>
+# include <unistd.h>
+
+namespace bp = ::boost::process;
+#endif
+
+#include <boost/filesystem/operations.hpp>
+#include <boost/test/unit_test.hpp>
+
+namespace bfs = ::boost::filesystem;
+namespace but = ::boost::unit_test;
+
+#if defined(BOOST_POSIX_API)
+class launcher
+{
+public:
+ bp::posix_child operator()(const std::vector<std::string> args,
+ bp::posix_context ctx,
+ bp::stream_behavior bstdin = bp::close_stream(),
+ bp::stream_behavior bstdout = bp::close_stream(),
+ bp::stream_behavior bstderr = bp::close_stream(),
+ bool usein = false)
+ const
+ {
+ if (bstdin.get_type() != bp::stream_behavior::close)
+ ctx.input_behavior.insert(bp::behavior_map::value_type(STDIN_FILENO, bstdin));
+
+ if (bstdout.get_type() != bp::stream_behavior::close)
+ ctx.output_behavior.insert(bp::behavior_map::value_type(STDOUT_FILENO, bstdout));
+
+ if (bstderr.get_type() != bp::stream_behavior::close)
+ ctx.output_behavior.insert(bp::behavior_map::value_type(STDERR_FILENO, bstderr));
+
+ if (ctx.environment.empty())
+ ctx.environment = bp::self::get_environment();
+
+ return bp::posix_launch(get_helpers_path(), args, ctx);
+ }
+};
+
+void test_input()
+{
+ std::vector<std::string> args;
+ args.push_back("helpers");
+ args.push_back("stdin-to-stdout");
+
+ bp::posix_context ctx;
+ ctx.input_behavior.insert(bp::behavior_map::value_type(STDIN_FILENO, bp::capture_stream()));
+ ctx.output_behavior.insert(bp::behavior_map::value_type(STDOUT_FILENO, bp::capture_stream()));
+ ctx.environment = bp::self::get_environment();
+
+ bp::posix_child c = bp::posix_launch(get_helpers_path(), args, ctx);
+
+ bp::postream &os = c.get_input(STDIN_FILENO);
+ bp::pistream &is = c.get_output(STDOUT_FILENO);
+
+ os << "message-to-process" << std::endl;
+ os.close();
+
+ std::string word;
+ is >> word;
+ BOOST_CHECK_EQUAL(word, "message-to-process");
+
+ const bp::status s = c.wait();
+ BOOST_REQUIRE(s.exited());
+ BOOST_CHECK_EQUAL(s.exit_status(), EXIT_SUCCESS);
+}
+
+void check_output(int desc, const std::string &msg)
+{
+ std::vector<std::string> args;
+ args.push_back("helpers");
+ args.push_back("posix-echo-one");
+ args.push_back(boost::str(boost::format("%1%") % desc));
+ args.push_back(msg);
+
+ bp::posix_context ctx;
+ ctx.output_behavior.insert(bp::behavior_map::value_type(desc, bp::capture_stream()));
+ ctx.environment = bp::self::get_environment();
+
+ bp::posix_child c = posix_launch(get_helpers_path(), args, ctx);
+
+ bp::pistream &is = c.get_output(desc);
+ std::string word;
+ is >> word;
+ BOOST_CHECK_EQUAL(word, msg);
+
+ const bp::status s = c.wait();
+ BOOST_REQUIRE(s.exited());
+ BOOST_CHECK_EQUAL(s.exit_status(), EXIT_SUCCESS);
+}
+
+static void test_output()
+{
+ check_output(STDOUT_FILENO, "message1-stdout");
+ check_output(STDOUT_FILENO, "message2-stdout");
+ check_output(STDERR_FILENO, "message1-stderr");
+ check_output(STDERR_FILENO, "message2-stderr");
+ check_output(10, "message1-10");
+ check_output(10, "message2-10");
+}
+
+void check_redirect(int desc1, int desc2, const std::string &msg)
+{
+ std::vector<std::string> args;
+ args.push_back("helpers");
+ args.push_back("posix-echo-two");
+ args.push_back(boost::str(boost::format("%1%") % desc1));
+ args.push_back(boost::str(boost::format("%1%") % desc2));
+ args.push_back(msg);
+
+ bp::posix_context ctx;
+ ctx.output_behavior.insert(bp::behavior_map::value_type(desc1, bp::capture_stream()));
+ ctx.output_behavior.insert(bp::behavior_map::value_type(desc2, bp::posix_redirect_stream(desc1)));
+ ctx.environment = bp::self::get_environment();
+
+ bp::posix_child c = posix_launch(get_helpers_path(), args, ctx);
+
+ bp::pistream &is = c.get_output(desc1);
+ int dtmp;
+ std::string word;
+ is >> dtmp;
+ BOOST_CHECK_EQUAL(dtmp, desc1);
+ is >> word;
+ BOOST_CHECK_EQUAL(word, msg);
+ is >> dtmp;
+ BOOST_CHECK_EQUAL(dtmp, desc2);
+ is >> word;
+ BOOST_CHECK_EQUAL(word, msg);
+
+ const bp::status s = c.wait();
+ BOOST_REQUIRE(s.exited());
+ BOOST_CHECK_EQUAL(s.exit_status(), EXIT_SUCCESS);
+}
+
+static void test_redirect()
+{
+ check_redirect(STDOUT_FILENO, STDERR_FILENO, "message");
+ check_redirect(STDERR_FILENO, STDOUT_FILENO, "message");
+ check_redirect(4, 5, "message");
+ check_redirect(10, 20, "message");
+}
+
+static void test_default_ids()
+{
+ bp::posix_context ctx;
+ BOOST_CHECK_EQUAL(ctx.gid, ::getgid());
+ BOOST_CHECK_EQUAL(ctx.egid, ::getegid());
+ BOOST_CHECK_EQUAL(ctx.uid, ::getuid());
+ BOOST_CHECK_EQUAL(ctx.euid, ::geteuid());
+}
+#endif
+
+#if !defined(BOOST_POSIX_API)
+static void test_dummy()
+{
+}
+#endif
+
+but::test_suite *init_unit_test_suite(int argc, char *argv[])
+{
+ bfs::initial_path();
+
+ but::test_suite *test = BOOST_TEST_SUITE("posix_launch test suite");
+
+#if defined(BOOST_POSIX_API)
+ add_tests_launch_base<launcher, bp::posix_context, bp::child>(test);
+ add_tests_launch_base<launcher, bp::posix_context, bp::posix_child>(test);
+
+ test->add(BOOST_TEST_CASE(&test_output), 0, 10);
+ test->add(BOOST_TEST_CASE(&test_redirect), 0, 10);
+ test->add(BOOST_TEST_CASE(&test_input), 0, 10);
+ test->add(BOOST_TEST_CASE(&test_default_ids));
+#else
+ test->add(BOOST_TEST_CASE(&test_dummy));
+#endif
+
+ return test;
+}
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/test/posix_status_test.cpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,46 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/process/config.hpp>
+
+#if defined(BOOST_POSIX_API)
+# include "status_base_test.hpp"
+# include <boost/process/posix_status.hpp>
+
+namespace bp = ::boost::process;
+#endif
+
+#include <boost/filesystem/operations.hpp>
+#include <boost/test/unit_test.hpp>
+
+namespace bfs = ::boost::filesystem;
+namespace but = ::boost::unit_test;
+
+#if !defined(BOOST_POSIX_API)
+static void test_dummy()
+{
+}
+#endif
+
+but::test_suite *init_unit_test_suite(int argc, char *argv[])
+{
+ bfs::initial_path();
+
+ but::test_suite *test = BOOST_TEST_SUITE("posix_status test suite");
+
+#if defined(BOOST_POSIX_API)
+ add_tests_status_base<bp::posix_status>(test);
+#else
+ test->add(BOOST_TEST_CASE(&test_dummy));
+#endif
+
+ return test;
+}
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/test/postream_test.cpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,47 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/process/postream.hpp>
+#include <boost/process/detail/pipe.hpp>
+#include <boost/process/detail/systembuf.hpp>
+#include <boost/test/unit_test.hpp>
+#include <istream>
+#include <string>
+
+namespace bp = ::boost::process;
+namespace bpd = ::boost::process::detail;
+namespace but = ::boost::unit_test;
+
+static void test_it()
+{
+ bpd::pipe p;
+ bpd::systembuf rbuf(p.rend().get());
+ std::istream rend(&rbuf);
+ bp::postream wend(p.wend());
+
+ // This assumes that the pipe's buffer is big enough to accept
+ // the data written without blocking!
+ wend << "1Test 1message" << std::endl;
+ std::string tmp;
+ rend >> tmp;
+ BOOST_CHECK_EQUAL(tmp, "1Test");
+ rend >> tmp;
+ BOOST_CHECK_EQUAL(tmp, "1message");
+}
+
+but::test_suite *init_unit_test_suite(int argc, char *argv[])
+{
+ but::test_suite *test = BOOST_TEST_SUITE("postream test suite");
+
+ test->add(BOOST_TEST_CASE(&test_it));
+
+ return test;
+}
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/test/process_base_test.hpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,102 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/process/config.hpp>
+
+#if defined(BOOST_POSIX_API)
+# include <boost/process/posix_status.hpp>
+#elif defined(BOOST_WINDOWS_API)
+# include <cstdlib>
+#else
+# error "Unsupported platform."
+#endif
+
+#include "misc.hpp"
+#include <boost/process/child.hpp>
+#include <boost/process/self.hpp>
+#include <boost/process/context.hpp>
+#include <boost/process/operations.hpp>
+#include <boost/process/status.hpp>
+#include <boost/test/unit_test.hpp>
+#include <vector>
+#include <string>
+
+namespace bp = ::boost::process;
+namespace bpd = ::boost::process::detail;
+namespace but = ::boost::unit_test;
+
+namespace process_base_test {
+
+//
+// Overview
+// --------
+//
+// The functions below implement tests for the basic Process implementation.
+// In order to ensure appropriate behavior, all implementations must
+// have the same behavior in common public methods; keeping this set of
+// tests generic makes it easy to check this restriction because the tests
+// can easily be applied to any specific Process implementation.
+//
+// Factory concept
+// ---------------
+//
+// The functions in this file all rely on a Factory concept. This concept
+// provides a class whose () operator constructs a new Process instance
+// based on a process's identifier. Note that this is the most possible
+// generic construction, which should be conceptually supported by all
+// implementations.
+//
+
+template <class Process, class Factory>
+static void test_getters()
+{
+ typename Process::id_type id = static_cast<typename Process::id_type>(0);
+ Process c = Factory()(id);
+
+ BOOST_CHECK_EQUAL(c.get_id(), id);
+}
+
+template <class Process, class Factory>
+static void test_terminate()
+{
+ std::vector<std::string> args;
+ args.push_back("helpers");
+ args.push_back("loop");
+
+ bp::context ctx;
+ ctx.environment = bp::self::get_environment();
+
+ bp::child c = bp::launch(get_helpers_path(), args, ctx);
+
+ Process p = Factory()(c.get_id());
+ p.terminate();
+
+ bp::status s = c.wait();
+#if defined(BOOST_POSIX_API)
+ BOOST_REQUIRE(!s.exited());
+ bp::posix_status ps = s;
+ BOOST_REQUIRE(ps.signaled());
+#elif defined(BOOST_WINDOWS_API)
+ BOOST_REQUIRE(s.exited());
+ BOOST_REQUIRE_EQUAL(s.exit_status(), EXIT_FAILURE);
+#endif
+}
+
+}
+
+template <class Process, class Factory>
+void add_tests_process_base(boost::unit_test::test_suite *ts)
+{
+ using namespace process_base_test;
+
+ ts->add(BOOST_TEST_CASE(&(test_getters<Process, Factory>)));
+ ts->add(BOOST_TEST_CASE(&(test_terminate<Process, Factory>)));
+}
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/test/process_test.cpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,36 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include "process_base_test.hpp"
+#include <boost/process/process.hpp>
+#include <boost/test/unit_test.hpp>
+
+namespace bp = ::boost::process;
+namespace bpd = ::boost::process::detail;
+namespace but = ::boost::unit_test;
+
+class launcher
+{
+public:
+ bp::process operator()(bp::process::id_type id)
+ {
+ return bp::process(id);
+ }
+};
+
+but::test_suite *init_unit_test_suite(int argc, char *argv[])
+{
+ but::test_suite *test = BOOST_TEST_SUITE("process test suite");
+
+ add_tests_process_base<bp::process, launcher>(test);
+
+ return test;
+}
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/test/self_test.cpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,77 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/process/config.hpp>
+
+#if defined(BOOST_POSIX_API)
+# include <stdlib.h>
+# include <unistd.h>
+#elif defined(BOOST_WINDOWS_API)
+# include <windows.h>
+#else
+# error "Unsupported platform."
+#endif
+
+#include <boost/process/self.hpp>
+#include <boost/process/environment.hpp>
+#include <boost/test/unit_test.hpp>
+
+namespace bp = ::boost::process;
+namespace but = ::boost::unit_test;
+
+class launcher
+{
+public:
+ bp::self &operator()(bp::self::id_type id)
+ {
+ return bp::self::get_instance();
+ }
+};
+
+static void test_id()
+{
+ bp::self &p = bp::self::get_instance();
+
+#if defined(BOOST_POSIX_API)
+ BOOST_REQUIRE(p.get_id() == ::getpid());
+#elif defined(BOOST_WINDOWS_API)
+ BOOST_REQUIRE(p.get_id() == ::GetCurrentProcessId());
+#endif
+}
+
+static void test_get_environment()
+{
+ bp::self &p = bp::self::get_instance();
+
+ bp::environment env1 = p.get_environment();
+ BOOST_CHECK(env1.find("THIS_SHOULD_NOT_BE_DEFINED") == env1.end());
+
+#if defined(BOOST_POSIX_API)
+ BOOST_REQUIRE(::setenv("THIS_SHOULD_BE_DEFINED", "some-value", 1) == 0);
+#elif defined(BOOST_WINDOWS_API)
+ BOOST_REQUIRE(::SetEnvironmentVariableA("THIS_SHOULD_BE_DEFINED", "some-value") != 0);
+#endif
+
+ bp::environment env2 = p.get_environment();
+ bp::environment::const_iterator it = env2.find("THIS_SHOULD_BE_DEFINED");
+ BOOST_CHECK(it != env2.end());
+ BOOST_CHECK_EQUAL(it->second, "some-value");
+}
+
+but::test_suite *init_unit_test_suite(int argc, char *argv[])
+{
+ but::test_suite *test = BOOST_TEST_SUITE("self test suite");
+
+ test->add(BOOST_TEST_CASE(&test_id));
+ test->add(BOOST_TEST_CASE(&test_get_environment));
+
+ return test;
+}
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/test/shell_test.cpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,60 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include "misc.hpp"
+#include <boost/process/child.hpp>
+#include <boost/process/context.hpp>
+#include <boost/process/stream_behavior.hpp>
+#include <boost/process/operations.hpp>
+#include <boost/process/pistream.hpp>
+#include <boost/process/status.hpp>
+#include <boost/test/unit_test.hpp>
+#include <string>
+#include <cstdlib>
+
+namespace bp = ::boost::process;
+namespace but = ::boost::unit_test;
+
+static void test_shell_execution()
+{
+ std::string command;
+ if (bp_api_type == posix_api)
+ command = "echo test | sed 's,^,LINE-,'";
+ else if (bp_api_type == win32_api)
+ command = "if foo==foo echo LINE-test";
+ else
+ BOOST_REQUIRE(false);
+
+ bp::context ctx;
+ ctx.stdout_behavior = bp::capture_stream();
+ // Julio: Without the following line, bash returns an exit status of 4,
+ // which makes the test fail... Why? I don't know.
+ ctx.stderr_behavior = bp::redirect_stream_to_stdout();
+ bp::child c = bp::launch_shell(command, ctx);
+
+ bp::pistream &is = c.get_stdout();
+ std::string word;
+ is >> word;
+ BOOST_CHECK_EQUAL(word, "LINE-test");
+
+ const bp::status s = c.wait();
+ BOOST_REQUIRE(s.exited());
+ BOOST_CHECK_EQUAL(s.exit_status(), EXIT_SUCCESS);
+}
+
+but::test_suite *init_unit_test_suite(int argc, char *argv[])
+{
+ but::test_suite *test = BOOST_TEST_SUITE("shell test suite");
+
+ test->add(BOOST_TEST_CASE(&test_shell_execution));
+
+ return test;
+}
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/test/status_base_test.hpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,61 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include "misc.hpp"
+#include <boost/process/child.hpp>
+#include <boost/process/self.hpp>
+#include <boost/process/context.hpp>
+#include <boost/process/operations.hpp>
+#include <boost/test/unit_test.hpp>
+#include <string>
+#include <vector>
+#include <cstdlib>
+
+namespace bp = ::boost::process;
+
+namespace status_base_test {
+
+static bp::child launch_helper(const std::string &name)
+{
+ std::vector<std::string> args;
+ args.push_back("helpers");
+ args.push_back(name);
+ bp::context ctx;
+ ctx.environment = bp::self::get_environment();
+ return bp::launch(get_helpers_path(), args, ctx);
+}
+
+template <class Exit_Status>
+void test_exit_failure()
+{
+ const Exit_Status s = launch_helper("exit-failure").wait();
+ BOOST_REQUIRE(s.exited());
+ BOOST_CHECK_EQUAL(s.exit_status(), EXIT_FAILURE);
+}
+
+template <class Exit_Status>
+void test_exit_success()
+{
+ const Exit_Status s = launch_helper("exit-success").wait();
+ BOOST_REQUIRE(s.exited());
+ BOOST_CHECK_EQUAL(s.exit_status(), EXIT_SUCCESS);
+}
+
+}
+
+template <class Exit_Status>
+void add_tests_status_base(boost::unit_test::test_suite *ts)
+{
+ using namespace status_base_test;
+
+ ts->add(BOOST_TEST_CASE(&(test_exit_success<Exit_Status>)), 0, 10);
+ ts->add(BOOST_TEST_CASE(&(test_exit_failure<Exit_Status>)), 0, 10);
+}
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/test/status_test.cpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,30 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include "status_base_test.hpp"
+#include <boost/process/status.hpp>
+#include <boost/filesystem/operations.hpp>
+#include <boost/test/unit_test.hpp>
+
+namespace bfs = ::boost::filesystem;
+namespace bp = ::boost::process;
+namespace but = ::boost::unit_test;
+
+but::test_suite *init_unit_test_suite(int argc, char *argv[])
+{
+ bfs::initial_path();
+
+ but::test_suite *test = BOOST_TEST_SUITE("status test suite");
+
+ add_tests_status_base<bp::status>(test);
+
+ return test;
+}
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/test/stream_behavior_test.cpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,94 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/process/config.hpp>
+#include <boost/process/stream_behavior.hpp>
+#include <boost/test/unit_test.hpp>
+
+namespace bp = ::boost::process;
+namespace but = ::boost::unit_test;
+
+namespace boost {
+namespace process {
+namespace detail {
+
+// Tests are declared in this class so that we can access stream_behavior's
+// internals. This is the only way to check the constructors.
+struct stream_info
+{
+ static void test_capture()
+ {
+ bp::stream_behavior sb = bp::capture_stream();
+ BOOST_CHECK_EQUAL(sb.get_type(), bp::stream_behavior::capture);
+ }
+
+ static void test_close()
+ {
+ bp::stream_behavior sb = bp::close_stream();
+ BOOST_CHECK_EQUAL(sb.get_type(), bp::stream_behavior::close);
+ }
+
+ static void test_inherit()
+ {
+ bp::stream_behavior sb = bp::inherit_stream();
+ BOOST_CHECK_EQUAL(sb.get_type(), bp::stream_behavior::inherit);
+ }
+
+ static void test_redirect_to_stdout()
+ {
+ bp::stream_behavior sb = bp::redirect_stream_to_stdout();
+ BOOST_CHECK_EQUAL(sb.get_type(),
+ bp::stream_behavior::redirect_to_stdout);
+ }
+
+ static void test_silence()
+ {
+ bp::stream_behavior sb = bp::silence_stream();
+ BOOST_CHECK_EQUAL(sb.get_type(), bp::stream_behavior::silence);
+ }
+
+#if defined(BOOST_POSIX_API)
+ static void test_posix_redirect()
+ {
+ bp::stream_behavior sb1 = bp::posix_redirect_stream(1);
+ BOOST_CHECK_EQUAL(sb1.get_type(),
+ bp::stream_behavior::posix_redirect);
+ BOOST_CHECK_EQUAL(sb1.desc_to_, 1);
+
+ bp::stream_behavior sb2 = bp::posix_redirect_stream(2);
+ BOOST_CHECK_EQUAL(sb2.get_type(),
+ bp::stream_behavior::posix_redirect);
+ BOOST_CHECK_EQUAL(sb2.desc_to_, 2);
+ }
+#endif
+};
+
+}
+}
+}
+
+but::test_suite *init_unit_test_suite(int argc, char *argv[])
+{
+ using boost::process::detail::stream_info;
+
+ but::test_suite *test = BOOST_TEST_SUITE("stream_behavior test suite");
+
+ test->add(BOOST_TEST_CASE(&stream_info::test_capture));
+ test->add(BOOST_TEST_CASE(&stream_info::test_close));
+ test->add(BOOST_TEST_CASE(&stream_info::test_inherit));
+ test->add(BOOST_TEST_CASE(&stream_info::test_redirect_to_stdout));
+ test->add(BOOST_TEST_CASE(&stream_info::test_silence));
+#if defined(BOOST_POSIX_API)
+ test->add(BOOST_TEST_CASE(&stream_info::test_posix_redirect));
+#endif
+
+ return test;
+}
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/test/win32_child_test.cpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,98 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/process/config.hpp>
+
+#if defined(BOOST_WINDOWS_API)
+# include "child_base_test.hpp"
+# include <boost/process/win32_child.hpp>
+# include <boost/process/detail/file_handle.hpp>
+# include <windows.h>
+
+namespace bp = ::boost::process;
+namespace bpd = ::boost::process::detail;
+#endif
+
+#include <boost/test/unit_test.hpp>
+
+namespace but = ::boost::unit_test;
+
+#if defined(BOOST_WINDOWS_API)
+namespace boost {
+namespace process {
+
+class win32_launcher
+{
+public:
+ bp::win32_child operator()(bp::win32_child::id_type id)
+ {
+ PROCESS_INFORMATION pi;
+ pi.dwProcessId = id;
+ bpd::file_handle fhinvalid;
+ return bp::win32_child(pi, fhinvalid, fhinvalid, fhinvalid);
+ }
+
+ bp::win32_child operator()(bp::win32_child::id_type id, bpd::file_handle fhstdin,
+ bpd::file_handle fhstdout, bpd::file_handle fhstderr)
+ {
+ PROCESS_INFORMATION pi;
+ pi.dwProcessId = id;
+ return bp::win32_child(pi, fhstdin, fhstdout, fhstderr);
+ }
+
+ bp::win32_child operator()(PROCESS_INFORMATION &pi, bpd::file_handle fhstdin,
+ bpd::file_handle fhstdout, bpd::file_handle fhstderr)
+ {
+ return bp::win32_child(pi, fhstdin, fhstdout, fhstderr);
+ }
+};
+
+}
+}
+
+static void test_getters()
+{
+ PROCESS_INFORMATION pi;
+ pi.hProcess = reinterpret_cast<HANDLE>(0x1234);
+ pi.dwProcessId = 1111;
+ pi.hThread = reinterpret_cast<HANDLE>(0x5678);
+ pi.dwThreadId = 2222;
+
+ bpd::file_handle fh;
+
+ bp::win32_child c = bp::win32_launcher()(pi, fh, fh, fh);
+
+ BOOST_CHECK_EQUAL(c.get_handle(), pi.hProcess);
+ BOOST_CHECK_EQUAL(c.get_id(), pi.dwProcessId);
+ BOOST_CHECK_EQUAL(c.get_primary_thread_handle(), pi.hThread);
+ BOOST_CHECK_EQUAL(c.get_primary_thread_id(), pi.dwThreadId);
+}
+#endif
+
+#if !defined(BOOST_WINDOWS_API)
+static void test_dummy()
+{
+}
+#endif
+
+but::test_suite *init_unit_test_suite(int argc, char *argv[])
+{
+ but::test_suite *test = BOOST_TEST_SUITE("win32_child test suite");
+
+#if defined(BOOST_WINDOWS_API)
+ add_tests_child_base<bp::win32_child, bp::win32_launcher>(test);
+ test->add(BOOST_TEST_CASE(&test_getters));
+#else
+ test->add(BOOST_TEST_CASE(&test_dummy));
+#endif
+
+ return test;
+}
==============================================================================
--- (empty file)
+++ sandbox/process/libs/process/test/win32_launch_test.cpp 2008-12-29 18:16:11 EST (Mon, 29 Dec 2008)
@@ -0,0 +1,141 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/process/config.hpp>
+#if defined(BOOST_WINDOWS_API)
+# include "launch_base_test.hpp"
+# include <boost/process/child.hpp>
+# include <boost/process/self.hpp>
+# include <boost/process/status.hpp>
+# include <boost/process/win32_child.hpp>
+# include <boost/process/win32_context.hpp>
+# include <boost/process/win32_operations.hpp>
+# include <boost/process/stream_behavior.hpp>
+# include <vector>
+# include <string>
+# include <sstream>
+# include <cstdlib>
+# include <windows.h>
+
+namespace bp = ::boost::process;
+#endif
+
+#include <boost/filesystem/operations.hpp>
+#include <boost/test/unit_test.hpp>
+
+namespace bfs = ::boost::filesystem;
+namespace but = ::boost::unit_test;
+
+#if defined(BOOST_WINDOWS_API)
+class launcher
+{
+public:
+ bp::win32_child operator()(const std::vector<std::string> args,
+ bp::win32_context ctx,
+ bp::stream_behavior bstdin = bp::close_stream(),
+ bp::stream_behavior bstdout = bp::close_stream(),
+ bp::stream_behavior bstderr = bp::close_stream(),
+ bool usein = false)
+ const
+ {
+ ctx.stdin_behavior = bstdin;
+ ctx.stdout_behavior = bstdout;
+ ctx.stderr_behavior = bstderr;
+ if (ctx.environment.empty())
+ ctx.environment = bp::self::get_environment();
+ return bp::win32_launch(get_helpers_path(), args, ctx);
+ }
+};
+
+template <class Child>
+static void test_startupinfo()
+{
+ std::vector<std::string> args;
+ args.push_back("helpers");
+ args.push_back("win32-print-startupinfo");
+
+ std::string line;
+ std::ostringstream flags;
+
+ bp::win32_context ctx1;
+ ctx1.stdout_behavior = bp::capture_stream();
+ ctx1.environment = bp::self::get_environment();
+ flags << STARTF_USESTDHANDLES;
+ Child c1 = bp::win32_launch(get_helpers_path(), args, ctx1);
+ portable_getline(c1.get_stdout(), line);
+ BOOST_CHECK_EQUAL(line, "dwFlags = " + flags.str());
+ flags.str("");
+ portable_getline(c1.get_stdout(), line);
+ BOOST_CHECK_EQUAL(line, "dwX = 0");
+ portable_getline(c1.get_stdout(), line);
+ BOOST_CHECK_EQUAL(line, "dwY = 0");
+ portable_getline(c1.get_stdout(), line);
+ BOOST_CHECK_EQUAL(line, "dwXSize = 0");
+ portable_getline(c1.get_stdout(), line);
+ BOOST_CHECK_EQUAL(line, "dwYSize = 0");
+ const bp::status s1 = c1.wait();
+ BOOST_REQUIRE(s1.exited());
+ BOOST_CHECK_EQUAL(s1.exit_status(), EXIT_SUCCESS);
+
+ STARTUPINFO si;
+ ::ZeroMemory(&si, sizeof(si));
+ si.cb = sizeof(si);
+ si.dwFlags = STARTF_USEPOSITION | STARTF_USESIZE;
+ si.dwX = 100;
+ si.dwY = 200;
+ si.dwXSize = 300;
+ si.dwYSize = 400;
+ bp::win32_context ctx2;
+ ctx2.startupinfo = &si;
+ ctx2.stdout_behavior = bp::capture_stream();
+ ctx2.environment = bp::self::get_environment();
+ flags << (STARTF_USESTDHANDLES | STARTF_USEPOSITION | STARTF_USESIZE);
+ Child c2 = bp::win32_launch(get_helpers_path(), args, ctx2);
+ portable_getline(c2.get_stdout(), line);
+ BOOST_CHECK_EQUAL(line, "dwFlags = " + flags.str());
+ flags.str("");
+ portable_getline(c2.get_stdout(), line);
+ BOOST_CHECK_EQUAL(line, "dwX = 100");
+ portable_getline(c2.get_stdout(), line);
+ BOOST_CHECK_EQUAL(line, "dwY = 200");
+ portable_getline(c2.get_stdout(), line);
+ BOOST_CHECK_EQUAL(line, "dwXSize = 300");
+ portable_getline(c2.get_stdout(), line);
+ BOOST_CHECK_EQUAL(line, "dwYSize = 400");
+ const bp::status s2 = c2.wait();
+ BOOST_REQUIRE(s2.exited());
+ BOOST_CHECK_EQUAL(s2.exit_status(), EXIT_SUCCESS);
+}
+#endif
+
+#if !defined(BOOST_WINDOWS_API)
+static void test_dummy()
+{
+}
+#endif
+
+but::test_suite *init_unit_test_suite(int argc, char *argv[])
+{
+ bfs::initial_path();
+
+ but::test_suite *test = BOOST_TEST_SUITE("win32_launch test suite");
+
+#if defined(BOOST_WINDOWS_API)
+ add_tests_launch_base<launcher, bp::win32_context, bp::child>(test);
+ add_tests_launch_base<launcher, bp::win32_context, bp::win32_child>(test);
+ test->add(BOOST_TEST_CASE(&(test_startupinfo<bp::child>)));
+ test->add(BOOST_TEST_CASE(&(test_startupinfo<bp::win32_child>)));
+#else
+ test->add(BOOST_TEST_CASE(&test_dummy));
+#endif
+
+ return test;
+}