22 #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)    70 #define SI_NEWLINE_A "\r\n"    71 #define SI_NEWLINE_W L"\r\n"    73 #define SI_NEWLINE_A "\n"    74 #define SI_NEWLINE_W L"\n"    78 #define SI_HAS_WIDE_FILE    79 #define SI_WCHAR_T wchar_t    80 #elif defined(SI_CONVERT_ICU)    81 #define SI_HAS_WIDE_FILE    82 #define SI_WCHAR_T UChar   108 template <
class SI_CHAR, 
class SI_STRLESS, 
class SI_CONVERTER>
   119         Entry(
const SI_CHAR* a_pszItem = 
nullptr, 
int a_nOrder = 0)
   132 #if (defined(_MSC_VER) && _MSC_VER <= 1200)   137             return LoadOrder()(*
this, rhs);
   139         bool operator>(
const Entry& rhs)
 const   141             return LoadOrder()(rhs, *
this);
   146         struct KeyOrder : std::function<bool(Entry, Entry)>
   150                 const static SI_STRLESS isLess = SI_STRLESS();
   171         std::multimap<Entry, const SI_CHAR*, typename Entry::KeyOrder>;
   174     using TSection = std::map<Entry, TKeyVal, typename Entry::KeyOrder>;
   189         virtual void Write(
const char* a_pBuf) = 0;
   203         void Write(
const char* a_pBuf)
 override { fputs(a_pBuf, 
m_file); }
   224 #ifdef SI_SUPPORT_IOSTREAMS   238 #endif  // SI_SUPPORT_IOSTREAMS   255             size_t uLen = this->SizeToStore(a_pszString);
   256             if (uLen == (
size_t)(-1))
   264             return SI_CONVERTER::ConvertToStore(
   265                 a_pszString, const_cast<char*>(
m_scratch.data()),
   363 #ifdef SI_HAS_WIDE_FILE   371 #endif  // SI_HAS_WIDE_FILE   382 #ifdef SI_SUPPORT_IOSTREAMS   390 #endif  // SI_SUPPORT_IOSTREAMS   400         return Load(a_strData.c_str(), a_strData.size());
   426 #ifdef SI_HAS_WIDE_FILE   473 #ifdef SI_SUPPORT_IOSTREAMS   485 #endif  // SI_SUPPORT_IOSTREAMS   549         const SI_CHAR* a_pSection, 
const SI_CHAR* a_pKey,
   597         const SI_CHAR* a_pSection, 
const SI_CHAR* a_pKey,
   598         const SI_CHAR* a_pDefault = 
nullptr,
   599         bool* a_pHasMultiple = 
nullptr) 
const;
   625         const SI_CHAR* a_pSection, 
const SI_CHAR* a_pKey,
   626         const SI_CHAR* a_pValue, 
const SI_CHAR* a_pComment = 
nullptr)
   628         return AddEntry(a_pSection, a_pKey, a_pValue, a_pComment, 
true);
   650         const SI_CHAR* a_pSection, 
const SI_CHAR* a_pKey,
   651         bool a_bRemoveEmpty = 
false);
   676         SI_CHAR*& a_pData, 
const SI_CHAR*& a_pSection, 
const SI_CHAR*& a_pKey,
   677         const SI_CHAR*& a_pVal, 
const SI_CHAR*& a_pComment) 
const;
   696         const SI_CHAR* a_pSection, 
const SI_CHAR* a_pKey,
   697         const SI_CHAR* a_pValue, 
const SI_CHAR* a_pComment,
   698         bool a_bCopyStrings);
   701     inline bool IsSpace(SI_CHAR ch)
 const   703         return (ch == 
' ' || ch == 
'\t' || ch == 
'\r' || ch == 
'\n');
   707     inline bool IsComment(SI_CHAR ch)
 const { 
return (ch == 
';' || ch == 
'#'); }
   711         a_pData += (*a_pData == 
'\r' && *(a_pData + 1) == 
'\n') ? 2 : 1;
   721     bool IsLess(
const SI_CHAR* a_pLeft, 
const SI_CHAR* a_pRight)
 const   723         const static SI_STRLESS isLess = SI_STRLESS();
   724         return isLess(a_pLeft, a_pRight);
   730         SI_CHAR*& a_pData, 
