mirror of https://github.com/JAJames/Jupiter.git
Jessica James
8 years ago
9 changed files with 804 additions and 3 deletions
@ -0,0 +1,145 @@ |
|||||
|
/**
|
||||
|
* Copyright (C) 2016 Jessica James. |
||||
|
* |
||||
|
* Permission to use, copy, modify, and/or distribute this software for any |
||||
|
* purpose with or without fee is hereby granted, provided that the above |
||||
|
* copyright notice and this permission notice appear in all copies. |
||||
|
* |
||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
||||
|
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
||||
|
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
||||
|
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
||||
|
* |
||||
|
* Written by Jessica James <jessica.aj@outlook.com> |
||||
|
*/ |
||||
|
|
||||
|
#include "Config.h" |
||||
|
|
||||
|
const Jupiter::Config o_null_section; |
||||
|
|
||||
|
const Jupiter::ReadableString &Jupiter::Config::get(const Jupiter::ReadableString &in_key, const Jupiter::ReadableString &in_default_value) const |
||||
|
{ |
||||
|
const Jupiter::ReadableString *result = m_table.get(in_key); |
||||
|
|
||||
|
if (result == nullptr) |
||||
|
return in_default_value; |
||||
|
|
||||
|
return *result; |
||||
|
} |
||||
|
|
||||
|
const Jupiter::ReadableString *Jupiter::Config::getValue(const Jupiter::ReadableString &in_key) const |
||||
|
{ |
||||
|
return m_table.get(in_key); |
||||
|
} |
||||
|
|
||||
|
Jupiter::Config *Jupiter::Config::getSection(const Jupiter::ReadableString &in_key) const |
||||
|
{ |
||||
|
return m_sections.get(in_key); |
||||
|
} |
||||
|
|
||||
|
Jupiter::Config &Jupiter::Config::getSectionReference(const Jupiter::ReadableString &in_key) |
||||
|
{ |
||||
|
Config *section = m_sections.get(in_key); |
||||
|
|
||||
|
if (section == nullptr) |
||||
|
{ |
||||
|
m_sections.set(in_key); |
||||
|
section = m_sections.get(in_key); |
||||
|
section->m_name = in_key; |
||||
|
return *section; |
||||
|
} |
||||
|
|
||||
|
return *section; |
||||
|
} |
||||
|
|
||||
|
bool Jupiter::Config::set(const Jupiter::ReadableString &in_key, const Jupiter::ReadableString &in_value) |
||||
|
{ |
||||
|
return m_table.set(in_key, in_value); |
||||
|
} |
||||
|
|
||||
|
bool Jupiter::Config::remove(const Jupiter::ReadableString &in_key) |
||||
|
{ |
||||
|
return m_table.remove(in_key); |
||||
|
} |
||||
|
|
||||
|
const Jupiter::ReadableString &Jupiter::Config::getName() const |
||||
|
{ |
||||
|
return m_name; |
||||
|
} |
||||
|
|
||||
|
void Jupiter::Config::erase() |
||||
|
{ |
||||
|
m_table.erase(); |
||||
|
m_sections.erase(); |
||||
|
} |
||||
|
|
||||
|
bool Jupiter::Config::read(const char *in_filename) |
||||
|
{ |
||||
|
m_name = in_filename; |
||||
|
return this->read_internal(in_filename); |
||||
|
} |
||||
|
|
||||
|
bool Jupiter::Config::read(const Jupiter::ReadableString &in_filename) |
||||
|
{ |
||||
|
m_name = in_filename; |
||||
|
return this->read_internal(m_name.c_str()); |
||||
|
} |
||||
|
|
||||
|
bool Jupiter::Config::write() |
||||
|
{ |
||||
|
return this->write(m_name.c_str()); |
||||
|
} |
||||
|
|
||||
|
bool Jupiter::Config::write(const char *) |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
bool Jupiter::Config::write(const Jupiter::ReadableString &in_filename) |
||||
|
{ |
||||
|
return this->write(Jupiter::CStringS(in_filename).c_str()); |
||||
|
} |
||||
|
|
||||
|
bool Jupiter::Config::reload() |
||||
|
{ |
||||
|
this->erase(); |
||||
|
return this->read_internal(m_name.c_str()); |
||||
|
} |
||||
|
|
||||
|
bool Jupiter::Config::reload(const char *in_filename) |
||||
|
{ |
||||
|
this->erase(); |
||||
|
return this->read(in_filename); |
||||
|
} |
||||
|
|
||||
|
bool Jupiter::Config::reload(const Jupiter::ReadableString &in_filename) |
||||
|
{ |
||||
|
this->erase(); |
||||
|
return this->read(in_filename); |
||||
|
} |
||||
|
|
||||
|
/** Operators */ |
||||
|
Jupiter::Config &Jupiter::Config::operator[](const Jupiter::ReadableString &in_key) |
||||
|
{ |
||||
|
return this->getSectionReference(in_key); |
||||
|
} |
||||
|
|
||||
|
/** Private functions */ |
||||
|
|
||||
|
bool Jupiter::Config::read_internal(const char *) |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
void Jupiter::Config::Buffer::set_length(size_t in_length) |
||||
|
{ |
||||
|
this->length = in_length; |
||||
|
} |
||||
|
|
||||
|
char *Jupiter::Config::Buffer::get_str() const |
||||
|
{ |
||||
|
return this->str; |
||||
|
} |
@ -0,0 +1,253 @@ |
|||||
|
/**
|
||||
|
* Copyright (C) 2016 Jessica James. |
||||
|
* |
||||
|
* Permission to use, copy, modify, and/or distribute this software for any |
||||
|
* purpose with or without fee is hereby granted, provided that the above |
||||
|
* copyright notice and this permission notice appear in all copies. |
||||
|
* |
||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
||||
|
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
||||
|
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
||||
|
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
||||
|
* |
||||
|
* Written by Jessica James <jessica.aj@outlook.com> |
||||
|
*/ |
||||
|
|
||||
|
#if !defined JUPITER_CONFIG_H_HEADER |
||||
|
#define JUPITER_CONFIG_H_HEADER |
||||
|
|
||||
|
/**
|
||||
|
* @file Config.h |
||||
|
* @brief Defines the Config class, which provides common functionality for Config files in differing formats. |
||||
|
*/ |
||||
|
|
||||
|
#include "Jupiter.h" |
||||
|
#include "Hash_Table.h" |
||||
|
#include "Reference_String.h" |
||||
|
#include "CString.h" |
||||
|
|
||||
|
/** DLL Linkage Nagging */ |
||||
|
#if defined _MSC_VER |
||||
|
#pragma warning(push) |
||||
|
#pragma warning(disable: 4251) |
||||
|
#endif |
||||
|
|
||||
|
namespace Jupiter |
||||
|
{ |
||||
|
/**
|
||||
|
* @brief Base class for all Config type files |
||||
|
*/ |
||||
|
class JUPITER_API Config |
||||
|
{ |
||||
|
public: |
||||
|
/** Hash_Table type for sections */ |
||||
|
typedef Hash_Table<StringS, Config, ReadableString> SectionHashTable; |
||||
|
|
||||
|
/**
|
||||
|
* @brief Fetches the value of an entry. |
||||
|
* |
||||
|
* @param in_key Key of the entry to fetch |
||||
|
* @param in_default_value Value to return if no such entry exists |
||||
|
* @return Value of the entry if it exists, an empty string otherwise. |
||||
|
*/ |
||||
|
const Jupiter::ReadableString &get(const Jupiter::ReadableString &in_key, const Jupiter::ReadableString &in_default_value = Jupiter::ReferenceString::empty) const; |
||||
|
|
||||
|
/**
|
||||
|
* @brief Fetches the value of an entry |
||||
|
* |
||||
|
* @param in_key Key of the entry to fetch |
||||
|
* @return Pointer to the value of the entry on success, nullptr otherwise |
||||
|
*/ |
||||
|
const Jupiter::ReadableString *getValue(const Jupiter::ReadableString &in_key) const; |
||||
|
|
||||
|
/**
|
||||
|
* @brief Fetches the value of an entry and interprets it as another type. |
||||
|
* |
||||
|
* @param T Type to interpret the value as |
||||
|
* |
||||
|
* @param in_key Key of the entry to fetch |
||||
|
* @param in_default_value Value to return if no such entry exists |
||||
|
* @return Value of the entry if it exists, 0 otherwise. |
||||
|
*/ |
||||
|
template<typename T> T get(const Jupiter::ReadableString &in_key, T in_default_value = 0); |
||||
|
|
||||
|
/**
|
||||
|
* @brief Fetches a section based on its name |
||||
|
* |
||||
|
* @param in_key Name of the section to fetch |
||||
|
* @return Pointer to a section if it exists, nullptr otherwise |
||||
|
*/ |
||||
|
Config *getSection(const Jupiter::ReadableString &in_key) const; |
||||
|
|
||||
|
/**
|
||||
|
* @brief Fetches a section based on its name |
||||
|
* Note: This will create new sections as necessary if they do not exist |
||||
|
* |
||||
|
* @param in_key Name of the section to fetch |
||||
|
* @return Reference to the section |
||||
|
*/ |
||||
|
Config &getSectionReference(const Jupiter::ReadableString &in_key); |
||||
|
|
||||
|
/**
|
||||
|
* @brief Sets an entry's value in the table |
||||
|
* |
||||
|
* @param in_key Key of the entry to write to |
||||
|
* @param in_value Value to write to the entry |
||||
|
* @return True if a new entry was added, false if an entry was overwritten |
||||
|
*/ |
||||
|
bool set(const Jupiter::ReadableString &in_key, const Jupiter::ReadableString &in_value); |
||||
|
|
||||
|
/**
|
||||
|
* @brief Removes an entry from the table |
||||
|
* |
||||
|
* @param in_key Key of the entry to remove |
||||
|
* @return True if an entry was removed, false otherwise |
||||
|
*/ |
||||
|
bool remove(const Jupiter::ReadableString &in_key); |
||||
|
|
||||
|
/**
|
||||
|
* @brief Fetches the name of this config section |
||||
|
* Note: This is the filename on the root node |
||||
|
* |
||||
|
* @return Name of this section |
||||
|
*/ |
||||
|
const Jupiter::ReadableString &getName() const; |
||||
|
|
||||
|
/**
|
||||
|
* @brief Erases all data from this section |
||||
|
*/ |
||||
|
void erase(); |
||||
|
|
||||
|
/**
|
||||
|
* @brief Reads config data from a file and stores it in this config |
||||
|
* |
||||
|
* @param in_filename Name of the file to read from |
||||
|
* @return True on success, false otherwise |
||||
|
*/ |
||||
|
bool read(const char *in_filename); |
||||
|
|
||||
|
/**
|
||||
|
* @brief Reads config data from a file and stores it in this config |
||||
|
* |
||||
|
* @param in_filename Name of the file to read from |
||||
|
* @return True on success, false otherwise |
||||
|
*/ |
||||
|
bool read(const Jupiter::ReadableString &in_filename); |
||||
|
|
||||
|
/**
|
||||
|
* @brief Writes config data to the last read file |
||||
|
* |
||||
|
* @return True on success, false otherwise |
||||
|
*/ |
||||
|
bool write(); |
||||
|
|
||||
|
/**
|
||||
|
* @brief Writes config data to a file |
||||
|
* |
||||
|
* @param in_filename Name of the file to write to |
||||
|
* @return True on success, false otherwise |
||||
|
*/ |
||||
|
virtual bool write(const char *in_filename); |
||||
|
|
||||
|
/**
|
||||
|
* @brief Writes config data to a file |
||||
|
* |
||||
|
* @param in_filename Name of the file to write to |
||||
|
* @return True on success, false otherwise |
||||
|
*/ |
||||
|
bool write(const Jupiter::ReadableString &in_filename); |
||||
|
|
||||
|
/**
|
||||
|
* @brief Empties config data from memory and reads from the last read file |
||||
|
* |
||||
|
* @return True on success, false otherwise |
||||
|
*/ |
||||
|
bool reload(); |
||||
|
|
||||
|
/**
|
||||
|
* @brief Empties config data from memory and reads from a file |
||||
|
* |
||||
|
* @param in_filename Name of the file to read from |
||||
|
* @return True on success, false otherwise |
||||
|
*/ |
||||
|
bool reload(const char *in_filename); |
||||
|
|
||||
|
/**
|
||||
|
* @brief Empties config data from memory and reads from a file |
||||
|
* |
||||
|
* @param in_filename Name of the file to read from |
||||
|
* @return True on success, false otherwise |
||||
|
*/ |
||||
|
bool reload(const Jupiter::ReadableString &in_filename); |
||||
|
|
||||
|
/**
|
||||
|
* @brief Fetches a reference to this config's entry table |
||||
|
* |
||||
|
* @return Reference to m_table |
||||
|
*/ |
||||
|
inline const HashTable &getTable() const { return m_table; } |
||||
|
|
||||
|
/**
|
||||
|
* @brief Fetches a reference to this config's subsections |
||||
|
* |
||||
|
* @return Reference to m_sections |
||||
|
*/ |
||||
|
inline const SectionHashTable getSections() const { return m_sections; } |
||||
|
|
||||
|
/** Subscript operator */ |
||||
|
Config &operator[](const Jupiter::ReadableString &in_key); |
||||
|
|
||||
|
/** Used for low-level string operations */ |
||||
|
class Buffer : public Jupiter::StringL |
||||
|
{ |
||||
|
public: |
||||
|
/**
|
||||
|
* @brief Sets the length of the string |
||||
|
* |
||||
|
* @param in_length Length of the string |
||||
|
*/ |
||||
|
void set_length(size_t in_length); |
||||
|
|
||||
|
/**
|
||||
|
* @brief Returns a pointer to the underlying string |
||||
|
* |
||||
|
* @return Pointer to an array of characters |
||||
|
*/ |
||||
|
char *get_str() const; |
||||
|
}; |
||||
|
|
||||
|
protected: |
||||
|
virtual bool read_internal(const char *in_filename); |
||||
|
|
||||
|
/** Name of this Config section. This is empty or the filename at the root level. */ |
||||
|
Jupiter::CStringS m_name; |
||||
|
|
||||
|
/** Table of entries within this section */ |
||||
|
HashTable m_table; |
||||
|
|
||||
|
/** Table of sections within this section */ |
||||
|
SectionHashTable m_sections; |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
/** Template function implementations */ |
||||
|
|
||||
|
template<typename T> inline T Jupiter::Config::get(const Jupiter::ReadableString &in_key, T in_default_value) |
||||
|
{ |
||||
|
const Jupiter::ReadableString *result = m_table.get(in_key); |
||||
|
|
||||
|
if (result == nullptr) |
||||
|
return in_default_value; |
||||
|
|
||||
|
return static_cast<T>(*result); |
||||
|
} |
||||
|
|
||||
|
/** Re-enable warnings */ |
||||
|
#if defined _MSC_VER |
||||
|
#pragma warning(pop) |
||||
|
#endif |
||||
|
|
||||
|
#endif // JUPITER_CONFIG_H_HEADER
|
@ -0,0 +1,285 @@ |
|||||
|
/**
|
||||
|
* Copyright (C) 2016 Jessica James. |
||||
|
* |
||||
|
* Permission to use, copy, modify, and/or distribute this software for any |
||||
|
* purpose with or without fee is hereby granted, provided that the above |
||||
|
* copyright notice and this permission notice appear in all copies. |
||||
|
* |
||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
||||
|
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
||||
|
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
||||
|
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
||||
|
* |
||||
|
* Written by Jessica James <jessica.aj@outlook.com> |
||||
|
*/ |
||||
|
|
||||
|
#include <stack> |
||||
|
#include <functional> |
||||
|
#include "INIConfig.h" |
||||
|
#include "Socket.h" |
||||
|
|
||||
|
void Jupiter::INIConfig::write_helper(FILE *in_file, const Jupiter::Config *in_section, size_t in_depth) |
||||
|
{ |
||||
|
size_t index; |
||||
|
|
||||
|
if (in_depth != 0) |
||||
|
{ |
||||
|
// Write header
|
||||
|
|
||||
|
fputs("\r\n", in_file); |
||||
|
|
||||
|
// Tabs
|
||||
|
for (index = 1; index < in_depth; ++index) |
||||
|
fputc('\t', in_file); |
||||
|
|
||||
|
for (index = 0; index != in_depth; ++index) |
||||
|
fputc('[', in_file); |
||||
|
|
||||
|
in_section->getName().print(in_file); |
||||
|
|
||||
|
for (index = 0; index != in_depth; ++index) |
||||
|
fputc(']', in_file); |
||||
|
|
||||
|
fputs("\r\n", in_file); |
||||
|
} |
||||
|
|
||||
|
// Write table entries
|
||||
|
{ |
||||
|
auto bucket_itr = in_section->getTable().begin(); |
||||
|
auto bucket_end = in_section->getTable().end(); |
||||
|
Jupiter::SLList<HashTable::Bucket::Entry>::Node *entry_itr; |
||||
|
|
||||
|
while (bucket_itr != bucket_end) |
||||
|
{ |
||||
|
for (entry_itr = bucket_itr->m_entries.getHead(); entry_itr != nullptr; entry_itr = entry_itr->next) |
||||
|
{ |
||||
|
// Tabs
|
||||
|
for (index = 1; index < in_depth; ++index) |
||||
|
fputc('\t', in_file); |
||||
|
|
||||
|
// Write entry
|
||||
|
entry_itr->data->key.print(in_file); |
||||
|
fputs(" = ", in_file); |
||||
|
entry_itr->data->value.println(in_file); |
||||
|
} |
||||
|
|
||||
|
++bucket_itr; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// Write subsections
|
||||
|
{ |
||||
|
auto bucket_itr = in_section->getSections().begin(); |
||||
|
auto bucket_end = in_section->getSections().end(); |
||||
|
Jupiter::SLList<SectionHashTable::Bucket::Entry>::Node *entry_itr; |
||||
|
|
||||
|
while (bucket_itr != bucket_end) |
||||
|
{ |
||||
|
for (entry_itr = bucket_itr->m_entries.getHead(); entry_itr != nullptr; entry_itr = entry_itr->next) |
||||
|
write_helper(in_file, &entry_itr->data->value, in_depth + 1); |
||||
|
|
||||
|
++bucket_itr; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
bool Jupiter::INIConfig::write(const char *in_filename) |
||||
|
{ |
||||
|
// Open file
|
||||
|
FILE *file = fopen(in_filename, "wb"); |
||||
|
|
||||
|
if (file == nullptr) |
||||
|
return false; |
||||
|
|
||||
|
// Iterate through table and sections
|
||||
|
write_helper(file, this, 0); |
||||
|
|
||||
|
// File writing completed; close and return
|
||||
|
fclose(file); |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
bool Jupiter::INIConfig::read_internal(const char *in_filename) |
||||
|
{ |
||||
|
Jupiter::ReferenceString line; |
||||
|
std::stack<Jupiter::Config *> section_stack; |
||||
|
|
||||
|
section_stack.push(this); |
||||
|
|
||||
|
auto process_line = [&line, §ion_stack]() |
||||
|
{ |
||||
|
const char *itr = line.ptr(); |
||||
|
const char *end = itr + line.size(); // guaranteed to be greater than itr
|
||||
|
|
||||
|
// Shift to right of spaces
|
||||
|
|
||||
|
while (isspace(*itr)) |
||||
|
if (++itr == end) |
||||
|
return; // Line is purely whitespace
|
||||
|
|
||||
|
line.shiftRight(itr - line.ptr()); |
||||
|
|
||||
|
if (*itr == ';') |
||||
|
return; // Comment
|
||||
|
|
||||
|
if (*itr == '[') |
||||
|
{ |
||||
|
// Parse header
|
||||
|
|
||||
|
size_t depth = 1; |
||||
|
|
||||
|
for (++itr; itr != end && *itr == '['; ++itr) |
||||
|
++depth; |
||||
|
|
||||
|
line.shiftRight(itr - line.ptr()); |
||||
|
|
||||
|
while (end != itr) |
||||
|
{ |
||||
|
--end; |
||||
|
if (*end != ']' && isspace(*end) == 0) |
||||
|
{ |
||||
|
++end; |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
line.set(itr, end - itr); |
||||
|
|
||||
|
// Add section to stack; pop sections or push blanks as necessary
|
||||
|
|
||||
|
while (depth < section_stack.size()) |
||||
|
section_stack.pop(); |
||||
|
|
||||
|
while (depth > section_stack.size()) |
||||
|
section_stack.push(std::addressof(section_stack.top()->getSectionReference(Jupiter::ReferenceString::empty))); |
||||
|
|
||||
|
section_stack.push(§ion_stack.top()->getSectionReference(line)); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
// Truncate spaces
|
||||
|
--end; |
||||
|
|
||||
|
while (isspace(*end)) |
||||
|
--end; // don't need a safety check since we know there is at least 1 non-space character
|
||||
|
// end now points to a non-space character within the bounds
|
||||
|
|
||||
|
++end; |
||||
|
line.truncate(itr + line.size() - end); |
||||
|
|
||||
|
// Parse key (can be empty)
|
||||
|
|
||||
|
while (*itr != '=') |
||||
|
if (++itr == end) |
||||
|
return; // Error: no assignment exists; ignore line
|
||||
|
|
||||
|
Jupiter::ReferenceString key; |
||||
|
|
||||
|
if (itr != line.ptr()) |
||||
|
{ |
||||
|
// Truncate spaces from key; a non-space character is guaranteed
|
||||
|
end = itr - 1; |
||||
|
|
||||
|
while (isspace(*end)) |
||||
|
--end; |
||||
|
|
||||
|
key = line.substring(size_t{ 0 }, end + 1 - line.ptr()); |
||||
|
|
||||
|
end = line.ptr() + line.size(); |
||||
|
} |
||||
|
|
||||
|
// Parse value (can be empty)
|
||||
|
|
||||
|
if (++itr != end) |
||||
|
{ |
||||
|
// Shift to right of spaces; a non-space character is guaranteed
|
||||
|
while (isspace(*itr)) |
||||
|
++itr; |
||||
|
|
||||
|
line.shiftRight(itr - line.ptr()); |
||||
|
} |
||||
|
else |
||||
|
line = Jupiter::ReferenceString::empty; |
||||
|
|
||||
|
// Add entry to current table on stack
|
||||
|
section_stack.top()->set(key, line); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
constexpr size_t READ_CHUNK_SIZE = 1024; |
||||
|
size_t read_count = READ_CHUNK_SIZE; |
||||
|
Buffer buffer; |
||||
|
char *itr; |
||||
|
char *end; |
||||
|
|
||||
|
// Open file
|
||||
|
FILE *file = fopen(in_filename, "rb"); |
||||
|
|
||||
|
if (file == nullptr) |
||||
|
return false; |
||||
|
|
||||
|
buffer.setBufferSize(READ_CHUNK_SIZE * 2); |
||||
|
|
||||
|
// Parse file contents
|
||||
|
while (read_count == READ_CHUNK_SIZE) |
||||
|
{ |
||||
|
// Ensure the buffer has at least READ_CHUNK_SIZE space remaining
|
||||
|
buffer.setBufferSize(buffer.size() + READ_CHUNK_SIZE); |
||||
|
|
||||
|
// Read data from file to end of buffer
|
||||
|
itr = buffer.get_str(); |
||||
|
read_count = fread(itr + buffer.size(), sizeof(char), READ_CHUNK_SIZE, file); |
||||
|
buffer.set_length(buffer.size() + read_count); |
||||
|
end = itr + buffer.size(); |
||||
|
|
||||
|
// Reset line
|
||||
|
line.set(buffer.ptr(), 0); |
||||
|
|
||||
|
// Parse buffer for lines
|
||||
|
while (itr != end) |
||||
|
{ |
||||
|
// Check if the line is over
|
||||
|
if (*itr == '\n' || *itr == '\r') |
||||
|
{ |
||||
|
// Process line
|
||||
|
line.set(buffer.ptr(), itr - buffer.ptr()); |
||||
|
if (line.isNotEmpty()) |
||||
|
process_line(); |
||||
|
|
||||
|
// Keep iterating until next non-newline character
|
||||
|
while (true) |
||||
|
{ |
||||
|
++itr; |
||||
|
|
||||
|
if (itr == end) |
||||
|
{ |
||||
|
// No data remains to be parsed in buffer; erase buffer and break
|
||||
|
buffer.erase(); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
if (*itr != '\n' && *itr != '\r') |
||||
|
{ |
||||
|
// Shift buffer and break
|
||||
|
buffer.shiftRight(itr - buffer.ptr()); |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
else |
||||
|
++itr; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// Process data remaining in buffer as a line
|
||||
|
line.set(buffer.ptr(), buffer.size()); |
||||
|
if (line.isNotEmpty()) |
||||
|
process_line(); |
||||
|
|
||||
|
// File has been successfully read, or an error occurred.
|
||||
|
fclose(file); |
||||
|
return true; |
||||
|
} |
@ -0,0 +1,62 @@ |
|||||
|
/**
|
||||
|
* Copyright (C) 2016 Jessica James. |
||||
|
* |
||||
|
* Permission to use, copy, modify, and/or distribute this software for any |
||||
|
* purpose with or without fee is hereby granted, provided that the above |
||||
|
* copyright notice and this permission notice appear in all copies. |
||||
|
* |
||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
||||
|
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
||||
|
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
||||
|
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
||||
|
* |
||||
|
* Written by Jessica James <jessica.aj@outlook.com> |
||||
|
*/ |
||||
|
|
||||
|
#if !defined JUPITER_INICONFIG_H_HEADER |
||||
|
#define JUPITER_INICONFIG_H_HEADER |
||||
|
|
||||
|
/**
|
||||
|
* @file INIConfig.h |
||||
|
* @brief Provides an INI config implementation for the Config interface. |
||||
|
*/ |
||||
|
|
||||
|
#include "Config.h" |
||||
|
|
||||
|
/** DLL Linkage Nagging */ |
||||
|
#if defined _MSC_VER |
||||
|
#pragma warning(push) |
||||
|
#pragma warning(disable: 4251) |
||||
|
#endif |
||||
|
|
||||
|
namespace Jupiter |
||||
|
{ |
||||
|
/**
|
||||
|
* @brief INI-based Config class |
||||
|
*/ |
||||
|
class JUPITER_API INIConfig : public Jupiter::Config |
||||
|
{ |
||||
|
public: |
||||
|
/**
|
||||
|
* @brief Writes config data to a file |
||||
|
* |
||||
|
* @param in_filename Name of the file to write to |
||||
|
* @return True on success, false otherwise |
||||
|
*/ |
||||
|
bool write(const char *in_filename); |
||||
|
|
||||
|
private: |
||||
|
bool read_internal(const char *in_filename); |
||||
|
void write_helper(FILE *in_file, const Jupiter::Config *in_section, size_t in_depth); |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
/** Re-enable warnings */ |
||||
|
#if defined _MSC_VER |
||||
|
#pragma warning(pop) |
||||
|
#endif |
||||
|
|
||||
|
#endif // JUPITER_INICONFIG_H_HEADER
|
Loading…
Reference in new issue