/************************************************************************* * Copyright (C) 2009 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 // Use a tmpfile() as a buffer for a C++/C I/O interface. namespace Dimension { namespace { // Write an input stream completely to a FILE*; this works poorly for // console input, which may not have an EOF in the near future void write_cookie(FILE* file, std::istream& istr) { const unsigned int bs = 8192; // Bytes to read at once unsigned int count, pos; char buffer[bs]; pos = istr.tellg(); // Get the stream's current position istr.seekg(0); // Seek to the beginning while (true) { // Read the whole stream into `file', `bs' bytes at a time istr.read(buffer, bs); count = istr.gcount(); if (count != bs) { if (istr.eof()) { // We reached EOF; write the last count bytes fwrite(buffer, 1, count, file); break; } else { // Some other error throw Dimension_Error("Error reading from input stream."); } } // Write the next `bs' bytes fwrite(buffer, 1, bs, file); } fseek(file, pos, SEEK_SET); // Seek to the stream's initial position } // Read a C++ stream completely from a file void read_cookie(std::ostream& ostr, FILE* file) { const unsigned int bs = 8192; // Bytes to read at a time unsigned int count, pos; char buffer[bs]; pos = ftell(file); // Get the initial position rewind(file); // Seek to the beginning while (true) { count = fread(buffer, 1, bs, file); if (count != bs) { if (feof(file)) { // Reached EOF, write the last `count' bytes ostr.write(buffer, count); break; } else { // Some other error throw Dimension_Error("Error reading from temporary file."); } } // Write the next `bs' bytes ostr.write(buffer, bs); } ostr.seekp(pos); // Seek to the initial position of `file' } } // Make an input FILE_Cookie FILE_Cookie::FILE_Cookie(std::istream& istr) : m_file(std::tmpfile()), m_istr(&istr), m_ostr(0) { if (!m_file) { throw Dimension_Error("Error opening temporary file for C++/C I/O" " interface."); } // Write the input stream to the temporary file write_cookie(m_file, *m_istr); } // Make an output FILE_Cookie FILE_Cookie::FILE_Cookie(std::ostream& ostr) : m_file(std::tmpfile()), m_istr(0), m_ostr(&ostr) { if (!m_file) { throw Dimension_Error("Error opening temporary file for C++/C I/O" " interface."); } } // Make an I/O FILE_Cookie FILE_Cookie::FILE_Cookie(std::iostream& iostr) : m_file(std::tmpfile()), m_istr(&iostr), m_ostr(&iostr) { if (!m_file) { throw Dimension_Error("Error opening temporary file for C++/C I/O" " interface."); } // Write the input stream to the temporary file write_cookie(m_file, *m_istr); } // Close the tmpfile, maybe syncing a C++ stream to it first FILE_Cookie::~FILE_Cookie() { if (is_output()) { read_cookie(*m_ostr, m_file); } std::fclose(m_file); } // Get the 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; } // Get the C++ streams std::istream& FILE_Cookie::istr() { if (is_input()) { return *m_istr; } else { throw Dimension_Error("Attempted to get input stream from non-input" " FILE_Cookie."); } } const std::istream& FILE_Cookie::istr() const { if (is_input()) { return *m_istr; } else { throw Dimension_Error("Attempted to get input stream from non-input" " FILE_Cookie."); } } std::ostream& FILE_Cookie::ostr() { if (is_output()) { return *m_ostr; } else { throw Dimension_Error("Attempted to get output stream from non-input" " FILE_Cookie."); } } const std::ostream& FILE_Cookie::ostr() const { if (is_output()) { return *m_ostr; } else { throw Dimension_Error("Attempted to get output stream from non-input" " FILE_Cookie."); } } }