/** @file
$Id$
$Date$
$Author$
@copy © Marc Wäckerlin
@license LGPL, see file COPYING
$Log$
Revision 1.7 2004/12/18 20:58:19 marc
pipes can be blocking, non blocking or blocking on one side only
default is again blocking, because it causes less trouble
Revision 1.6 2004/12/14 20:32:10 marc
support for connect_cin
pipe is now non blocking by default
Revision 1.5 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
- 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
Revision 1.4 2004/08/25 08:35:09 marc
change in file header
Revision 1.3 2004/08/25 08:22:19 marc
added file header
*/
#ifndef __MRW_UNISTD_HPP__
#define __MRW_UNISTD_HPP__
#include // pipe, close
#include // fcntl (O_NONBLOCK)
#include // errno
namespace mrw {
/** @addtogroup AutoTools */
//@{
/** @brief class that implements an unnamed UNIX pipe
@pre #include
Implements a UNIX pipe that is automatically closed in
destructor and offers some facilities. */
class Pipe {
private:
/// the filedescriptor, [0] to read and [1] to write
int _fd[2];
int _lastError;
public:
/// blocking mode
enum BlockingMode {
non_blocking, ///< both sides are non blocking
block_input, ///< pipe input is blocking
block_output, ///< pipe output is blocking
blocking ///< both sides are blocking
};
/// creates a unix pipe
/** @param mode Flag whether the pipe is blocking (default: yes) */
Pipe(BlockingMode mode=blocking) throw(std::bad_exception):
_lastError(-1) {
_fd[0] = -1;
_fd[1] = -1;
if (::pipe(_fd)==-1) {
_lastError=errno;
return;
}
if (mode==non_blocking || mode==block_output) {
int val(fcntl(_fd[0], F_GETFL, 0));
if (fcntl(_fd[0], F_SETFL, (val!=-1?val:0)|O_NONBLOCK) == -1)
_lastError=errno;
}
if (mode==non_blocking || mode==block_input) {
int val(fcntl(_fd[1], F_GETFL, 0));
if (fcntl(_fd[1], F_SETFL, (val!=-1?val:0)|O_NONBLOCK) == -1)
_lastError=errno;
}
}
/// destructor closes pipe if still open
~Pipe() throw(std::bad_exception) {
close();
}
/// closes pipe if open
void close() throw(std::bad_exception) {
close_in();
close_out();
}
/// closes input pipe if open
void close_in() throw(std::bad_exception) {
if (_fd[0]!=-1) while (::close(_fd[0])==-1) if (errno!=EINTR) {
_lastError = errno;
break;
}
_fd[0] = -1;
}
/// closes output pipe if open
void close_out() throw(std::bad_exception) {
if (_fd[1]!=-1) while (::close(_fd[1])==-1) if (errno!=EINTR) {
_lastError = errno;
break;
}
_fd[1] = -1;
}
/** @return true if no error occured */
operator bool() throw() {
return _lastError == -1;
}
/** @return last error code, -1 if no error */
int error() throw() {
return _lastError;
}
/// connect input stream to @c stdin
void connect_cin() throw(std::bad_exception) {
while (::dup2(_fd[0], 0)==-1) if (errno!=EINTR) {
_lastError = errno;
return;
}
}
/// connect output stream to @c stdout
void connect_cout() throw(std::bad_exception) {
while (::dup2(_fd[1], 1)==-1) if (errno!=EINTR) {
_lastError = errno;
return;
}
}
/// connect output stream to @c stderr
void connect_cerr() throw(std::bad_exception) {
while (::dup2(_fd[1], 2)==-1) if (errno!=EINTR) {
_lastError = errno;
return;
}
}
/// get an input stream
/** @return stream to read from
@note invalid after destruction or @c close or @c close_in */
int istream() throw(std::bad_exception) {
return _fd[0];
}
/// get an output stream
/** @return stream to write to
@note invalid after destruction or @c close or @c close_out */
int ostream() throw(std::bad_exception) {
return _fd[1];
}
};
//@}
}
#endif