const SI_CHAR*& a_pVal, 
const SI_CHAR* a_pTagName,
   731         bool a_bAllowBlankLinesInComment = 
false) 
const;
   735         OutputWriter& a_oOutput, Converter& a_oConverter,
   736         const SI_CHAR* a_pText) 
const;
   780 template <
class SI_CHAR, 
class SI_STRLESS, 
class SI_CONVERTER>
   782     bool a_bAllowMultiKey, 
bool a_bAllowMultiLine)
   785       m_pFileComment(NULL),
   786       m_bAllowMultiKey(a_bAllowMultiKey),
   787       m_bAllowMultiLine(a_bAllowMultiLine),
   792 template <
class SI_CHAR, 
class SI_STRLESS, 
class SI_CONVERTER>
   798 template <
class SI_CHAR, 
class SI_STRLESS, 
class SI_CONVERTER>
   805     m_pFileComment = 
nullptr;
   808         m_data.erase(m_data.begin(), m_data.end());
   812     if (!m_strings.empty())
   814         auto i = m_strings.begin();
   815         for (; i != m_strings.end(); ++i)
   817             delete[] 
const_cast<SI_CHAR*
>(i->pItem);
   819         m_strings.erase(m_strings.begin(), m_strings.end());
   823 template <
class SI_CHAR, 
class SI_STRLESS, 
class SI_CONVERTER>
   825     const char* a_pszFile)
   828 #if __STDC_WANT_SECURE_LIB__   829     fopen_s(&fp, a_pszFile, 
"rb");
   831     fp = 
fopen(a_pszFile, 
"rb");
   842 #ifdef SI_HAS_WIDE_FILE   843 template <
class SI_CHAR, 
class SI_STRLESS, 
class SI_CONVERTER>
   849 #if __STDC_WANT_SECURE_LIB__   850     _wfopen_s(&fp, a_pwszFile, L
"rb");
   852     fp = _wfopen(a_pwszFile, L
"rb");
   858 #else  // SI_CONVERT_ICU   860     u_austrncpy(szFile, a_pwszFile, 
sizeof(szFile));
   861     return LoadFile(szFile);
   864 #endif  // SI_HAS_WIDE_FILE   866 template <
class SI_CHAR, 
class SI_STRLESS, 
class SI_CONVERTER>
   871     int retval = fseek(a_fpFile, 0, SEEK_END);
   876     long lSize = ftell(a_fpFile);
   881     char* pData = 
new char[lSize];
   886     fseek(a_fpFile, 0, SEEK_SET);
   887     size_t uRead = fread(pData, 
sizeof(
char), lSize, a_fpFile);
   888     if (uRead != (
size_t)lSize)
   900 template <
class SI_CHAR, 
class SI_STRLESS, 
class SI_CONVERTER>
   902     const char* a_pData, 
size_t a_uDataLen)
   904     SI_CONVERTER converter;
   907     size_t uLen = converter.SizeFromStore(a_pData, a_uDataLen);
   908     if (uLen == (
size_t)(-1))
   915     auto* pData = 
new SI_CHAR[uLen + 1];
   920     memset(pData, 0, 
sizeof(SI_CHAR) * (uLen + 1));
   923     if (!converter.ConvertFromStore(a_pData, a_uDataLen, pData, uLen))
   930     const static SI_CHAR 
empty = 0;
   931     SI_CHAR* pWork = pData;
   932     const SI_CHAR* pSection = &
empty;
   933     const SI_CHAR* pItem = 
nullptr;
   934     const SI_CHAR* pVal = 
nullptr;
   935     const SI_CHAR* pComment = 
nullptr;
   939     bool bCopyStrings = (m_pData != 
nullptr);
   943     SI_Error rc = FindFileComment(pWork, bCopyStrings);
   944     if (rc < 0) 
return rc;
   947     while (FindEntry(pWork, pSection, pItem, pVal, pComment))
   949         rc = AddEntry(pSection, pItem, pVal, pComment, bCopyStrings);
   950         if (rc < 0) 
return rc;
   961         m_uDataLen = uLen + 1;
   967 #ifdef SI_SUPPORT_IOSTREAMS   968 template <
