mirror of
https://git.rtems.org/rtems-tools/
synced 2025-10-19 13:50:30 +08:00
rtemstoolkit: Update SimpleIni to latest
The resolves C++17 warnings. Updates #4970
This commit is contained in:
@@ -3,9 +3,9 @@
|
||||
<table>
|
||||
<tr><th>Library <td>SimpleIni
|
||||
<tr><th>File <td>SimpleIni.h
|
||||
<tr><th>Author <td>Brodie Thiesfield [code at jellycan dot com]
|
||||
<tr><th>Author <td>Brodie Thiesfield
|
||||
<tr><th>Source <td>https://github.com/brofield/simpleini
|
||||
<tr><th>Version <td>4.17
|
||||
<tr><th>Version <td>4.20
|
||||
</table>
|
||||
|
||||
Jump to the @link CSimpleIniTempl CSimpleIni @endlink interface documentation.
|
||||
@@ -20,7 +20,7 @@
|
||||
@section features FEATURES
|
||||
|
||||
- MIT Licence allows free use in all software (including GPL and commercial)
|
||||
- multi-platform (Windows 95/98/ME/NT/2K/XP/2003, Windows CE, Linux, Unix)
|
||||
- multi-platform (Windows CE/9x/NT..10/etc, Linux, MacOSX, Unix)
|
||||
- loading and saving of INI-style configuration files
|
||||
- configuration files can have any newline format on all platforms
|
||||
- liberal acceptance of file format
|
||||
@@ -42,22 +42,31 @@
|
||||
- Windows/VC6 (warning level 3)
|
||||
- Windows/VC.NET 2003 (warning level 4)
|
||||
- Windows/VC 2005 (warning level 4)
|
||||
- Windows/VC 2019 (warning level 4)
|
||||
- Linux/gcc (-Wall)
|
||||
|
||||
|
||||
@section usage USAGE SUMMARY
|
||||
|
||||
-# Decide if you will be using utf8 or MBCS files, and working with the
|
||||
data in utf8, wchar_t or ICU chars.
|
||||
-# If you will only be using straight utf8 files and access the data via the
|
||||
char interface, then you do not need any conversion library and could define
|
||||
SI_NO_CONVERSION. Note that no conversion also means no validation of the data.
|
||||
If no converter is specified then the default converter is SI_CONVERT_GENERIC
|
||||
on Mac/Linux and SI_CONVERT_WIN32 on Windows. If you need widechar support on
|
||||
Mac/Linux then use either SI_CONVERT_GENERIC or SI_CONVERT_ICU. These are also
|
||||
supported on all platforms.
|
||||
-# Define the appropriate symbol for the converter you wish to use and
|
||||
include the SimpleIni.h header file. If no specific converter is defined
|
||||
then the default converter is used. The default conversion mode uses
|
||||
SI_CONVERT_WIN32 on Windows and SI_CONVERT_GENERIC on all other
|
||||
platforms. If you are using ICU then SI_CONVERT_ICU is supported on all
|
||||
platforms.
|
||||
-# Declare an instance the appropriate class. Note that the following
|
||||
include the SimpleIni.h header file.
|
||||
-# Declare an instance of the appropriate class. Note that the following
|
||||
definitions are just shortcuts for commonly used types. Other types
|
||||
(PRUnichar, unsigned short, unsigned char) are also possible.
|
||||
<table>
|
||||
<tr><th>Interface <th>Case-sensitive <th>Load UTF-8 <th>Load MBCS <th>Typedef
|
||||
<tr><th>SI_NO_CONVERSION
|
||||
<tr><td>char <td>No <td>Yes <td>No <td>CSimpleIniA
|
||||
<tr><td>char <td>Yes <td>Yes <td>No <td>CSimpleIniCaseA
|
||||
<tr><th>SI_CONVERT_GENERIC
|
||||
<tr><td>char <td>No <td>Yes <td>Yes #1 <td>CSimpleIniA
|
||||
<tr><td>char <td>Yes <td>Yes <td>Yes <td>CSimpleIniCaseA
|
||||
@@ -88,6 +97,8 @@
|
||||
<tr><td>GetValue <td>Return a value for a section & key
|
||||
<tr><td>SetValue <td>Add or update a value for a section & key
|
||||
<tr><td>Delete <td>Remove a section, or a key from a section
|
||||
<tr><td>SectionExists <td>Does a section exist?
|
||||
<tr><td>KeyExists <td>Does a key exist?
|
||||
</table>
|
||||
-# Call Save() or SaveFile() to save the INI configuration data
|
||||
|
||||
@@ -161,6 +172,7 @@
|
||||
SI_STRLESS class, or by sorting the strings external to this library.
|
||||
- Usage of the <mbstring.h> header on Windows can be disabled by defining
|
||||
SI_NO_MBCS. This is defined automatically on Windows CE platforms.
|
||||
- Not thread-safe so manage your own locking
|
||||
|
||||
@section contrib CONTRIBUTIONS
|
||||
|
||||
@@ -213,11 +225,11 @@
|
||||
#endif
|
||||
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <list>
|
||||
#include <algorithm>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef SI_SUPPORT_IOSTREAMS
|
||||
@@ -233,16 +245,16 @@
|
||||
# define SI_ASSERT(x)
|
||||
#endif
|
||||
|
||||
enum SI_Error {
|
||||
SI_OK = 0, //!< No error
|
||||
SI_UPDATED = 1, //!< An existing value was updated
|
||||
SI_INSERTED = 2, //!< A new value was inserted
|
||||
using SI_Error = int;
|
||||
|
||||
// note: test for any error with (retval < 0)
|
||||
SI_FAIL = -1, //!< Generic failure
|
||||
SI_NOMEM = -2, //!< Out of memory error
|
||||
SI_FILE = -3 //!< File error (see errno for detail error)
|
||||
};
|
||||
constexpr int SI_OK = 0; //!< No error
|
||||
constexpr int SI_UPDATED = 1; //!< An existing value was updated
|
||||
constexpr int SI_INSERTED = 2; //!< A new value was inserted
|
||||
|
||||
// note: test for any error with (retval < 0)
|
||||
constexpr int SI_FAIL = -1; //!< Generic failure
|
||||
constexpr int SI_NOMEM = -2; //!< Out of memory error
|
||||
constexpr int SI_FILE = -3; //!< File error (see errno for detail error)
|
||||
|
||||
#define SI_UTF8_SIGNATURE "\xEF\xBB\xBF"
|
||||
|
||||
@@ -327,7 +339,7 @@ public:
|
||||
#endif
|
||||
|
||||
/** Strict less ordering by name of key only */
|
||||
struct KeyOrder : std::binary_function<Entry, Entry, bool> {
|
||||
struct KeyOrder {
|
||||
bool operator()(const Entry & lhs, const Entry & rhs) const {
|
||||
const static SI_STRLESS isLess = SI_STRLESS();
|
||||
return isLess(lhs.pItem, rhs.pItem);
|
||||
@@ -335,7 +347,7 @@ public:
|
||||
};
|
||||
|
||||
/** Strict less ordering by order, and then name of key */
|
||||
struct LoadOrder : std::binary_function<Entry, Entry, bool> {
|
||||
struct LoadOrder {
|
||||
bool operator()(const Entry & lhs, const Entry & rhs) const {
|
||||
if (lhs.nOrder != rhs.nOrder) {
|
||||
return lhs.nOrder < rhs.nOrder;
|
||||
@@ -541,6 +553,35 @@ public:
|
||||
/** Query the status of spaces output */
|
||||
bool UsingSpaces() const { return m_bSpaces; }
|
||||
|
||||
|
||||
/** Should we recognise and parse quotes in single line values?
|
||||
|
||||
\param a_bParseQuotes Parse quoted data in values?
|
||||
*/
|
||||
void SetQuotes(bool a_bParseQuotes = true) {
|
||||
m_bParseQuotes = a_bParseQuotes;
|
||||
}
|
||||
|
||||
/** Are we permitting keys and values to be quoted? */
|
||||
bool UsingQuotes() const { return m_bParseQuotes; }
|
||||
|
||||
/** When reading/writing an ini file, do we require every key to have an equals
|
||||
sign to delineate a valid key value. If false, then every valid key must
|
||||
have an equals sign and any lines without an equals sign is ignored. If
|
||||
true then keys do not require an equals sign to be considered a key. Note
|
||||
that this means that any non-commented line of text would become a key.
|
||||
|
||||
\param a_bAllowKeyOnly Permit keys without an equals sign or value.
|
||||
*/
|
||||
void SetAllowKeyOnly(bool a_bAllowKeyOnly = true) {
|
||||
m_bAllowKeyOnly = a_bAllowKeyOnly;
|
||||
}
|
||||
|
||||
/** Do we allow keys to exist without a value or equals sign? */
|
||||
bool GetAllowKeyOnly() const { return m_bAllowKeyOnly; }
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/** @}
|
||||
@{ @name Loading INI Data */
|
||||
@@ -837,13 +878,27 @@ public:
|
||||
are in use!
|
||||
|
||||
@param a_pSection Name of the section to return
|
||||
@return boolean Was a section matching the supplied
|
||||
name found.
|
||||
@return Section data
|
||||
*/
|
||||
const TKeyVal * GetSection(
|
||||
const SI_CHAR * a_pSection
|
||||
) const;
|
||||
|
||||
/** Test if a section exists. Convenience function */
|
||||
inline bool SectionExists(
|
||||
const SI_CHAR * a_pSection
|
||||
) const {
|
||||
return GetSection(a_pSection) != NULL;
|
||||
}
|
||||
|
||||
/** Test if the key exists in a section. Convenience function. */
|
||||
inline bool KeyExists(
|
||||
const SI_CHAR * a_pSection,
|
||||
const SI_CHAR * a_pKey
|
||||
) const {
|
||||
return GetValue(a_pSection, a_pKey) != NULL;
|
||||
}
|
||||
|
||||
/** Retrieve the value for a specific key. If multiple keys are enabled
|
||||
(see SetMultiKey) then only the first value associated with that key
|
||||
will be returned, see GetAllValues for getting all values with multikey.
|
||||
@@ -1065,8 +1120,8 @@ public:
|
||||
data returned by GetSection is invalid and must not be used after
|
||||
anything has been deleted from that section using this method.
|
||||
Note when multiple keys is enabled, this will delete all keys with
|
||||
that name; there is no way to selectively delete individual key/values
|
||||
in this situation.
|
||||
that name; to selectively delete individual key/values, use
|
||||
DeleteValue.
|
||||
|
||||
@param a_pSection Section to delete key from, or if
|
||||
a_pKey is NULL, the section to remove.
|
||||
@@ -1085,6 +1140,33 @@ public:
|
||||
bool a_bRemoveEmpty = false
|
||||
);
|
||||
|
||||
/** Delete an entire section, or a key from a section. If value is
|
||||
provided, only remove keys with the value. Note that the data
|
||||
returned by GetSection is invalid and must not be used after
|
||||
anything has been deleted from that section using this method.
|
||||
Note when multiple keys is enabled, all keys with the value will
|
||||
be deleted.
|
||||
|
||||
@param a_pSection Section to delete key from, or if
|
||||
a_pKey is NULL, the section to remove.
|
||||
@param a_pKey Key to remove from the section. Set to
|
||||
NULL to remove the entire section.
|
||||
@param a_pValue Value of key to remove from the section.
|
||||
Set to NULL to remove all keys.
|
||||
@param a_bRemoveEmpty If the section is empty after this key has
|
||||
been deleted, should the empty section be
|
||||
removed?
|
||||
|
||||
@return true Key/value or section was deleted.
|
||||
@return false Key/value or section was not found.
|
||||
*/
|
||||
bool DeleteValue(
|
||||
const SI_CHAR * a_pSection,
|
||||
const SI_CHAR * a_pKey,
|
||||
const SI_CHAR * a_pValue,
|
||||
bool a_bRemoveEmpty = false
|
||||
);
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/** @}
|
||||
@{ @name Converter */
|
||||
@@ -1186,6 +1268,7 @@ private:
|
||||
|
||||
bool IsMultiLineTag(const SI_CHAR * a_pData) const;
|
||||
bool IsMultiLineData(const SI_CHAR * a_pData) const;
|
||||
bool IsSingleLineQuotedValue(const SI_CHAR* a_pData) const;
|
||||
bool LoadMultiLineText(
|
||||
SI_CHAR *& a_pData,
|
||||
const SI_CHAR *& a_pVal,
|
||||
@@ -1217,6 +1300,9 @@ private:
|
||||
/** File comment for this data, if one exists. */
|
||||
const SI_CHAR * m_pFileComment;
|
||||
|
||||
/** constant empty string */
|
||||
const SI_CHAR m_cEmptyString;
|
||||
|
||||
/** Parsed INI data. Section -> (Key -> Value). */
|
||||
TSection m_data;
|
||||
|
||||
@@ -1238,6 +1324,12 @@ private:
|
||||
/** Should spaces be written out surrounding the equals sign? */
|
||||
bool m_bSpaces;
|
||||
|
||||
/** Should quoted data in values be recognized and parsed? */
|
||||
bool m_bParseQuotes;
|
||||
|
||||
/** Do keys always need to have an equals sign when reading/writing? */
|
||||
bool m_bAllowKeyOnly;
|
||||
|
||||
/** Next order value, used to ensure sections and keys are output in the
|
||||
same order that they are loaded/added.
|
||||
*/
|
||||
@@ -1257,10 +1349,13 @@ CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::CSimpleIniTempl(
|
||||
: m_pData(0)
|
||||
, m_uDataLen(0)
|
||||
, m_pFileComment(NULL)
|
||||
, m_cEmptyString(0)
|
||||
, m_bStoreIsUtf8(a_bIsUtf8)
|
||||
, m_bAllowMultiKey(a_bAllowMultiKey)
|
||||
, m_bAllowMultiLine(a_bAllowMultiLine)
|
||||
, m_bSpaces(true)
|
||||
, m_bParseQuotes(false)
|
||||
, m_bAllowKeyOnly(false)
|
||||
, m_nOrder(0)
|
||||
{ }
|
||||
|
||||
@@ -1359,7 +1454,7 @@ CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::LoadFile(
|
||||
}
|
||||
|
||||
// allocate and ensure NULL terminated
|
||||
char * pData = new char[lSize+1];
|
||||
char * pData = new(std::nothrow) char[lSize+static_cast<size_t>(1)];
|
||||
if (!pData) {
|
||||
return SI_NOMEM;
|
||||
}
|
||||
@@ -1386,21 +1481,26 @@ CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::LoadData(
|
||||
size_t a_uDataLen
|
||||
)
|
||||
{
|
||||
SI_CONVERTER converter(m_bStoreIsUtf8);
|
||||
if (!a_pData) {
|
||||
return SI_OK;
|
||||
}
|
||||
|
||||
// if the UTF-8 BOM exists, consume it and set mode to unicode, if we have
|
||||
// already loaded data and try to change mode half-way through then this will
|
||||
// be ignored and we will assert in debug versions
|
||||
if (a_uDataLen >= 3 && memcmp(a_pData, SI_UTF8_SIGNATURE, 3) == 0) {
|
||||
a_pData += 3;
|
||||
a_uDataLen -= 3;
|
||||
SI_ASSERT(m_bStoreIsUtf8 || !m_pData); // we don't expect mixed mode data
|
||||
SetUnicode();
|
||||
}
|
||||
|
||||
if (a_uDataLen == 0) {
|
||||
return SI_OK;
|
||||
}
|
||||
|
||||
// consume the UTF-8 BOM if it exists
|
||||
if (m_bStoreIsUtf8 && a_uDataLen >= 3) {
|
||||
if (memcmp(a_pData, SI_UTF8_SIGNATURE, 3) == 0) {
|
||||
a_pData += 3;
|
||||
a_uDataLen -= 3;
|
||||
}
|
||||
}
|
||||
|
||||
// determine the length of the converted data
|
||||
SI_CONVERTER converter(m_bStoreIsUtf8);
|
||||
size_t uLen = converter.SizeFromStore(a_pData, a_uDataLen);
|
||||
if (uLen == (size_t)(-1)) {
|
||||
return SI_FAIL;
|
||||
@@ -1408,7 +1508,7 @@ CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::LoadData(
|
||||
|
||||
// allocate memory for the data, ensure that there is a NULL
|
||||
// terminator wherever the converted data ends
|
||||
SI_CHAR * pData = new SI_CHAR[uLen+1];
|
||||
SI_CHAR * pData = new(std::nothrow) SI_CHAR[uLen+1];
|
||||
if (!pData) {
|
||||
return SI_NOMEM;
|
||||
}
|
||||
@@ -1512,6 +1612,7 @@ CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::FindEntry(
|
||||
{
|
||||
a_pComment = NULL;
|
||||
|
||||
bool bHaveValue = false;
|
||||
SI_CHAR * pTrail = NULL;
|
||||
while (*a_pData) {
|
||||
// skip spaces and empty lines
|
||||
@@ -1569,19 +1670,20 @@ CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::FindEntry(
|
||||
}
|
||||
|
||||
// find the end of the key name (it may contain spaces)
|
||||
// and convert it to lowercase as necessary
|
||||
a_pKey = a_pData;
|
||||
while (*a_pData && *a_pData != '=' && !IsNewLineChar(*a_pData)) {
|
||||
++a_pData;
|
||||
}
|
||||
// *a_pData is null, equals, or newline
|
||||
|
||||
// if it's an invalid line, just skip it
|
||||
if (*a_pData != '=') {
|
||||
// if no value and we don't allow no value, then invalid
|
||||
bHaveValue = (*a_pData == '=');
|
||||
if (!bHaveValue && !m_bAllowKeyOnly) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// empty keys are invalid
|
||||
if (a_pKey == a_pData) {
|
||||
if (bHaveValue && a_pKey == a_pData) {
|
||||
while (*a_pData && !IsNewLineChar(*a_pData)) {
|
||||
++a_pData;
|
||||
}
|
||||
@@ -1594,6 +1696,9 @@ CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::FindEntry(
|
||||
--pTrail;
|
||||
}
|
||||
++pTrail;
|
||||
|
||||
if (bHaveValue) {
|
||||
// process the value
|
||||
*pTrail = 0;
|
||||
|
||||
// skip leading whitespace on the value
|
||||
@@ -1622,10 +1727,27 @@ CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::FindEntry(
|
||||
// check for multi-line entries
|
||||
if (m_bAllowMultiLine && IsMultiLineTag(a_pVal)) {
|
||||
// skip the "<<<" to get the tag that will end the multiline
|
||||
const SI_CHAR * pTagName = a_pVal + 3;
|
||||
const SI_CHAR* pTagName = a_pVal + 3;
|
||||
return LoadMultiLineText(a_pData, a_pVal, pTagName);
|
||||
}
|
||||
|
||||
// check for quoted values, we are not supporting escapes in quoted values (yet)
|
||||
if (m_bParseQuotes) {
|
||||
--pTrail;
|
||||
if (pTrail > a_pVal && *a_pVal == '"' && *pTrail == '"') {
|
||||
++a_pVal;
|
||||
*pTrail = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// no value to process, just prepare for the next
|
||||
if (*a_pData) {
|
||||
SkipNewLine(a_pData);
|
||||
}
|
||||
*pTrail = 0;
|
||||
}
|
||||
|
||||
// return the standard entry
|
||||
return true;
|
||||
}
|
||||
@@ -1683,6 +1805,41 @@ CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::IsMultiLineData(
|
||||
return false;
|
||||
}
|
||||
|
||||
template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
|
||||
bool
|
||||
CSimpleIniTempl<SI_CHAR, SI_STRLESS, SI_CONVERTER>::IsSingleLineQuotedValue(
|
||||
const SI_CHAR* a_pData
|
||||
) const
|
||||
{
|
||||
// data needs quoting if it starts or ends with whitespace
|
||||
// and doesn't have embedded newlines
|
||||
|
||||
// empty string
|
||||
if (!*a_pData) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// check for prefix
|
||||
if (IsSpace(*a_pData)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// embedded newlines
|
||||
while (*a_pData) {
|
||||
if (IsNewLineChar(*a_pData)) {
|
||||
return false;
|
||||
}
|
||||
++a_pData;
|
||||
}
|
||||
|
||||
// check for suffix
|
||||
if (IsSpace(*--a_pData)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
|
||||
bool
|
||||
CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::IsNewLineChar(
|
||||
@@ -1716,8 +1873,8 @@ CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::LoadMultiLineText(
|
||||
a_pVal = a_pData;
|
||||
|
||||
// find the end tag. This tag must start in column 1 and be
|
||||
// followed by a newline. No whitespace removal is done while
|
||||
// searching for this tag.
|
||||
// followed by a newline. We ignore any whitespace after the end
|
||||
// tag but not whitespace before it.
|
||||
SI_CHAR cEndOfLineChar = *a_pData;
|
||||
for(;;) {
|
||||
// if we are loading comments then we need a comment character as
|
||||
@@ -1773,12 +1930,20 @@ CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::LoadMultiLineText(
|
||||
// if are looking for a tag then do the check now. This is done before
|
||||
// checking for end of the data, so that if we have the tag at the end
|
||||
// of the data then the tag is removed correctly.
|
||||
if (a_pTagName &&
|
||||
(!IsLess(pDataLine, a_pTagName) && !IsLess(a_pTagName, pDataLine)))
|
||||
{
|
||||
if (a_pTagName) {
|
||||
// strip whitespace from the end of this tag
|
||||
SI_CHAR* pc = a_pData - 1;
|
||||
while (pc > pDataLine && IsSpace(*pc)) --pc;
|
||||
SI_CHAR ch = *++pc;
|
||||
*pc = 0;
|
||||
|
||||
if (!IsLess(pDataLine, a_pTagName) && !IsLess(a_pTagName, pDataLine)) {
|
||||
break;
|
||||
}
|
||||
|
||||
*pc = ch;
|
||||
}
|
||||
|
||||
// if we are at the end of the data then we just automatically end
|
||||
// this entry and return the current data.
|
||||
if (!cEndOfLineChar) {
|
||||
@@ -1833,7 +1998,7 @@ CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::CopyString(
|
||||
for ( ; a_pString[uLen]; ++uLen) /*loop*/ ;
|
||||
}
|
||||
++uLen; // NULL character
|
||||
SI_CHAR * pCopy = new SI_CHAR[uLen];
|
||||
SI_CHAR * pCopy = new(std::nothrow) SI_CHAR[uLen];
|
||||
if (!pCopy) {
|
||||
return SI_NOMEM;
|
||||
}
|
||||
@@ -1878,7 +2043,7 @@ CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::AddEntry(
|
||||
|
||||
// only set the comment if this is a section only entry
|
||||
Entry oSection(a_pSection, ++m_nOrder);
|
||||
if (a_pComment && (!a_pKey || !a_pValue)) {
|
||||
if (a_pComment && !a_pKey) {
|
||||
oSection.pComment = a_pComment;
|
||||
}
|
||||
|
||||
@@ -1888,14 +2053,15 @@ CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::AddEntry(
|
||||
iSection = i.first;
|
||||
bInserted = true;
|
||||
}
|
||||
if (!a_pKey || !a_pValue) {
|
||||
// section only entries are specified with pItem and pVal as NULL
|
||||
if (!a_pKey) {
|
||||
// section only entries are specified with pItem as NULL
|
||||
return bInserted ? SI_INSERTED : SI_UPDATED;
|
||||
}
|
||||
|
||||
// check for existence of the key
|
||||
TKeyVal & keyval = iSection->second;
|
||||
typename TKeyVal::iterator iKey = keyval.find(a_pKey);
|
||||
bInserted = iKey == keyval.end();
|
||||
|
||||
// remove all existing entries but save the load order and
|
||||
// comment of the first entry
|
||||
@@ -1918,6 +2084,11 @@ CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::AddEntry(
|
||||
iKey = keyval.end();
|
||||
}
|
||||
|
||||
// values need to be a valid string, even if they are an empty string
|
||||
if (!a_pValue) {
|
||||
a_pValue = &m_cEmptyString;
|
||||
}
|
||||
|
||||
// make string copies if necessary
|
||||
bool bForceCreateNewKey = m_bAllowMultiKey && !a_bForceReplace;
|
||||
if (a_bCopyStrings) {
|
||||
@@ -1942,8 +2113,8 @@ CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::AddEntry(
|
||||
}
|
||||
typename TKeyVal::value_type oEntry(oKey, static_cast<const SI_CHAR *>(NULL));
|
||||
iKey = keyval.insert(oEntry);
|
||||
bInserted = true;
|
||||
}
|
||||
|
||||
iKey->second = a_pValue;
|
||||
return bInserted ? SI_INSERTED : SI_UPDATED;
|
||||
}
|
||||
@@ -2010,10 +2181,10 @@ CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::GetLongValue(
|
||||
char * pszSuffix = szValue;
|
||||
if (szValue[0] == '0' && (szValue[1] == 'x' || szValue[1] == 'X')) {
|
||||
if (!szValue[2]) return a_nDefault;
|
||||
nValue = ::strtol(&szValue[2], &pszSuffix, 16);
|
||||
nValue = strtol(&szValue[2], &pszSuffix, 16);
|
||||
}
|
||||
else {
|
||||
nValue = ::strtol(szValue, &pszSuffix, 10);
|
||||
nValue = strtol(szValue, &pszSuffix, 10);
|
||||
}
|
||||
|
||||
// any invalid strings will return the default value
|
||||
@@ -2043,7 +2214,7 @@ CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::SetLongValue(
|
||||
#if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE
|
||||
sprintf_s(szInput, a_bUseHex ? "0x%lx" : "%ld", a_nValue);
|
||||
#else // !__STDC_WANT_SECURE_LIB__
|
||||
sprintf(szInput, a_bUseHex ? "0x%lx" : "%ld", a_nValue);
|
||||
snprintf(szInput, sizeof(szInput), a_bUseHex ? "0x%lx" : "%ld", a_nValue);
|
||||
#endif // __STDC_WANT_SECURE_LIB__
|
||||
|
||||
// convert to output text
|
||||
@@ -2105,7 +2276,7 @@ CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::SetDoubleValue(
|
||||
#if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE
|
||||
sprintf_s(szInput, "%f", a_nValue);
|
||||
#else // !__STDC_WANT_SECURE_LIB__
|
||||
sprintf(szInput, "%f", a_nValue);
|
||||
snprintf(szInput, sizeof(szInput), "%f", a_nValue);
|
||||
#endif // __STDC_WANT_SECURE_LIB__
|
||||
|
||||
// convert to output text
|
||||
@@ -2390,6 +2561,19 @@ CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::Save(
|
||||
oSections.sort(typename Entry::LoadOrder());
|
||||
#endif
|
||||
|
||||
// if there is an empty section name, then it must be written out first
|
||||
// regardless of the load order
|
||||
typename TNamesDepend::iterator is = oSections.begin();
|
||||
for (; is != oSections.end(); ++is) {
|
||||
if (!*is->pItem) {
|
||||
// move the empty section name to the front of the section list
|
||||
if (is != oSections.begin()) {
|
||||
oSections.splice(oSections.begin(), oSections, is, std::next(is));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// write the file comment if we have one
|
||||
bool bNeedNewLine = false;
|
||||
if (m_pFileComment) {
|
||||
@@ -2465,12 +2649,20 @@ CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::Save(
|
||||
}
|
||||
a_oOutput.Write(convert.Data());
|
||||
|
||||
// write the value
|
||||
// write the value as long
|
||||
if (*iValue->pItem || !m_bAllowKeyOnly) {
|
||||
if (!convert.ConvertToStore(iValue->pItem)) {
|
||||
return SI_FAIL;
|
||||
}
|
||||
a_oOutput.Write(m_bSpaces ? " = " : "=");
|
||||
if (m_bAllowMultiLine && IsMultiLineData(iValue->pItem)) {
|
||||
if (m_bParseQuotes && IsSingleLineQuotedValue(iValue->pItem)) {
|
||||
// the only way to preserve external whitespace on a value (i.e. before or after)
|
||||
// is to quote it. This is simple quoting, we don't escape quotes within the data.
|
||||
a_oOutput.Write("\"");
|
||||
a_oOutput.Write(convert.Data());
|
||||
a_oOutput.Write("\"");
|
||||
}
|
||||
else if (m_bAllowMultiLine && IsMultiLineData(iValue->pItem)) {
|
||||
// multi-line data needs to be processed specially to ensure
|
||||
// that we use the correct newline format for the current system
|
||||
a_oOutput.Write("<<<END_OF_TEXT" SI_NEWLINE_A);
|
||||
@@ -2482,6 +2674,7 @@ CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::Save(
|
||||
else {
|
||||
a_oOutput.Write(convert.Data());
|
||||
}
|
||||
}
|
||||
a_oOutput.Write(SI_NEWLINE_A);
|
||||
}
|
||||
}
|
||||
@@ -2528,6 +2721,18 @@ CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::Delete(
|
||||
const SI_CHAR * a_pKey,
|
||||
bool a_bRemoveEmpty
|
||||
)
|
||||
{
|
||||
return DeleteValue(a_pSection, a_pKey, NULL, a_bRemoveEmpty);
|
||||
}
|
||||
|
||||
template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
|
||||
bool
|
||||
CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::DeleteValue(
|
||||
const SI_CHAR * a_pSection,
|
||||
const SI_CHAR * a_pKey,
|
||||
const SI_CHAR * a_pValue,
|
||||
bool a_bRemoveEmpty
|
||||
)
|
||||
{
|
||||
if (!a_pSection) {
|
||||
return false;
|
||||
@@ -2545,18 +2750,30 @@ CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::Delete(
|
||||
return false;
|
||||
}
|
||||
|
||||
const static SI_STRLESS isLess = SI_STRLESS();
|
||||
|
||||
// remove any copied strings and then the key
|
||||
typename TKeyVal::iterator iDelete;
|
||||
bool bDeleted = false;
|
||||
do {
|
||||
iDelete = iKeyVal++;
|
||||
|
||||
if(a_pValue == NULL ||
|
||||
(isLess(a_pValue, iDelete->second) == false &&
|
||||
isLess(iDelete->second, a_pValue) == false)) {
|
||||
DeleteString(iDelete->first.pItem);
|
||||
DeleteString(iDelete->second);
|
||||
iSection->second.erase(iDelete);
|
||||
bDeleted = true;
|
||||
}
|
||||
}
|
||||
while (iKeyVal != iSection->second.end()
|
||||
&& !IsLess(a_pKey, iKeyVal->first.pItem));
|
||||
|
||||
if(!bDeleted) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// done now if the section is not empty or we are not pruning away
|
||||
// the empty sections. Otherwise let it fall through into the section
|
||||
// deletion code
|
||||
@@ -2610,13 +2827,15 @@ CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::DeleteString(
|
||||
// SimpleIni.h, set the converter that you wish you use by defining one of the
|
||||
// following symbols.
|
||||
//
|
||||
// SI_NO_CONVERSION Do not make the "W" wide character version of the
|
||||
// library available. Only CSimpleIniA etc is defined.
|
||||
// SI_CONVERT_GENERIC Use the Unicode reference conversion library in
|
||||
// the accompanying files ConvertUTF.h/c
|
||||
// SI_CONVERT_ICU Use the IBM ICU conversion library. Requires
|
||||
// ICU headers on include path and icuuc.lib
|
||||
// SI_CONVERT_WIN32 Use the Win32 API functions for conversion.
|
||||
|
||||
#if !defined(SI_CONVERT_GENERIC) && !defined(SI_CONVERT_WIN32) && !defined(SI_CONVERT_ICU)
|
||||
#if !defined(SI_NO_CONVERSION) && !defined(SI_CONVERT_GENERIC) && !defined(SI_CONVERT_WIN32) && !defined(SI_CONVERT_ICU)
|
||||
# ifdef _WIN32
|
||||
# define SI_CONVERT_WIN32
|
||||
# else
|
||||
@@ -2873,7 +3092,7 @@ public:
|
||||
// This uses the Unicode reference implementation to do the
|
||||
// conversion from UTF-8 to wchar_t. The required files are
|
||||
// ConvertUTF.h and ConvertUTF.c which should be included in
|
||||
// the distribution but are publically available from unicode.org
|
||||
// the distribution but are publicly available from unicode.org
|
||||
// at http://www.unicode.org/Public/PROGRAMS/CVTUTF/
|
||||
ConversionResult retval;
|
||||
const UTF8 * pUtf8 = (const UTF8 *) a_pInputData;
|
||||
@@ -2960,7 +3179,7 @@ public:
|
||||
// This uses the Unicode reference implementation to do the
|
||||
// conversion from wchar_t to UTF-8. The required files are
|
||||
// ConvertUTF.h and ConvertUTF.c which should be included in
|
||||
// the distribution but are publically available from unicode.org
|
||||
// the distribution but are publicly available from unicode.org
|
||||
// at http://www.unicode.org/Public/PROGRAMS/CVTUTF/
|
||||
ConversionResult retval;
|
||||
UTF8 * pUtf8 = (UTF8 *) a_pOutputData;
|
||||
@@ -3346,6 +3565,19 @@ public:
|
||||
#endif // SI_CONVERT_WIN32
|
||||
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// SI_NO_CONVERSION
|
||||
// ---------------------------------------------------------------------------
|
||||
#ifdef SI_NO_CONVERSION
|
||||
|
||||
#define SI_Case SI_GenericCase
|
||||
#define SI_NoCase SI_GenericNoCase
|
||||
|
||||
#endif // SI_NO_CONVERSION
|
||||
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// TYPE DEFINITIONS
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -3355,27 +3587,35 @@ typedef CSimpleIniTempl<char,
|
||||
typedef CSimpleIniTempl<char,
|
||||
SI_Case<char>,SI_ConvertA<char> > CSimpleIniCaseA;
|
||||
|
||||
#if defined(SI_CONVERT_ICU)
|
||||
#if defined(SI_NO_CONVERSION)
|
||||
// if there is no wide char conversion then we don't need to define the
|
||||
// widechar "W" versions of CSimpleIni
|
||||
# define CSimpleIni CSimpleIniA
|
||||
# define CSimpleIniCase CSimpleIniCaseA
|
||||
# define SI_NEWLINE SI_NEWLINE_A
|
||||
#else
|
||||
# if defined(SI_CONVERT_ICU)
|
||||
typedef CSimpleIniTempl<UChar,
|
||||
SI_NoCase<UChar>,SI_ConvertW<UChar> > CSimpleIniW;
|
||||
typedef CSimpleIniTempl<UChar,
|
||||
SI_Case<UChar>,SI_ConvertW<UChar> > CSimpleIniCaseW;
|
||||
#else
|
||||
# else
|
||||
typedef CSimpleIniTempl<wchar_t,
|
||||
SI_NoCase<wchar_t>,SI_ConvertW<wchar_t> > CSimpleIniW;
|
||||
typedef CSimpleIniTempl<wchar_t,
|
||||
SI_Case<wchar_t>,SI_ConvertW<wchar_t> > CSimpleIniCaseW;
|
||||
#endif
|
||||
# endif
|
||||
|
||||
#ifdef _UNICODE
|
||||
# ifdef _UNICODE
|
||||
# define CSimpleIni CSimpleIniW
|
||||
# define CSimpleIniCase CSimpleIniCaseW
|
||||
# define SI_NEWLINE SI_NEWLINE_W
|
||||
#else // !_UNICODE
|
||||
# else // !_UNICODE
|
||||
# define CSimpleIni CSimpleIniA
|
||||
# define CSimpleIniCase CSimpleIniCaseA
|
||||
# define SI_NEWLINE SI_NEWLINE_A
|
||||
#endif // _UNICODE
|
||||
# endif // _UNICODE
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning (pop)
|
||||
|
Reference in New Issue
Block a user