file_util: File descriptor streams

This commit is contained in:
Michael Carlberg 2016-12-26 10:29:32 +01:00
parent 00ac4bea63
commit f80d8ebf5b
2 changed files with 188 additions and 39 deletions

View File

@ -10,14 +10,16 @@ class file_ptr {
explicit file_ptr(const string& path, const string& mode = "a+");
~file_ptr();
file_ptr(const file_ptr& o) = delete;
file_ptr& operator=(const file_ptr& o) = delete;
explicit operator bool();
operator bool() const;
operator bool();
explicit operator FILE*();
operator FILE*() const;
FILE* operator()();
explicit operator int();
operator int() const;
protected:
private:
FILE* m_ptr = nullptr;
string m_path;
string m_mode;
@ -28,10 +30,65 @@ class file_descriptor {
explicit file_descriptor(const string& path, int flags = 0);
explicit file_descriptor(int fd);
~file_descriptor();
operator int();
file_descriptor& operator=(const int);
explicit operator bool();
operator bool() const;
explicit operator int();
operator int() const;
protected:
int m_fd{0};
void close();
private:
int m_fd{-1};
};
class fd_streambuf : public std::streambuf {
public:
using traits_type = std::streambuf::traits_type;
explicit fd_streambuf(int fd);
~fd_streambuf();
explicit operator int();
operator int() const;
void open(int fd);
void close();
protected:
int sync();
int overflow(int c);
int underflow();
private:
file_descriptor m_fd;
char m_out[BUFSIZ];
char m_in[BUFSIZ - 1];
};
template <typename StreamType = std::ostream>
class fd_stream : public StreamType {
public:
using type = fd_stream<StreamType>;
explicit fd_stream(int fd) : m_buf(fd) {
StreamType::rdbuf(&m_buf);
}
explicit operator int() {
return static_cast<const type&>(*this);
}
operator int() const {
return m_buf;
}
protected:
fd_streambuf m_buf;
};
namespace file_util {

View File

@ -2,72 +2,164 @@
#include <sys/stat.h>
#include <cstdio>
#include <fstream>
#include <streambuf>
#include "errors.hpp"
#include "utils/file.hpp"
POLYBAR_NS
/**
* Deconstruct file wrapper
*/
// implementation of file_ptr {{{
file_ptr::file_ptr(const string& path, const string& mode) : m_path(string(path)), m_mode(string(mode)) {
m_ptr = fopen(m_path.c_str(), m_mode.c_str());
}
/**
* Deconstruct file wrapper
*/
file_ptr::~file_ptr() {
if (m_ptr != nullptr) {
fclose(m_ptr);
}
}
/**
* Logical operator testing if the file handler was created
*/
file_ptr::operator bool() {
return static_cast<const file_ptr&>(*this);
}
file_ptr::operator bool() const {
return m_ptr != nullptr;
}
/**
* Call operator returning a pointer to the file handler
*/
FILE* file_ptr::operator()() {
file_ptr::operator FILE*() {
return static_cast<const file_ptr&>(*this);
}
file_ptr::operator FILE*() const {
return m_ptr;
}
/**
* Construct file descriptor wrapper
*/
file_ptr::operator int() {
return static_cast<const file_ptr&>(*this);
}
file_ptr::operator int() const {
return fileno(*this);
}
// }}}
// implementation of file_descriptor {{{
file_descriptor::file_descriptor(const string& path, int flags) {
if ((m_fd = open(path.c_str(), flags)) == -1) {
throw system_error("Failed to open file descriptor");
}
}
/**
* Construct file descriptor wrapper from an existing handle
*/
file_descriptor::file_descriptor(int fd) : m_fd(fd) {}
/**
* Deconstruct file descriptor wrapper
*/
file_descriptor::~file_descriptor() {
if (m_fd > 0) {
close(m_fd);
file_descriptor::file_descriptor(int fd) : m_fd(fd) {
if (!*this) {
throw system_error("Given file descriptor is not valid");
}
}
/**
* Conversion operator returning the fd handle
*/
file_descriptor::~file_descriptor() {
close();
}
file_descriptor& file_descriptor::operator=(const int fd) {
close();
m_fd = fd;
return *this;
}
file_descriptor::operator int() {
return static_cast<const file_descriptor&>(*this);
}
file_descriptor::operator int() const {
return m_fd;
}
file_descriptor::operator bool() {
return static_cast<const file_descriptor&>(*this);
}
file_descriptor::operator bool() const {
errno = 0; // reset since fcntl only changes it on error
if ((fcntl(m_fd, F_GETFD) == -1) || errno == EBADF) {
errno = EBADF;
return false;
}
return true;
}
void file_descriptor::close() {
if (m_fd == -1) {
return;
} else if (::close(m_fd) == -1) {
throw system_error("Failed to close file descriptor");
}
m_fd = -1;
}
// }}}
// implementation of file_streambuf {{{
fd_streambuf::fd_streambuf(int fd) : m_fd(fd) {}
fd_streambuf::~fd_streambuf() {
sync();
}
fd_streambuf::operator int() {
return static_cast<const fd_streambuf&>(*this);
}
fd_streambuf::operator int() const {
return m_fd;
}
void fd_streambuf::open(int fd) {
if (m_fd) {
sync();
}
m_fd = fd;
setg(m_in, m_in, m_in);
setp(m_out, m_out + sizeof(m_in));
}
void fd_streambuf::close() {
if (m_fd) {
sync();
m_fd = -1;
}
}
int fd_streambuf::sync() {
if (pbase() != pptr()) {
auto size = pptr() - pbase();
auto bytes = ::write(m_fd, m_out, size);
if (bytes > 0) {
std::copy(pbase() + bytes, pptr(), pbase());
setp(pbase(), epptr());
pbump(size - bytes);
}
}
return pptr() != epptr() ? 0 : -1;
}
int fd_streambuf::overflow(int c) {
if (!traits_type::eq_int_type(c, traits_type::eof())) {
*pptr() = traits_type::to_char_type(c);
pbump(1);
}
return sync() == -1 ? traits_type::eof() : traits_type::not_eof(c);
}
int fd_streambuf::underflow() {
if (gptr() == egptr()) {
auto pback = std::min(gptr() - eback(), std::ptrdiff_t(m_in));
std::copy(egptr() - pback, egptr(), eback());
auto bytes = ::read(m_fd, eback() + pback, BUFSIZ);
setg(eback(), eback() + pback, eback() + pback + std::max(0L, bytes));
}
return gptr() == egptr() ? traits_type::eof() : traits_type::to_int_type(*gptr());
}
// }}}
namespace file_util {
/**
* Checks if the given file exist
@ -86,7 +178,7 @@ namespace file_util {
string contents((std::istreambuf_iterator<char>(ifs)), (std::istreambuf_iterator<char>()));
return contents;
} catch (std::ios_base::failure& e) {
return string{""};
return "";
}
}
@ -95,7 +187,7 @@ namespace file_util {
*/
bool is_fifo(string filename) {
auto fileptr = factory_util::unique<file_ptr>(filename);
int fd = fileno((*fileptr)());
int fd = fileno(*fileptr);
struct stat statbuf {};
fstat(fd, &statbuf);
return S_ISFIFO(statbuf.st_mode);