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.
524 lines
20 KiB
524 lines
20 KiB
21 years ago
|
/** @file
|
||
|
|
||
|
$Id$
|
||
|
|
||
|
$Date$
|
||
|
$Author$
|
||
|
|
||
|
@copy © Marc Wäckerlin
|
||
|
@license LGPL, see file <a href="license.html">COPYING</a>
|
||
|
|
||
|
$Log$
|
||
20 years ago
|
Revision 1.8 2005/11/29 12:39:42 marc
|
||
|
make it compilable with gcc 4.0.2 and newer doxygen
|
||
|
|
||
21 years ago
|
Revision 1.7 2005/04/20 18:12:55 marc
|
||
|
added kill() for PartialExec
|
||
|
|
||
21 years ago
|
Revision 1.6 2005/04/19 18:48:00 marc
|
||
|
new feature PartialExec
|
||
|
|
||
21 years ago
|
Revision 1.5 2004/12/14 20:30:09 marc
|
||
|
added possibility to pass string to stdin of child process
|
||
|
|
||
21 years ago
|
Revision 1.4 2004/10/07 09:27:01 marc
|
||
|
errors in documentation
|
||
|
|
||
21 years ago
|
Revision 1.3 2004/08/28 16:21:25 marc
|
||
|
mrw-c++-0.92 (mrw)
|
||
14 years ago
|
- new file: version.cxx
|
||
21 years ago
|
- 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
|
||
|
|
||
|
*/
|
||
22 years ago
|
#ifndef __MRW_EXEC_HPP__
|
||
|
#define __MRW_EXEC_HPP__
|
||
|
|
||
|
#include <string>
|
||
|
#include <list>
|
||
14 years ago
|
#include <memory>
|
||
14 years ago
|
#include <mrw/exception.hxx>
|
||
|
#include <mrw/unistd.hxx>
|
||
22 years ago
|
|
||
|
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
|
||
21 years ago
|
|
||
|
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
|
||
21 years ago
|
@endcode */
|
||
22 years ago
|
//@{
|
||
|
|
||
|
class Cmd;
|
||
21 years ago
|
|
||
|
//============================================================================
|
||
22 years ago
|
/** @brief Exception: Execution of command failed.
|
||
14 years ago
|
@pre \#include <mrw/exec.hxx>
|
||
22 years ago
|
|
||
|
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
|
||
21 years ago
|
mrw::Exec::error(). */
|
||
22 years ago
|
class ExecutionFailedExc: public mrw::exception {
|
||
21 years ago
|
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;
|
||
22 years ago
|
};
|
||
|
|
||
21 years ago
|
//============================================================================
|
||
22 years ago
|
/** @brief Execute a command in a new process.
|
||
14 years ago
|
@pre \#include <mrw/exec.hxx>
|
||
22 years ago
|
|
||
|
This class handles the execution of a command in a new process
|
||
22 years ago
|
and returns the two streams @c cout and @c cerr, also known as @c
|
||
|
stderr and @c stdout.
|
||
22 years ago
|
|
||
21 years ago
|
Method @c execute can optionally also take a string parameter
|
||
|
that is passed to @c stdin of the child process.
|
||
|
|
||
22 years ago
|
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
|
||
|
|
||
21 years ago
|
@note Please note that the command execution may throw an exception. */
|
||
22 years ago
|
class Exec {
|
||
21 years ago
|
|
||
|
//................................................................ methods
|
||
|
public:
|
||
22 years ago
|
|
||
21 years ago
|
/** @brief Create an executor given a command.
|
||
|
Construction without passing a command is not possible. */
|
||
|
Exec(const mrw::Cmd&) throw(std::bad_exception);
|
||
22 years ago
|
|
||
21 years ago
|
Exec(const mrw::Exec&) throw(std::bad_exception);
|
||
|
~Exec() throw();
|
||
|
Exec& operator=(const mrw::Exec&) throw(std::bad_exception);
|
||
22 years ago
|
|
||
21 years ago
|
/** @brief Execute the command.
|
||
22 years ago
|
|
||
21 years ago
|
@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
|
||
22 years ago
|
|
||
21 years ago
|
@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);
|
||
22 years ago
|
|
||
21 years ago
|
/** @brief Execute the command, pass @c stdin.
|
||
21 years ago
|
|
||
21 years ago
|
@param input Input that is passed to @c stdin of the child process.
|
||
21 years ago
|
|
||
21 years ago
|
@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
|
||
21 years ago
|
|
||
21 years ago
|
@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);
|
||
21 years ago
|
|
||
21 years ago
|
/** @brief Execute the command, pass @c stdin.
|
||
21 years ago
|
|
||
21 years ago
|
@param input Input that is passed to @c stdin of the child process.
|
||
21 years ago
|
|
||
21 years ago
|
@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
|
||
21 years ago
|
|
||
21 years ago
|
@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
|
||
22 years ago
|
|
||
21 years ago
|
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.
|
||
22 years ago
|
|
||
21 years ago
|
@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);
|
||
22 years ago
|
|
||
21 years ago
|
/** @brief Executes the command if not done, returns @c stdout as string
|
||
22 years ago
|
|
||
21 years ago
|
If the command has not yet been executed successfully, it is
|
||
|
first executed, then the @c stdout output of the called
|
||
|
program is returned.
|
||
22 years ago
|
|
||
21 years ago
|
@return @c stdout of the called program
|
||
22 years ago
|
|
||
21 years ago
|
@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);
|
||
22 years ago
|
|
||
21 years ago
|
/** @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);
|
||
22 years ago
|
|
||
21 years ago
|
/** @brief Executes the command if not done, returns @c stdout as string
|
||
22 years ago
|
|
||
21 years ago
|
If the command has not yet been executed successfully, it is
|
||
|
first executed, then the @c stdout output of the called
|
||
|
program is returned.
|
||
22 years ago
|
|
||
21 years ago
|
@return @c stdout of the called program
|
||
22 years ago
|
|
||
21 years ago
|
@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);
|
||
22 years ago
|
|
||
21 years ago
|
/** @brief Executes the command if not done, returns @c stderr as string
|
||
22 years ago
|
|
||
21 years ago
|
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.
|
||
22 years ago
|
|
||
21 years ago
|
@return @c stderr of the called program
|
||
22 years ago
|
|
||
21 years ago
|
@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);
|
||
22 years ago
|
|
||
21 years ago
|
/** @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;
|
||
22 years ago
|
};
|
||
|
|
||
21 years ago
|
//============================================================================
|
||
|
/** @brief Execute a UNIX program in non blocking parts.
|
||
14 years ago
|
@pre \#include <mrw/exec.hxx>
|
||
21 years ago
|
|
||
|
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();
|
||
|
|
||
21 years ago
|
/// Kills a running job by sending @c SIGKILL to the child process.
|
||
|
PartialExec& kill() throw();
|
||
|
|
||
21 years ago
|
//................................................................ 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;
|
||
|
};
|
||
|
|
||
|
//============================================================================
|
||
22 years ago
|
/** @brief A system command to be executed
|
||
14 years ago
|
@pre \#include <mrw/exec.hxx>
|
||
22 years ago
|
|
||
21 years ago
|
This class is used in conjunction with mrw::Exec. It must be
|
||
22 years ago
|
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 {
|
||
21 years ago
|
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);
|
||
22 years ago
|
|
||
21 years ago
|
/** @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);
|
||
22 years ago
|
|
||
21 years ago
|
/** @return the command including parameter */
|
||
|
operator std::string() const throw(std::bad_exception);
|
||
22 years ago
|
|
||
21 years ago
|
/** @return a mrw::Exec that's constructed with this class */
|
||
|
operator mrw::Exec() const throw(std::bad_exception);
|
||
22 years ago
|
|
||
21 years ago
|
/** @return a mrw::PartialExec that's constructed with this class */
|
||
|
operator mrw::PartialExec() const throw(std::bad_exception);
|
||
22 years ago
|
|
||
21 years ago
|
/** @brief Create a mrw::Exec and execute a child process.
|
||
|
@see Exec::execute(bool) */
|
||
|
Exec execute(bool exc=true) const throw(std::exception);
|
||
22 years ago
|
|
||
21 years ago
|
/** @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);
|
||
21 years ago
|
|
||
21 years ago
|
/** @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);
|
||
|
}
|
||
21 years ago
|
|
||
21 years ago
|
/** @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);
|
||
21 years ago
|
|
||
22 years ago
|
private:
|
||
21 years ago
|
// Exec and PartialExec are allowed to call @c path() and @c args().
|
||
21 years ago
|
friend class Exec;
|
||
21 years ago
|
friend class PartialExec;
|
||
|
Cmd(); // No default constructor.
|
||
22 years ago
|
const char* path() const throw(std::bad_exception);
|
||
|
char** args() const throw(std::bad_exception);
|
||
|
typedef std::list<std::string> ArgList;
|
||
|
ArgList _cmd;
|
||
|
};
|
||
21 years ago
|
|
||
22 years ago
|
//@}
|
||
|
}
|
||
|
#endif
|