10 #ifndef INCLUDED_SimpleIni_h 11 #define INCLUDED_SimpleIni_h 23 #pragma warning(disable : 4127 4503 4702 4786) 36 #define SI_SUPPORT_IOSTREAMS 38 #ifdef SI_SUPPORT_IOSTREAMS 40 #endif // SI_SUPPORT_IOSTREAMS 44 #define SI_ASSERT(x) assert(x) 74 #define SI_NEWLINE_A "\r\n" 75 #define SI_NEWLINE_W L"\r\n" 77 #define SI_NEWLINE_A "\n" 78 #define SI_NEWLINE_W L"\n" 82 #define SI_HAS_WIDE_FILE 83 #define SI_WCHAR_T wchar_t 84 #elif defined(SI_CONVERT_ICU) 85 #define SI_HAS_WIDE_FILE 86 #define SI_WCHAR_T UChar 112 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
123 Entry(
const SI_CHAR* a_pszItem =
nullptr,
int a_nOrder = 0)
136 #if (defined(_MSC_VER) && _MSC_VER <= 1200) || defined(__BORLANDC__) 141 return LoadOrder()(*
this, rhs);
143 bool operator>(
const Entry& rhs)
const 145 return LoadOrder()(rhs, *
this);
150 struct KeyOrder : std::binary_function<Entry, Entry, bool>
154 const static SI_STRLESS isLess = SI_STRLESS();
160 struct LoadOrder : std::binary_function<Entry, Entry, bool>
174 typedef std::multimap<Entry, const SI_CHAR*, typename Entry::KeyOrder>
178 typedef std::map<Entry, TKeyVal, typename Entry::KeyOrder>
TSection;
193 virtual void Write(
const char* a_pBuf) = 0;
207 void Write(
const char* a_pBuf)
override { fputs(a_pBuf,
m_file); }
226 #ifdef SI_SUPPORT_IOSTREAMS 239 #endif // SI_SUPPORT_IOSTREAMS 256 size_t uLen = this->SizeToStore(a_pszString);
257 if (uLen == (
size_t)(-1))
265 return SI_CONVERTER::ConvertToStore(
266 a_pszString, const_cast<char*>(
m_scratch.data()),
346 #ifdef SI_HAS_WIDE_FILE 354 #endif // SI_HAS_WIDE_FILE 365 #ifdef SI_SUPPORT_IOSTREAMS 373 #endif // SI_SUPPORT_IOSTREAMS 383 return Load(a_strData.c_str(), a_strData.size());
409 #ifdef SI_HAS_WIDE_FILE 456 #ifdef SI_SUPPORT_IOSTREAMS 468 #endif // SI_SUPPORT_IOSTREAMS 532 const SI_CHAR* a_pSection,
const SI_CHAR* a_pKey,
580 const SI_CHAR* a_pSection,
const SI_CHAR* a_pKey,
581 const SI_CHAR* a_pDefault =
nullptr,
582 bool* a_pHasMultiple =
nullptr)
const;
608 const SI_CHAR* a_pSection,
const SI_CHAR* a_pKey,
609 const SI_CHAR* a_pValue,
const SI_CHAR* a_pComment =
nullptr)
611 return AddEntry(a_pSection, a_pKey, a_pValue, a_pComment,
true);
633 const SI_CHAR* a_pSection,
const SI_CHAR* a_pKey,
634 bool a_bRemoveEmpty =
false);
659 SI_CHAR*& a_pData,
const SI_CHAR*& a_pSection,
const SI_CHAR*& a_pKey,
660 const SI_CHAR*& a_pVal,
const SI_CHAR*& a_pComment)
const;
679 const SI_CHAR* a_pSection,
const SI_CHAR* a_pKey,
680 const SI_CHAR* a_pValue,
const SI_CHAR* a_pComment,
681 bool a_bCopyStrings);
684 inline bool IsSpace(SI_CHAR ch)
const 686 return (ch ==
' ' || ch ==
'\t' || ch ==
'\r' || ch ==
'\n');
690 inline bool IsComment(SI_CHAR ch)
const {
return (ch ==
';' || ch ==
'#'); }
694 a_pData += (*a_pData ==
'\r' && *(a_pData + 1) ==
'\n') ? 2 : 1;
704 bool IsLess(
const SI_CHAR* a_pLeft,
const SI_CHAR* a_pRight)
const 706 const static SI_STRLESS isLess = SI_STRLESS();
707 return isLess(a_pLeft, a_pRight);
713 SI_CHAR*& a_pData,
const SI_CHAR*& a_pVal,
const SI_CHAR* a_pTagName,
714 bool a_bAllowBlankLinesInComment =
false)
const;
718 OutputWriter& a_oOutput, Converter& a_oConverter,
719 const SI_CHAR* a_pText)
const;
763 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
765 bool a_bAllowMultiKey,
bool a_bAllowMultiLine)
768 m_pFileComment(NULL),
769 m_bAllowMultiKey(a_bAllowMultiKey),
770 m_bAllowMultiLine(a_bAllowMultiLine),
775 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
781 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
788 m_pFileComment =
nullptr;
791 m_data.erase(m_data.begin(), m_data.end());
795 if (!m_strings.empty())
798 for (; i != m_strings.end(); ++i)
800 delete[]
const_cast<SI_CHAR*
>(i->pItem);
802 m_strings.erase(m_strings.begin(), m_strings.end());
806 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
808 const char* a_pszFile)
811 #if __STDC_WANT_SECURE_LIB__ 812 fopen_s(&fp, a_pszFile,
"rb");
814 fp =
fopen(a_pszFile,
"rb");
825 #ifdef SI_HAS_WIDE_FILE 826 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
832 #if __STDC_WANT_SECURE_LIB__ 833 _wfopen_s(&fp, a_pwszFile, L
"rb");
835 fp = _wfopen(a_pwszFile, L
"rb");
841 #else // SI_CONVERT_ICU 843 u_austrncpy(szFile, a_pwszFile,
sizeof(szFile));
844 return LoadFile(szFile);
847 #endif // SI_HAS_WIDE_FILE 849 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
854 int retval = fseek(a_fpFile, 0,
SEEK_END);
859 long lSize = ftell(a_fpFile);
864 char* pData =
new char[lSize];
870 size_t uRead = fread(pData,
sizeof(
char), lSize, a_fpFile);
871 if (uRead != (
size_t)lSize)
883 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
885 const char* a_pData,
size_t a_uDataLen)
887 SI_CONVERTER converter;
890 size_t uLen = converter.SizeFromStore(a_pData, a_uDataLen);
891 if (uLen == (
size_t)(-1))
898 SI_CHAR* pData =
new SI_CHAR[uLen + 1];
903 memset(pData, 0,
sizeof(SI_CHAR) * (uLen + 1));
906 if (!converter.ConvertFromStore(a_pData, a_uDataLen, pData, uLen))
913 const static SI_CHAR
empty = 0;
914 SI_CHAR* pWork = pData;
915 const SI_CHAR* pSection = &
empty;
916 const SI_CHAR* pItem =
nullptr;
917 const SI_CHAR* pVal =
nullptr;
918 const SI_CHAR* pComment =
nullptr;
922 bool bCopyStrings = (m_pData !=
nullptr);
926 SI_Error rc = FindFileComment(pWork, bCopyStrings);
927 if (rc < 0)
return rc;
930 while (FindEntry(pWork, pSection, pItem, pVal, pComment))
932 rc = AddEntry(pSection, pItem, pVal, pComment, bCopyStrings);
933 if (rc < 0)
return rc;
944 m_uDataLen = uLen + 1;
950 #ifdef SI_SUPPORT_IOSTREAMS 951 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
953 std::istream& a_istream)
959 a_istream.get(szBuf,
sizeof(szBuf),
'\0');
960 strData.append(szBuf);
961 }
while (a_istream.good());
962 return Load(strData);
964 #endif // SI_SUPPORT_IOSTREAMS 966 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
968 SI_CHAR*& a_pData,
bool a_bCopyStrings)
978 if (!LoadMultiLineText(a_pData, m_pFileComment,
nullptr,
false))
986 SI_Error rc = CopyString(m_pFileComment);
987 if (rc < 0)
return rc;
993 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
995 SI_CHAR*& a_pData,
const SI_CHAR*& a_pSection,
const SI_CHAR*& a_pKey,
996 const SI_CHAR*& a_pVal,
const SI_CHAR*& a_pComment)
const 998 a_pComment =
nullptr;
1000 SI_CHAR* pTrail =
nullptr;
1004 while (*a_pData && IsSpace(*a_pData))
1015 if (IsComment(*a_pData))
1017 LoadMultiLineText(a_pData, a_pComment,
nullptr,
true);
1022 if (*a_pData ==
'[')
1026 while (*a_pData && IsSpace(*a_pData))
1033 a_pSection = a_pData;
1034 while (*a_pData && *a_pData !=
']' && !IsNewLineChar(*a_pData))
1040 if (*a_pData !=
']')
1046 pTrail = a_pData - 1;
1047 while (pTrail >= a_pSection && IsSpace(*pTrail))
1056 while (*a_pData && !IsNewLineChar(*a_pData))
1069 while (*a_pData && *a_pData !=
'=' && !IsNewLineChar(*a_pData))
1075 if (*a_pData !=
'=')
1081 if (a_pKey == a_pData)
1083 while (*a_pData && !IsNewLineChar(*a_pData))
1091 pTrail = a_pData - 1;
1092 while (pTrail >= a_pKey && IsSpace(*pTrail))
1101 while (*a_pData && !IsNewLineChar(*a_pData) && IsSpace(*a_pData))
1108 while (*a_pData && !IsNewLineChar(*a_pData))
1114 pTrail = a_pData - 1;
1117 SkipNewLine(a_pData);
1119 while (pTrail >= a_pVal && IsSpace(*pTrail))
1127 if (m_bAllowMultiLine && IsMultiLineTag(a_pVal))
1130 const SI_CHAR* pTagName = a_pVal + 3;
1131 return LoadMultiLineText(a_pData, a_pVal, pTagName);
1141 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1143 const SI_CHAR* a_pVal)
const 1146 if (*a_pVal++ !=
'<')
return false;
1147 if (*a_pVal++ !=
'<')
return false;
1148 if (*a_pVal++ !=
'<')
return false;
1152 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1154 const SI_CHAR* a_pData)
const 1168 if (IsSpace(*a_pData))
1176 if (IsNewLineChar(*a_pData))
1184 if (IsSpace(*--a_pData))
1192 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1196 return (a_c ==
'\n' || a_c ==
'\r');
1199 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1201 SI_CHAR*& a_pData,
const SI_CHAR*& a_pVal,
const SI_CHAR* a_pTagName,
1202 bool a_bAllowBlankLinesInComment)
const 1212 SI_CHAR* pDataLine = a_pData;
1221 SI_CHAR cEndOfLineChar = *a_pData;
1226 if (!a_pTagName && !IsComment(*a_pData))
1229 if (!a_bAllowBlankLinesInComment)
1237 SI_CHAR* pCurr = a_pData;
1239 while (IsSpace(*pCurr))
1241 if (IsNewLineChar(*pCurr))
1254 if (IsComment(*pCurr))
1256 for (; nNewLines > 0; --nNewLines) *pDataLine++ =
'\n';
1266 pCurrLine = a_pData;
1267 while (*a_pData && !IsNewLineChar(*a_pData)) ++a_pData;
1270 if (pDataLine < pCurrLine)
1272 memmove(pDataLine, pCurrLine, a_pData - pCurrLine);
1273 pDataLine[a_pData - pCurrLine] =
'\0';
1277 cEndOfLineChar = *a_pData;
1284 (!IsLess(pDataLine, a_pTagName) && !IsLess(a_pTagName, pDataLine)))
1291 if (!cEndOfLineChar)
1298 pDataLine += (a_pData - pCurrLine);
1299 *a_pData = cEndOfLineChar;
1300 SkipNewLine(a_pData);
1301 *pDataLine++ =
'\n';
1305 if (a_pVal == a_pData)
1315 *--pDataLine =
'\0';
1319 if (a_pTagName && cEndOfLineChar)
1321 SI_ASSERT(IsNewLineChar(cEndOfLineChar));
1322 *a_pData = cEndOfLineChar;
1323 SkipNewLine(a_pData);
1329 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1331 const SI_CHAR*& a_pString)
1334 if (
sizeof(SI_CHAR) ==
sizeof(
char))
1336 uLen = strlen((
const char*)a_pString);
1338 else if (
sizeof(SI_CHAR) ==
sizeof(
wchar_t))
1340 uLen = wcslen((
const wchar_t*)a_pString);
1344 for (; a_pString[uLen]; ++uLen)
1348 SI_CHAR* pCopy =
new SI_CHAR[uLen];
1353 memcpy(pCopy, a_pString,
sizeof(SI_CHAR) * uLen);
1354 m_strings.push_back(pCopy);
1359 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1361 const SI_CHAR* a_pSection,
const SI_CHAR* a_pKey,
const SI_CHAR* a_pValue,
1362 const SI_CHAR* a_pComment,
bool a_bCopyStrings)
1365 bool bInserted =
false;
1367 SI_ASSERT(!a_pComment || IsComment(*a_pComment));
1371 if (a_bCopyStrings && a_pComment)
1373 rc = CopyString(a_pComment);
1374 if (rc < 0)
return rc;
1381 iSection = m_data.find(a_pSection);
1382 if (iSection == m_data.end())
1387 rc = CopyString(a_pSection);
1388 if (rc < 0)
return rc;
1393 if (iSection == m_data.end())
1395 Entry oKey(a_pSection, ++m_nOrder);
1396 if (a_pComment && (!a_pKey || !a_pValue))
1400 typename TSection::value_type oEntry(oKey,
TKeyVal());
1402 std::pair<SectionIterator, bool> i = m_data.insert(oEntry);
1406 if (!a_pKey || !a_pValue)
1413 TKeyVal& keyval = iSection->second;
1419 if (m_bAllowMultiKey || iKey == keyval.end())
1424 rc = CopyString(a_pKey);
1425 if (rc < 0)
return rc;
1429 rc = CopyString(a_pValue);
1430 if (rc < 0)
return rc;
1434 if (iKey == keyval.end() || m_bAllowMultiKey)
1436 Entry oKey(a_pKey, ++m_nOrder);
1441 typename TKeyVal::value_type oEntry(
1442 oKey, static_cast<const char*>(
nullptr));
1443 iKey = keyval.insert(oEntry);
1446 iKey->second = a_pValue;
1450 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1452 const SI_CHAR* a_pSection,
const SI_CHAR* a_pKey,
const SI_CHAR* a_pDefault,
1453 bool* a_pHasMultiple)
const 1457 *a_pHasMultiple =
false;
1459 if (!a_pSection || !a_pKey)
1464 if (iSection == m_data.end())
1469 if (iKeyVal == iSection->second.end())
1475 if (m_bAllowMultiKey && a_pHasMultiple)
1478 if (++iTemp != iSection->second.end())
1480 if (!IsLess(a_pKey, iTemp->first.pItem))
1482 *a_pHasMultiple =
true;
1487 return iKeyVal->second;
1490 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1492 const SI_CHAR* a_pSection,
const SI_CHAR* a_pKey,
1495 if (!a_pSection || !a_pKey)
1500 if (iSection == m_data.end())
1505 if (iKeyVal == iSection->second.end())
1511 a_values.push_back(iKeyVal->second);
1512 if (m_bAllowMultiKey)
1515 while (iKeyVal != iSection->second.end() &&
1516 !IsLess(a_pKey, iKeyVal->first.pItem))
1518 a_values.push_back(
Entry(iKeyVal->second, iKeyVal->first.nOrder));
1526 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1528 const SI_CHAR* a_pSection)
const 1536 if (iSection == m_data.end())
1540 const TKeyVal& section = iSection->second;
1544 if (!m_bAllowMultiKey || section.empty())
1546 return (
int)section.size();
1551 const SI_CHAR* pLastKey =
nullptr;
1553 for (
int n = 0; iKeyVal != section.end(); ++iKeyVal, ++
n)
1555 if (!pLastKey || IsLess(pLastKey, iKeyVal->first.pItem))
1558 pLastKey = iKeyVal->first.pItem;
1564 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1567 const SI_CHAR* a_pSection)
const 1572 if (i != m_data.end())
1574 return &(i->second);
1580 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1585 for (
int n = 0; i != m_data.end(); ++i, ++
n)
1587 a_names.push_back(i->first);
1591 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1593 const SI_CHAR* a_pSection,
TNamesDepend& a_names)
const 1601 if (iSection == m_data.end())
1606 const TKeyVal& section = iSection->second;
1607 const SI_CHAR* pLastKey =
nullptr;
1609 for (
int n = 0; iKeyVal != section.end(); ++iKeyVal, ++
n)
1611 if (!pLastKey || IsLess(pLastKey, iKeyVal->first.pItem))
1613 a_names.push_back(iKeyVal->first);
1614 pLastKey = iKeyVal->first.pItem;
1621 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1623 const char* a_pszFile)
const 1626 #if __STDC_WANT_SECURE_LIB__ 1627 fopen_s(&fp, a_pszFile,
"wb");
1629 fp =
fopen(a_pszFile,
"wb");
1637 #ifdef SI_HAS_WIDE_FILE 1638 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1643 FILE* fp = _wfopen(a_pwszFile, L
"wb");
1648 #else // SI_CONVERT_ICU 1650 u_austrncpy(szFile, a_pwszFile,
sizeof(szFile));
1651 return SaveFile(szFile);
1654 #endif // SI_HAS_WIDE_FILE 1656 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1658 FILE* a_pFile)
const 1661 return Save(writer);
1664 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1672 GetAllSections(oSections);
1673 #if (defined(_MSC_VER) && _MSC_VER <= 1200) || defined(__BORLANDC__) 1680 bool bNeedNewLine =
false;
1683 if (!OutputMultiLineText(a_oOutput, convert, m_pFileComment))
1687 bNeedNewLine =
true;
1692 for (; iSection != oSections.end(); ++iSection)
1695 if (iSection->pComment)
1708 bNeedNewLine =
false;
1715 bNeedNewLine =
false;
1719 if (*iSection->pItem)
1725 a_oOutput.
Write(
"[");
1727 a_oOutput.
Write(
"]");
1733 GetAllKeys(iSection->pItem, oKeys);
1734 #if (defined(_MSC_VER) && _MSC_VER <= 1200) || defined(__BORLANDC__) 1742 for (; iKey != oKeys.end(); ++iKey)
1746 GetAllValues(iSection->pItem, iKey->pItem, oValues);
1752 if (!OutputMultiLineText(a_oOutput, convert, iKey->pComment))
1759 for (; iValue != oValues.end(); ++iValue)
1773 a_oOutput.
Write(
"=");
1774 if (m_bAllowMultiLine && IsMultiLineData(iValue->pItem))
1780 if (!OutputMultiLineText(a_oOutput, convert, iValue->pItem))
1784 a_oOutput.
Write(
"SI-END-OF-MULTILINE-TEXT");
1794 bNeedNewLine =
true;
1800 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1803 const SI_CHAR* a_pText)
const 1805 const SI_CHAR* pEndOfLine;
1806 SI_CHAR cEndOfLineChar = *a_pText;
1807 while (cEndOfLineChar)
1810 pEndOfLine = a_pText;
1811 for (; *pEndOfLine && *pEndOfLine !=
'\n'; ++pEndOfLine)
1813 cEndOfLineChar = *pEndOfLine;
1816 *
const_cast<SI_CHAR*
>(pEndOfLine) = 0;
1821 *
const_cast<SI_CHAR*
>(pEndOfLine) = cEndOfLineChar;
1822 a_pText += (pEndOfLine - a_pText) + 1;
1829 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1831 const SI_CHAR* a_pSection,
const SI_CHAR* a_pKey,
bool a_bRemoveEmpty)
1839 if (iSection == m_data.end())
1848 if (iKeyVal == iSection->second.end())
1857 iDelete = iKeyVal++;
1859 DeleteString(iDelete->first.pItem);
1860 DeleteString(iDelete->second);
1861 iSection->second.erase(iDelete);
1862 }
while (iKeyVal != iSection->second.end() &&
1863 !IsLess(a_pKey, iKeyVal->first.pItem));
1868 if (!a_bRemoveEmpty || !iSection->second.empty())
1878 for (; iKeyVal != iSection->second.end(); ++iKeyVal)
1880 DeleteString(iKeyVal->first.pItem);
1881 DeleteString(iKeyVal->second);
1886 DeleteString(iSection->first.pItem);
1887 m_data.erase(iSection);
1892 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1894 const SI_CHAR* a_pString)
1899 if (a_pString < m_pData || a_pString >= m_pData + m_uDataLen)
1902 for (; i != m_strings.end(); ++i)
1904 if (a_pString == i->pItem)
1906 delete[]
const_cast<SI_CHAR*
>(i->pItem);
1923 template <
class SI_CHAR>
1926 bool operator()(
const SI_CHAR* pLeft,
const SI_CHAR* pRight)
const 1929 for (; *pLeft && *pRight; ++pLeft, ++pRight)
1931 cmp = (long)*pLeft - (
long)*pRight;
1937 return *pRight != 0;
1947 template <
class SI_CHAR>
1952 return (ch < 'A' || ch >
'Z') ? ch : (ch -
'A' +
'a');
1954 bool operator()(
const SI_CHAR* pLeft,
const SI_CHAR* pRight)
const 1957 for (; *pLeft && *pRight; ++pLeft, ++pRight)
1965 return *pRight != 0;
1972 template <
class SI_CHAR>
1996 const char* a_pInputData,
size_t a_uInputDataLen)
1999 SI_ASSERT(a_uInputDataLen != (
size_t)-1);
2002 return a_uInputDataLen;
2020 const char* a_pInputData,
size_t a_uInputDataLen,
2021 SI_CHAR* a_pOutputData,
size_t a_uOutputDataSize)
2024 if (a_uInputDataLen > a_uOutputDataSize)
2028 memcpy(a_pOutputData, a_pInputData, a_uInputDataLen);
2046 return strlen((
const char*)a_pInputData) + 1;
2063 const SI_CHAR* a_pInputData,
char* a_pOutputData,
2064 size_t a_uOutputDataSize)
2067 size_t uInputLen = strlen((
const char*)a_pInputData) + 1;
2068 if (uInputLen > a_uOutputDataSize)
2074 memcpy(a_pOutputData, a_pInputData, uInputLen);
2097 const char* a_pInputData,
size_t a_uInputDataLen)
override 2099 SI_ASSERT(a_uInputDataLen != (
size_t)-1);
2100 return do_parse(a_pInputData, a_uInputDataLen,
nullptr);
2104 const char* a_pInputData,
size_t a_uInputDataLen,
char* a_pOutputData,
2105 size_t a_uOutputDataSize)
override 2107 this->
do_parse(a_pInputData, a_uInputDataLen, a_pOutputData);
2123 while (expr.size() > 6)
2125 auto p = expr.find(
"$eval{");
2126 if (
p == std::string::npos)
break;
2127 auto pend = expr.find(
"}",
p);
2128 if (pend == std::string::npos)
2129 throw std::runtime_error(
2131 "Line %u: Expected closing `}` near: `%s`",
2134 const auto substr = expr.substr(
p + 6, pend -
p - 6);
2135 mrpt::math::CRuntimeCompiledExpression cexpr;
2142 new_expr += expr.substr(pend + 1);
2144 new_expr.swap(expr);
2153 if (!var_name.empty())
2156 if (!var_value.empty())
2166 size_t do_parse(
const char* in_str,
const size_t in_len,
char* out_str)
2169 size_t out_len = 0, i = 0;
2172 const char c = in_str[i];
2178 if (
c ==
'\\' && i < in_len - 1 &&
2179 (in_str[i + 1] ==
'\r' || in_str[i + 1] ==
'\n'))
2183 if (i < in_len - 2 && in_str[i + 1] ==
'\r' &&
2184 in_str[i + 2] ==
'\n')
2189 else if (in_str[i + 1] ==
'\r' || in_str[i + 1] ==
'\n')
2196 throw std::runtime_error(
2197 "MRPT_IniFileParser: parse error, shouldn't reach " 2204 if (in_len > i + 7 && !::strncmp(in_str + i,
"@define", 7))
2209 bool in_var_name =
false, done_var_name =
false;
2210 while (i < in_len && in_str[i] !=
'\r' && in_str[i] !=
'\n')
2212 const char c = in_str[i];
2214 if (
c !=
' ' &&
c !=
'\t')
2217 if (!in_var_name && !done_var_name)
2227 in_var_name =
false;
2228 done_var_name =
true;
2246 if (in_len > i + 4 && in_str[i] ==
'$' && in_str[i + 1] ==
'{')
2251 bool end_ok =
false;
2252 while (i < in_len && in_str[i] !=
'\n' && in_str[i] !=
'\r')
2254 const char ch = in_str[i];
2265 throw std::runtime_error(
2267 "Line %u: Expected closing `}` near: `%s`",
2273 throw std::runtime_error(
2275 "Line %u: Unknown variable `${%s}`",
2280 for (
const char ch : str_out)
2282 if (out_str) out_str[out_len] = ch;
2289 if (in_len > i + 7 && !strncmp(in_str + i,
"$eval{", 6))
2293 bool end_ok =
false;
2294 while (i < in_len && in_str[i] !=
'\n' && in_str[i] !=
'\r')
2296 const char ch = in_str[i];
2307 throw std::runtime_error(
2309 "Line %u: Expected closing `}` near: `%s`",
2315 for (
const char ch :
res)
2317 if (out_str) out_str[out_len] = ch;
2326 out_str[out_len] =
c;
2340 typedef CSimpleIniTempl<char, SI_GenericNoCase<char>, SI_ConvertA<char>>
2349 #define CSimpleIni CSimpleIniW 2350 #define CSimpleIniCase CSimpleIniCaseW 2351 #define SI_NEWLINE SI_NEWLINE_W 2353 #define CSimpleIni CSimpleIniA 2354 #define CSimpleIniCase CSimpleIniCaseA 2355 #define SI_NEWLINE SI_NEWLINE_A 2362 #endif // INCLUDED_SimpleIni_h Converter(const Converter &rhs)
Converter & operator=(const Converter &rhs)
OutputWriter & operator=(const OutputWriter &)
SI_CHAR locase(SI_CHAR ch) const
FileWriter & operator=(const FileWriter &)
std::map< std::string, std::string > defined_vars
int m_nOrder
Next order value, used to ensure sections and keys are output in the same order that they are loaded/...
Null conversion class for MBCS/UTF-8 to char (or equivalent).
std::string format(const char *fmt,...) MRPT_printf_format_check(1
A std::string version of C sprintf.
StringWriter(std::string &a_string)
int GetSectionSize(const SI_CHAR *a_pSection) const
Query the number of keys in a specific section.
bool IsSpace(SI_CHAR ch) const
Is the supplied character a whitespace character?
bool operator()(const Entry &lhs, const Entry &rhs) const
int void fclose(FILE *f)
An OS-independent version of fclose.
OutputWriter class to write the INI data to an ostream.
Entry & operator=(const Entry &rhs)
bool m_bAllowMultiKey
Are multiple values permitted for the same key?
bool IsMultiKey() const
Get the storage format of the INI data.
bool operator()(const Entry &lhs, const Entry &rhs) const
bool IsMultiLineTag(const SI_CHAR *a_pData) const
std::map< std::string, double > defined_vars_values
void SetMultiLine(bool a_bAllowMultiLine=true)
Should data values be permitted to span multiple lines in the file.
Entry(const SI_CHAR *a_pszItem=nullptr, int a_nOrder=0)
interface definition for the OutputWriter object to pass to Save() in order to output the INI file da...
void SkipNewLine(SI_CHAR *&a_pData) const
Skip over a newline character (or characters) for either DOS or UNIX.
void DeleteString(const SI_CHAR *a_pString)
Delete a string from the copied strings buffer if necessary.
const Scalar * const_iterator
SI_Error LoadFile(const char *a_pszFile)
Load an INI file from disk into memory.
SI_Error SetValue(const SI_CHAR *a_pSection, const SI_CHAR *a_pKey, const SI_CHAR *a_pValue, const SI_CHAR *a_pComment=nullptr)
Add or update a section or value.
bool m_bAllowMultiLine
Are data values permitted to span multiple lines?
size_t SizeToStore(const SI_CHAR *a_pInputData)
Calculate the number of char required by the storage format of this data.
~CSimpleIniTempl()
Destructor.
void SetMultiKey(bool a_bAllowMultiKey=true)
Should multiple identical keys be permitted in the file.
MRPT custom INI file parser to allow minimal file preprocessing:
size_t do_parse(const char *in_str, const size_t in_len, char *out_str)
Shared code for the two virtual methods.
bool ConvertToStore(const SI_CHAR *a_pszString)
bool GetAllKeys(const SI_CHAR *a_pSection, TNamesDepend &a_names) const
Retrieve all unique key names in a section.
CSimpleIniTempl< char, SI_GenericNoCase< char >, MRPT_IniFileParser > MRPT_CSimpleIni
SI_Error AddEntry(const SI_CHAR *a_pSection, const SI_CHAR *a_pKey, const SI_CHAR *a_pValue, const SI_CHAR *a_pComment, bool a_bCopyStrings)
Add the section/key/value to our data.
TNamesDepend m_strings
This vector stores allocated memory for copies of strings that have been supplied after the file load...
Converter GetConverter() const
Return a conversion object to convert text to the same encoding as is used by the Save()...
virtual bool ConvertFromStore(const char *a_pInputData, size_t a_uInputDataLen, SI_CHAR *a_pOutputData, size_t a_uOutputDataSize)
Convert the input string from the storage format to SI_CHAR.
CSimpleIniTempl< char, SI_GenericNoCase< char >, SI_ConvertA< char > > CSimpleIniA
std::map< Entry, TKeyVal, typename Entry::KeyOrder > TSection
map sections to key/value map
virtual bool ConvertFromStore(const char *a_pInputData, size_t a_uInputDataLen, char *a_pOutputData, size_t a_uOutputDataSize) override
Convert the input string from the storage format to SI_CHAR.
Strict less ordering by name of key only.
void GetAllSections(TNamesDepend &a_names) const
Retrieve all section names.
SI_Error Load(std::istream &a_istream)
Load INI file data from an istream.
bool operator()(const SI_CHAR *pLeft, const SI_CHAR *pRight) const
File error (see errno for detail error)
GLsizei const GLchar ** string
An existing value was updated.
SI_ConvertA & operator=(const SI_ConvertA &rhs)
virtual size_t SizeFromStore(const char *a_pInputData, size_t a_uInputDataLen) override
Calculate the number of SI_CHAR required for converting the input from the storage format...
Characterset conversion utility class to convert strings to the same format as is used for the storag...
void Write(const char *a_pBuf)
CSimpleIniTempl(bool a_bMultiKey=false, bool a_bMultiLine=false)
Default constructor.
SI_ConvertA(const SI_ConvertA &rhs)
bool IsMultiLineData(const SI_CHAR *a_pData) const
SI_CHAR * m_pData
Copy of the INI file data in our character format.
bool operator()(const SI_CHAR *pLeft, const SI_CHAR *pRight) const
TSection m_data
Parsed INI data.
SI_Error SaveFile(const char *a_pszFile) const
Save an INI file from memory to disk.
bool Delete(const SI_CHAR *a_pSection, const SI_CHAR *a_pKey, bool a_bRemoveEmpty=false)
Delete an entire section, or a key from a section.
Generic ASCII case-insensitive less than comparison.
bool IsNewLineChar(SI_CHAR a_c) const
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
bool ConvertToStore(const SI_CHAR *a_pInputData, char *a_pOutputData, size_t a_uOutputDataSize)
Convert the input string to the storage format of this data.
MRPT_IniFileParser(const MRPT_IniFileParser &rhs)
bool FindEntry(SI_CHAR *&a_pData, const SI_CHAR *&a_pSection, const SI_CHAR *&a_pKey, const SI_CHAR *&a_pVal, const SI_CHAR *&a_pComment) const
Parse the data looking for the next valid entry.
size_t m_uDataLen
Length of the data that we have stored.
SI_Error FindFileComment(SI_CHAR *&a_pData, bool a_bCopyStrings)
Parse the data looking for a file comment and store it if found.
void Write(const char *a_pBuf) override
virtual void Write(const char *a_pBuf)=0
bool OutputMultiLineText(OutputWriter &a_oOutput, Converter &a_oConverter, const SI_CHAR *a_pText) const
A new value was inserted.
const TKeyVal * GetSection(const SI_CHAR *a_pSection) const
Retrieve all key and value pairs for a section.
OutputWriter class to write the INI data to a file.
void Write(const char *a_pBuf) override
Generic case-sensitive less than comparison.
CSimpleIniTempl< char, SI_GenericCase< char >, SI_ConvertA< char > > CSimpleIniCaseA
const SI_CHAR * GetValue(const SI_CHAR *a_pSection, const SI_CHAR *a_pKey, const SI_CHAR *a_pDefault=nullptr, bool *a_pHasMultiple=nullptr) const
Retrieve the value for a specific key.
std::list< Entry > TNamesDepend
set of dependent string pointers.
bool GetAllValues(const SI_CHAR *a_pSection, const SI_CHAR *a_pKey, TNamesDepend &a_values) const
Retrieve all values for a specific key.
void parse_process_var_define(ParseContext &pc, const std::string &var_name, const std::string &var_value)
const SI_CHAR * m_pFileComment
File comment for this data, if one exists.
StreamWriter & operator=(const StreamWriter &)
virtual size_t SizeFromStore(const char *a_pInputData, size_t a_uInputDataLen)
Calculate the number of SI_CHAR required for converting the input from the storage format...
Strict less ordering by order, and then name of key.
std::string trim(const std::string &str)
Removes leading and trailing spaces.
void Reset()
Deallocate all memory stored by this object.
MRPT_IniFileParser & operator=(const MRPT_IniFileParser &rhs)
FILE * fopen(const char *fileName, const char *mode) noexcept
An OS-independent version of fopen.
typedef void(APIENTRYP PFNGLBLENDCOLORPROC)(GLclampf red
SI_Error Save(OutputWriter &a_oOutput) const
Save the INI data.
SI_Error CopyString(const SI_CHAR *&a_pString)
Make a copy of the supplied string, replacing the original pointer.
bool operator<(const TMatchingPair &a, const TMatchingPair &b)
A comparison operator, for sorting lists of TMatchingPair's, first order by this_idx, if equals, by other_idx.
bool IsMultiLine() const
Query the status of multi-line data.
StreamWriter(std::ostream &a_ostream)
std::multimap< Entry, const SI_CHAR *, typename Entry::KeyOrder > TKeyVal
map keys to values
std::string parse_process_var_eval(const ParseContext &pc, std::string expr)
bool LoadMultiLineText(SI_CHAR *&a_pData, const SI_CHAR *&a_pVal, const SI_CHAR *a_pTagName, bool a_bAllowBlankLinesInComment=false) const
bool IsComment(SI_CHAR ch) const
Does the supplied character start a comment line?
OutputWriter class to write the INI data to a string.
void memcpy(void *dest, size_t destSize, const void *src, size_t copyCount) noexcept
An OS and compiler independent version of "memcpy".
bool IsLess(const SI_CHAR *a_pLeft, const SI_CHAR *a_pRight) const
Internal use of our string comparison function.
StringWriter & operator=(const StringWriter &)