|
|
|
@ -9,6 +9,9 @@ |
|
|
|
|
@license LGPL, see file <a href="license.html">COPYING</a> |
|
|
|
|
|
|
|
|
|
$Log$ |
|
|
|
|
Revision 1.6 2005/04/19 18:48:00 marc |
|
|
|
|
new feature PartialExec |
|
|
|
|
|
|
|
|
|
Revision 1.5 2004/12/14 20:30:09 marc |
|
|
|
|
added possibility to pass string to stdin of child process |
|
|
|
|
|
|
|
|
@ -35,6 +38,7 @@ |
|
|
|
|
#include <string> |
|
|
|
|
#include <list> |
|
|
|
|
#include <mrw/exception.hpp> |
|
|
|
|
#include <mrw/unistd.hpp> |
|
|
|
|
|
|
|
|
|
namespace mrw { |
|
|
|
|
|
|
|
|
@ -81,12 +85,12 @@ namespace mrw { |
|
|
|
|
// "cat" passes all from stdin to stdout, therefore:
|
|
|
|
|
assert(cat.result()=="this is passed to stdin"); |
|
|
|
|
} catch (...) {} // ignore
|
|
|
|
|
@endcode |
|
|
|
|
*/ |
|
|
|
|
@endcode */ |
|
|
|
|
//@{
|
|
|
|
|
|
|
|
|
|
class Cmd; |
|
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
|
/** @brief Exception: Execution of command failed.
|
|
|
|
|
@pre #include <mrw/exec.hpp> |
|
|
|
|
|
|
|
|
@ -95,8 +99,7 @@ namespace mrw { |
|
|
|
|
to create the necessary pipes, or the command executing process |
|
|
|
|
terminated with an error. In the last case, you can access the |
|
|
|
|
error stream from @c stderr respectively @c cerr with method |
|
|
|
|
mrw::Exec::error(). |
|
|
|
|
*/ |
|
|
|
|
mrw::Exec::error(). */ |
|
|
|
|
class ExecutionFailedExc: public mrw::exception { |
|
|
|
|
public: |
|
|
|
|
ExecutionFailedExc(const std::string&, const std::string&) |
|
|
|
@ -107,6 +110,7 @@ namespace mrw { |
|
|
|
|
std::string _what; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
|
/** @brief Execute a command in a new process.
|
|
|
|
|
@pre #include <mrw/exec.hpp> |
|
|
|
|
|
|
|
|
@ -137,9 +141,10 @@ namespace mrw { |
|
|
|
|
// ls.error() contains stderr
|
|
|
|
|
@endcode |
|
|
|
|
|
|
|
|
|
@note Please note that the command execution may throw an exception. |
|
|
|
|
*/ |
|
|
|
|
@note Please note that the command execution may throw an exception. */ |
|
|
|
|
class Exec { |
|
|
|
|
|
|
|
|
|
//................................................................ methods
|
|
|
|
|
public: |
|
|
|
|
|
|
|
|
|
/** @brief Create an executor given a command.
|
|
|
|
@ -160,8 +165,7 @@ namespace mrw { |
|
|
|
|
- fork fails |
|
|
|
|
- creation or setup of pipes failed |
|
|
|
|
- if given parameter is @c true (the default) also if the |
|
|
|
|
executed program terminates with an error |
|
|
|
|
*/ |
|
|
|
|
executed program terminates with an error */ |
|
|
|
|
Exec& execute(bool exc=true) throw(std::exception); |
|
|
|
|
|
|
|
|
|
/** @brief Execute the command, pass @c stdin.
|
|
|
|
@ -176,8 +180,7 @@ namespace mrw { |
|
|
|
|
- fork fails |
|
|
|
|
- creation or setup of pipes failed |
|
|
|
|
- if given parameter is @c true (the default) also if the |
|
|
|
|
executed program terminates with an error |
|
|
|
|
*/ |
|
|
|
|
executed program terminates with an error */ |
|
|
|
|
Exec& execute(const std::string& input, bool exc=true) |
|
|
|
|
throw(std::exception); |
|
|
|
|
|
|
|
|
@ -193,22 +196,21 @@ namespace mrw { |
|
|
|
|
- fork fails |
|
|
|
|
- creation or setup of pipes failed |
|
|
|
|
- if given parameter is @c true (the default) also if the |
|
|
|
|
executed program terminates with an error |
|
|
|
|
*/ |
|
|
|
|
executed program terminates with an error */ |
|
|
|
|
Exec& execute(char const*const input, bool exc=true) |
|
|
|
|
throw(std::exception) { |
|
|
|
|
return execute(std::string(input), exc); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** @brief Executes the command if not done, streams @c stdout into a string
|
|
|
|
|
/** @brief Executes the command if not done, streams @c stdout
|
|
|
|
|
into a string |
|
|
|
|
|
|
|
|
|
If the command has not yet been executed successfully, it is |
|
|
|
|
first executed, then the @c stdout output of the called |
|
|
|
|
program is appended to the string. |
|
|
|
|
|
|
|
|
|
@throw ExecutionFailedExc in case of any failure or if the |
|
|
|
|
executed program does not return a zero exit status. |
|
|
|
|
*/ |
|
|
|
|
executed program does not return a zero exit status. */ |
|
|
|
|
Exec& operator>>(std::string&) throw(std::exception); |
|
|
|
|
|
|
|
|
|
/** @brief Executes the command if not done, returns @c stdout as string
|
|
|
|
@ -220,15 +222,13 @@ namespace mrw { |
|
|
|
|
@return @c stdout of the called program |
|
|
|
|
|
|
|
|
|
@throw ExecutionFailedExc in case of any failure or if the |
|
|
|
|
executed program does not return a zero exit status. |
|
|
|
|
*/ |
|
|
|
|
executed program does not return a zero exit status. */ |
|
|
|
|
operator std::string&() throw(std::exception); |
|
|
|
|
|
|
|
|
|
/** @return
|
|
|
|
|
- @c true if the last execution was successful |
|
|
|
|
- @c false if the last execution failed or the command was |
|
|
|
|
never executed |
|
|
|
|
*/ |
|
|
|
|
never executed */ |
|
|
|
|
operator bool() throw(std::bad_exception); |
|
|
|
|
|
|
|
|
|
/** @brief Executes the command if not done, returns @c stdout as string
|
|
|
|
@ -240,8 +240,7 @@ namespace mrw { |
|
|
|
|
@return @c stdout of the called program |
|
|
|
|
|
|
|
|
|
@throw ExecutionFailedExc in case of any failure or if the |
|
|
|
|
executed program does not return a zero exit status. |
|
|
|
|
*/ |
|
|
|
|
executed program does not return a zero exit status. */ |
|
|
|
|
std::string& result() throw(std::exception); |
|
|
|
|
|
|
|
|
|
/** @brief Executes the command if not done, returns @c stderr as string
|
|
|
|
@ -253,24 +252,184 @@ namespace mrw { |
|
|
|
|
@return @c stderr of the called program |
|
|
|
|
|
|
|
|
|
@throw ExecutionFailedExc in case of any failure or if the |
|
|
|
|
executed program does not return a zero exit status. |
|
|
|
|
*/ |
|
|
|
|
executed program does not return a zero exit status. */ |
|
|
|
|
std::string& error() throw(std::exception); |
|
|
|
|
|
|
|
|
|
/** @return
|
|
|
|
|
- @c true if the last execution was successful |
|
|
|
|
- @c false if the last execution failed or the command was |
|
|
|
|
never executed |
|
|
|
|
*/ |
|
|
|
|
never executed */ |
|
|
|
|
bool success() throw(std::bad_exception); |
|
|
|
|
|
|
|
|
|
//................................................................ methods
|
|
|
|
|
private: |
|
|
|
|
|
|
|
|
|
Exec(); // no default constructor
|
|
|
|
|
|
|
|
|
|
//.............................................................. variables
|
|
|
|
|
private: |
|
|
|
|
|
|
|
|
|
friend class PartialExec; // don't want the variables protected
|
|
|
|
|
mrw::Cmd* _cmd; |
|
|
|
|
std::string _res, _err; |
|
|
|
|
bool _success; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
|
/** @brief Execute a UNIX program in non blocking parts.
|
|
|
|
|
@pre #include <mrw/exec.hpp> |
|
|
|
|
|
|
|
|
|
A given UNIX command is executed, but the class does not wait |
|
|
|
|
until it is finished, instead it gives back the control to the |
|
|
|
|
caller. This behaviour is achieved using non blocking |
|
|
|
|
communication. But the caller is responsible to retrieve all |
|
|
|
|
information from the client, and if necessary to close the input |
|
|
|
|
pipe of the client executable program. Therefore you have to |
|
|
|
|
give back control from time to time, normally this is doen in a |
|
|
|
|
@c while loop, where you can execute also different thing, |
|
|
|
|
e.g. update a display of the result or similar. |
|
|
|
|
|
|
|
|
|
With this class, you can communicate with a child process, and |
|
|
|
|
do other things at the same time, without the need for multi |
|
|
|
|
threading. |
|
|
|
|
|
|
|
|
|
Execution of a program works the following way: |
|
|
|
|
- do not use execute() (otherwise the behaviours is identical |
|
|
|
|
to class mrw::Exec, you gain nothing, but also loose nothing) |
|
|
|
|
- use start() to start the external program |
|
|
|
|
- use start() or @c start(false) if you don't want to pass |
|
|
|
|
input to the child process |
|
|
|
|
- use @c start(true) if you want to pass input to the |
|
|
|
|
child process |
|
|
|
|
- if you called @c start(true), call finish() if you have no more |
|
|
|
|
input to send to the child process (it's like an end-of-file) |
|
|
|
|
- the execution is not terminated, before finished() returns |
|
|
|
|
@c true |
|
|
|
|
- while finished() is false, subsequently call read() to read |
|
|
|
|
the output of the child process |
|
|
|
|
|
|
|
|
|
@warning After calling finish(), or if you did not call |
|
|
|
|
start() with parameter @c true, it is forbidden to |
|
|
|
|
pass anything but an empty string as first parameter to |
|
|
|
|
read()! Anything else is a programming error and |
|
|
|
|
results in an assertion failure and a core dump! |
|
|
|
|
|
|
|
|
|
@note If your program seems to hang, check if you call finish() |
|
|
|
|
correctly! |
|
|
|
|
|
|
|
|
|
Here an example: |
|
|
|
|
@code |
|
|
|
|
mrw::PartialExec exec = mrw::Cmd("/bin/cat").start(true); |
|
|
|
|
std::string res = exec.read("This is a test\n").first; |
|
|
|
|
res += exec.read("This is another test\n").first; |
|
|
|
|
exec.finish(); // close the input pipe of @c cat
|
|
|
|
|
while (!exec.finished()) res+=exec.read().first; |
|
|
|
|
@endcode */ |
|
|
|
|
class PartialExec: public Exec { |
|
|
|
|
|
|
|
|
|
//................................................................ methods
|
|
|
|
|
public: |
|
|
|
|
|
|
|
|
|
/** @brief Create an executor given a command.
|
|
|
|
|
Construction without passing a command is not possible. */ |
|
|
|
|
PartialExec(const mrw::Cmd&) throw(std::bad_exception); |
|
|
|
|
|
|
|
|
|
/** @brief Copy construction invalidates the original object.
|
|
|
|
|
|
|
|
|
|
All opened pipes (opened with start()) are lost in the |
|
|
|
|
original object and are then owned by the new object. */ |
|
|
|
|
PartialExec(mrw::PartialExec&) throw(std::bad_exception); |
|
|
|
|
|
|
|
|
|
/** @brief Copy construction invalidates the original object.
|
|
|
|
|
|
|
|
|
|
@copydoc PartialExec(mrw::PartialExec&) |
|
|
|
|
|
|
|
|
|
@warning @c const for the argument is a fake! It is casted away! |
|
|
|
|
|
|
|
|
|
@param e @b Warning: const is casted away! */ |
|
|
|
|
PartialExec(const mrw::PartialExec& e) throw(std::bad_exception); |
|
|
|
|
|
|
|
|
|
/** @brief Assignment invalidates the original object.
|
|
|
|
|
|
|
|
|
|
@copydoc PartialExec(mrw::PartialExec&) */ |
|
|
|
|
PartialExec& operator=(mrw::PartialExec&) throw(std::bad_exception); |
|
|
|
|
|
|
|
|
|
/** @brief Close the input pipe of the child process.
|
|
|
|
|
|
|
|
|
|
If start() is called with argument @c false, then you |
|
|
|
|
can pass input to @c stdin of the child process, but you @b |
|
|
|
|
must call this method, after passing the last input |
|
|
|
|
string. Otherwise, the child's input pipe won't be closed, |
|
|
|
|
the child process does not stop waiting for more input! If |
|
|
|
|
your program seems to hang, check if you call finish() |
|
|
|
|
correctly! */ |
|
|
|
|
PartialExec& finish() throw(); |
|
|
|
|
|
|
|
|
|
/** @brief Check if there's more data left to read().
|
|
|
|
|
@return @c true if the child process has finished and all |
|
|
|
|
data is read. */ |
|
|
|
|
bool finished() throw(); |
|
|
|
|
|
|
|
|
|
/** @brief Start a new child process.
|
|
|
|
|
|
|
|
|
|
At most one child process can run at the same time. |
|
|
|
|
|
|
|
|
|
@throw mrw::runtime_error if a previous child has not finished() yet |
|
|
|
|
@throw mrw::ExecutionFailedExc if the child process cannot be started |
|
|
|
|
@param useInput |
|
|
|
|
- @c true if input will be sent to the child's @c stdin |
|
|
|
|
- pass all input in the first parameter of read() |
|
|
|
|
- finish() must be called when all input is sent |
|
|
|
|
- @c false if no input is sent to the child's @c stdin |
|
|
|
|
- the first parameter of read must allways be passed an |
|
|
|
|
empty string */ |
|
|
|
|
PartialExec& start(bool useInput=false) throw(std::exception); |
|
|
|
|
|
|
|
|
|
/** @brief Read from the subprocess, optionally pass an @c input to
|
|
|
|
|
@c stdin of the subprocess. |
|
|
|
|
|
|
|
|
|
@param input a string to pass to the child processes @c stdin |
|
|
|
|
|
|
|
|
|
@param exc |
|
|
|
|
- @c true throw an exception if return status is not zero |
|
|
|
|
- @c false throw only an exception in case of a fatal error |
|
|
|
|
|
|
|
|
|
@return a pair containing the last read @c stdout and @c stderr |
|
|
|
|
of the child |
|
|
|
|
|
|
|
|
|
@throw ExecutionFailedExc is thrown if |
|
|
|
|
- fork fails |
|
|
|
|
- creation or setup of pipes failed |
|
|
|
|
- if given parameter is @c true (the default) also if the |
|
|
|
|
executed program terminates with an error |
|
|
|
|
|
|
|
|
|
@note If start() was not called with parameter @c true, then |
|
|
|
|
@c input must always be an empty string! |
|
|
|
|
|
|
|
|
|
@pre start() was called */ |
|
|
|
|
std::pair<std::string, std::string> read(const std::string& input="", |
|
|
|
|
bool exc=true) |
|
|
|
|
throw(std::exception); |
|
|
|
|
|
|
|
|
|
/// Terminates a running job by sending @c SIGTERM to the child process.
|
|
|
|
|
PartialExec& terminate() throw(); |
|
|
|
|
|
|
|
|
|
//................................................................ methods
|
|
|
|
|
private: |
|
|
|
|
|
|
|
|
|
PartialExec(); // no default constructor
|
|
|
|
|
|
|
|
|
|
//.............................................................. variables
|
|
|
|
|
private: |
|
|
|
|
|
|
|
|
|
bool _finished; |
|
|
|
|
bool _finish; |
|
|
|
|
std::auto_ptr<mrw::Pipe> _stdIn, _stdOut, _stdErr; |
|
|
|
|
std::string _input; |
|
|
|
|
int _num0, _num1, _num2, _lastPid, _pid; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
|
/** @brief A system command to be executed
|
|
|
|
|
@pre #include <mrw/exec.hpp> |
|
|
|
|
|
|
|
|
@ -315,93 +474,40 @@ namespace mrw { |
|
|
|
|
/** @return a mrw::Exec that's constructed with this class */ |
|
|
|
|
operator mrw::Exec() const throw(std::bad_exception); |
|
|
|
|
|
|
|
|
|
/** @brief Create a mrw::Exec and execute the command
|
|
|
|
|
|
|
|
|
|
Creates a mrw::Exec, executes the command, passes the flag to |
|
|
|
|
mrw::Exec::execute() and returns the created mrw::Exec. The |
|
|
|
|
result of the execution can be retrieved through the returned |
|
|
|
|
mrw::Exec object: The methods mrw::Exec::success(), |
|
|
|
|
mrw::Exec::result() and mrw::Exec::error() provide the |
|
|
|
|
necessary information. |
|
|
|
|
|
|
|
|
|
@param exc |
|
|
|
|
- @c true throw an exception if return status is not zero |
|
|
|
|
- @c false throw only an exception in case of a fatal error |
|
|
|
|
|
|
|
|
|
@return the mrw::Exec that has executed the command |
|
|
|
|
/** @return a mrw::PartialExec that's constructed with this class */ |
|
|
|
|
operator mrw::PartialExec() const throw(std::bad_exception); |
|
|
|
|
|
|
|
|
|
@throw ExecutionFailedExc is thrown if |
|
|
|
|
- fork fails |
|
|
|
|
- creation or setup of pipes failed |
|
|
|
|
- if given parameter is @c true (the default) also if the |
|
|
|
|
executed program terminates with an error |
|
|
|
|
*/ |
|
|
|
|
/** @brief Create a mrw::Exec and execute a child process.
|
|
|
|
|
@see Exec::execute(bool) */ |
|
|
|
|
Exec execute(bool exc=true) const throw(std::exception); |
|
|
|
|
|
|
|
|
|
/** @brief Create a mrw::Exec and execute the command given an input
|
|
|
|
|
|
|
|
|
|
Creates a mrw::Exec, executes the command, passes the input |
|
|
|
|
and the flag to mrw::Exec::execute() and returns the created |
|
|
|
|
mrw::Exec. The result of the execution can be retrieved |
|
|
|
|
through the returned mrw::Exec object: The methods |
|
|
|
|
mrw::Exec::success(), mrw::Exec::result() and |
|
|
|
|
mrw::Exec::error() provide the necessary information. |
|
|
|
|
|
|
|
|
|
@param input Input that is passed to @c stdin of the child process. |
|
|
|
|
|
|
|
|
|
@param exc |
|
|
|
|
- @c true throw an exception if return status is not zero |
|
|
|
|
- @c false throw only an exception in case of a fatal error |
|
|
|
|
|
|
|
|
|
@return the mrw::Exec that has executed the command |
|
|
|
|
|
|
|
|
|
@throw ExecutionFailedExc is thrown if |
|
|
|
|
- fork fails |
|
|
|
|
- creation or setup of pipes failed |
|
|
|
|
- if given parameter is @c true (the default) also if the |
|
|
|
|
executed program terminates with an error |
|
|
|
|
*/ |
|
|
|
|
/** @brief Create a mrw::Exec and execute a child process.
|
|
|
|
|
@see Exec::execute(const std::string&, bool) */ |
|
|
|
|
Exec execute(const std::string& input, bool exc=true) const |
|
|
|
|
throw(std::exception); |
|
|
|
|
|
|
|
|
|
/** @brief Create a mrw::Exec and execute the command given an input
|
|
|
|
|
|
|
|
|
|
Creates a mrw::Exec, executes the command, passes the input |
|
|
|
|
and the flag to mrw::Exec::execute() and returns the created |
|
|
|
|
mrw::Exec. The result of the execution can be retrieved |
|
|
|
|
through the returned mrw::Exec object: The methods |
|
|
|
|
mrw::Exec::success(), mrw::Exec::result() and |
|
|
|
|
mrw::Exec::error() provide the necessary information. |
|
|
|
|
|
|
|
|
|
@param input Input that is passed to @c stdin of the child process. |
|
|
|
|
|
|
|
|
|
@param exc |
|
|
|
|
- @c true throw an exception if return status is not zero |
|
|
|
|
- @c false throw only an exception in case of a fatal error |
|
|
|
|
|
|
|
|
|
@return the mrw::Exec that has executed the command |
|
|
|
|
|
|
|
|
|
@throw ExecutionFailedExc is thrown if |
|
|
|
|
- fork fails |
|
|
|
|
- creation or setup of pipes failed |
|
|
|
|
- if given parameter is @c true (the default) also if the |
|
|
|
|
executed program terminates with an error |
|
|
|
|
*/ |
|
|
|
|
/** @brief Create a mrw::Exec and execute a child process.
|
|
|
|
|
@see Exec::execute(char const*const, bool) */ |
|
|
|
|
Exec execute(char const*const input, bool exc=true) const |
|
|
|
|
throw(std::exception) { |
|
|
|
|
return execute(std::string(input), exc); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** @brief Create a new mrw::PartialExec and start a new child process.
|
|
|
|
|
@see PartialExec::start(bool) */ |
|
|
|
|
PartialExec start(bool useInput=false) const throw(std::exception); |
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
/// Exec is allowed to call @c path() and @c args().
|
|
|
|
|
// Exec and PartialExec are allowed to call @c path() and @c args().
|
|
|
|
|
friend class Exec; |
|
|
|
|
/// No default constructor.
|
|
|
|
|
Cmd();
|
|
|
|
|
friend class PartialExec; |
|
|
|
|
Cmd(); // No default constructor.
|
|
|
|
|
const char* path() const throw(std::bad_exception); |
|
|
|
|
char** args() const throw(std::bad_exception); |
|
|
|
|
typedef std::list<std::string> ArgList; |
|
|
|
|
ArgList _cmd; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
//@}
|
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|