class SI_CHAR, 
class SI_STRLESS, 
class SI_CONVERTER>
   970     std::istream& a_istream)
   976         a_istream.get(szBuf, 
sizeof(szBuf), 
'\0');
   977         strData.append(szBuf);
   978     } 
while (a_istream.good());
   979     return Load(strData);
   981 #endif  // SI_SUPPORT_IOSTREAMS   983 template <
class SI_CHAR, 
class SI_STRLESS, 
class SI_CONVERTER>
   985     SI_CHAR*& a_pData, 
bool a_bCopyStrings)
   995     if (!LoadMultiLineText(a_pData, m_pFileComment, 
nullptr, 
false))
  1003         SI_Error rc = CopyString(m_pFileComment);
  1004         if (rc < 0) 
return rc;
  1010 template <
class SI_CHAR, 
class SI_STRLESS, 
class SI_CONVERTER>
  1012     SI_CHAR*& a_pData, 
const SI_CHAR*& a_pSection, 
const SI_CHAR*& a_pKey,
  1013     const SI_CHAR*& a_pVal, 
const SI_CHAR*& a_pComment)
 const  1015     a_pComment = 
nullptr;
  1017     SI_CHAR* pTrail = 
nullptr;
  1021         while (*a_pData && IsSpace(*a_pData))
  1032         if (IsComment(*a_pData))
  1034             LoadMultiLineText(a_pData, a_pComment, 
nullptr, 
true);
  1039         if (*a_pData == 
'[')
  1043             while (*a_pData && IsSpace(*a_pData))
  1050             a_pSection = a_pData;
  1051             while (*a_pData && *a_pData != 
']' && !IsNewLineChar(*a_pData))
  1057             if (*a_pData != 
']')
  1063             pTrail = a_pData - 1;
  1064             while (pTrail >= a_pSection && IsSpace(*pTrail))
  1073             while (*a_pData && !IsNewLineChar(*a_pData))
  1086         while (*a_pData && *a_pData != 
'=' && !IsNewLineChar(*a_pData))
  1092         if (*a_pData != 
'=')
  1098         if (a_pKey == a_pData)
  1100             while (*a_pData && !IsNewLineChar(*a_pData))
  1108         pTrail = a_pData - 1;
  1109         while (pTrail >= a_pKey && IsSpace(*pTrail))
  1118         while (*a_pData && !IsNewLineChar(*a_pData) && IsSpace(*a_pData))
  1125         while (*a_pData && !IsNewLineChar(*a_pData))
  1131         pTrail = a_pData - 1;
  1134             SkipNewLine(a_pData);
  1136         while (pTrail >= a_pVal && IsSpace(*pTrail))
  1144         if (m_bAllowMultiLine && IsMultiLineTag(a_pVal))
  1147             const SI_CHAR* pTagName = a_pVal + 3;
  1148             return LoadMultiLineText(a_pData, a_pVal, pTagName);
  1158 template <
class SI_CHAR, 
class SI_STRLESS, 
class SI_CONVERTER>
  1160     const SI_CHAR* a_pVal)
 const  1163     if (*a_pVal++ != 
'<') 
return false;
  1164     if (*a_pVal++ != 
'<') 
return false;
  1165     if (*a_pVal++ != 
'<') 
return false;
  1169 template <
class SI_CHAR, 
class SI_STRLESS, 
class SI_CONVERTER>
  1171     const SI_CHAR* a_pData)
 const  1185     if (IsSpace(*a_pData))
  1193         if (IsNewLineChar(*a_pData))
  1201     if (IsSpace(*--a_pData))
  1209 template <
class SI_CHAR, 
class SI_STRLESS, 
class SI_CONVERTER>
  1213     return (a_c == 
'\n' || a_c == 
'\r');
  1216 template <
class SI_CHAR, 
class SI_STRLESS, 
class SI_CONVERTER>
  1218     SI_CHAR*& a_pData, 
