10 #ifndef INCLUDED_SimpleIni_h 11 #define INCLUDED_SimpleIni_h 23 #pragma warning(disable : 4127 4503 4702 4786) 37 #define SI_SUPPORT_IOSTREAMS 39 #ifdef SI_SUPPORT_IOSTREAMS 41 #endif // SI_SUPPORT_IOSTREAMS 45 #define SI_ASSERT(x) assert(x) 71 #define SI_NEWLINE_A "\r\n" 72 #define SI_NEWLINE_W L"\r\n" 74 #define SI_NEWLINE_A "\n" 75 #define SI_NEWLINE_W L"\n" 79 #define SI_HAS_WIDE_FILE 80 #define SI_WCHAR_T wchar_t 81 #elif defined(SI_CONVERT_ICU) 82 #define SI_HAS_WIDE_FILE 83 #define SI_WCHAR_T UChar 109 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
120 Entry(
const SI_CHAR* a_pszItem =
nullptr,
int a_nOrder = 0)
133 #if (defined(_MSC_VER) && _MSC_VER <= 1200) 138 return LoadOrder()(*
this, rhs);
140 bool operator>(
const Entry& rhs)
const 142 return LoadOrder()(rhs, *
this);
147 struct KeyOrder : std::function<bool(Entry, Entry)>
151 const static SI_STRLESS isLess = SI_STRLESS();
172 std::multimap<Entry, const SI_CHAR*, typename Entry::KeyOrder>;
175 using TSection = std::map<Entry, TKeyVal, typename Entry::KeyOrder>;
190 virtual void Write(
const char* a_pBuf) = 0;
204 void Write(
const char* a_pBuf)
override { fputs(a_pBuf,
m_file); }
225 #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()),
364 #ifdef SI_HAS_WIDE_FILE 372 #endif // SI_HAS_WIDE_FILE 383 #ifdef SI_SUPPORT_IOSTREAMS 391 #endif // SI_SUPPORT_IOSTREAMS 401 return Load(a_strData.c_str(), a_strData.size());
427 #ifdef SI_HAS_WIDE_FILE 474 #ifdef SI_SUPPORT_IOSTREAMS 486 #endif // SI_SUPPORT_IOSTREAMS 550 const SI_CHAR* a_pSection,
const SI_CHAR* a_pKey,
598 const SI_CHAR* a_pSection,
const SI_CHAR* a_pKey,
599 const SI_CHAR* a_pDefault =
nullptr,
600 bool* a_pHasMultiple =
nullptr)
const;
626 const SI_CHAR* a_pSection,
const SI_CHAR* a_pKey,
627 const SI_CHAR* a_pValue,
const SI_CHAR* a_pComment =
nullptr)
629 return AddEntry(a_pSection, a_pKey, a_pValue, a_pComment,
true);
651 const SI_CHAR* a_pSection,
const SI_CHAR* a_pKey,
652 bool a_bRemoveEmpty =
false);
677 SI_CHAR*& a_pData,
const SI_CHAR*& a_pSection,
const SI_CHAR*& a_pKey,
678 const SI_CHAR*& a_pVal,
const SI_CHAR*& a_pComment)
const;
697 const SI_CHAR* a_pSection,
const SI_CHAR* a_pKey,
698 const SI_CHAR* a_pValue,
const SI_CHAR* a_pComment,
699 bool a_bCopyStrings);
702 inline bool IsSpace(SI_CHAR ch)
const 704 return (ch ==
' ' || ch ==
'\t' || ch ==
'\r' || ch ==
'\n');
708 inline bool IsComment(SI_CHAR ch)
const {
return (ch ==
';' || ch ==
'#'); }
712 a_pData += (*a_pData ==
'\r' && *(a_pData + 1) ==
'\n') ? 2 : 1;
722 bool IsLess(
const SI_CHAR* a_pLeft,
const SI_CHAR* a_pRight)
const 724 const static SI_STRLESS isLess = SI_STRLESS();
725 return isLess(a_pLeft, a_pRight);
731 SI_CHAR*& a_pData,
const SI_CHAR*& a_pVal,
const SI_CHAR* a_pTagName,
732 bool a_bAllowBlankLinesInComment =
false)
const;
736 OutputWriter& a_oOutput, Converter& a_oConverter,
737 const SI_CHAR* a_pText)
const;
781 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
783 bool a_bAllowMultiKey,
bool a_bAllowMultiLine)
786 m_pFileComment(NULL),
787 m_bAllowMultiKey(a_bAllowMultiKey),
788 m_bAllowMultiLine(a_bAllowMultiLine),
793 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
799 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
806 m_pFileComment =
nullptr;
809 m_data.erase(m_data.begin(), m_data.end());
813 if (!m_strings.empty())
816 for (; i != m_strings.end(); ++i)
818 delete[]
const_cast<SI_CHAR*
>(i->pItem);
820 m_strings.erase(m_strings.begin(), m_strings.end());
824 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
826 const char* a_pszFile)
829 #if __STDC_WANT_SECURE_LIB__ 830 fopen_s(&fp, a_pszFile,
"rb");
832 fp =
fopen(a_pszFile,
"rb");
843 #ifdef SI_HAS_WIDE_FILE 844 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
850 #if __STDC_WANT_SECURE_LIB__ 851 _wfopen_s(&fp, a_pwszFile, L
"rb");
853 fp = _wfopen(a_pwszFile, L
"rb");
859 #else // SI_CONVERT_ICU 861 u_austrncpy(szFile, a_pwszFile,
sizeof(szFile));
862 return LoadFile(szFile);
865 #endif // SI_HAS_WIDE_FILE 867 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
872 int retval = fseek(a_fpFile, 0,
SEEK_END);
877 long lSize = ftell(a_fpFile);
882 char* pData =
new char[lSize];
888 size_t uRead = fread(pData,
sizeof(
char), lSize, a_fpFile);
889 if (uRead != (
size_t)lSize)
901 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
903 const char* a_pData,
size_t a_uDataLen)
905 SI_CONVERTER converter;
908 size_t uLen = converter.SizeFromStore(a_pData, a_uDataLen);
909 if (uLen == (
size_t)(-1))
916 SI_CHAR* pData =
new SI_CHAR[uLen + 1];
921 memset(pData, 0,
sizeof(SI_CHAR) * (uLen + 1));
924 if (!converter.ConvertFromStore(a_pData, a_uDataLen, pData, uLen))
931 const static SI_CHAR
empty = 0;
932 SI_CHAR* pWork = pData;
933 const SI_CHAR* pSection = &
empty;
934 const SI_CHAR* pItem =
nullptr;
935 const SI_CHAR* pVal =
nullptr;
936 const SI_CHAR* pComment =
nullptr;
940 bool bCopyStrings = (m_pData !=
nullptr);
944 SI_Error rc = FindFileComment(pWork, bCopyStrings);
945 if (rc < 0)
return rc;
948 while (FindEntry(pWork, pSection, pItem, pVal, pComment))
950 rc = AddEntry(pSection, pItem, pVal, pComment, bCopyStrings);
951 if (rc < 0)
return rc;
962 m_uDataLen = uLen + 1;
968 #ifdef SI_SUPPORT_IOSTREAMS 969 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
971 std::istream& a_istream)
977 a_istream.get(szBuf,
sizeof(szBuf),
'\0');
978 strData.append(szBuf);
979 }
while (a_istream.good());
980 return Load(strData);
982 #endif // SI_SUPPORT_IOSTREAMS 984 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
986 SI_CHAR*& a_pData,
bool a_bCopyStrings)
996 if (!LoadMultiLineText(a_pData, m_pFileComment,
nullptr,
false))
1004 SI_Error rc = CopyString(m_pFileComment);
1005 if (rc < 0)
return rc;
1011 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1013 SI_CHAR*& a_pData,
const SI_CHAR*& a_pSection,
const SI_CHAR*& a_pKey,
1014 const SI_CHAR*& a_pVal,
const SI_CHAR*& a_pComment)
const 1016 a_pComment =
nullptr;
1018 SI_CHAR* pTrail =
nullptr;
1022 while (*a_pData && IsSpace(*a_pData))
1033 if (IsComment(*a_pData))
1035 LoadMultiLineText(a_pData, a_pComment,
nullptr,
true);
1040 if (*a_pData ==
'[')
1044 while (*a_pData && IsSpace(*a_pData))
1051 a_pSection = a_pData;
1052 while (*a_pData && *a_pData !=
']' && !IsNewLineChar(*a_pData))
1058 if (*a_pData !=
']')
1064 pTrail = a_pData - 1;
1065 while (pTrail >= a_pSection && IsSpace(*pTrail))
1074 while (*a_pData && !IsNewLineChar(*a_pData))
1087 while (*a_pData && *a_pData !=
'=' && !IsNewLineChar(*a_pData))
1093 if (*a_pData !=
'=')
1099 if (a_pKey == a_pData)
1101 while (*a_pData && !IsNewLineChar(*a_pData))
1109 pTrail = a_pData - 1;
1110 while (pTrail >= a_pKey && IsSpace(*pTrail))
1119 while (*a_pData && !IsNewLineChar(*a_pData) && IsSpace(*a_pData))
1126 while (*a_pData && !IsNewLineChar(*a_pData))
1132 pTrail = a_pData - 1;
1135 SkipNewLine(a_pData);
1137 while (pTrail >= a_pVal && IsSpace(*pTrail))
1145 if (m_bAllowMultiLine && IsMultiLineTag(a_pVal))
1148 const SI_CHAR* pTagName = a_pVal + 3;
1149 return LoadMultiLineText(a_pData, a_pVal, pTagName);
1159 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1161 const SI_CHAR* a_pVal)
const 1164 if (*a_pVal++ !=
'<')
return false;
1165 if (*a_pVal++ !=
'<')
return false;
1166 if (*a_pVal++ !=
'<')
return false;
1170 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1172 const SI_CHAR* a_pData)
const 1186 if (IsSpace(*a_pData))
1194 if (IsNewLineChar(*a_pData))
1202 if (IsSpace(*--a_pData))
1210 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1214 return (a_c ==
'\n' || a_c ==
'\r');
1217 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1219 SI_CHAR*& a_pData,
const SI_CHAR*& a_pVal,
const SI_CHAR* a_pTagName,
1220 bool a_bAllowBlankLinesInComment)
const 1230 SI_CHAR* pDataLine = a_pData;
1239 SI_CHAR cEndOfLineChar = *a_pData;
1244 if (!a_pTagName && !IsComment(*a_pData))
1247 if (!a_bAllowBlankLinesInComment)
1255 SI_CHAR* pCurr = a_pData;
1257 while (IsSpace(*pCurr))
1259 if (IsNewLineChar(*pCurr))
1272 if (IsComment(*pCurr))
1274 for (; nNewLines > 0; --nNewLines) *pDataLine++ =
'\n';
1284 pCurrLine = a_pData;
1285 while (*a_pData && !IsNewLineChar(*a_pData)) ++a_pData;
1288 if (pDataLine < pCurrLine)
1290 memmove(pDataLine, pCurrLine, a_pData - pCurrLine);
1291 pDataLine[a_pData - pCurrLine] =
'\0';
1295 cEndOfLineChar = *a_pData;
1302 (!IsLess(pDataLine, a_pTagName) && !IsLess(a_pTagName, pDataLine)))
1309 if (!cEndOfLineChar)
1316 pDataLine += (a_pData - pCurrLine);
1317 *a_pData = cEndOfLineChar;
1318 SkipNewLine(a_pData);
1319 *pDataLine++ =
'\n';
1323 if (a_pVal == a_pData)
1333 *--pDataLine =
'\0';
1337 if (a_pTagName && cEndOfLineChar)
1339 SI_ASSERT(IsNewLineChar(cEndOfLineChar));
1340 *a_pData = cEndOfLineChar;
1341 SkipNewLine(a_pData);
1347 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1349 const SI_CHAR*& a_pString)
1352 if (
sizeof(SI_CHAR) ==
sizeof(
char))
1354 uLen = strlen((
const char*)a_pString);
1356 else if (
sizeof(SI_CHAR) ==
sizeof(
wchar_t))
1358 uLen = wcslen((
const wchar_t*)a_pString);
1362 for (; a_pString[uLen]; ++uLen)
1366 SI_CHAR* pCopy =
new SI_CHAR[uLen];
1371 memcpy(pCopy, a_pString,
sizeof(SI_CHAR) * uLen);
1372 m_strings.push_back(pCopy);
1377 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1379 const SI_CHAR* a_pSection,
const SI_CHAR* a_pKey,
const SI_CHAR* a_pValue,
1380 const SI_CHAR* a_pComment,
bool a_bCopyStrings)
1383 bool bInserted =
false;
1385 SI_ASSERT(!a_pComment || IsComment(*a_pComment));
1389 if (a_bCopyStrings && a_pComment)
1391 rc = CopyString(a_pComment);
1392 if (rc < 0)
return rc;
1399 iSection = m_data.find(a_pSection);
1400 if (iSection == m_data.end())
1405 rc = CopyString(a_pSection);
1406 if (rc < 0)
return rc;
1411 if (iSection == m_data.end())
1413 Entry oKey(a_pSection, ++m_nOrder);
1414 if (a_pComment && (!a_pKey || !a_pValue))
1418 typename TSection::value_type oEntry(oKey,
TKeyVal());
1420 std::pair<SectionIterator, bool> i = m_data.insert(oEntry);
1424 if (!a_pKey || !a_pValue)
1431 TKeyVal& keyval = iSection->second;
1437 if (m_bAllowMultiKey || iKey == keyval.end())
1442 rc = CopyString(a_pKey);
1443 if (rc < 0)
return rc;
1447 rc = CopyString(a_pValue);
1448 if (rc < 0)
return rc;
1452 if (iKey == keyval.end() || m_bAllowMultiKey)
1454 Entry oKey(a_pKey, ++m_nOrder);
1459 typename TKeyVal::value_type oEntry(
1460 oKey, static_cast<const char*>(
nullptr));
1461 iKey = keyval.insert(oEntry);
1464 iKey->second = a_pValue;
1468 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1470 const SI_CHAR* a_pSection,
const SI_CHAR* a_pKey,
const SI_CHAR* a_pDefault,
1471 bool* a_pHasMultiple)
const 1475 *a_pHasMultiple =
false;
1477 if (!a_pSection || !a_pKey)
1482 if (iSection == m_data.end())
1487 if (iKeyVal == iSection->second.end())
1493 if (m_bAllowMultiKey && a_pHasMultiple)
1496 if (++iTemp != iSection->second.end())
1498 if (!IsLess(a_pKey, iTemp->first.pItem))
1500 *a_pHasMultiple =
true;
1505 return iKeyVal->second;
1508 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1510 const SI_CHAR* a_pSection,
const SI_CHAR* a_pKey,
1513 if (!a_pSection || !a_pKey)
1518 if (iSection == m_data.end())
1523 if (iKeyVal == iSection->second.end())
1529 a_values.push_back(iKeyVal->second);
1530 if (m_bAllowMultiKey)
1533 while (iKeyVal != iSection->second.end() &&
1534 !IsLess(a_pKey, iKeyVal->first.pItem))
1536 a_values.push_back(
Entry(iKeyVal->second, iKeyVal->first.nOrder));
1544 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1546 const SI_CHAR* a_pSection)
const 1554 if (iSection == m_data.end())
1558 const TKeyVal& section = iSection->second;
1562 if (!m_bAllowMultiKey || section.empty())
1564 return (
int)section.size();
1569 const SI_CHAR* pLastKey =
nullptr;
1571 for (
int n = 0; iKeyVal != section.end(); ++iKeyVal, ++
n)
1573 if (!pLastKey || IsLess(pLastKey, iKeyVal->first.pItem))
1576 pLastKey = iKeyVal->first.pItem;
1582 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1585 const SI_CHAR* a_pSection)
const 1590 if (i != m_data.end())
1592 return &(i->second);
1598 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1603 for (
int n = 0; i != m_data.end(); ++i, ++
n)
1605 a_names.push_back(i->first);
1609 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1611 const SI_CHAR* a_pSection,
TNamesDepend& a_names)
const 1619 if (iSection == m_data.end())
1624 const TKeyVal& section = iSection->second;
1625 const SI_CHAR* pLastKey =
nullptr;
1627 for (
int n = 0; iKeyVal != section.end(); ++iKeyVal, ++
n)
1629 if (!pLastKey || IsLess(pLastKey, iKeyVal->first.pItem))
1631 a_names.push_back(iKeyVal->first);
1632 pLastKey = iKeyVal->first.pItem;
1639 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1641 const char* a_pszFile)
const 1644 #if __STDC_WANT_SECURE_LIB__ 1645 fopen_s(&fp, a_pszFile,
"wb");
1647 fp =
fopen(a_pszFile,
"wb");
1655 #ifdef SI_HAS_WIDE_FILE 1656 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1661 FILE* fp = _wfopen(a_pwszFile, L
"wb");
1666 #else // SI_CONVERT_ICU 1668 u_austrncpy(szFile, a_pwszFile,
sizeof(szFile));
1669 return SaveFile(szFile);
1672 #endif // SI_HAS_WIDE_FILE 1674 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1676 FILE* a_pFile)
const 1679 return Save(writer);
1682 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1690 GetAllSections(oSections);
1691 #if (defined(_MSC_VER) && _MSC_VER <= 1200) 1698 bool bNeedNewLine =
false;
1701 if (!OutputMultiLineText(a_oOutput, convert, m_pFileComment))
1705 bNeedNewLine =
true;
1710 for (; iSection != oSections.end(); ++iSection)
1713 if (iSection->pComment)
1726 bNeedNewLine =
false;
1733 bNeedNewLine =
false;
1737 if (*iSection->pItem)
1743 a_oOutput.
Write(
"[");
1745 a_oOutput.
Write(
"]");
1751 GetAllKeys(iSection->pItem, oKeys);
1752 #if (defined(_MSC_VER) && _MSC_VER <= 1200) 1760 for (; iKey != oKeys.end(); ++iKey)
1764 GetAllValues(iSection->pItem, iKey->pItem, oValues);
1770 if (!OutputMultiLineText(a_oOutput, convert, iKey->pComment))
1777 for (; iValue != oValues.end(); ++iValue)
1791 a_oOutput.
Write(
"=");
1792 if (m_bAllowMultiLine && IsMultiLineData(iValue->pItem))
1798 if (!OutputMultiLineText(a_oOutput, convert, iValue->pItem))
1802 a_oOutput.
Write(
"SI-END-OF-MULTILINE-TEXT");
1812 bNeedNewLine =
true;
1818 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1821 const SI_CHAR* a_pText)
const 1823 const SI_CHAR* pEndOfLine;
1824 SI_CHAR cEndOfLineChar = *a_pText;
1825 while (cEndOfLineChar)
1828 pEndOfLine = a_pText;
1829 for (; *pEndOfLine && *pEndOfLine !=
'\n'; ++pEndOfLine)
1831 cEndOfLineChar = *pEndOfLine;
1834 *
const_cast<SI_CHAR*
>(pEndOfLine) = 0;
1839 *
const_cast<SI_CHAR*
>(pEndOfLine) = cEndOfLineChar;
1840 a_pText += (pEndOfLine - a_pText) + 1;
1847 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1849 const SI_CHAR* a_pSection,
const SI_CHAR* a_pKey,
bool a_bRemoveEmpty)
1857 if (iSection == m_data.end())
1866 if (iKeyVal == iSection->second.end())
1875 iDelete = iKeyVal++;
1877 DeleteString(iDelete->first.pItem);
1878 DeleteString(iDelete->second);
1879 iSection->second.erase(iDelete);
1880 }
while (iKeyVal != iSection->second.end() &&
1881 !IsLess(a_pKey, iKeyVal->first.pItem));
1886 if (!a_bRemoveEmpty || !iSection->second.empty())
1896 for (; iKeyVal != iSection->second.end(); ++iKeyVal)
1898 DeleteString(iKeyVal->first.pItem);
1899 DeleteString(iKeyVal->second);
1904 DeleteString(iSection->first.pItem);
1905 m_data.erase(iSection);
1910 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1912 const SI_CHAR* a_pString)
1917 if (a_pString < m_pData || a_pString >= m_pData + m_uDataLen)
1920 for (; i != m_strings.end(); ++i)
1922 if (a_pString == i->pItem)
1924 delete[]
const_cast<SI_CHAR*
>(i->pItem);
1941 template <
class SI_CHAR>
1944 bool operator()(
const SI_CHAR* pLeft,
const SI_CHAR* pRight)
const 1947 for (; *pLeft && *pRight; ++pLeft, ++pRight)
1949 cmp = (long)*pLeft - (
long)*pRight;
1955 return *pRight != 0;
1965 template <
class SI_CHAR>
1970 return (ch < 'A' || ch >
'Z') ? ch : (ch -
'A' +
'a');
1972 bool operator()(
const SI_CHAR* pLeft,
const SI_CHAR* pRight)
const 1975 for (; *pLeft && *pRight; ++pLeft, ++pRight)
1983 return *pRight != 0;
1990 template <
class SI_CHAR>
2014 const char* a_pInputData,
size_t a_uInputDataLen)
2017 SI_ASSERT(a_uInputDataLen != (
size_t)-1);
2020 return a_uInputDataLen;
2038 const char* a_pInputData,
size_t a_uInputDataLen,
2039 SI_CHAR* a_pOutputData,
size_t a_uOutputDataSize)
2042 if (a_uInputDataLen > a_uOutputDataSize)
2046 memcpy(a_pOutputData, a_pInputData, a_uInputDataLen);
2064 return strlen((
const char*)a_pInputData) + 1;
2081 const SI_CHAR* a_pInputData,
char* a_pOutputData,
2082 size_t a_uOutputDataSize)
2085 size_t uInputLen = strlen((
const char*)a_pInputData) + 1;
2086 if (uInputLen > a_uOutputDataSize)
2092 memcpy(a_pOutputData, a_pInputData, uInputLen);
2115 const char* a_pInputData,
size_t a_uInputDataLen)
override 2117 SI_ASSERT(a_uInputDataLen != (
size_t)-1);
2118 return do_parse(a_pInputData, a_uInputDataLen,
nullptr);
2122 const char* a_pInputData,
size_t a_uInputDataLen,
char* a_pOutputData,
2123 size_t a_uOutputDataSize)
override 2125 this->
do_parse(a_pInputData, a_uInputDataLen, a_pOutputData);
2141 while (expr.size() > 5)
2143 auto p = expr.find(
"$env{");
2144 if (
p != std::string::npos)
2146 auto pend = expr.find(
"}",
p);
2147 if (pend == std::string::npos)
2149 "Line %u: Expected closing `}` near: `%s`",
2151 const auto substr = expr.substr(
p + 5, pend -
p - 5);
2153 auto env_val = ::getenv(substr.c_str());
2155 new_expr += expr.substr(pend + 1);
2156 new_expr.swap(expr);
2158 else if ((
p = expr.find(
"$eval{")) != std::string::npos)
2160 auto pend = expr.find(
"}",
p);
2161 if (pend == std::string::npos)
2163 "Line %u: Expected closing `}` near: `%s`",
2166 const auto substr = expr.substr(
p + 6, pend -
p - 6);
2174 new_expr += expr.substr(pend + 1);
2175 new_expr.swap(expr);
2187 if (!var_name.empty())
2190 if (!var_value.empty())
2200 size_t do_parse(
const char* in_str,
const size_t in_len,
char* out_str)
2203 size_t out_len = 0, i = 0;
2206 const char c = in_str[i];
2212 if (
c ==
'\\' && i < in_len - 1 &&
2213 (in_str[i + 1] ==
'\r' || in_str[i + 1] ==
'\n'))
2217 if (i < in_len - 2 && in_str[i + 1] ==
'\r' &&
2218 in_str[i + 2] ==
'\n')
2223 else if (in_str[i + 1] ==
'\r' || in_str[i + 1] ==
'\n')
2230 throw std::runtime_error(
2231 "MRPT_IniFileParser: parse error, shouldn't reach " 2238 if (in_len > i + 7 && !::strncmp(in_str + i,
"@define", 7))
2243 bool in_var_name =
false, done_var_name =
false;
2244 while (i < in_len && in_str[i] !=
'\r' && in_str[i] !=
'\n')
2246 const char ch = in_str[i];
2248 if (ch !=
' ' && ch !=
'\t')
2251 if (!in_var_name && !done_var_name)
2261 in_var_name =
false;
2262 done_var_name =
true;
2280 if (in_len > i + 4 && in_str[i] ==
'$' && in_str[i + 1] ==
'{')
2285 bool end_ok =
false;
2286 while (i < in_len && in_str[i] !=
'\n' && in_str[i] !=
'\r')
2288 const char ch = in_str[i];
2300 "Line %u: Expected closing `}` near: `%s`",
2307 "Line %u: Unknown variable `${%s}`", pc.
line_count,
2312 for (
const char ch : str_out)
2314 if (out_str) out_str[out_len] = ch;
2321 if (in_len > i + 7 && !strncmp(in_str + i,
"$eval{", 6))
2325 bool end_ok =
false;
2326 while (i < in_len && in_str[i] !=
'\n' && in_str[i] !=
'\r')
2328 const char ch = in_str[i];
2340 "Line %u: Expected closing `}` near: `%s`",
2346 for (
const char ch :
res)
2348 if (out_str) out_str[out_len] = ch;
2355 if (in_len > i + 6 && !strncmp(in_str + i,
"$env{", 5))
2359 bool end_ok =
false;
2360 while (i < in_len && in_str[i] !=
'\n' && in_str[i] !=
'\r')
2362 const char ch = in_str[i];
2374 "Line %u: Expected closing `}` near: `%s`",
2380 for (
const char ch :
res)
2382 if (out_str) out_str[out_len] = ch;
2391 out_str[out_len] =
c;
2414 #define CSimpleIni CSimpleIniW 2415 #define CSimpleIniCase CSimpleIniCaseW 2416 #define SI_NEWLINE SI_NEWLINE_W 2418 #define CSimpleIni CSimpleIniA 2419 #define CSimpleIniCase CSimpleIniCaseA 2420 #define SI_NEWLINE SI_NEWLINE_A 2424 #endif // INCLUDED_SimpleIni_h SI_Error LoadFile(const char *a_pszFile)
Load an INI file from disk into memory.
bool IsComment(SI_CHAR ch) const
Does the supplied character start a comment line?
void GetAllSections(TNamesDepend &a_names) const
Retrieve all section names.
SI_CHAR locase(SI_CHAR ch) const
EIGEN_STRONG_INLINE bool empty() const
StringWriter(std::string &a_string)
Entry(const SI_CHAR *a_pszItem=nullptr, int a_nOrder=0)
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.
bool m_bAllowMultiLine
Are data values permitted to span multiple lines?
SI_Error CopyString(const SI_CHAR *&a_pString)
Make a copy of the supplied string, replacing the original pointer.
Strict less ordering by order, and then name of key.
bool IsMultiLineData(const SI_CHAR *a_pData) const
StreamWriter(std::ostream &a_ostream)
TSection m_data
Parsed INI data.
int void fclose(FILE *f)
An OS-independent version of fclose.
Generic ASCII case-insensitive less than comparison.
OutputWriter class to write the INI data to a string.
void DeleteString(const SI_CHAR *a_pString)
Delete a string from the copied strings buffer if necessary.
A wrapper of exprtk runtime expression compiler: it takes a string representing an expression (from a...
Strict less ordering by name of key only.
bool ConvertToStore(const SI_CHAR *a_pszString)
void Write(const char *a_pBuf) override
bool IsMultiLineTag(const SI_CHAR *a_pData) const
StringWriter & operator=(const StringWriter &)
bool IsMultiKey() const
Get the storage format of the INI data.
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.
A new value was inserted.
FileWriter & operator=(const FileWriter &)
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.
~CSimpleIniTempl()
Destructor.
virtual void Write(const char *a_pBuf)=0
void Reset()
Deallocate all memory stored by this object.
OutputWriter class to write the INI data to a file.
Characterset conversion utility class to convert strings to the same format as is used for the storag...
bool operator()(const Entry &lhs, const Entry &rhs) const
bool GetAllValues(const SI_CHAR *a_pSection, const SI_CHAR *a_pKey, TNamesDepend &a_values) const
Retrieve all values for a specific key.
Generic case-sensitive less than comparison.
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...
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.
void SetMultiLine(bool a_bAllowMultiLine=true)
Should data values be permitted to span multiple lines in the file.
File error (see errno for detail error)
Converter(const Converter &rhs)
SI_Error FindFileComment(SI_CHAR *&a_pData, bool a_bCopyStrings)
Parse the data looking for a file comment and store it if found.
CSimpleIniTempl< char, SI_GenericNoCase< char >, SI_ConvertA< char > > CSimpleIniA
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...
interface definition for the OutputWriter object to pass to Save() in order to output the INI file da...
void SetMultiKey(bool a_bAllowMultiKey=true)
Should multiple identical keys be permitted in the file.
bool GetAllKeys(const SI_CHAR *a_pSection, TNamesDepend &a_names) const
Retrieve all unique key names in a section.
size_t SizeToStore(const SI_CHAR *a_pInputData)
Calculate the number of char required by the storage format of this data.
bool operator()(const Entry &lhs, const Entry &rhs) const
void Write(const char *a_pBuf) override
CSimpleIniTempl(const CSimpleIniTempl< SI_CHAR, SI_STRLESS, SI_CONVERTER > &o)
Copy.
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 IsMultiLine() const
Query the status of multi-line data.
void parse_process_var_define(ParseContext &pc, const std::string &var_name, const std::string &var_value)
Converter GetConverter() const
Return a conversion object to convert text to the same encoding as is used by the Save()...
GLsizei const GLchar ** string
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.
OutputWriter & operator=(const OutputWriter &)
int m_nOrder
Next order value, used to ensure sections and keys are output in the same order that they are loaded/...
bool operator()(const SI_CHAR *pLeft, const SI_CHAR *pRight) const
bool OutputMultiLineText(OutputWriter &a_oOutput, Converter &a_oConverter, const SI_CHAR *a_pText) const
MRPT custom INI file parser to allow minimal file preprocessing:
TNamesDepend m_strings
This vector stores allocated memory for copies of strings that have been supplied after the file load...
void compile(const std::string &expression, const std::map< std::string, double > &variables=std::map< std::string, double >(), const std::string &expr_name_for_error_reporting=std::string())
Initializes the object by compiling an expression.
bool m_bAllowMultiKey
Are multiple values permitted for the same key?
const TKeyVal * GetSection(const SI_CHAR *a_pSection) const
Retrieve all key and value pairs for a section.
bool IsNewLineChar(SI_CHAR a_c) const
An existing value was updated.
Null conversion class for MBCS/UTF-8 to char (or equivalent).
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.
std::string format(const char *fmt,...) MRPT_printf_format_check(1
A std::string version of C sprintf.
std::map< std::string, double > defined_vars_values
size_t do_parse(const char *in_str, const size_t in_len, char *out_str)
Shared code for the two virtual methods.
double eval() const
Evaluates the current value of the precompiled formula.
void SkipNewLine(SI_CHAR *&a_pData) const
Skip over a newline character (or characters) for either DOS or UNIX.
Converter & operator=(const Converter &rhs)
SI_ConvertA & operator=(const SI_ConvertA &rhs)
bool IsLess(const SI_CHAR *a_pLeft, const SI_CHAR *a_pRight) const
Internal use of our string comparison function.
size_t m_uDataLen
Length of the data that we have stored.
Entry & operator=(const Entry &rhs)
std::multimap< Entry, const SI_CHAR *, typename Entry::KeyOrder > TKeyVal
map keys to values
bool IsSpace(SI_CHAR ch) const
Is the supplied character a whitespace character?
std::string trim(const std::string &str)
Removes leading and trailing spaces.
FILE * fopen(const char *fileName, const char *mode) noexcept
An OS-independent version of fopen.
typedef void(APIENTRYP PFNGLBLENDCOLORPROC)(GLclampf red
const SI_CHAR * m_pFileComment
File comment for this data, if one exists.
bool operator()(const SI_CHAR *pLeft, const SI_CHAR *pRight) const
int GetSectionSize(const SI_CHAR *a_pSection) const
Query the number of keys in a specific section.
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.
SI_Error Load(std::istream &a_istream)
Load INI file data from an istream.
void Write(const char *a_pBuf)
bool operator<(const COccupancyGridMap2D::TPairLikelihoodIndex &e1, const COccupancyGridMap2D::TPairLikelihoodIndex &e2)
SI_ConvertA(const SI_ConvertA &rhs)
std::map< std::string, std::string > defined_vars
CSimpleIniTempl< SI_CHAR, SI_STRLESS, SI_CONVERTER > & operator=(const CSimpleIniTempl< SI_CHAR, SI_STRLESS, SI_CONVERTER > &o)
CSimpleIniTempl(bool a_bMultiKey=false, bool a_bMultiLine=false)
Default constructor.
const Scalar * const_iterator
MRPT_IniFileParser(const MRPT_IniFileParser &rhs)
bool LoadMultiLineText(SI_CHAR *&a_pData, const SI_CHAR *&a_pVal, const SI_CHAR *a_pTagName, bool a_bAllowBlankLinesInComment=false) const
OutputWriter class to write the INI data to an ostream.
std::list< Entry > TNamesDepend
set of dependent string pointers.
std::map< Entry, TKeyVal, typename Entry::KeyOrder > TSection
map sections to key/value map
SI_Error SaveFile(const char *a_pszFile) const
Save an INI file from memory to disk.
SI_CHAR * m_pData
Copy of the INI file data in our character format.
void memcpy(void *dest, size_t destSize, const void *src, size_t copyCount) noexcept
An OS and compiler independent version of "memcpy".
SI_Error Save(OutputWriter &a_oOutput) const
Save the INI data.
MRPT_IniFileParser & operator=(const MRPT_IniFileParser &rhs)
StreamWriter & operator=(const StreamWriter &)
std::string parse_process_var_eval(const ParseContext &pc, std::string expr)