jmmv a817576754 Import atf-0.19:
Experimental version released on February 7th, 2014.

This is the last release to bundle the code for the deprecated tools.
The next release will drop their code and will stop worrying about
backwards compatibility between the ATF libraries and what the old tools
may or may not support.

If you still require the old tools for some reason, grab a copy of the
'tools' directory now.  The code in this directory is standalone and
does not depend on any internal details of atf-c++ any longer.

* Various fixes and improvements to support running as part of the FreeBSD
  test suite.

* Project hosting moved from Google Code (as a subproject of Kyua) to
  GitHub (as a first-class project).  The main reason for the change is
  the suppression of binary downloads in Google Code on Jan 15th, 2014.
  See https://github.com/jmmv/atf/

* Removed builtin help from atf-sh(1) and atf-check(1) for simplicity
  reasons.  In other words, their -h option is gone.

* Moved the code of the deprecated tools into a 'tools' directory and
  completely decoupled their code from the internals of atf-c++.  The
  reason for this is to painlessly allow a third-party to maintain a
  copy of these tools after we delete them because upcoming changes to
  atf-c++ would break the stale tools.
2014-02-14 14:41:25 +00:00

437 lines
15 KiB
C++

//
// Automated Testing Framework (atf)
//
// Copyright (c) 2007 The NetBSD Foundation, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#if !defined(TOOLS_IO_HPP)
#define TOOLS_IO_HPP
#include <istream>
#include <ostream>
#include <streambuf>
#include "auto_array.hpp"
#include "fs.hpp"
namespace tools {
namespace io {
// ------------------------------------------------------------------------
// The "file_handle" class.
// ------------------------------------------------------------------------
//!
//! \brief Simple RAII model for system file handles.
//!
//! The \a file_handle class is a simple RAII model for native system file
//! handles. This class wraps one of such handles grabbing its ownership,
//! and automaticaly closes it upon destruction. It is basically used
//! inside the library to avoid leaking open file handles, shall an
//! unexpected execution trace occur.
//!
//! A \a file_handle object can be copied but doing so invalidates the
//! source object. There can only be a single valid \a file_handle object
//! for a given system file handle. This is similar to std::auto_ptr\<\>'s
//! semantics.
//!
//! This class also provides some convenience methods to issue special file
//! operations under their respective platforms.
//!
class file_handle
{
public:
//!
//! \brief Opaque name for the native handle type.
//!
//! Each operating system identifies file handles using a specific type.
//! The \a handle_type type is used to transparently refer to file
//! handles regarless of the operating system in which this class is
//! used.
//!
//! If this class is used in a POSIX system, \a NativeSystemHandle is
//! an integer type while it is a \a HANDLE in a Win32 system.
//!
typedef int handle_type;
//!
//! \brief Constructs an invalid file handle.
//!
//! This constructor creates a new \a file_handle object that represents
//! an invalid file handle. An invalid file handle can be copied but
//! cannot be manipulated in any way (except checking for its validity).
//!
//! \see is_valid()
//!
file_handle(void);
//!
//! \brief Constructs a new file handle from a native file handle.
//!
//! This constructor creates a new \a file_handle object that takes
//! ownership of the given \a h native file handle. The user must not
//! close \a h on his own during the lifetime of the new object.
//! Ownership can be reclaimed using disown().
//!
//! \pre The native file handle must be valid; a close operation must
//! succeed on it.
//!
//! \see disown()
//!
file_handle(handle_type h);
//!
//! \brief Copy constructor; invalidates the source handle.
//!
//! This copy constructor creates a new file handle from a given one.
//! Ownership of the native file handle is transferred to the new
//! object, effectively invalidating the source file handle. This
//! avoids having two live \a file_handle objects referring to the
//! same native file handle. The source file handle need not be
//! valid in the name of simplicity.
//!
//! \post The source file handle is invalid.
//! \post The new file handle owns the source's native file handle.
//!
file_handle(const file_handle& fh);
//!
//! \brief Releases resources if the handle is valid.
//!
//! If the file handle is valid, the destructor closes it.
//!
//! \see is_valid()
//!
~file_handle(void);
//!
//! \brief Assignment operator; invalidates the source handle.
//!
//! This assignment operator transfers ownership of the RHS file
//! handle to the LHS one, effectively invalidating the source file
//! handle. This avoids having two live \a file_handle objects
//! referring to the same native file handle. The source file
//! handle need not be valid in the name of simplicity.
//!
//! \post The RHS file handle is invalid.
//! \post The LHS file handle owns RHS' native file handle.
//! \return A reference to the LHS file handle.
//!
file_handle& operator=(const file_handle& fh);
//!
//! \brief Checks whether the file handle is valid or not.
//!
//! Returns a boolean indicating whether the file handle is valid or
//! not. If the file handle is invalid, no other applications can be
//! executed other than the destructor.
//!
//! \return True if the file handle is valid; false otherwise.
//!
bool is_valid(void) const;
//!
//! \brief Closes the file handle.
//!
//! Explicitly closes the file handle, which must be valid. Upon
//! exit, the handle is not valid any more.
//!
//! \pre The file handle is valid.
//! \post The file handle is invalid.
//! \post The native file handle is closed.
//!
void close(void);
//!
//! \brief Reclaims ownership of the native file handle.
//!
//! Explicitly reclaims ownership of the native file handle contained
//! in the \a file_handle object, returning the native file handle.
//! The caller is responsible of closing it later on.
//!
//! \pre The file handle is valid.
//! \post The file handle is invalid.
//! \return The native file handle.
//!
handle_type disown(void);
//!
//! \brief Gets the native file handle.
//!
//! Returns the native file handle for the \a file_handle object.
//! The caller can issue any operation on it except closing it.
//! If closing is required, disown() shall be used.
//!
//! \pre The file handle is valid.
//! \return The native file handle.
//!
handle_type get(void) const;
//!
//! \brief Changes the native file handle to the given one.
//!
//! Given a new native file handle \a h, this operation assigns this
//! handle to the current object, closing its old native file handle.
//! In other words, it first calls dup2() to remap the old handle to
//! the new one and then closes the old handle.
//!
//! If \a h matches the current value of the handle, this is a no-op.
//! This is done for simplicity, to avoid the caller having to check
//! this condition on its own.
//!
//! If \a h is open, it is automatically closed by dup2().
//!
//! This operation is only available in POSIX systems.
//!
//! \pre The file handle is valid.
//! \pre The native file handle \a h is valid; i.e., it must be
//! closeable.
//! \post The file handle's native file handle is \a h.
//! \throw system_error If the internal remapping operation fails.
//!
void posix_remap(handle_type h);
private:
//!
//! \brief Internal handle value.
//!
//! This variable holds the native handle value for the file handle
//! hold by this object. It is interesting to note that this needs
//! to be mutable because the copy constructor and the assignment
//! operator invalidate the source object.
//!
mutable handle_type m_handle;
//!
//! \brief Constant function representing an invalid handle value.
//!
//! Returns the platform-specific handle value that represents an
//! invalid handle. This is a constant function rather than a regular
//! constant because, in the latter case, we cannot define it under
//! Win32 due to the value being of a complex type.
//!
static handle_type invalid_value(void);
};
// ------------------------------------------------------------------------
// The "systembuf" class.
// ------------------------------------------------------------------------
//!
//! \brief std::streambuf implementation for system file handles.
//!
//! systembuf provides a std::streambuf implementation for system file
//! handles. Contrarywise to file_handle, this class does \b not take
//! ownership of the native file handle; this should be taken care of
//! somewhere else.
//!
//! This class follows the expected semantics of a std::streambuf object.
//! However, it is not copyable to avoid introducing inconsistences with
//! the on-disk file and the in-memory buffers.
//!
class systembuf : public std::streambuf
{
// Non-copyable.
systembuf(const systembuf&);
systembuf& operator=(const systembuf&);
public:
typedef int handle_type;
//!
//! \brief Constructs a new systembuf for the given file handle.
//!
//! This constructor creates a new systembuf object that reads or
//! writes data from/to the \a h native file handle. This handle
//! is \b not owned by the created systembuf object; the code
//! should take care of it externally.
//!
//! This class buffers input and output; the buffer size may be
//! tuned through the \a bufsize parameter, which defaults to 8192
//! bytes.
//!
//! \see pistream.
//!
explicit systembuf(handle_type h, std::size_t bufsize = 8192);
~systembuf(void);
private:
//!
//! \brief Native file handle used by the systembuf object.
//!
handle_type m_handle;
//!
//! \brief Internal buffer size used during read and write operations.
//!
std::size_t m_bufsize;
//!
//! \brief Internal buffer used during read operations.
//!
char* m_read_buf;
//!
//! \brief Internal buffer used during write operations.
//!
char* m_write_buf;
protected:
//!
//! \brief Reads new data from the native file handle.
//!
//! This operation is called by input methods when there are no more
//! data in the input buffer. The function fills the buffer with new
//! data, if available.
//!
//! \pre All input positions are exhausted (gptr() >= egptr()).
//! \post The input buffer has new data, if available.
//! \returns traits_type::eof() if a read error occurrs or there are
//! no more data to be read. Otherwise returns
//! traits_type::to_int_type(*gptr()).
//!
virtual int_type underflow(void);
//!
//! \brief Makes room in the write buffer for additional data.
//!
//! This operation is called by output methods when there is no more
//! space in the output buffer to hold a new element. The function
//! first flushes the buffer's contents to disk and then clears it to
//! leave room for more characters. The given \a c character is
//! stored at the beginning of the new space.
//!
//! \pre All output positions are exhausted (pptr() >= epptr()).
//! \post The output buffer has more space if no errors occurred
//! during the write to disk.
//! \post *(pptr() - 1) is \a c.
//! \returns traits_type::eof() if a write error occurrs. Otherwise
//! returns traits_type::not_eof(c).
//!
virtual int_type overflow(int c);
//!
//! \brief Flushes the output buffer to disk.
//!
//! Synchronizes the systembuf buffers with the contents of the file
//! associated to this object through the native file handle. The
//! output buffer is flushed to disk and cleared to leave new room
//! for more data.
//!
//! \returns 0 on success, -1 if an error occurred.
//!
virtual int sync(void);
};
// ------------------------------------------------------------------------
// The "pistream" class.
// ------------------------------------------------------------------------
//!
//! \brief Child process' output stream.
//!
//! The pistream class represents an output communication channel with the
//! child process. The child process writes data to this stream and the
//! parent process can read it through the pistream object. In other
//! words, from the child's point of view, the communication channel is an
//! output one, but from the parent's point of view it is an input one;
//! hence the confusing pistream name.
//!
//! pistream objects cannot be copied because they own the file handle
//! they use to communicate with the child and because they buffer data
//! that flows through the communication channel.
//!
//! A pistream object behaves as a std::istream stream in all senses.
//! The class is only provided because it must provide a method to let
//! the caller explicitly close the communication channel.
//!
//! \remark <b>Blocking remarks</b>: Functions that read data from this
//! stream can block if the associated file handle blocks during the read.
//! As this class is used to communicate with child processes through
//! anonymous pipes, the most typical blocking condition happens when the
//! child has no more data to send to the pipe's system buffer. When
//! this happens, the buffer eventually empties and the system blocks
//! until the writer generates some data.
//!
class pistream : public std::istream
{
// Non-copyable.
pistream(const pistream&);
pistream& operator=(const pistream&);
//!
//! \brief The systembuf object used to manage this stream's data.
//!
systembuf m_systembuf;
public:
//!
//! \brief Creates a new process' output stream.
//!
//! Given a file handle, this constructor creates a new pistream
//! object that owns the given file handle \a fh. Ownership of
//! \a fh is transferred to the created pistream object.
//!
//! \pre \a fh is valid.
//! \post \a fh is invalid.
//! \post The new pistream object owns \a fh.
//!
explicit pistream(const int);
};
// ------------------------------------------------------------------------
// The "muxer" class.
// ------------------------------------------------------------------------
class muxer {
// Non-copyable.
muxer(const muxer&);
muxer& operator=(const muxer&);
const int* m_fds;
const size_t m_nfds;
const size_t m_bufsize;
tools::auto_array< std::string > m_buffers;
protected:
virtual void line_callback(const size_t, const std::string&) = 0;
size_t read_one(const size_t, const int, std::string&, const bool);
public:
muxer(const int*, const size_t, const size_t bufsize = 1024);
virtual ~muxer(void);
void mux(volatile const bool&);
void flush(void);
};
} // namespace io
} // namespace tools
#endif // !defined(TOOLS_IO_HPP)