const SI_CHAR*& a_pVal, 
const SI_CHAR* a_pTagName,
  1219     bool a_bAllowBlankLinesInComment)
 const  1229     SI_CHAR* pDataLine = a_pData;
  1238     SI_CHAR cEndOfLineChar = *a_pData;
  1243         if (!a_pTagName && !IsComment(*a_pData))
  1246             if (!a_bAllowBlankLinesInComment)
  1254             SI_CHAR* pCurr = a_pData;
  1256             while (IsSpace(*pCurr))
  1258                 if (IsNewLineChar(*pCurr))
  1271             if (IsComment(*pCurr))
  1273                 for (; nNewLines > 0; --nNewLines) *pDataLine++ = 
'\n';
  1283         pCurrLine = a_pData;
  1284         while (*a_pData && !IsNewLineChar(*a_pData)) ++a_pData;
  1287         if (pDataLine < pCurrLine)
  1289             memmove(pDataLine, pCurrLine, a_pData - pCurrLine);
  1290             pDataLine[a_pData - pCurrLine] = 
'\0';
  1294         cEndOfLineChar = *a_pData;
  1301             (!IsLess(pDataLine, a_pTagName) && !IsLess(a_pTagName, pDataLine)))
  1308         if (!cEndOfLineChar)
  1315         pDataLine += (a_pData - pCurrLine);
  1316         *a_pData = cEndOfLineChar;
  1317         SkipNewLine(a_pData);
  1318         *pDataLine++ = 
'\n';
  1322     if (a_pVal == a_pData)
  1332     *--pDataLine = 
'\0';
  1336     if (a_pTagName && cEndOfLineChar)
  1338         SI_ASSERT(IsNewLineChar(cEndOfLineChar));
  1339         *a_pData = cEndOfLineChar;
  1340         SkipNewLine(a_pData);
  1346 template <
class SI_CHAR, 
class SI_STRLESS, 
class SI_CONVERTER>
  1348     const SI_CHAR*& a_pString)
  1351     if (
sizeof(SI_CHAR) == 
sizeof(
char))
  1353         uLen = strlen((
const char*)a_pString);
  1355     else if (
sizeof(SI_CHAR) == 
sizeof(
wchar_t))
  1357         uLen = wcslen((
const wchar_t*)a_pString);
  1361         for (; a_pString[uLen]; ++uLen) 
  1365     auto* pCopy = 
new SI_CHAR[uLen];
  1370     memcpy(pCopy, a_pString, 
sizeof(SI_CHAR) * uLen);
  1371     m_strings.push_back(pCopy);
  1376 template <
class SI_CHAR, 
class SI_STRLESS, 
class SI_CONVERTER>
  1378     const SI_CHAR* a_pSection, 
const SI_CHAR* a_pKey, 
const SI_CHAR* a_pValue,
  1379     const SI_CHAR* a_pComment, 
bool a_bCopyStrings)
  1382     bool bInserted = 
false;
  1384     SI_ASSERT(!a_pComment || IsComment(*a_pComment));
  1388     if (a_bCopyStrings && a_pComment)
  1390         rc = CopyString(a_pComment);
  1391         if (rc < 0) 
return rc;
  1395     auto iSection = m_data.end();
  1398         iSection = m_data.find(a_pSection);
  1399         if (iSection == m_data.end())
  1404             rc = CopyString(a_pSection);
  1405             if (rc < 0) 
return rc;
  1410     if (iSection == m_data.end())
  1412         Entry oKey(a_pSection, ++m_nOrder);
  1413         if (a_pComment && (!a_pKey || !a_pValue))
  1417         typename TSection::value_type oEntry(oKey, 
TKeyVal());
  1418         using SectionIterator = 
typename TSection::iterator;
  1419         std::pair<SectionIterator, bool> i = m_data.insert(oEntry);
  1423     if (!a_pKey || !a_pValue)
  1430     TKeyVal& keyval = iSection->second;
  1431     auto iKey = keyval.find(a_pKey);
  1436         if (m_bAllowMultiKey || iKey == keyval.end())
  1441             rc = CopyString(a_pKey);
  1442             if (rc < 0) 
return rc;
  1446         rc = CopyString(a_pValue);
  1447         if (rc < 0) 
return rc;
  1451     if (iKey == keyval.end() || m_bAllowMultiKey)
  1453         Entry oKey(a_pKey, ++m_nOrder);
  1458         typename TKeyVal::value_type oEntry(
  1459             oKey, static_cast<const char*>(
nullptr));
  1460         iKey = keyval.insert(oEntry);
  1463     iKey->second = a_pValue;
  1467 template <
