From 4e2f7c8e8fdcdb1dbf6f2346e13f46f8ce3eca48 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Mon, 20 Apr 2009 04:02:15 +0000 Subject: Add tmpfile() implementation of FILE_Cookie. --- libdimensionxx/cookie-fopencookie.cpp | 173 ++++++++++++++++++++++++++++++++++ 1 file changed, 173 insertions(+) create mode 100644 libdimensionxx/cookie-fopencookie.cpp (limited to 'libdimensionxx/cookie-fopencookie.cpp') diff --git a/libdimensionxx/cookie-fopencookie.cpp b/libdimensionxx/cookie-fopencookie.cpp new file mode 100644 index 0000000..9fd4e07 --- /dev/null +++ b/libdimensionxx/cookie-fopencookie.cpp @@ -0,0 +1,173 @@ +/************************************************************************* + * Copyright (C) 2008 Tavian Barnes * + * * + * This file is part of The Dimension Library. * + * * + * The Dimension Library is free software; you can redistribute it and/ * + * or modify it under the terms of the GNU Lesser General Public License * + * as published by the Free Software Foundation; either version 3 of the * + * License, or (at your option) any later version. * + * * + * The Dimension Library is distributed in the hope that it will be * + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty * + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this program. If not, see * + * . * + *************************************************************************/ + +#include "dimensionxx.hpp" +#include + +// The conundrum: libdimension and libdimension-* use C I/O, with FILE*'s. +// We want to use C++ I/O with std::i/ostreams. If present, we use the +// nonportable GNU stdio extension fopencookie(), which creates a FILE* with +// custom read/write/seek functions. BSD also has a similar function, funopen() +// which we should use too. Failing in all that, fall back on a tmpfile() +// buffer (see cookie-tmpfile.cpp). + +namespace Dimension +{ + namespace + { + // Cookie read function + ssize_t + cookie_read(void* cookie, char* buf, size_t size) + { + FILE_Cookie* streams = reinterpret_cast(cookie); + + // Do the unformatted read + streams->istr().read(buf, size); + + if (streams->istr().eof() || streams->istr().good()) { + return streams->istr().gcount(); // This returns 0 on an immediate EOF + // for us. + } else { + // Some non-EOF error + return -1; + } + } + + // Cookie write function + ssize_t + cookie_write(void* cookie, const char* buf, size_t size) + { + FILE_Cookie* streams = reinterpret_cast(cookie); + + // Do the unformatted write + streams->ostr().write(buf, size); + + if (streams->ostr().good()) { + // Write operation succeeded, so we must've written size bytes + return size; + } else { + // Write operation failed + return -1; + } + } + + // Cookie seek function + int + cookie_seek(void* cookie, off64_t* offset, int whence) + { + FILE_Cookie* streams = reinterpret_cast(cookie); + + if (streams->is_input()) { + // If we have an input stream, seek it + switch (whence) { + case SEEK_SET: + streams->istr().seekg(*offset, std::ios::beg); + break; + case SEEK_CUR: + streams->istr().seekg(*offset, std::ios::cur); + break; + case SEEK_END: + streams->istr().seekg(*offset, std::ios::end); + break; + } + + if (!streams->istr().good()) { + // Seek failed + return 1; + } + } + + if (streams->is_output()) { + // If we have an output stream, seek it too + switch (whence) { + case SEEK_SET: + streams->ostr().seekp(*offset, std::ios::beg); + break; + case SEEK_CUR: + streams->ostr().seekp(*offset, std::ios::cur); + break; + case SEEK_END: + streams->ostr().seekp(*offset, std::ios::end); + } + + if (!streams->ostr().good()) { + // Seek failed + return 1; + } + } + + // Seek succeeded + return 0; + } + } + + // Make an input FILE_Cookie + FILE_Cookie::FILE_Cookie(std::istream& istr) + : m_istr(&istr), m_ostr(0) + { + cookie_io_functions_t io_funcs; + io_funcs.read = &cookie_read; + io_funcs.write = 0; + io_funcs.seek = &cookie_seek; + io_funcs.close = 0; + + m_file = fopencookie(reinterpret_cast(this), "r", io_funcs); + } + + // Make an output FILE_Cookie + FILE_Cookie::FILE_Cookie(std::ostream& ostr) + : m_istr(0), m_ostr(&ostr) + { + cookie_io_functions_t io_funcs; + io_funcs.read = 0; + io_funcs.write = &cookie_write; + io_funcs.seek = &cookie_seek; + io_funcs.close = 0; + + m_file = fopencookie(reinterpret_cast(this), "w", io_funcs); + } + + // Make an I/O FILE_Cookie + FILE_Cookie::FILE_Cookie(std::istream& istr, std::ostream& ostr) + : m_istr(&istr), m_ostr(&ostr) + { + cookie_io_functions_t io_funcs; + io_funcs.read = &cookie_read; + io_funcs.write = &cookie_write; + io_funcs.seek = &cookie_seek; + io_funcs.close = 0; + + m_file = fopencookie(reinterpret_cast(this), "r+", io_funcs); + } + + // Close the file + FILE_Cookie::~FILE_Cookie() { std::fclose(m_file); } + + FILE* FILE_Cookie::file() { return m_file; } + const FILE* FILE_Cookie::file() const { return m_file; } + + bool FILE_Cookie::is_input() const { return m_istr; } + bool FILE_Cookie::is_output() const { return m_ostr; } + + std::istream& FILE_Cookie::istr() { return *m_istr; } + const std::istream& FILE_Cookie::istr() const { return *m_istr; } + std::ostream& FILE_Cookie::ostr() { return *m_ostr; } + const std::ostream& FILE_Cookie::ostr() const { return *m_ostr; } +} -- cgit v1.2.3