/***************************************************************************
* GUrlFile.cpp - File URL class *
* ----------------------------------------------------------------------- *
* copyright (C) 2013-2015 by Juergen Knoedlseder *
* ----------------------------------------------------------------------- *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program 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 General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see . *
* *
***************************************************************************/
/**
* @file GUrlFile.cpp
* @brief File URL class interface implementation
* @author Juergen Knoedlseder
*/
/* __ Includes ___________________________________________________________ */
#ifdef HAVE_CONFIG_H
#include
#endif
#include // std::va_list
#include // std::fopen, std::fgets, std::fclose, etc...
#include "GUrlFile.hpp"
#include "GTools.hpp"
#include "GException.hpp"
/* __ Method name definitions ____________________________________________ */
#define G_OPEN "GUrlFile::open(std::string&, std::string&)"
/* __ Macros _____________________________________________________________ */
/* __ Coding definitions _________________________________________________ */
/* __ Debug definitions __________________________________________________ */
/*==========================================================================
= =
= Constructors/destructors =
= =
==========================================================================*/
/***********************************************************************//**
* @brief Void constructor
***************************************************************************/
GUrlFile::GUrlFile(void) : GUrl()
{
// Initialise members
init_members();
// Return
return;
}
/***********************************************************************//**
* @brief Opening constructor
*
* @param[in] url File name.
* @param[in] mode File mode.
*
* Constructs GUrlFile object by opening a file @p url in the specified
* @p mode. Any environment variable present in the file name will be
* automatically expanded.
***************************************************************************/
GUrlFile::GUrlFile(const std::string& url, const std::string& mode) : GUrl()
{
// Initialise members
init_members();
// Open file
open(url, mode);
// Return
return;
}
/***********************************************************************//**
* @brief Copy constructor
*
* @param[in] url URL.
***************************************************************************/
GUrlFile::GUrlFile(const GUrlFile& url) : GUrl(url)
{
// Initialise members
init_members();
// Copy members
copy_members(url);
// Return
return;
}
/***********************************************************************//**
* @brief Destructor
***************************************************************************/
GUrlFile::~GUrlFile(void)
{
// Free members
free_members();
// Return
return;
}
/*==========================================================================
= =
= Operators =
= =
==========================================================================*/
/***********************************************************************//**
* @brief Assignment operator
*
* @param[in] url URL.
* @return URL.
***************************************************************************/
GUrlFile& GUrlFile::operator=(const GUrlFile& url)
{
// Execute only if object is not identical
if (this != &url) {
// Copy base class members
this->GUrl::operator=(url);
// Free members
free_members();
// Initialise members
init_members();
// Copy members
copy_members(url);
} // endif: object was not identical
// Return
return *this;
}
/*==========================================================================
= =
= Public methods =
= =
==========================================================================*/
/***********************************************************************//**
* @brief Clear instance
***************************************************************************/
void GUrlFile::clear(void)
{
// Free class members
free_members();
this->GUrl::free_members();
// Initialise members
this->GUrl::init_members();
init_members();
// Return
return;
}
/***********************************************************************//**
* @brief Clone instance
*
* @return Pointer to deep copy of file URL.
***************************************************************************/
GUrlFile* GUrlFile::clone(void) const
{
// Clone object
return new GUrlFile(*this);
}
/***********************************************************************//**
* @brief Open file
*
* @param[in] url File name.
* @param[in] mode File mode.
*
* @exception GException::file_open_error
* Unable to open file.
*
* Opens a file @p url in the specified @p mode. Any environment variable
* present in the filename will be automatically expanded.
*
* @todo Strip any file:// prefix
***************************************************************************/
void GUrlFile::open(const std::string& url, const std::string& mode)
{
// First close any existing file
close();
// Expand environment variables
std::string filename = gammalib::expand_env(url);
// Try opening file. Throw an exception if opening failed.
m_fptr = std::fopen(filename.c_str(), mode.c_str());
if (m_fptr == NULL) {
throw GException::file_open_error(G_OPEN, filename);
}
// Store URL and mode
m_url = url;
m_mode = mode;
// Return
return;
}
/***********************************************************************//**
* @brief Close file
***************************************************************************/
void GUrlFile::close(void)
{
// Close file
if (m_fptr != NULL) {
std::fclose(m_fptr);
}
// Reset members
m_url.clear();
m_mode.clear();
m_fptr = NULL;
// Return
return;
}
/***********************************************************************//**
* @brief Read block of data from file in buffer
*
* @param[in] buffer Data buffer.
* @param[in] nbyte Number of Bytes to be read.
* @return Number of Bytes that were effectively read.
*
* Reads @p nbyte Bytes from the file into a @p buffer. The position
* indicator of the file is advanced by the total amount of bytes read.
*
* The total number of Bytes successfully read is returned. If this number
* differs from the @p nbyte parameter, either a reading error occurred or
* the end-of-file was reached while reading. In both cases, the proper
* indicator is set.
*
* If either @p buffer is NULL or @p nbyte is zero, the method returns zero
* and both the file state and the content pointed by @p buffer remain
* unchanged.
*
* If no file has been opened, the method returns zero and both the file
* state and the content pointed by @p buffer remain unchanged.
***************************************************************************/
int GUrlFile::read(void* buffer, const int& nbyte)
{
// Initialise number of Bytes read
int nread = 0;
// Continue only if file is opened
if (m_fptr != NULL) {
// Continue only if buffer is valid and nbyte is positive
if (buffer != NULL && nbyte > 0) {
nread = std::fread(buffer, 1, nbyte, m_fptr);
}
} // endif: File was opened
// Return number of Bytes read
return nread;
}
/***********************************************************************//**
* @brief Write block of data buffer into file
*
* @param[in] buffer Data buffer.
* @param[in] nbyte Number of Bytes to be written.
* @return Number of Bytes that were effectively written.
*
* Writes @p nbyte Bytes from a @p buffer into the file. The position
* indicator of the file is advanced by the total amount of bytes written.
*
* The total number of Bytes successfully written is returned. If this number
* differs from the @p nbyte parameter, a writing error prevented the
* function from completing.
*
* If either @p buffer is NULL or @p nbyte is zero, the method returns zero
* and both the file state and the content pointed by @p buffer remain
* unchanged.
*
* If no file has been opened, the method returns zero and both the file
* state and the content pointed by @p buffer remain unchanged.
***************************************************************************/
int GUrlFile::write(const void* buffer, const int& nbyte)
{
// Initialise number of Bytes written
int nwritten = 0;
// Continue only if file is opened
if (m_fptr != NULL) {
// Continue only if buffer is valid and nbyte is positive
if (buffer != NULL && nbyte > 0) {
nwritten = std::fwrite(buffer, 1, nbyte, m_fptr);
}
} // endif: File was opened
// Return number of Bytes written
return nwritten;
}
/***********************************************************************//**
* @brief Return next character from file
*
* @return Next character in file.
*
* Returns the character currently pointed by the internal file position
* indicator of the file. The internal file position indicator is then
* advanced to the next character.
*
* If the stream is at the end-of-file when called, the function returns EOF
* and sets the end-of-file indicator for the file.
*
* If a read error occurs, the method returns EOF.
*
* If no file has been opened, the method returns EOF.
***************************************************************************/
int GUrlFile::get_char(void) const
{
// Initialise character to EOF
int character = EOF;
// Continue only if file is opened
if (m_fptr != NULL) {
// Get next character
character = std::fgetc(m_fptr);
} // endif: File was opened
// Return character
return character;
}
/***********************************************************************//**
* @brief Write character into file
*
* @param[in] character Character.
*
* Writes a character to the file and advances the position indicator.
*
* If no file has been opened, the method does nothing.
***************************************************************************/
void GUrlFile::put_char(const int& character)
{
// Continue only if file is opened
if (m_fptr != NULL) {
// Write character
std::fputc(character, m_fptr);
} // endif: File was opened
// Return
return;
}
/***********************************************************************//**
* @brief Read formatted data from file
*
* @param[in] format Format.
* @param[in] ... Optional parameters.
*
* Reads data from a file and stores them according to the parameter format
* into the locations pointed by the additional arguments. The additional
* arguments should point to already allocated objects of the type specified
* by their corresponding format specifier within the format string.
*
* If no file has been opened, the method does nothing.
***************************************************************************/
void GUrlFile::scanf(const char* format, ...)
{
// Continue only if file is opened
if (m_fptr != NULL) {
// Declare argument pointer
std::va_list arg_ptr;
// Set start argument
va_start(arg_ptr, format);
// Read data from file
vfscanf(m_fptr, format, arg_ptr);
// Stop argument reading
va_end(arg_ptr);
} // endif: File was opened
// Return
return;
}
/***********************************************************************//**
* @brief Write formatted data into file
*
* @param[in] format Format.
* @param[in] ... Optional parameters.
*
* Writes the C string pointed by format to the file. If format includes
* format specifiers (subsequences beginning with %), the additional
* arguments following format are formatted and inserted in the resulting
* string replacing their respective specifiers.
*
* After the format parameter, the function expects at least as many
* additional arguments as specified by format.
*
* If no file has been opened, the method does nothing.
***************************************************************************/
void GUrlFile::printf(const char* format, ...)
{
// Continue only if file is opened
if (m_fptr != NULL) {
// Declare argument pointer
std::va_list arg_ptr;
// Set start argument
va_start(arg_ptr, format);
// Write data into file
std::vfprintf(m_fptr, format, arg_ptr);
// Stop argument reading
va_end(arg_ptr);
} // endif: File was opened
// Return
return;
}
/***********************************************************************//**
* @brief Print URL information
*
* @param[in] chatter Chattiness (defaults to NORMAL).
* @return String containing URL information.
***************************************************************************/
std::string GUrlFile::print(const GChatter& chatter) const
{
// Initialise result string
std::string result;
// Continue only if chatter is not silent
if (chatter != SILENT) {
// Append header
result.append("=== GUrlFile ===");
// Append information
if (m_fptr != NULL) {
// Get information
int pos = std::ftell(m_fptr);
int err = std::ferror(m_fptr);
// Append it
result.append("\n"+gammalib::parformat("File URL")+m_url);
result.append("\n"+gammalib::parformat("File mode")+m_mode);
result.append("\n"+gammalib::parformat("File position indicator"));
result.append(gammalib::str(pos));
result.append("\n"+gammalib::parformat("File error"));
if (err == 0) {
result.append("none");
}
else {
result.append(gammalib::str(err));
}
}
else {
result.append("\n"+gammalib::parformat("URL")+"none");
}
} // endif: chatter was not silent
// Return result
return result;
}
/*==========================================================================
= =
= Private methods =
= =
==========================================================================*/
/***********************************************************************//**
* @brief Initialise class members
***************************************************************************/
void GUrlFile::init_members(void)
{
// Initialise members
m_url.clear();
m_mode.clear();
m_fptr = NULL;
// Return
return;
}
/***********************************************************************//**
* @brief Copy class members
*
* @param[in] url URL.
*
* @todo The simple copying of the file pointer is not clean as we have no
* control anymore over the object. The file pointer should be cloned
* somehow.
***************************************************************************/
void GUrlFile::copy_members(const GUrlFile& url)
{
// Copy members
m_url = url.m_url;
m_mode = url.m_mode;
m_fptr = url.m_fptr;
// Return
return;
}
/***********************************************************************//**
* @brief Delete class members
***************************************************************************/
void GUrlFile::free_members(void)
{
// Close file
close();
// Return
return;
}