class SI_CHAR, 
class SI_STRLESS, 
class SI_CONVERTER>
  1469     const SI_CHAR* a_pSection, 
const SI_CHAR* a_pKey, 
const SI_CHAR* a_pDefault,
  1470     bool* a_pHasMultiple)
 const  1474         *a_pHasMultiple = 
false;
  1476     if (!a_pSection || !a_pKey)
  1480     auto iSection = m_data.find(a_pSection);
  1481     if (iSection == m_data.end())
  1485     auto iKeyVal = iSection->second.find(a_pKey);
  1486     if (iKeyVal == iSection->second.end())
  1492     if (m_bAllowMultiKey && a_pHasMultiple)
  1494         auto iTemp = iKeyVal;
  1495         if (++iTemp != iSection->second.end())
  1497             if (!IsLess(a_pKey, iTemp->first.pItem))
  1499                 *a_pHasMultiple = 
true;
  1504     return iKeyVal->second;
  1507 template <
class SI_CHAR, 
class SI_STRLESS, 
class SI_CONVERTER>
  1509     const SI_CHAR* a_pSection, 
const SI_CHAR* a_pKey,
  1512     if (!a_pSection || !a_pKey)
  1516     auto iSection = m_data.find(a_pSection);
  1517     if (iSection == m_data.end())
  1521     auto iKeyVal = iSection->second.find(a_pKey);
  1522     if (iKeyVal == iSection->second.end())
  1528     a_values.push_back(iKeyVal->second);
  1529     if (m_bAllowMultiKey)
  1532         while (iKeyVal != iSection->second.end() &&
  1533                !IsLess(a_pKey, iKeyVal->first.pItem))
  1535             a_values.push_back(
Entry(iKeyVal->second, iKeyVal->first.nOrder));
  1543 template <
class SI_CHAR, 
class SI_STRLESS, 
class SI_CONVERTER>
  1545     const SI_CHAR* a_pSection)
 const  1552     typename TSection::const_iterator iSection = m_data.find(a_pSection);
  1553     if (iSection == m_data.end())
  1557     const TKeyVal& section = iSection->second;
  1561     if (!m_bAllowMultiKey || section.empty())
  1563         return (
int)section.size();
  1568     const SI_CHAR* pLastKey = 
nullptr;
  1569     typename TKeyVal::const_iterator iKeyVal = section.begin();
  1570     for (
int n = 0; iKeyVal != section.end(); ++iKeyVal, ++n)
  1572         if (!pLastKey || IsLess(pLastKey, iKeyVal->first.pItem))
  1575             pLastKey = iKeyVal->first.pItem;
  1581 template <
class SI_CHAR, 
class SI_STRLESS, 
class SI_CONVERTER>
  1584         const SI_CHAR* a_pSection)
 const  1588         typename TSection::const_iterator i = m_data.find(a_pSection);
  1589         if (i != m_data.end())
  1591             return &(i->second);
  1597 template <
class SI_CHAR, 
class SI_STRLESS, 
class SI_CONVERTER>
  1601     auto i = m_data.begin();
  1602     for (
int n = 0; i != m_data.end(); ++i, ++n)
  1604         a_names.push_back(i->first);
  1608 template <
class SI_CHAR, 
class SI_STRLESS, 
class SI_CONVERTER>
  1610     const SI_CHAR* a_pSection, 
TNamesDepend& a_names)
 const  1617     auto iSection = m_data.find(a_pSection);
  1618     if (iSection == m_data.end())
  1623     const TKeyVal& section = iSection->second;
  1624     const SI_CHAR* pLastKey = 
nullptr;
  1625     auto iKeyVal = section.begin();
  1626     for (
int n = 0; iKeyVal != section.end(); ++iKeyVal, ++n)
  1628         if (!pLastKey || IsLess(pLastKey, iKeyVal->first.pItem))
  1630             a_names.push_back(iKeyVal->first);
  1631             pLastKey = iKeyVal->first.pItem;
  1638 template <
class SI_CHAR, 
class SI_STRLESS, 
class SI_CONVERTER>
  1640     const char* a_pszFile)
 const  1643 #if __STDC_WANT_SECURE_LIB__  1644     fopen_s(&fp, a_pszFile, 
