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.

408 lines
14 KiB

/** @file
$Id$
$Date$
$Author$
@copy © Marc Wäckerlin
@license LGPL, see file <a href="license.html">COPYING</a>
$Log$
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>
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.
21 years ago
@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.
21 years ago
@pre #include <mrw/exec.hpp>
This class handles the execution of a command in a new process
21 years ago
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 {
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);
private:
Exec(); // no default constructor
mrw::Cmd* _cmd;
std::string _res, _err;
bool _success;
};
/** @brief A system command to be executed
21 years ago
@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&nbsp;/ 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&nbsp;/ 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);
/** @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
@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) 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
*/
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
*/
Exec execute(char const*const input, bool exc=true) const
throw(std::exception) {
return execute(std::string(input), exc);
}
private:
/// Exec is allowed to call @c path() and @c args().
friend class Exec;
/// No default constructor.
Cmd();
const char* path() const throw(std::bad_exception);
char** args() const throw(std::bad_exception);
typedef std::list<std::string> ArgList;
ArgList _cmd;
};
//@}
}
#endif