C++ Library containing a lot of needful things: Stack Trace, Command Line Parser, Resource Handling, Configuration Files, Unix Command Execution, Directories, Regular Expressions, Tokenizer, Function Trace, Standard Extensions.
522 lines
20 KiB
522 lines
20 KiB
/** @file |
|
|
|
$Id$ |
|
|
|
$Date$ |
|
$Author$ |
|
|
|
@copy © Marc Wäckerlin |
|
@license LGPL, see file <a href="license.html">COPYING</a> |
|
|
|
$Log$ |
|
Revision 1.8 2005/11/29 12:39:42 marc |
|
make it compilable with gcc 4.0.2 and newer doxygen |
|
|
|
Revision 1.7 2005/04/20 18:12:55 marc |
|
added kill() for PartialExec |
|
|
|
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 |
|
|
|
Revision 1.4 2004/10/07 09:27:01 marc |
|
errors in documentation |
|
|
|
Revision 1.3 2004/08/28 16:21:25 marc |
|
mrw-c++-0.92 (mrw) |
|
- new file: version.cpp |
|
- new file header for all sources |
|
- work around warning in mrw::auto<T> |
|
- possibility to compile without log4cxx |
|
- work around bugs in demangle.h and libiberty.h |
|
- corrections in documentation |
|
- added simple tracing mechanism |
|
- more warnings |
|
- small corrections in Auto<>::Free and a new test for it |
|
- possibility to compile without stack trace |
|
|
|
*/ |
|
#ifndef __MRW_EXEC_HPP__ |
|
#define __MRW_EXEC_HPP__ |
|
|
|
#include <string> |
|
#include <list> |
|
#include <mrw/exception.hpp> |
|
#include <mrw/unistd.hpp> |
|
|
|
namespace mrw { |
|
|
|
/** @defgroup CmdExec Execute UNIX Commands |
|
|
|
There is no easy way to safely execute UNIX commands and to |
|
return the output of the callee to the caller. @c system ist |
|
first of all known to be unsafe, because it opens a shell, and |
|
second there is no way to transfer the output back to the |
|
caller. On the other hand, starting a new process with @c fork |
|
and @c exec and passing the output of the callee to the caller |
|
using pipes is quite complex and needs much more than one simple |
|
line of code. This is the gap that is filled with this command |
|
execution classes. There's a class for the command to be |
|
executed and a class for the execution of the command. |
|
|
|
Forking a subprocess and evaluating the result becomes so easy: |
|
|
|
@code |
|
try { |
|
// execute the command: /bin/ls -l /tmp |
|
mrw::Exec ls = |
|
(mrw::Cmd("/bin/ls"), "-l", "/tmp").execute(false); |
|
// evaluate the result |
|
if (ls.success()) |
|
std::cout<<"Execution successful, result was:"<<std::endl; |
|
else |
|
std::cerr<<"Error in execution, error was:"<<std::endl; |
|
std::cout<<ls.result()<<std::endl; |
|
std::cerr<<ls.error()<<std::endl; |
|
} catch (ExecutionFailedExc& x) { |
|
// a fatal execution error occurred |
|
// you can trace x.what() and x.stacktrace() |
|
} |
|
@endcode |
|
|
|
It is also possible to pass an @c stdin input argument to the |
|
subprocess called: |
|
|
|
@code |
|
try { |
|
mrw::Exec cat = mrw::Cmd("/bin/cat") |
|
.execute("this is passed to stdin"); |
|
// "cat" passes all from stdin to stdout, therefore: |
|
assert(cat.result()=="this is passed to stdin"); |
|
} catch (...) {} // ignore |
|
@endcode */ |
|
//@{ |
|
|
|
class Cmd; |
|
|
|
//============================================================================ |
|
/** @brief Exception: Execution of command failed. |
|
@pre \#include <mrw/exec.hpp> |
|
|
|
This exception is thrown, if the exection of a command in |
|
mrw::Exec is failed. That means, it was not possible to fork or |
|
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(). */ |
|
class ExecutionFailedExc: public mrw::exception { |
|
public: |
|
ExecutionFailedExc(const std::string&, const std::string&) |
|
throw(std::bad_exception); |
|
virtual ~ExecutionFailedExc() throw() {} |
|
virtual const char* what() const throw() {return _what.c_str();} |
|
private: |
|
std::string _what; |
|
}; |
|
|
|
//============================================================================ |
|
/** @brief Execute a command in a new process. |
|
@pre \#include <mrw/exec.hpp> |
|
|
|
This class handles the execution of a command in a new process |
|
and returns the two streams @c cout and @c cerr, also known as @c |
|
stderr and @c stdout. |
|
|
|
Method @c execute can optionally also take a string parameter |
|
that is passed to @c stdin of the child process. |
|
|
|
There are different ways of usage for this class. A simple way, |
|
one line of code, to get only the resulting stream (no error) |
|
is: |
|
|
|
@code |
|
string stdout = |
|
(mrw::Cmd("/bin/ls"), "-l", "/tmp").execute(false).result(); |
|
@endcode |
|
|
|
If you need not only the resulting @c stdout stream, but also |
|
the error stream @c stderr, then you need to store the result: |
|
|
|
@code |
|
mrw::Exec ls = |
|
(mrw::Cmd("/bin/ls"), "-l", "/tmp").execute(false); |
|
if (!ls) ...; // command termianted with error |
|
// ls.result() contains stdout |
|
// ls.error() contains stderr |
|
@endcode |
|
|
|
@note Please note that the command execution may throw an exception. */ |
|
class Exec { |
|
|
|
//................................................................ methods |
|
public: |
|
|
|
/** @brief Create an executor given a command. |
|
Construction without passing a command is not possible. */ |
|
Exec(const mrw::Cmd&) throw(std::bad_exception); |
|
|
|
Exec(const mrw::Exec&) throw(std::bad_exception); |
|
~Exec() throw(); |
|
Exec& operator=(const mrw::Exec&) throw(std::bad_exception); |
|
|
|
/** @brief Execute the command. |
|
|
|
@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 |
|
|
|
@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 */ |
|
Exec& execute(bool exc=true) throw(std::exception); |
|
|
|
/** @brief Execute the command, pass @c stdin. |
|
|
|
@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 |
|
|
|
@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 */ |
|
Exec& execute(const std::string& input, bool exc=true) |
|
throw(std::exception); |
|
|
|
/** @brief Execute the command, pass @c stdin. |
|
|
|
@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 |
|
|
|
@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 */ |
|
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 |
|
|
|
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. */ |
|
Exec& operator>>(std::string&) throw(std::exception); |
|
|
|
/** @brief Executes the command if not done, returns @c stdout as string |
|
|
|
If the command has not yet been executed successfully, it is |
|
first executed, then the @c stdout output of the called |
|
program is returned. |
|
|
|
@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. */ |
|
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 */ |
|
operator bool() throw(std::bad_exception); |
|
|
|
/** @brief Executes the command if not done, returns @c stdout as string |
|
|
|
If the command has not yet been executed successfully, it is |
|
first executed, then the @c stdout output of the called |
|
program is returned. |
|
|
|
@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. */ |
|
std::string& result() throw(std::exception); |
|
|
|
/** @brief Executes the command if not done, returns @c stderr as string |
|
|
|
If the command has not yet been executed successfully, it is |
|
first executed, then the @c stderr error output of the called |
|
program is returned. |
|
|
|
@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. */ |
|
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 */ |
|
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(); |
|
|
|
/// Kills a running job by sending @c SIGKILL to the child process. |
|
PartialExec& kill() 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> |
|
|
|
This class is used in conjunction with mrw::Exec. It must be |
|
initialized with the command name, then the command parameters |
|
are appended either with commas, or by streaming them into the |
|
command, whatever you like. |
|
|
|
You can stream the data into the class: |
|
|
|
@code |
|
mrw::Cmd ls("/bin/ls"); // the command to execute is: /bin/ls |
|
ls<<"-l"<<"/tmp"; // the command is now: /bin/ls -l /tmp |
|
@endcode |
|
|
|
Or you can setup your command with commas: |
|
|
|
@code |
|
mrw::Cmd ls = (mrw::Cmd(/bin/ls), "-l", "/tmp"); |
|
@endcode |
|
*/ |
|
class Cmd { |
|
public: |
|
/** @brief Create a command given the name of the executable |
|
@param command the name of the program to execute (no parameter) |
|
@note There is no default constructor. */ |
|
Cmd(const std::string& command) throw(std::bad_exception); |
|
|
|
/** @brief Append a parameter to a command |
|
@param param a parameter / commandline argument |
|
to append to the command */ |
|
Cmd& operator,(const std::string& param) throw(std::bad_exception); |
|
|
|
/** @brief Append a parameter to a command |
|
@param param a parameter / commandline argument |
|
to append to the command */ |
|
Cmd& operator<<(const std::string& param) throw(std::bad_exception); |
|
|
|
/** @return the command including parameter */ |
|
operator std::string() const throw(std::bad_exception); |
|
|
|
/** @return a mrw::Exec that's constructed with this class */ |
|
operator mrw::Exec() const throw(std::bad_exception); |
|
|
|
/** @return a mrw::PartialExec that's constructed with this class */ |
|
operator mrw::PartialExec() const throw(std::bad_exception); |
|
|
|
/** @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 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 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 and PartialExec are allowed to call @c path() and @c args(). |
|
friend class Exec; |
|
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
|
|
|