"wb");
  1646     fp = 
fopen(a_pszFile, 
"wb");
  1654 #ifdef SI_HAS_WIDE_FILE  1655 template <
class SI_CHAR, 
class SI_STRLESS, 
class SI_CONVERTER>
  1660     FILE* fp = _wfopen(a_pwszFile, L
"wb");
  1665 #else  // SI_CONVERT_ICU  1667     u_austrncpy(szFile, a_pwszFile, 
sizeof(szFile));
  1668     return SaveFile(szFile);
  1671 #endif  // SI_HAS_WIDE_FILE  1673 template <
class SI_CHAR, 
class SI_STRLESS, 
class SI_CONVERTER>
  1675     FILE* a_pFile)
 const  1678     return Save(writer);
  1681 template <
class SI_CHAR, 
class SI_STRLESS, 
class SI_CONVERTER>
  1689     GetAllSections(oSections);
  1690 #if (defined(_MSC_VER) && _MSC_VER <= 1200)  1697     bool bNeedNewLine = 
false;
  1700         if (!OutputMultiLineText(a_oOutput, 
convert, m_pFileComment))
  1704         bNeedNewLine = 
true;
  1708     auto iSection = oSections.begin();
  1709     for (; iSection != oSections.end(); ++iSection)
  1712         if (iSection->pComment)
  1714             if (!
convert.ConvertToStore(iSection->pComment))
  1725             bNeedNewLine = 
false;
  1732             bNeedNewLine = 
false;
  1736         if (*iSection->pItem)
  1738             if (!
convert.ConvertToStore(iSection->pItem))
  1742             a_oOutput.
Write(
"[");
  1744             a_oOutput.
Write(
"]");
  1750         GetAllKeys(iSection->pItem, oKeys);
  1751 #if (defined(_MSC_VER) && _MSC_VER <= 1200)  1758         auto iKey = oKeys.begin();
  1759         for (; iKey != oKeys.end(); ++iKey)
  1763             GetAllValues(iSection->pItem, iKey->pItem, oValues);
  1769                 if (!OutputMultiLineText(a_oOutput, 
convert, iKey->pComment))
  1775             auto iValue = oValues.begin();
  1776             for (; iValue != oValues.end(); ++iValue)
  1779                 if (!
convert.ConvertToStore(iKey->pItem))
  1786                 if (!
convert.ConvertToStore(iValue->pItem))
  1790                 a_oOutput.
Write(
"=");
  1791                 if (m_bAllowMultiLine && IsMultiLineData(iValue->pItem))
  1797                     if (!OutputMultiLineText(a_oOutput, 
convert, iValue->pItem))
  1801                     a_oOutput.
Write(
"SI-END-OF-MULTILINE-TEXT");
  1811         bNeedNewLine = 
true;
  1817 template <
class SI_CHAR, 
class SI_STRLESS, 
class SI_CONVERTER>
  1820     const SI_CHAR* a_pText)
 const  1822     const SI_CHAR* pEndOfLine;
  1823     SI_CHAR cEndOfLineChar = *a_pText;
  1824     while (cEndOfLineChar)
  1827         pEndOfLine = a_pText;
  1828         for (; *pEndOfLine && *pEndOfLine != 
'\n'; ++pEndOfLine) 
  1830         cEndOfLineChar = *pEndOfLine;
  1833         *
const_cast<SI_CHAR*
>(pEndOfLine) = 0;
  1838         *
const_cast<SI_CHAR*
>(pEndOfLine) = cEndOfLineChar;
  1839         a_pText += (pEndOfLine - a_pText) + 1;
  1846 template <
class SI_CHAR, 
class SI_STRLESS, 
class SI_CONVERTER>
  1848     const SI_CHAR* a_pSection, 
const SI_CHAR* a_pKey, 
bool a_bRemoveEmpty)
  1855     typename TSection::iterator iSection = m_data.find(a_pSection);
  1856     if (iSection == m_data.end())
  1864         typename TKeyVal::iterator iKeyVal = iSection->second.find(a_pKey);
  1865         if (iKeyVal == iSection->second.end())
  1871         typename TKeyVal::iterator iDelete;
  1874             iDelete = iKeyVal++;
  1876             DeleteString(iDelete->first.pItem);
  1877             DeleteString(iDelete->second);
  1878             iSection->second.erase(iDelete);
  1879         } 
