/** @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