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);
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