summaryrefslogtreecommitdiffstats
path: root/libdimensionxx/cookie-fopencookie.cpp
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@gmail.com>2009-04-20 04:02:15 +0000
committerTavian Barnes <tavianator@gmail.com>2009-04-20 04:02:15 +0000
commit4e2f7c8e8fdcdb1dbf6f2346e13f46f8ce3eca48 (patch)
treedc679317f6b432fc872422476922d05a8aaab388 /libdimensionxx/cookie-fopencookie.cpp
parente15353792ff60640e55e8a97c7737e0338289f97 (diff)
downloaddimension-4e2f7c8e8fdcdb1dbf6f2346e13f46f8ce3eca48.tar.xz
Add tmpfile() implementation of FILE_Cookie.
Diffstat (limited to 'libdimensionxx/cookie-fopencookie.cpp')
-rw-r--r--libdimensionxx/cookie-fopencookie.cpp173
1 files changed, 173 insertions, 0 deletions
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 <tavianator@gmail.com> *
+ * *
+ * 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 *
+ * <http://www.gnu.org/licenses/>. *
+ *************************************************************************/
+
+#include "dimensionxx.hpp"
+#include <stdio.h>
+
+// 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<FILE_Cookie*>(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<FILE_Cookie*>(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<FILE_Cookie*>(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<void*>(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<void*>(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<void*>(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; }
+}