/* Compile this program by: * $ g++ -O3 -std=c++11 receptor1.cpp -o receptor1 */ const char* docstring="" "receptor1 input.pdb output.pdb\n" " renumber residue index in input.pdb to start from 1. output reindexed\n" " pdb to output.pdb\n" "\n" "receptor1 inputdir/ outputdir/ list\n" " renumber all pdb files listed by 'list' in inputdir/. output reindexed\n" " pdb to outputdir/\n" ; #include #include #include #include #include #include #include #include #include #include #include using namespace std; /* StringTools START */ /* split a long string into vectors by whitespace * line - input string * line_vec - output vector * delimiter - delimiter */ void Split(const string &line, vector &line_vec, const char delimiter=' ') { bool within_word = false; for (size_t pos=0;pos=shortString.size() && longString.substr(0,shortString.size())==shortString); } inline bool EndsWith(const string &longString, const string &shortString) { return (longString.size()>=shortString.size() && longString.substr(longString.size()-shortString.size(), shortString.size())==shortString); } /* StringTools END */ /* pstream START */ // PStreams - POSIX Process I/O for C++ // Copyright (C) 2001 - 2017 Jonathan Wakely // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // /* do not compile on windows, which does not have cygwin */ #if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) && !defined(__CYGWIN__) #define NO_PSTREAM #else #ifndef REDI_PSTREAM_H_SEEN #define REDI_PSTREAM_H_SEEN #include #include #include #include #include #include #include // for min() #include // for errno #include // for size_t, NULL #include // for exit() #include // for pid_t #include // for waitpid() #include // for ioctl() and FIONREAD #if defined(__sun) # include // for FIONREAD on Solaris 2.5 #endif #include // for pipe() fork() exec() and filedes functions #include // for kill() #include // for fcntl() #if REDI_EVISCERATE_PSTREAMS # include // for FILE, fdopen() #endif /// The library version. #define PSTREAMS_VERSION 0x0101 // 1.0.1 /** * @namespace redi * @brief All PStreams classes are declared in namespace redi. * * Like the standard iostreams, PStreams is a set of class templates, * taking a character type and traits type. As with the standard streams * they are most likely to be used with @c char and the default * traits type, so typedefs for this most common case are provided. * * The @c pstream_common class template is not intended to be used directly, * it is used internally to provide the common functionality for the * other stream classes. */ namespace redi { /// Common base class providing constants and typenames. struct pstreams { /// Type used to specify how to connect to the process. typedef std::ios_base::openmode pmode; /// Type used to hold the arguments for a command. typedef std::vector argv_type; /// Type used for file descriptors. typedef int fd_type; static const pmode pstdin = std::ios_base::out; ///< Write to stdin static const pmode pstdout = std::ios_base::in; ///< Read from stdout static const pmode pstderr = std::ios_base::app; ///< Read from stderr /// Create a new process group for the child process. static const pmode newpg = std::ios_base::trunc; protected: enum { bufsz = 32 }; ///< Size of pstreambuf buffers. enum { pbsz = 2 }; ///< Number of putback characters kept. }; /// Class template for stream buffer. template > class basic_pstreambuf : public std::basic_streambuf , public pstreams { public: // Type definitions for dependent types typedef CharT char_type; typedef Traits traits_type; typedef typename traits_type::int_type int_type; typedef typename traits_type::off_type off_type; typedef typename traits_type::pos_type pos_type; /** @deprecated use pstreams::fd_type instead. */ typedef fd_type fd_t; /// Default constructor. basic_pstreambuf(); /// Constructor that initialises the buffer with @a cmd. basic_pstreambuf(const std::string& cmd, pmode mode); /// Constructor that initialises the buffer with @a file and @a argv. basic_pstreambuf( const std::string& file, const argv_type& argv, pmode mode ); /// Destructor. ~basic_pstreambuf(); /// Initialise the stream buffer with @a cmd. basic_pstreambuf* open(const std::string& cmd, pmode mode); /// Initialise the stream buffer with @a file and @a argv. basic_pstreambuf* open(const std::string& file, const argv_type& argv, pmode mode); /// Close the stream buffer and wait for the process to exit. basic_pstreambuf* close(); /// Send a signal to the process. basic_pstreambuf* kill(int signal = SIGTERM); /// Send a signal to the process' process group. basic_pstreambuf* killpg(int signal = SIGTERM); /// Close the pipe connected to the process' stdin. void peof(); /// Change active input source. bool read_err(bool readerr = true); /// Report whether the stream buffer has been initialised. bool is_open() const; /// Report whether the process has exited. bool exited(); #if REDI_EVISCERATE_PSTREAMS /// Obtain FILE pointers for each of the process' standard streams. std::size_t fopen(FILE*& in, FILE*& out, FILE*& err); #endif /// Return the exit status of the process. int status() const; /// Return the error number (errno) for the most recent failed operation. int error() const; protected: /// Transfer characters to the pipe when character buffer overflows. int_type overflow(int_type c); /// Transfer characters from the pipe when the character buffer is empty. int_type underflow(); /// Make a character available to be returned by the next extraction. int_type pbackfail(int_type c = traits_type::eof()); /// Write any buffered characters to the stream. int sync(); /// Insert multiple characters into the pipe. std::streamsize xsputn(const char_type* s, std::streamsize n); /// Insert a sequence of characters into the pipe. std::streamsize write(const char_type* s, std::streamsize n); /// Extract a sequence of characters from the pipe. std::streamsize read(char_type* s, std::streamsize n); /// Report how many characters can be read from active input without blocking. std::streamsize showmanyc(); protected: /// Enumerated type to indicate whether stdout or stderr is to be read. enum buf_read_src { rsrc_out = 0, rsrc_err = 1 }; /// Initialise pipes and fork process. pid_t fork(pmode mode); /// Wait for the child process to exit. int wait(bool nohang = false); /// Return the file descriptor for the output pipe. fd_type& wpipe(); /// Return the file descriptor for the active input pipe. fd_type& rpipe(); /// Return the file descriptor for the specified input pipe. fd_type& rpipe(buf_read_src which); void create_buffers(pmode mode); void destroy_buffers(pmode mode); /// Writes buffered characters to the process' stdin pipe. bool empty_buffer(); bool fill_buffer(bool non_blocking = false); /// Return the active input buffer. char_type* rbuffer(); buf_read_src switch_read_buffer(buf_read_src); private: basic_pstreambuf(const basic_pstreambuf&); basic_pstreambuf& operator=(const basic_pstreambuf&); void init_rbuffers(); pid_t ppid_; // pid of process fd_type wpipe_; // pipe used to write to process' stdin fd_type rpipe_[2]; // two pipes to read from, stdout and stderr char_type* wbuffer_; char_type* rbuffer_[2]; char_type* rbufstate_[3]; /// Index into rpipe_[] to indicate active source for read operations. buf_read_src rsrc_; int status_; // hold exit status of child process int error_; // hold errno if fork() or exec() fails }; /// Class template for common base class. template > class pstream_common : virtual public std::basic_ios , virtual public pstreams { protected: typedef basic_pstreambuf streambuf_type; typedef pstreams::pmode pmode; typedef pstreams::argv_type argv_type; /// Default constructor. pstream_common(); /// Constructor that initialises the stream by starting a process. pstream_common(const std::string& cmd, pmode mode); /// Constructor that initialises the stream by starting a process. pstream_common(const std::string& file, const argv_type& argv, pmode mode); /// Pure virtual destructor. virtual ~pstream_common() = 0; /// Start a process. void do_open(const std::string& cmd, pmode mode); /// Start a process. void do_open(const std::string& file, const argv_type& argv, pmode mode); public: /// Close the pipe. void close(); /// Report whether the stream's buffer has been initialised. bool is_open() const; /// Return the command used to initialise the stream. const std::string& command() const; /// Return a pointer to the stream buffer. streambuf_type* rdbuf() const; #if REDI_EVISCERATE_PSTREAMS /// Obtain FILE pointers for each of the process' standard streams. std::size_t fopen(FILE*& in, FILE*& out, FILE*& err); #endif protected: std::string command_; ///< The command used to start the process. streambuf_type buf_; ///< The stream buffer. }; /** * @class basic_ipstream * @brief Class template for Input PStreams. * * Reading from an ipstream reads the command's standard output and/or * standard error (depending on how the ipstream is opened) * and the command's standard input is the same as that of the process * that created the object, unless altered by the command itself. */ template > class basic_ipstream : public std::basic_istream , public pstream_common , virtual public pstreams { typedef std::basic_istream istream_type; typedef pstream_common pbase_type; using pbase_type::buf_; // declare name in this scope // Ensure a basic_ipstream will read from at least one pipe pmode readable(pmode mode) { if (!(mode & (pstdout|pstderr))) mode |= pstdout; return mode; } public: /// Type used to specify how to connect to the process. typedef typename pbase_type::pmode pmode; /// Type used to hold the arguments for a command. typedef typename pbase_type::argv_type argv_type; /// Default constructor, creates an uninitialised stream. basic_ipstream() : istream_type(NULL), pbase_type() { } /** * @brief Constructor that initialises the stream by starting a process. * * Initialises the stream buffer by calling do_open() with the supplied * arguments. * * @param cmd a string containing a shell command. * @param mode the I/O mode to use when opening the pipe. * @see do_open(const std::string&, pmode) */ explicit basic_ipstream(const std::string& cmd, pmode mode = pstdout) : istream_type(NULL), pbase_type(cmd, readable(mode)) { } /** * @brief Constructor that initialises the stream by starting a process. * * Initialises the stream buffer by calling do_open() with the supplied * arguments. * * @param file a string containing the pathname of a program to execute. * @param argv a vector of argument strings passed to the new program. * @param mode the I/O mode to use when opening the pipe. * @see do_open(const std::string&, const argv_type&, pmode) */ basic_ipstream( const std::string& file, const argv_type& argv, pmode mode = pstdout ) : istream_type(NULL), pbase_type(file, argv, readable(mode)) { } /** * @brief Constructor that initialises the stream by starting a process. * * Initialises the stream buffer by calling * @c do_open(argv[0],argv,mode|pstdout) * * @param argv a vector of argument strings passed to the new program. * @param mode the I/O mode to use when opening the pipe. * @see do_open(const std::string&, const argv_type&, pmode) */ explicit basic_ipstream(const argv_type& argv, pmode mode = pstdout) : istream_type(NULL), pbase_type(argv.at(0), argv, readable(mode)) { } #if __cplusplus >= 201103L template explicit basic_ipstream(std::initializer_list args, pmode mode = pstdout) : basic_ipstream(argv_type(args.begin(), args.end()), mode) { } #endif /** * @brief Destructor. * * Closes the stream and waits for the child to exit. */ ~basic_ipstream() { } /** * @brief Start a process. * * Calls do_open( @a cmd , @a mode|pstdout ). * * @param cmd a string containing a shell command. * @param mode the I/O mode to use when opening the pipe. * @see do_open(const std::string&, pmode) */ void open(const std::string& cmd, pmode mode = pstdout) { this->do_open(cmd, readable(mode)); } /** * @brief Start a process. * * Calls do_open( @a file , @a argv , @a mode|pstdout ). * * @param file a string containing the pathname of a program to execute. * @param argv a vector of argument strings passed to the new program. * @param mode the I/O mode to use when opening the pipe. * @see do_open(const std::string&, const argv_type&, pmode) */ void open( const std::string& file, const argv_type& argv, pmode mode = pstdout ) { this->do_open(file, argv, readable(mode)); } /** * @brief Set streambuf to read from process' @c stdout. * @return @c *this */ basic_ipstream& out() { this->buf_.read_err(false); return *this; } }; /** * @class basic_opstream * @brief Class template for Output PStreams. * * Writing to an open opstream writes to the standard input of the command; * the command's standard output is the same as that of the process that * created the pstream object, unless altered by the command itself. */ template > class basic_opstream : public std::basic_ostream , public pstream_common , virtual public pstreams { typedef std::basic_ostream ostream_type; typedef pstream_common pbase_type; using pbase_type::buf_; // declare name in this scope public: /// Type used to specify how to connect to the process. typedef typename pbase_type::pmode pmode; /// Type used to hold the arguments for a command. typedef typename pbase_type::argv_type argv_type; /// Default constructor, creates an uninitialised stream. basic_opstream() : ostream_type(NULL), pbase_type() { } /** * @brief Constructor that initialises the stream by starting a process. * * Initialises the stream buffer by calling do_open() with the supplied * arguments. * * @param cmd a string containing a shell command. * @param mode the I/O mode to use when opening the pipe. * @see do_open(const std::string&, pmode) */ explicit basic_opstream(const std::string& cmd, pmode mode = pstdin) : ostream_type(NULL), pbase_type(cmd, mode|pstdin) { } /** * @brief Constructor that initialises the stream by starting a process. * * Initialises the stream buffer by calling do_open() with the supplied * arguments. * * @param file a string containing the pathname of a program to execute. * @param argv a vector of argument strings passed to the new program. * @param mode the I/O mode to use when opening the pipe. * @see do_open(const std::string&, const argv_type&, pmode) */ basic_opstream( const std::string& file, const argv_type& argv, pmode mode = pstdin ) : ostream_type(NULL), pbase_type(file, argv, mode|pstdin) { } /** * @brief Constructor that initialises the stream by starting a process. * * Initialises the stream buffer by calling * @c do_open(argv[0],argv,mode|pstdin) * * @param argv a vector of argument strings passed to the new program. * @param mode the I/O mode to use when opening the pipe. * @see do_open(const std::string&, const argv_type&, pmode) */ explicit basic_opstream(const argv_type& argv, pmode mode = pstdin) : ostream_type(NULL), pbase_type(argv.at(0), argv, mode|pstdin) { } #if __cplusplus >= 201103L /** * @brief Constructor that initialises the stream by starting a process. * * @param args a list of argument strings passed to the new program. * @param mode the I/O mode to use when opening the pipe. * @see do_open(const std::string&, const argv_type&, pmode) */ template explicit basic_opstream(std::initializer_list args, pmode mode = pstdin) : basic_opstream(argv_type(args.begin(), args.end()), mode) { } #endif /** * @brief Destructor * * Closes the stream and waits for the child to exit. */ ~basic_opstream() { } /** * @brief Start a process. * * Calls do_open( @a cmd , @a mode|pstdin ). * * @param cmd a string containing a shell command. * @param mode the I/O mode to use when opening the pipe. * @see do_open(const std::string&, pmode) */ void open(const std::string& cmd, pmode mode = pstdin) { this->do_open(cmd, mode|pstdin); } /** * @brief Start a process. * * Calls do_open( @a file , @a argv , @a mode|pstdin ). * * @param file a string containing the pathname of a program to execute. * @param argv a vector of argument strings passed to the new program. * @param mode the I/O mode to use when opening the pipe. * @see do_open(const std::string&, const argv_type&, pmode) */ void open( const std::string& file, const argv_type& argv, pmode mode = pstdin) { this->do_open(file, argv, mode|pstdin); } }; /** * @class basic_pstream * @brief Class template for Bidirectional PStreams. * * Writing to a pstream opened with @c pmode @c pstdin writes to the * standard input of the command. * Reading from a pstream opened with @c pmode @c pstdout and/or @c pstderr * reads the command's standard output and/or standard error. * Any of the process' @c stdin, @c stdout or @c stderr that is not * connected to the pstream (as specified by the @c pmode) * will be the same as the process that created the pstream object, * unless altered by the command itself. */ template > class basic_pstream : public std::basic_iostream , public pstream_common , virtual public pstreams { typedef std::basic_iostream iostream_type; typedef pstream_common pbase_type; using pbase_type::buf_; // declare name in this scope public: /// Type used to specify how to connect to the process. typedef typename pbase_type::pmode pmode; /// Type used to hold the arguments for a command. typedef typename pbase_type::argv_type argv_type; /// Default constructor, creates an uninitialised stream. basic_pstream() : iostream_type(NULL), pbase_type() { } /** * @brief Constructor that initialises the stream by starting a process. * * Initialises the stream buffer by calling do_open() with the supplied * arguments. * * @param cmd a string containing a shell command. * @param mode the I/O mode to use when opening the pipe. * @see do_open(const std::string&, pmode) */ explicit basic_pstream(const std::string& cmd, pmode mode = pstdout|pstdin) : iostream_type(NULL), pbase_type(cmd, mode) { } /** * @brief Constructor that initialises the stream by starting a process. * * Initialises the stream buffer by calling do_open() with the supplied * arguments. * * @param file a string containing the pathname of a program to execute. * @param argv a vector of argument strings passed to the new program. * @param mode the I/O mode to use when opening the pipe. * @see do_open(const std::string&, const argv_type&, pmode) */ basic_pstream( const std::string& file, const argv_type& argv, pmode mode = pstdout|pstdin ) : iostream_type(NULL), pbase_type(file, argv, mode) { } /** * @brief Constructor that initialises the stream by starting a process. * * Initialises the stream buffer by calling * @c do_open(argv[0],argv,mode) * * @param argv a vector of argument strings passed to the new program. * @param mode the I/O mode to use when opening the pipe. * @see do_open(const std::string&, const argv_type&, pmode) */ explicit basic_pstream(const argv_type& argv, pmode mode = pstdout|pstdin) : iostream_type(NULL), pbase_type(argv.at(0), argv, mode) { } #if __cplusplus >= 201103L /** * @brief Constructor that initialises the stream by starting a process. * * @param l a list of argument strings passed to the new program. * @param mode the I/O mode to use when opening the pipe. * @see do_open(const std::string&, const argv_type&, pmode) */ template explicit basic_pstream(std::initializer_list l, pmode mode = pstdout|pstdin) : basic_pstream(argv_type(l.begin(), l.end()), mode) { } #endif /** * @brief Destructor * * Closes the stream and waits for the child to exit. */ ~basic_pstream() { } /** * @brief Start a process. * * Calls do_open( @a cnd , @a mode ). * * @param cmd a string containing a shell command. * @param mode the I/O mode to use when opening the pipe. * @see do_open(const std::string&, pmode) */ void open(const std::string& cmd, pmode mode = pstdout|pstdin) { this->do_open(cmd, mode); } /** * @brief Start a process. * * Calls do_open( @a file , @a argv , @a mode ). * * @param file a string containing the pathname of a program to execute. * @param argv a vector of argument strings passed to the new program. * @param mode the I/O mode to use when opening the pipe. * @see do_open(const std::string&, const argv_type&, pmode) */ void open( const std::string& file, const argv_type& argv, pmode mode = pstdout|pstdin ) { this->do_open(file, argv, mode); } /** * @brief Set streambuf to read from process' @c stdout. * @return @c *this */ basic_pstream& out() { this->buf_.read_err(false); return *this; } }; /** * @class basic_rpstream * @brief Class template for Restricted PStreams. * * Writing to an rpstream opened with @c pmode @c pstdin writes to the * standard input of the command. * It is not possible to read directly from an rpstream object, to use * an rpstream as in istream you must call either basic_rpstream::out() * or basic_rpstream::err(). This is to prevent accidental reads from * the wrong input source. If the rpstream was not opened with @c pmode * @c pstderr then the class cannot read the process' @c stderr, and * basic_rpstream::err() will return an istream that reads from the * process' @c stdout, and vice versa. * Reading from an rpstream opened with @c pmode @c pstdout and/or * @c pstderr reads the command's standard output and/or standard error. * Any of the process' @c stdin, @c stdout or @c stderr that is not * connected to the pstream (as specified by the @c pmode) * will be the same as the process that created the pstream object, * unless altered by the command itself. */ template > class basic_rpstream : public std::basic_ostream , private std::basic_istream , private pstream_common , virtual public pstreams { typedef std::basic_ostream ostream_type; typedef std::basic_istream istream_type; typedef pstream_common pbase_type; using pbase_type::buf_; // declare name in this scope public: /// Type used to specify how to connect to the process. typedef typename pbase_type::pmode pmode; /// Type used to hold the arguments for a command. typedef typename pbase_type::argv_type argv_type; /// Default constructor, creates an uninitialised stream. basic_rpstream() : ostream_type(NULL), istream_type(NULL), pbase_type() { } /** * @brief Constructor that initialises the stream by starting a process. * * Initialises the stream buffer by calling do_open() with the supplied * arguments. * * @param cmd a string containing a shell command. * @param mode the I/O mode to use when opening the pipe. * @see do_open(const std::string&, pmode) */ explicit basic_rpstream(const std::string& cmd, pmode mode = pstdout|pstdin) : ostream_type(NULL) , istream_type(NULL) , pbase_type(cmd, mode) { } /** * @brief Constructor that initialises the stream by starting a process. * * Initialises the stream buffer by calling do_open() with the supplied * arguments. * * @param file a string containing the pathname of a program to execute. * @param argv a vector of argument strings passed to the new program. * @param mode the I/O mode to use when opening the pipe. * @see do_open(const std::string&, const argv_type&, pmode) */ basic_rpstream( const std::string& file, const argv_type& argv, pmode mode = pstdout|pstdin ) : ostream_type(NULL), istream_type(NULL), pbase_type(file, argv, mode) { } /** * @brief Constructor that initialises the stream by starting a process. * * Initialises the stream buffer by calling * @c do_open(argv[0],argv,mode) * * @param argv a vector of argument strings passed to the new program. * @param mode the I/O mode to use when opening the pipe. * @see do_open(const std::string&, const argv_type&, pmode) */ explicit basic_rpstream(const argv_type& argv, pmode mode = pstdout|pstdin) : ostream_type(NULL), istream_type(NULL), pbase_type(argv.at(0), argv, mode) { } #if __cplusplus >= 201103L /** * @brief Constructor that initialises the stream by starting a process. * * @param l a list of argument strings passed to the new program. * @param mode the I/O mode to use when opening the pipe. * @see do_open(const std::string&, const argv_type&, pmode) */ template explicit basic_rpstream(std::initializer_list l, pmode mode = pstdout|pstdin) : basic_rpstream(argv_type(l.begin(), l.end()), mode) { } #endif /// Destructor ~basic_rpstream() { } /** * @brief Start a process. * * Calls do_open( @a cmd , @a mode ). * * @param cmd a string containing a shell command. * @param mode the I/O mode to use when opening the pipe. * @see do_open(const std::string&, pmode) */ void open(const std::string& cmd, pmode mode = pstdout|pstdin) { this->do_open(cmd, mode); } /** * @brief Start a process. * * Calls do_open( @a file , @a argv , @a mode ). * * @param file a string containing the pathname of a program to execute. * @param argv a vector of argument strings passed to the new program. * @param mode the I/O mode to use when opening the pipe. * @see do_open(const std::string&, const argv_type&, pmode) */ void open( const std::string& file, const argv_type& argv, pmode mode = pstdout|pstdin ) { this->do_open(file, argv, mode); } /** * @brief Obtain a reference to the istream that reads * the process' @c stdout. * @return @c *this */ istream_type& out() { this->buf_.read_err(false); return *this; } }; /// Type definition for common template specialisation. typedef basic_pstreambuf pstreambuf; /// Type definition for common template specialisation. typedef basic_ipstream ipstream; /// Type definition for common template specialisation. typedef basic_opstream opstream; /// Type definition for common template specialisation. typedef basic_pstream pstream; /// Type definition for common template specialisation. typedef basic_rpstream rpstream; /** * When inserted into an output pstream the manipulator calls * basic_pstreambuf::peof() to close the output pipe, * causing the child process to receive the end-of-file indicator * on subsequent reads from its @c stdin stream. * * @brief Manipulator to close the pipe connected to the process' stdin. * @param s An output PStream class. * @return The stream object the manipulator was invoked on. * @see basic_pstreambuf::peof() * @relates basic_opstream basic_pstream basic_rpstream */ template inline std::basic_ostream& peof(std::basic_ostream& s) { typedef basic_pstreambuf pstreambuf_type; if (pstreambuf_type* p = dynamic_cast(s.rdbuf())) p->peof(); return s; } /* * member definitions for pstreambuf */ /** * @class basic_pstreambuf * Provides underlying streambuf functionality for the PStreams classes. */ /** Creates an uninitialised stream buffer. */ template inline basic_pstreambuf::basic_pstreambuf() : ppid_(-1) // initialise to -1 to indicate no process run yet. , wpipe_(-1) , wbuffer_(NULL) , rsrc_(rsrc_out) , status_(-1) , error_(0) { init_rbuffers(); } /** * Initialises the stream buffer by calling open() with the supplied * arguments. * * @param cmd a string containing a shell command. * @param mode the I/O mode to use when opening the pipe. * @see open() */ template inline basic_pstreambuf::basic_pstreambuf(const std::string& cmd, pmode mode) : ppid_(-1) // initialise to -1 to indicate no process run yet. , wpipe_(-1) , wbuffer_(NULL) , rsrc_(rsrc_out) , status_(-1) , error_(0) { init_rbuffers(); open(cmd, mode); } /** * Initialises the stream buffer by calling open() with the supplied * arguments. * * @param file a string containing the name of a program to execute. * @param argv a vector of argument strings passsed to the new program. * @param mode the I/O mode to use when opening the pipe. * @see open() */ template inline basic_pstreambuf::basic_pstreambuf( const std::string& file, const argv_type& argv, pmode mode ) : ppid_(-1) // initialise to -1 to indicate no process run yet. , wpipe_(-1) , wbuffer_(NULL) , rsrc_(rsrc_out) , status_(-1) , error_(0) { init_rbuffers(); open(file, argv, mode); } /** * Closes the stream by calling close(). * @see close() */ template inline basic_pstreambuf::~basic_pstreambuf() { close(); } /** * Starts a new process by passing @a command to the shell (/bin/sh) * and opens pipes to the process with the specified @a mode. * * If @a mode contains @c pstdout the initial read source will be * the child process' stdout, otherwise if @a mode contains @c pstderr * the initial read source will be the child's stderr. * * Will duplicate the actions of the shell in searching for an * executable file if the specified file name does not contain a slash (/) * character. * * @warning * There is no way to tell whether the shell command succeeded, this * function will always succeed unless resource limits (such as * memory usage, or number of processes or open files) are exceeded. * This means is_open() will return true even if @a command cannot * be executed. * Use pstreambuf::open(const std::string&, const argv_type&, pmode) * if you need to know whether the command failed to execute. * * @param command a string containing a shell command. * @param mode a bitwise OR of one or more of @c out, @c in, @c err. * @return NULL if the shell could not be started or the * pipes could not be opened, @c this otherwise. * @see execl(3) */ template basic_pstreambuf* basic_pstreambuf::open(const std::string& command, pmode mode) { const char * shell_path = "/bin/sh"; #if 0 const std::string argv[] = { "sh", "-c", command }; return this->open(shell_path, argv_type(argv, argv+3), mode); #else basic_pstreambuf* ret = NULL; if (!is_open()) { switch(fork(mode)) { case 0 : // this is the new process, exec command ::execl(shell_path, "sh", "-c", command.c_str(), (char*)NULL); // can only reach this point if exec() failed // parent can get exit code from waitpid() ::_exit(errno); // using std::exit() would make static dtors run twice case -1 : // couldn't fork, error already handled in pstreambuf::fork() break; default : // this is the parent process // activate buffers create_buffers(mode); ret = this; } } return ret; #endif } /** * @brief Helper function to close a file descriptor. * * Inspects @a fd and calls close(3) if it has a non-negative value. * * @param fd a file descriptor. * @relates basic_pstreambuf */ inline void close_fd(pstreams::fd_type& fd) { if (fd >= 0 && ::close(fd) == 0) fd = -1; } /** * @brief Helper function to close an array of file descriptors. * * Calls @c close_fd() on each member of the array. * The length of the array is determined automatically by * template argument deduction to avoid errors. * * @param fds an array of file descriptors. * @relates basic_pstreambuf */ template inline void close_fd_array(pstreams::fd_type (&fds)[N]) { for (std::size_t i = 0; i < N; ++i) close_fd(fds[i]); } /** * Starts a new process by executing @a file with the arguments in * @a argv and opens pipes to the process with the specified @a mode. * * By convention @c argv[0] should be the file name of the file being * executed. * * If @a mode contains @c pstdout the initial read source will be * the child process' stdout, otherwise if @a mode contains @c pstderr * the initial read source will be the child's stderr. * * Will duplicate the actions of the shell in searching for an * executable file if the specified file name does not contain a slash (/) * character. * * Iff @a file is successfully executed then is_open() will return true. * Otherwise, pstreambuf::error() can be used to obtain the value of * @c errno that was set by execvp(3) in the child process. * * The exit status of the new process will be returned by * pstreambuf::status() after pstreambuf::exited() returns true. * * @param file a string containing the pathname of a program to execute. * @param argv a vector of argument strings passed to the new program. * @param mode a bitwise OR of one or more of @c out, @c in and @c err. * @return NULL if a pipe could not be opened or if the program could * not be executed, @c this otherwise. * @see execvp(3) */ template basic_pstreambuf* basic_pstreambuf::open( const std::string& file, const argv_type& argv, pmode mode ) { basic_pstreambuf* ret = NULL; if (!is_open()) { // constants for read/write ends of pipe enum { RD, WR }; // open another pipe and set close-on-exec fd_type ck_exec[] = { -1, -1 }; if (-1 == ::pipe(ck_exec) || -1 == ::fcntl(ck_exec[RD], F_SETFD, FD_CLOEXEC) || -1 == ::fcntl(ck_exec[WR], F_SETFD, FD_CLOEXEC)) { error_ = errno; close_fd_array(ck_exec); } else { switch(fork(mode)) { case 0 : // this is the new process, exec command { char** arg_v = new char*[argv.size()+1]; for (std::size_t i = 0; i < argv.size(); ++i) { const std::string& src = argv[i]; char*& dest = arg_v[i]; dest = new char[src.size()+1]; dest[ src.copy(dest, src.size()) ] = '\0'; } arg_v[argv.size()] = NULL; ::execvp(file.c_str(), arg_v); // can only reach this point if exec() failed // parent can get error code from ck_exec pipe error_ = errno; while (::write(ck_exec[WR], &error_, sizeof(error_)) == -1 && errno == EINTR) { } ::close(ck_exec[WR]); ::close(ck_exec[RD]); ::_exit(error_); // using std::exit() would make static dtors run twice } case -1 : // couldn't fork, error already handled in pstreambuf::fork() close_fd_array(ck_exec); break; default : // this is the parent process // check child called exec() successfully ::close(ck_exec[WR]); switch (::read(ck_exec[RD], &error_, sizeof(error_))) { case 0: // activate buffers create_buffers(mode); ret = this; break; case -1: error_ = errno; break; default: // error_ contains error code from child // call wait() to clean up and set ppid_ to 0 this->wait(); break; } ::close(ck_exec[RD]); } } } return ret; } /** * Creates pipes as specified by @a mode and calls @c fork() to create * a new process. If the fork is successful the parent process stores * the child's PID and the opened pipes and the child process replaces * its standard streams with the opened pipes. * * If an error occurs the error code will be set to one of the possible * errors for @c pipe() or @c fork(). * See your system's documentation for these error codes. * * @param mode an OR of pmodes specifying which of the child's * standard streams to connect to. * @return On success the PID of the child is returned in the parent's * context and zero is returned in the child's context. * On error -1 is returned and the error code is set appropriately. */ template pid_t basic_pstreambuf::fork(pmode mode) { pid_t pid = -1; // Three pairs of file descriptors, for pipes connected to the // process' stdin, stdout and stderr // (stored in a single array so close_fd_array() can close all at once) fd_type fd[] = { -1, -1, -1, -1, -1, -1 }; fd_type* const pin = fd; fd_type* const pout = fd+2; fd_type* const perr = fd+4; // constants for read/write ends of pipe enum { RD, WR }; // N.B. // For the pstreambuf pin is an output stream and // pout and perr are input streams. if (!error_ && mode&pstdin && ::pipe(pin)) error_ = errno; if (!error_ && mode&pstdout && ::pipe(pout)) error_ = errno; if (!error_ && mode&pstderr && ::pipe(perr)) error_ = errno; if (!error_) { pid = ::fork(); switch (pid) { case 0 : { // this is the new process // for each open pipe close one end and redirect the // respective standard stream to the other end if (*pin >= 0) { ::close(pin[WR]); ::dup2(pin[RD], STDIN_FILENO); ::close(pin[RD]); } if (*pout >= 0) { ::close(pout[RD]); ::dup2(pout[WR], STDOUT_FILENO); ::close(pout[WR]); } if (*perr >= 0) { ::close(perr[RD]); ::dup2(perr[WR], STDERR_FILENO); ::close(perr[WR]); } #ifdef _POSIX_JOB_CONTROL if (mode&newpg) ::setpgid(0, 0); // Change to a new process group #endif break; } case -1 : { // couldn't fork for some reason error_ = errno; // close any open pipes close_fd_array(fd); break; } default : { // this is the parent process, store process' pid ppid_ = pid; // store one end of open pipes and close other end if (*pin >= 0) { wpipe_ = pin[WR]; ::close(pin[RD]); } if (*pout >= 0) { rpipe_[rsrc_out] = pout[RD]; ::close(pout[WR]); } if (*perr >= 0) { rpipe_[rsrc_err] = perr[RD]; ::close(perr[WR]); } } } } else { // close any pipes we opened before failure close_fd_array(fd); } return pid; } /** * Closes all pipes and calls wait() to wait for the process to finish. * If an error occurs the error code will be set to one of the possible * errors for @c waitpid(). * See your system's documentation for these errors. * * @return @c this on successful close or @c NULL if there is no * process to close or if an error occurs. */ template basic_pstreambuf* basic_pstreambuf::close() { const bool running = is_open(); sync(); // this might call wait() and reap the child process // rather than trying to work out whether or not we need to clean up // just do it anyway, all cleanup functions are safe to call twice. destroy_buffers(pstdin|pstdout|pstderr); // close pipes before wait() so child gets EOF/SIGPIPE close_fd(wpipe_); close_fd_array(rpipe_); do { error_ = 0; } while (wait() == -1 && error() == EINTR); return running ? this : NULL; } /** * Called on construction to initialise the arrays used for reading. */ template inline void basic_pstreambuf::init_rbuffers() { rpipe_[rsrc_out] = rpipe_[rsrc_err] = -1; rbuffer_[rsrc_out] = rbuffer_[rsrc_err] = NULL; rbufstate_[0] = rbufstate_[1] = rbufstate_[2] = NULL; } template void basic_pstreambuf::create_buffers(pmode mode) { if (mode & pstdin) { delete[] wbuffer_; wbuffer_ = new char_type[bufsz]; this->setp(wbuffer_, wbuffer_ + bufsz); } if (mode & pstdout) { delete[] rbuffer_[rsrc_out]; rbuffer_[rsrc_out] = new char_type[bufsz]; rsrc_ = rsrc_out; this->setg(rbuffer_[rsrc_out] + pbsz, rbuffer_[rsrc_out] + pbsz, rbuffer_[rsrc_out] + pbsz); } if (mode & pstderr) { delete[] rbuffer_[rsrc_err]; rbuffer_[rsrc_err] = new char_type[bufsz]; if (!(mode & pstdout)) { rsrc_ = rsrc_err; this->setg(rbuffer_[rsrc_err] + pbsz, rbuffer_[rsrc_err] + pbsz, rbuffer_[rsrc_err] + pbsz); } } } template void basic_pstreambuf::destroy_buffers(pmode mode) { if (mode & pstdin) { this->setp(NULL, NULL); delete[] wbuffer_; wbuffer_ = NULL; } if (mode & pstdout) { if (rsrc_ == rsrc_out) this->setg(NULL, NULL, NULL); delete[] rbuffer_[rsrc_out]; rbuffer_[rsrc_out] = NULL; } if (mode & pstderr) { if (rsrc_ == rsrc_err) this->setg(NULL, NULL, NULL); delete[] rbuffer_[rsrc_err]; rbuffer_[rsrc_err] = NULL; } } template typename basic_pstreambuf::buf_read_src basic_pstreambuf::switch_read_buffer(buf_read_src src) { if (rsrc_ != src) { char_type* tmpbufstate[] = {this->eback(), this->gptr(), this->egptr()}; this->setg(rbufstate_[0], rbufstate_[1], rbufstate_[2]); for (std::size_t i = 0; i < 3; ++i) rbufstate_[i] = tmpbufstate[i]; rsrc_ = src; } return rsrc_; } /** * Suspends execution and waits for the associated process to exit, or * until a signal is delivered whose action is to terminate the current * process or to call a signal handling function. If the process has * already exited (i.e. it is a "zombie" process) then wait() returns * immediately. Waiting for the child process causes all its system * resources to be freed. * * error() will return EINTR if wait() is interrupted by a signal. * * @param nohang true to return immediately if the process has not exited. * @return 1 if the process has exited and wait() has not yet been called. * 0 if @a nohang is true and the process has not exited yet. * -1 if no process has been started or if an error occurs, * in which case the error can be found using error(). */ template int basic_pstreambuf::wait(bool nohang) { int child_exited = -1; if (is_open()) { int exit_status; switch(::waitpid(ppid_, &exit_status, nohang ? WNOHANG : 0)) { case 0 : // nohang was true and process has not exited child_exited = 0; break; case -1 : error_ = errno; break; default : // process has exited ppid_ = 0; status_ = exit_status; child_exited = 1; // Close wpipe, would get SIGPIPE if we used it. destroy_buffers(pstdin); close_fd(wpipe_); // Must free read buffers and pipes on destruction // or next call to open()/close() break; } } return child_exited; } /** * Sends the specified signal to the process. A signal can be used to * terminate a child process that would not exit otherwise. * * If an error occurs the error code will be set to one of the possible * errors for @c kill(). See your system's documentation for these errors. * * @param signal A signal to send to the child process. * @return @c this or @c NULL if @c kill() fails. */ template inline basic_pstreambuf* basic_pstreambuf::kill(int signal) { basic_pstreambuf* ret = NULL; if (is_open()) { if (::kill(ppid_, signal)) error_ = errno; else { #if 0 // TODO call exited() to check for exit and clean up? leave to user? if (signal==SIGTERM || signal==SIGKILL) this->exited(); #endif ret = this; } } return ret; } /** * Sends the specified signal to the process group of the child process. * A signal can be used to terminate a child process that would not exit * otherwise, or to kill the process and its own children. * * If an error occurs the error code will be set to one of the possible * errors for @c getpgid() or @c kill(). See your system's documentation * for these errors. If the child is in the current process group then * NULL will be returned and the error code set to EPERM. * * @param signal A signal to send to the child process. * @return @c this on success or @c NULL on failure. */ template inline basic_pstreambuf* basic_pstreambuf::killpg(int signal) { basic_pstreambuf* ret = NULL; #ifdef _POSIX_JOB_CONTROL if (is_open()) { pid_t pgid = ::getpgid(ppid_); if (pgid == -1) error_ = errno; else if (pgid == ::getpgrp()) error_ = EPERM; // Don't commit suicide else if (::killpg(pgid, signal)) error_ = errno; else ret = this; } #else error_ = ENOTSUP; #endif return ret; } /** * This function can call pstreambuf::wait() and so may change the * object's state if the child process has already exited. * * @return True if the associated process has exited, false otherwise. * @see basic_pstreambuf::wait() */ template inline bool basic_pstreambuf::exited() { return ppid_ == 0 || wait(true)==1; } /** * @return The error code of the most recently failed operation, or zero. */ template inline int basic_pstreambuf::error() const { return error_; } /** * Closes the output pipe, causing the child process to receive the * end-of-file indicator on subsequent reads from its @c stdin stream. */ template inline void basic_pstreambuf::peof() { sync(); destroy_buffers(pstdin); close_fd(wpipe_); } /** * Unlike pstreambuf::exited(), this function will not call wait() and * so will not change the object's state. This means that once a child * process is executed successfully this function will continue to * return true even after the process exits (until wait() is called.) * * @return true if a previous call to open() succeeded and wait() has * not been called and determined that the process has exited, * false otherwise. */ template inline bool basic_pstreambuf::is_open() const { return ppid_ > 0; } /** * Toggle the stream used for reading. If @a readerr is @c true then the * process' @c stderr output will be used for subsequent extractions, if * @a readerr is false the the process' stdout will be used. * @param readerr @c true to read @c stderr, @c false to read @c stdout. * @return @c true if the requested stream is open and will be used for * subsequent extractions, @c false otherwise. */ template inline bool basic_pstreambuf::read_err(bool readerr) { buf_read_src src = readerr ? rsrc_err : rsrc_out; if (rpipe_[src]>=0) { switch_read_buffer(src); return true; } return false; } /** * Called when the internal character buffer is not present or is full, * to transfer the buffer contents to the pipe. * * @param c a character to be written to the pipe. * @return @c traits_type::eof() if an error occurs, otherwise if @a c * is not equal to @c traits_type::eof() it will be buffered and * a value other than @c traits_type::eof() returned to indicate * success. */ template typename basic_pstreambuf::int_type basic_pstreambuf::overflow(int_type c) { if (!empty_buffer()) return traits_type::eof(); else if (!traits_type::eq_int_type(c, traits_type::eof())) return this->sputc(c); else return traits_type::not_eof(c); } template int basic_pstreambuf::sync() { return !exited() && empty_buffer() ? 0 : -1; } /** * @param s character buffer. * @param n buffer length. * @return the number of characters written. */ template std::streamsize basic_pstreambuf::xsputn(const char_type* s, std::streamsize n) { std::streamsize done = 0; while (done < n) { if (std::streamsize nbuf = this->epptr() - this->pptr()) { nbuf = std::min(nbuf, n - done); traits_type::copy(this->pptr(), s + done, nbuf); this->pbump(nbuf); done += nbuf; } else if (!empty_buffer()) break; } return done; } /** * @return true if the buffer was emptied, false otherwise. */ template bool basic_pstreambuf::empty_buffer() { const std::streamsize count = this->pptr() - this->pbase(); if (count > 0) { const std::streamsize written = this->write(this->wbuffer_, count); if (written > 0) { if (const std::streamsize unwritten = count - written) traits_type::move(this->pbase(), this->pbase()+written, unwritten); this->pbump(-written); return true; } } return false; } /** * Called when the internal character buffer is is empty, to re-fill it * from the pipe. * * @return The first available character in the buffer, * or @c traits_type::eof() in case of failure. */ template typename basic_pstreambuf::int_type basic_pstreambuf::underflow() { if (this->gptr() < this->egptr() || fill_buffer()) return traits_type::to_int_type(*this->gptr()); else return traits_type::eof(); } /** * Attempts to make @a c available as the next character to be read by * @c sgetc(). * * @param c a character to make available for extraction. * @return @a c if the character can be made available, * @c traits_type::eof() otherwise. */ template typename basic_pstreambuf::int_type basic_pstreambuf::pbackfail(int_type c) { if (this->gptr() != this->eback()) { this->gbump(-1); if (!traits_type::eq_int_type(c, traits_type::eof())) *this->gptr() = traits_type::to_char_type(c); return traits_type::not_eof(c); } else return traits_type::eof(); } template std::streamsize basic_pstreambuf::showmanyc() { int avail = 0; if (sizeof(char_type) == 1) avail = fill_buffer(true) ? this->egptr() - this->gptr() : -1; #ifdef FIONREAD else { if (::ioctl(rpipe(), FIONREAD, &avail) == -1) avail = -1; else if (avail) avail /= sizeof(char_type); } #endif return std::streamsize(avail); } /** * @return true if the buffer was filled, false otherwise. */ template bool basic_pstreambuf::fill_buffer(bool non_blocking) { const std::streamsize pb1 = this->gptr() - this->eback(); const std::streamsize pb2 = pbsz; const std::streamsize npb = std::min(pb1, pb2); char_type* const rbuf = rbuffer(); if (npb) traits_type::move(rbuf + pbsz - npb, this->gptr() - npb, npb); std::streamsize rc = -1; if (non_blocking) { const int flags = ::fcntl(rpipe(), F_GETFL); if (flags != -1) { const bool blocking = !(flags & O_NONBLOCK); if (blocking) ::fcntl(rpipe(), F_SETFL, flags | O_NONBLOCK); // set non-blocking error_ = 0; rc = read(rbuf + pbsz, bufsz - pbsz); if (rc == -1 && error_ == EAGAIN) // nothing available rc = 0; else if (rc == 0) // EOF rc = -1; if (blocking) ::fcntl(rpipe(), F_SETFL, flags); // restore } } else rc = read(rbuf + pbsz, bufsz - pbsz); if (rc > 0 || (rc == 0 && non_blocking)) { this->setg( rbuf + pbsz - npb, rbuf + pbsz, rbuf + pbsz + rc ); return true; } else { this->setg(NULL, NULL, NULL); return false; } } /** * Writes up to @a n characters to the pipe from the buffer @a s. * * @param s character buffer. * @param n buffer length. * @return the number of characters written. */ template inline std::streamsize basic_pstreambuf::write(const char_type* s, std::streamsize n) { std::streamsize nwritten = 0; if (wpipe() >= 0) { nwritten = ::write(wpipe(), s, n * sizeof(char_type)); if (nwritten == -1) error_ = errno; else nwritten /= sizeof(char_type); } return nwritten; } /** * Reads up to @a n characters from the pipe to the buffer @a s. * * @param s character buffer. * @param n buffer length. * @return the number of characters read. */ template inline std::streamsize basic_pstreambuf::read(char_type* s, std::streamsize n) { std::streamsize nread = 0; if (rpipe() >= 0) { nread = ::read(rpipe(), s, n * sizeof(char_type)); if (nread == -1) error_ = errno; else nread /= sizeof(char_type); } return nread; } /** @return a reference to the output file descriptor */ template inline pstreams::fd_type& basic_pstreambuf::wpipe() { return wpipe_; } /** @return a reference to the active input file descriptor */ template inline pstreams::fd_type& basic_pstreambuf::rpipe() { return rpipe_[rsrc_]; } /** @return a reference to the specified input file descriptor */ template inline pstreams::fd_type& basic_pstreambuf::rpipe(buf_read_src which) { return rpipe_[which]; } /** @return a pointer to the start of the active input buffer area. */ template inline typename basic_pstreambuf::char_type* basic_pstreambuf::rbuffer() { return rbuffer_[rsrc_]; } /* * member definitions for pstream_common */ /** * @class pstream_common * Abstract Base Class providing common functionality for basic_ipstream, * basic_opstream and basic_pstream. * pstream_common manages the basic_pstreambuf stream buffer that is used * by the derived classes to initialise an iostream class. */ /** Creates an uninitialised stream. */ template inline pstream_common::pstream_common() : std::basic_ios(NULL) , command_() , buf_() { this->std::basic_ios::rdbuf(&buf_); } /** * Initialises the stream buffer by calling * do_open( @a command , @a mode ) * * @param cmd a string containing a shell command. * @param mode the I/O mode to use when opening the pipe. * @see do_open(const std::string&, pmode) */ template inline pstream_common::pstream_common(const std::string& cmd, pmode mode) : std::basic_ios(NULL) , command_(cmd) , buf_() { this->std::basic_ios::rdbuf(&buf_); do_open(cmd, mode); } /** * Initialises the stream buffer by calling * do_open( @a file , @a argv , @a mode ) * * @param file a string containing the pathname of a program to execute. * @param argv a vector of argument strings passed to the new program. * @param mode the I/O mode to use when opening the pipe. * @see do_open(const std::string&, const argv_type&, pmode) */ template inline pstream_common::pstream_common( const std::string& file, const argv_type& argv, pmode mode ) : std::basic_ios(NULL) , command_(file) , buf_() { this->std::basic_ios::rdbuf(&buf_); do_open(file, argv, mode); } /** * This is a pure virtual function to make @c pstream_common abstract. * Because it is the destructor it will be called by derived classes * and so must be defined. It is also protected, to discourage use of * the PStreams classes through pointers or references to the base class. * * @sa If defining a pure virtual seems odd you should read * http://www.gotw.ca/gotw/031.htm (and the rest of the site as well!) */ template inline pstream_common::~pstream_common() { } /** * Calls rdbuf()->open( @a command , @a mode ) * and sets @c failbit on error. * * @param cmd a string containing a shell command. * @param mode the I/O mode to use when opening the pipe. * @see basic_pstreambuf::open(const std::string&, pmode) */ template inline void pstream_common::do_open(const std::string& cmd, pmode mode) { if (!buf_.open((command_=cmd), mode)) this->setstate(std::ios_base::failbit); } /** * Calls rdbuf()->open( @a file, @a argv, @a mode ) * and sets @c failbit on error. * * @param file a string containing the pathname of a program to execute. * @param argv a vector of argument strings passed to the new program. * @param mode the I/O mode to use when opening the pipe. * @see basic_pstreambuf::open(const std::string&, const argv_type&, pmode) */ template inline void pstream_common::do_open( const std::string& file, const argv_type& argv, pmode mode ) { if (!buf_.open((command_=file), argv, mode)) this->setstate(std::ios_base::failbit); } /** Calls rdbuf->close() and sets @c failbit on error. */ template inline void pstream_common::close() { if (!buf_.close()) this->setstate(std::ios_base::failbit); } /** * @return rdbuf()->is_open(). * @see basic_pstreambuf::is_open() */ template inline bool pstream_common::is_open() const { return buf_.is_open(); } /** @return a pointer to the private stream buffer member. */ // TODO document behaviour if buffer replaced. template inline typename pstream_common::streambuf_type* pstream_common::rdbuf() const { return const_cast(&buf_); } #if REDI_EVISCERATE_PSTREAMS /** * @def REDI_EVISCERATE_PSTREAMS * If this macro has a non-zero value then certain internals of the * @c basic_pstreambuf template class are exposed. In general this is * a Bad Thing, as the internal implementation is largely undocumented * and may be subject to change at any time, so this feature is only * provided because it might make PStreams useful in situations where * it is necessary to do Bad Things. */ /** * @warning This function exposes the internals of the stream buffer and * should be used with caution. It is the caller's responsibility * to flush streams etc. in order to clear any buffered data. * The POSIX.1 function fdopen(3) is used to obtain the * @c FILE pointers from the streambuf's private file descriptor * members so consult your system's documentation for * fdopen(3). * * @param in A FILE* that will refer to the process' stdin. * @param out A FILE* that will refer to the process' stdout. * @param err A FILE* that will refer to the process' stderr. * @return An OR of zero or more of @c pstdin, @c pstdout, @c pstderr. * * For each open stream shared with the child process a @c FILE* is * obtained and assigned to the corresponding parameter. For closed * streams @c NULL is assigned to the parameter. * The return value can be tested to see which parameters should be * @c !NULL by masking with the corresponding @c pmode value. * * @see fdopen(3) */ template std::size_t basic_pstreambuf::fopen(FILE*& in, FILE*& out, FILE*& err) { in = out = err = NULL; std::size_t open_files = 0; if (wpipe() > -1) { if ((in = ::fdopen(wpipe(), "w"))) { open_files |= pstdin; } } if (rpipe(rsrc_out) > -1) { if ((out = ::fdopen(rpipe(rsrc_out), "r"))) { open_files |= pstdout; } } if (rpipe(rsrc_err) > -1) { if ((err = ::fdopen(rpipe(rsrc_err), "r"))) { open_files |= pstderr; } } return open_files; } /** * @warning This function exposes the internals of the stream buffer and * should be used with caution. * * @param in A FILE* that will refer to the process' stdin. * @param out A FILE* that will refer to the process' stdout. * @param err A FILE* that will refer to the process' stderr. * @return A bitwise-or of zero or more of @c pstdin, @c pstdout, @c pstderr. * @see basic_pstreambuf::fopen() */ template inline std::size_t pstream_common::fopen(FILE*& fin, FILE*& fout, FILE*& ferr) { return buf_.fopen(fin, fout, ferr); } #endif // REDI_EVISCERATE_PSTREAMS } // namespace redi #endif // REDI_PSTREAM_H_SEEN #endif // WIN32 /* pstream END */ /* main START */ size_t readList(const string &infile,vector&lines) { stringstream buf; if (infile=="-") buf< lines; readList(infile,lines); /* renumber residue index */ size_t r=0; size_t l; string prev_resi=""; string resi=""; string newresi=""; string line; string txt=""; for (l=0;l=54 && (StartsWith(line,"ATOM ") ||StartsWith(line,"HETATM"))) { resi=line.substr(22,5); r+=(resi!=prev_resi); buf<().swap(lines); string ().swap(prev_resi); string ().swap(resi); string ().swap(newresi); string ().swap(line); string ().swap(txt); } int main(int argc,char **argv) { string infile =""; string outfile=""; string listfile=""; for (int a=1;a filename_list; readList(listfile,filename_list); size_t l; for (l=0;l ().swap(filename_list); } /* clean up */ string ().swap(infile); string ().swap(outfile); return 0; } /* main END */