while (iKeyVal != iSection->second.end() &&
  1880                  !IsLess(a_pKey, iKeyVal->first.pItem));
  1885         if (!a_bRemoveEmpty || !iSection->second.empty())
  1894         typename TKeyVal::iterator iKeyVal = iSection->second.begin();
  1895         for (; iKeyVal != iSection->second.end(); ++iKeyVal)
  1897             DeleteString(iKeyVal->first.pItem);
  1898             DeleteString(iKeyVal->second);
  1903     DeleteString(iSection->first.pItem);
  1904     m_data.erase(iSection);
  1909 template <
class SI_CHAR, 
class SI_STRLESS, 
class SI_CONVERTER>
  1911     const SI_CHAR* a_pString)
  1916     if (a_pString < m_pData || a_pString >= m_pData + m_uDataLen)
  1918         typename TNamesDepend::iterator i = m_strings.begin();
  1919         for (; i != m_strings.end(); ++i)
  1921             if (a_pString == i->pItem)
  1923                 delete[] 
const_cast<SI_CHAR*
>(i->pItem);
  1940 template <
class SI_CHAR>
  1943     bool operator()(
const SI_CHAR* pLeft, 
const SI_CHAR* pRight)
 const  1946         for (; *pLeft && *pRight; ++pLeft, ++pRight)
  1948             cmp = (long)*pLeft - (
long)*pRight;
  1954         return *pRight != 0;
  1964 template <
class SI_CHAR>
  1969         return (ch < 'A' || ch > 
'Z') ? ch : (ch - 
'A' + 
'a');
  1971     bool operator()(
const SI_CHAR* pLeft, 
const SI_CHAR* pRight)
 const  1974         for (; *pLeft && *pRight; ++pLeft, ++pRight)
  1982         return *pRight != 0;
  1989 template <
class SI_CHAR>
  2013         const char* a_pInputData, 
size_t a_uInputDataLen)
  2016         SI_ASSERT(a_uInputDataLen != (
size_t)-1);
  2019         return a_uInputDataLen;
  2037         const char* a_pInputData, 
size_t a_uInputDataLen,
  2038         SI_CHAR* a_pOutputData, 
size_t a_uOutputDataSize)
  2041         if (a_uInputDataLen > a_uOutputDataSize)
  2045         memcpy(a_pOutputData, a_pInputData, a_uInputDataLen);
  2063         return strlen((
const char*)a_pInputData) + 1;
  2080         const SI_CHAR* a_pInputData, 
char* a_pOutputData,
  2081         size_t a_uOutputDataSize)
  2084         size_t uInputLen = strlen((
const char*)a_pInputData) + 1;
  2085         if (uInputLen > a_uOutputDataSize)
  2091         memcpy(a_pOutputData, a_pInputData, uInputLen);
  2114         const char* a_pInputData, 
size_t a_uInputDataLen)
 override  2116         SI_ASSERT(a_uInputDataLen != (
size_t)-1);
  2117         return do_parse(a_pInputData, a_uInputDataLen, 
nullptr);
  2121         const char* a_pInputData, 
size_t a_uInputDataLen, 
char* a_pOutputData,
  2122         size_t a_uOutputDataSize)
 override  2124         this->
