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.
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
266 lines
9.2 KiB
266 lines
9.2 KiB
#ifndef __MRW_EXEC_HPP__ |
|
#define __MRW_EXEC_HPP__ |
|
|
|
#include <string> |
|
#include <list> |
|
#include <mrw/exception.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 |
|
*/ |
|
//@{ |
|
|
|
class Cmd; |
|
|
|
/** @brief Exception: Execution of command failed. |
|
|
|
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. |
|
|
|
This class handles the execution of a command in a new process |
|
and returns the two streams @c cout and @cerr, also known as @c |
|
stderr and @stdout. |
|
|
|
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 { |
|
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 bool |
|
- @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=true) throw(mrw::exception); |
|
|
|
/** @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(mrw::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(mrw::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(mrw::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(mrw::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); |
|
|
|
private: |
|
Exec(); // no default constructor |
|
mrw::Cmd* _cmd; |
|
std::string _res, _err; |
|
bool _success; |
|
}; |
|
|
|
/** @brief A system command to be executed |
|
|
|
This class is used in conjunction with mrw::Exec. It mus 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 std::string the name of the program to execute (no parameter) |
|
@note There is no default constructor. */ |
|
Cmd(const std::string&) throw(std::bad_exception); |
|
|
|
/** @brief Append a parameter to a command |
|
@param std::string a parameter / commandline argument |
|
to append to the command */ |
|
Cmd& operator,(const std::string&) throw(std::bad_exception); |
|
|
|
/** @brief Append a parameter to a command |
|
@param std::string a parameter / commandline argument |
|
to append to the command */ |
|
Cmd& operator<<(const std::string&) 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 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 bool |
|
- @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 |
|
*/ |
|
Exec execute(bool=true) const throw(mrw::exception); |
|
|
|
private: |
|
friend class Exec; // is allowed to call path() and args() |
|
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
|
|
|