do_parse(a_pInputData, a_uInputDataLen, a_pOutputData);
  2140         while (expr.size() > 5)
  2142             auto p = expr.find(
"$env{");
  2143             if (p != std::string::npos)
  2145                 auto pend = expr.find(
"}", p);
  2146                 if (pend == std::string::npos)
  2148                         "Line %u: Expected closing `}` near: `%s`",
  2150                 const auto substr = expr.substr(p + 5, pend - p - 5);
  2151                 std::string new_expr = expr.substr(0, p);
  2152                 auto env_val = ::getenv(substr.c_str());
  2153                 if (env_val) new_expr += std::string(env_val);
  2154                 new_expr += expr.substr(pend + 1);
  2155                 new_expr.swap(expr);
  2157             else if ((p = expr.find(
"$eval{")) != std::string::npos)
  2159                 auto pend = expr.find(
"}", p);
  2160                 if (pend == std::string::npos)
  2162                         "Line %u: Expected closing `}` near: `%s`",
  2165                 const auto substr = expr.substr(p + 6, pend - p - 6);
  2171                 std::string new_expr = expr.substr(0, p);
  2173                 new_expr += expr.substr(pend + 1);
  2174                 new_expr.swap(expr);
  2184         const std::string& var_value)
  2186         if (!var_name.empty())
  2189             if (!var_value.empty())
  2199     size_t do_parse(
const char* in_str, 
const size_t in_len, 
char* out_str)
  2202         size_t out_len = 0, i = 0;
  2205             const char c = in_str[i];
  2211             if (c == 
'\\' && i < in_len - 1 &&
  2212                 (in_str[i + 1] == 
'\r' || in_str[i + 1] == 
'\n'))
  2216                 if (i < in_len - 2 && in_str[i + 1] == 
'\r' &&
  2217                     in_str[i + 2] == 
'\n')
  2222                 else if (in_str[i + 1] == 
'\r' || in_str[i + 1] == 
'\n')
  2229                     throw std::runtime_error(
  2230                         "MRPT_IniFileParser: parse error, shouldn't reach "  2237                 if (in_len > i + 7 && !::strncmp(in_str + i, 
"@define", 7))
  2241                     std::string var_name, var_value;
  2242                     bool in_var_name = 
false, done_var_name = 
false;
  2243                     while (i < in_len && in_str[i] != 
'\r' && in_str[i] != 
'\n')
  2245                         const char ch = in_str[i];
  2247                         if (ch != 
' ' && ch != 
'\t')
  2250                             if (!in_var_name && !done_var_name)
  2260                                 in_var_name = 
false;
  2261                                 done_var_name = 
true;
  2279                 if (in_len > i + 4 && in_str[i] == 
'$' && in_str[i + 1] == 
'{')
  2283                     std::string varname;
  2284                     bool end_ok = 
false;
  2285                     while (i < in_len && in_str[i] != 
'\n' && in_str[i] != 
'\r')
  2287                         const char ch = in_str[i];
  2299                             "Line %u: Expected closing `}` near: `%s`",
  2306                             "Line %u: Unknown variable `${%s}`", pc.
line_count,
  2311                     for (
const char ch : str_out)
  2313                         if (out_str) out_str[out_len] = ch;
  2320                 if (in_len > i + 7 && !strncmp(in_str + i, 
"$eval{", 6))
  2324                     bool end_ok = 
false;
  2325                     while (i < in_len && in_str[i] != 
'\n' && in_str[i] != 
'\r')
  2327                         const char ch = in_str[i];
  2339                             "Line %u: Expected closing `}` near: `%s`",
  2345                     for (
const char ch : res)
  2347                         if (out_str) out_str[out_len] = ch;
  2354                 if (in_len > i + 6 && !strncmp(in_str + i, 
"$env{", 5))
  2358                     bool end_ok = 
false;
  2359                     while (i < in_len && in_str[i] != 
'\n' && in_str[i] != 
'\r')
  2361                         const char ch = in_str[i];
  2373                             "Line %u: Expected closing `}` near: `%s`",
  2379                     for (
const char ch : res)
  2381                         if (out_str) out_str[out_len] = ch;
  2390                     out_str[out_len] = c;
  2413 #define CSimpleIni CSimpleIniW  2414 #define CSimpleIniCase CSimpleIniCaseW  2415 #define SI_NEWLINE SI_NEWLINE_W  2417 #define CSimpleIni CSimpleIniA  2418 #define CSimpleIniCase CSimpleIniCaseA  2419 #define SI_NEWLINE SI_NEWLINE_A 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
 
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. 
 
std::string std::string format(std::string_view fmt, ARGS &&... args)
 
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)
 
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 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...
 
void SetMultiLine(bool a_bAllowMultiLine=true)
Should data values be permitted to span multiple lines in the file. 
 
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...
 
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
 
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()...
 
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 convert(const sensor_msgs::LaserScan &msg, const mrpt::poses::CPose3D &pose, mrpt::obs::CObservation2DRangeScan &obj)
 
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::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. 
 
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. 
 
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)