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)
75 #define SI_NEWLINE_A "\r\n"
76 #define SI_NEWLINE_W L"\r\n"
78 #define SI_NEWLINE_A "\n"
79 #define SI_NEWLINE_W L"\n"
83 #define SI_HAS_WIDE_FILE
84 #define SI_WCHAR_T wchar_t
85 #elif defined(SI_CONVERT_ICU)
86 #define SI_HAS_WIDE_FILE
87 #define SI_WCHAR_T UChar
113 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
124 Entry(
const SI_CHAR* a_pszItem =
nullptr,
int a_nOrder = 0)
137 #if (defined(_MSC_VER) && _MSC_VER <= 1200)
142 return LoadOrder()(*
this, rhs);
144 bool operator>(
const Entry& rhs)
const
146 return LoadOrder()(rhs, *
this);
151 struct KeyOrder : std::function<bool(Entry, Entry)>
155 const static SI_STRLESS isLess = SI_STRLESS();
176 std::multimap<Entry, const SI_CHAR*, typename Entry::KeyOrder>;
179 using TSection = std::map<Entry, TKeyVal, typename Entry::KeyOrder>;
194 virtual void Write(
const char* a_pBuf) = 0;
208 void Write(
const char* a_pBuf)
override { fputs(a_pBuf,
m_file); }
229 #ifdef SI_SUPPORT_IOSTREAMS
243 #endif // SI_SUPPORT_IOSTREAMS
260 size_t uLen = this->SizeToStore(a_pszString);
261 if (uLen == (
size_t)(-1))
269 return SI_CONVERTER::ConvertToStore(
270 a_pszString,
const_cast<char*
>(
m_scratch.data()),
368 #ifdef SI_HAS_WIDE_FILE
376 #endif // SI_HAS_WIDE_FILE
387 #ifdef SI_SUPPORT_IOSTREAMS
395 #endif // SI_SUPPORT_IOSTREAMS
405 return Load(a_strData.c_str(), a_strData.size());
431 #ifdef SI_HAS_WIDE_FILE
478 #ifdef SI_SUPPORT_IOSTREAMS
490 #endif // SI_SUPPORT_IOSTREAMS
554 const SI_CHAR* a_pSection,
const SI_CHAR* a_pKey,
602 const SI_CHAR* a_pSection,
const SI_CHAR* a_pKey,
603 const SI_CHAR* a_pDefault =
nullptr,
604 bool* a_pHasMultiple =
nullptr)
const;
630 const SI_CHAR* a_pSection,
const SI_CHAR* a_pKey,
631 const SI_CHAR* a_pValue,
const SI_CHAR* a_pComment =
nullptr)
633 return AddEntry(a_pSection, a_pKey, a_pValue, a_pComment,
true);
655 const SI_CHAR* a_pSection,
const SI_CHAR* a_pKey,
656 bool a_bRemoveEmpty =
false);
681 SI_CHAR*& a_pData,
const SI_CHAR*& a_pSection,
const SI_CHAR*& a_pKey,
682 const SI_CHAR*& a_pVal,
const SI_CHAR*& a_pComment)
const;
701 const SI_CHAR* a_pSection,
const SI_CHAR* a_pKey,
702 const SI_CHAR* a_pValue,
const SI_CHAR* a_pComment,
703 bool a_bCopyStrings);
708 return (ch ==
' ' || ch ==
'\t' || ch ==
'\r' || ch ==
'\n');
712 inline bool IsComment(SI_CHAR ch)
const {
return (ch ==
';' || ch ==
'#'); }
716 a_pData += (*a_pData ==
'\r' && *(a_pData + 1) ==
'\n') ? 2 : 1;
726 bool IsLess(
const SI_CHAR* a_pLeft,
const SI_CHAR* a_pRight)
const
728 const static SI_STRLESS isLess = SI_STRLESS();
729 return isLess(a_pLeft, a_pRight);
735 SI_CHAR*& a_pData,
const SI_CHAR*& a_pVal,
const SI_CHAR* a_pTagName,
736 bool a_bAllowBlankLinesInComment =
false)
const;
740 OutputWriter& a_oOutput, Converter& a_oConverter,
741 const SI_CHAR* a_pText)
const;
785 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
787 bool a_bAllowMultiKey,
bool a_bAllowMultiLine)
790 m_pFileComment(NULL),
791 m_bAllowMultiKey(a_bAllowMultiKey),
792 m_bAllowMultiLine(a_bAllowMultiLine),
797 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
803 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
810 m_pFileComment =
nullptr;
813 m_data.erase(m_data.begin(), m_data.end());
817 if (!m_strings.empty())
820 for (; i != m_strings.end(); ++i)
822 delete[]
const_cast<SI_CHAR*
>(i->pItem);
824 m_strings.erase(m_strings.begin(), m_strings.end());
828 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
830 const char* a_pszFile)
833 #if __STDC_WANT_SECURE_LIB__
834 fopen_s(&fp, a_pszFile,
"rb");
836 fp =
fopen(a_pszFile,
"rb");
847 #ifdef SI_HAS_WIDE_FILE
848 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
854 #if __STDC_WANT_SECURE_LIB__
855 _wfopen_s(&fp, a_pwszFile, L
"rb");
857 fp = _wfopen(a_pwszFile, L
"rb");
863 #else // SI_CONVERT_ICU
865 u_austrncpy(szFile, a_pwszFile,
sizeof(szFile));
866 return LoadFile(szFile);
869 #endif // SI_HAS_WIDE_FILE
871 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
876 int retval = fseek(a_fpFile, 0,
SEEK_END);
881 long lSize = ftell(a_fpFile);
886 char* pData =
new char[lSize];
892 size_t uRead = fread(pData,
sizeof(
char), lSize, a_fpFile);
893 if (uRead != (
size_t)lSize)
905 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
907 const char* a_pData,
size_t a_uDataLen)
909 SI_CONVERTER converter;
912 size_t uLen = converter.SizeFromStore(a_pData, a_uDataLen);
913 if (uLen == (
size_t)(-1))
920 SI_CHAR* pData =
new SI_CHAR[uLen + 1];
925 memset(pData, 0,
sizeof(SI_CHAR) * (uLen + 1));
928 if (!converter.ConvertFromStore(a_pData, a_uDataLen, pData, uLen))
935 const static SI_CHAR
empty = 0;
936 SI_CHAR* pWork = pData;
937 const SI_CHAR* pSection = &
empty;
938 const SI_CHAR* pItem =
nullptr;
939 const SI_CHAR* pVal =
nullptr;
940 const SI_CHAR* pComment =
nullptr;
944 bool bCopyStrings = (m_pData !=
nullptr);
948 SI_Error rc = FindFileComment(pWork, bCopyStrings);
949 if (rc < 0)
return rc;
952 while (FindEntry(pWork, pSection, pItem, pVal, pComment))
954 rc = AddEntry(pSection, pItem, pVal, pComment, bCopyStrings);
955 if (rc < 0)
return rc;
966 m_uDataLen = uLen + 1;
972 #ifdef SI_SUPPORT_IOSTREAMS
973 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
975 std::istream& a_istream)
981 a_istream.get(szBuf,
sizeof(szBuf),
'\0');
982 strData.append(szBuf);
983 }
while (a_istream.good());
984 return Load(strData);
986 #endif // SI_SUPPORT_IOSTREAMS
988 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
990 SI_CHAR*& a_pData,
bool a_bCopyStrings)
1000 if (!LoadMultiLineText(a_pData, m_pFileComment,
nullptr,
false))
1008 SI_Error rc = CopyString(m_pFileComment);
1009 if (rc < 0)
return rc;
1015 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1017 SI_CHAR*& a_pData,
const SI_CHAR*& a_pSection,
const SI_CHAR*& a_pKey,
1018 const SI_CHAR*& a_pVal,
const SI_CHAR*& a_pComment)
const
1020 a_pComment =
nullptr;
1022 SI_CHAR* pTrail =
nullptr;
1026 while (*a_pData && IsSpace(*a_pData))
1037 if (IsComment(*a_pData))
1039 LoadMultiLineText(a_pData, a_pComment,
nullptr,
true);
1044 if (*a_pData ==
'[')
1048 while (*a_pData && IsSpace(*a_pData))
1055 a_pSection = a_pData;
1056 while (*a_pData && *a_pData !=
']' && !IsNewLineChar(*a_pData))
1062 if (*a_pData !=
']')
1068 pTrail = a_pData - 1;
1069 while (pTrail >= a_pSection && IsSpace(*pTrail))
1078 while (*a_pData && !IsNewLineChar(*a_pData))
1091 while (*a_pData && *a_pData !=
'=' && !IsNewLineChar(*a_pData))
1097 if (*a_pData !=
'=')
1103 if (a_pKey == a_pData)
1105 while (*a_pData && !IsNewLineChar(*a_pData))
1113 pTrail = a_pData - 1;
1114 while (pTrail >= a_pKey && IsSpace(*pTrail))
1123 while (*a_pData && !IsNewLineChar(*a_pData) && IsSpace(*a_pData))
1130 while (*a_pData && !IsNewLineChar(*a_pData))
1136 pTrail = a_pData - 1;
1139 SkipNewLine(a_pData);
1141 while (pTrail >= a_pVal && IsSpace(*pTrail))
1149 if (m_bAllowMultiLine && IsMultiLineTag(a_pVal))
1152 const SI_CHAR* pTagName = a_pVal + 3;
1153 return LoadMultiLineText(a_pData, a_pVal, pTagName);
1163 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1165 const SI_CHAR* a_pVal)
const
1168 if (*a_pVal++ !=
'<')
return false;
1169 if (*a_pVal++ !=
'<')
return false;
1170 if (*a_pVal++ !=
'<')
return false;
1174 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1176 const SI_CHAR* a_pData)
const
1190 if (IsSpace(*a_pData))
1198 if (IsNewLineChar(*a_pData))
1206 if (IsSpace(*--a_pData))
1214 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1218 return (a_c ==
'\n' || a_c ==
'\r');
1221 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1223 SI_CHAR*& a_pData,
const SI_CHAR*& a_pVal,
const SI_CHAR* a_pTagName,
1224 bool a_bAllowBlankLinesInComment)
const
1234 SI_CHAR* pDataLine = a_pData;
1243 SI_CHAR cEndOfLineChar = *a_pData;
1248 if (!a_pTagName && !IsComment(*a_pData))
1251 if (!a_bAllowBlankLinesInComment)
1259 SI_CHAR* pCurr = a_pData;
1261 while (IsSpace(*pCurr))
1263 if (IsNewLineChar(*pCurr))
1276 if (IsComment(*pCurr))
1278 for (; nNewLines > 0; --nNewLines) *pDataLine++ =
'\n';
1288 pCurrLine = a_pData;
1289 while (*a_pData && !IsNewLineChar(*a_pData)) ++a_pData;
1292 if (pDataLine < pCurrLine)
1294 memmove(pDataLine, pCurrLine, a_pData - pCurrLine);
1295 pDataLine[a_pData - pCurrLine] =
'\0';
1299 cEndOfLineChar = *a_pData;
1306 (!IsLess(pDataLine, a_pTagName) && !IsLess(a_pTagName, pDataLine)))
1313 if (!cEndOfLineChar)
1320 pDataLine += (a_pData - pCurrLine);
1321 *a_pData = cEndOfLineChar;
1322 SkipNewLine(a_pData);
1323 *pDataLine++ =
'\n';
1327 if (a_pVal == a_pData)
1337 *--pDataLine =
'\0';
1341 if (a_pTagName && cEndOfLineChar)
1343 SI_ASSERT(IsNewLineChar(cEndOfLineChar));
1344 *a_pData = cEndOfLineChar;
1345 SkipNewLine(a_pData);
1351 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1353 const SI_CHAR*& a_pString)
1356 if (
sizeof(SI_CHAR) ==
sizeof(
char))
1358 uLen = strlen((
const char*)a_pString);
1360 else if (
sizeof(SI_CHAR) ==
sizeof(
wchar_t))
1362 uLen = wcslen((
const wchar_t*)a_pString);
1366 for (; a_pString[uLen]; ++uLen)
1370 SI_CHAR* pCopy =
new SI_CHAR[uLen];
1375 memcpy(pCopy, a_pString,
sizeof(SI_CHAR) * uLen);
1376 m_strings.push_back(pCopy);
1381 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1383 const SI_CHAR* a_pSection,
const SI_CHAR* a_pKey,
const SI_CHAR* a_pValue,
1384 const SI_CHAR* a_pComment,
bool a_bCopyStrings)
1387 bool bInserted =
false;
1389 SI_ASSERT(!a_pComment || IsComment(*a_pComment));
1393 if (a_bCopyStrings && a_pComment)
1395 rc = CopyString(a_pComment);
1396 if (rc < 0)
return rc;
1403 iSection = m_data.find(a_pSection);
1404 if (iSection == m_data.end())
1409 rc = CopyString(a_pSection);
1410 if (rc < 0)
return rc;
1415 if (iSection == m_data.end())
1417 Entry oKey(a_pSection, ++m_nOrder);
1418 if (a_pComment && (!a_pKey || !a_pValue))
1422 typename TSection::value_type oEntry(oKey,
TKeyVal());
1424 std::pair<SectionIterator, bool> i = m_data.insert(oEntry);
1428 if (!a_pKey || !a_pValue)
1435 TKeyVal& keyval = iSection->second;
1441 if (m_bAllowMultiKey || iKey == keyval.end())
1446 rc = CopyString(a_pKey);
1447 if (rc < 0)
return rc;
1451 rc = CopyString(a_pValue);
1452 if (rc < 0)
return rc;
1456 if (iKey == keyval.end() || m_bAllowMultiKey)
1458 Entry oKey(a_pKey, ++m_nOrder);
1463 typename TKeyVal::value_type oEntry(
1464 oKey,
static_cast<const char*
>(
nullptr));
1465 iKey = keyval.insert(oEntry);
1468 iKey->second = a_pValue;
1472 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1474 const SI_CHAR* a_pSection,
const SI_CHAR* a_pKey,
const SI_CHAR* a_pDefault,
1475 bool* a_pHasMultiple)
const
1479 *a_pHasMultiple =
false;
1481 if (!a_pSection || !a_pKey)
1486 if (iSection == m_data.end())
1491 if (iKeyVal == iSection->second.end())
1497 if (m_bAllowMultiKey && a_pHasMultiple)
1500 if (++iTemp != iSection->second.end())
1502 if (!IsLess(a_pKey, iTemp->first.pItem))
1504 *a_pHasMultiple =
true;
1509 return iKeyVal->second;
1512 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1514 const SI_CHAR* a_pSection,
const SI_CHAR* a_pKey,
1517 if (!a_pSection || !a_pKey)
1522 if (iSection == m_data.end())
1527 if (iKeyVal == iSection->second.end())
1533 a_values.push_back(iKeyVal->second);
1534 if (m_bAllowMultiKey)
1537 while (iKeyVal != iSection->second.end() &&
1538 !IsLess(a_pKey, iKeyVal->first.pItem))
1540 a_values.push_back(
Entry(iKeyVal->second, iKeyVal->first.nOrder));
1548 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1550 const SI_CHAR* a_pSection)
const
1558 if (iSection == m_data.end())
1562 const TKeyVal& section = iSection->second;
1566 if (!m_bAllowMultiKey || section.empty())
1568 return (
int)section.size();
1573 const SI_CHAR* pLastKey =
nullptr;
1575 for (
int n = 0; iKeyVal != section.end(); ++iKeyVal, ++
n)
1577 if (!pLastKey || IsLess(pLastKey, iKeyVal->first.pItem))
1580 pLastKey = iKeyVal->first.pItem;
1586 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1589 const SI_CHAR* a_pSection)
const
1594 if (i != m_data.end())
1596 return &(i->second);
1602 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1607 for (
int n = 0; i != m_data.end(); ++i, ++
n)
1609 a_names.push_back(i->first);
1613 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1615 const SI_CHAR* a_pSection,
TNamesDepend& a_names)
const
1623 if (iSection == m_data.end())
1628 const TKeyVal& section = iSection->second;
1629 const SI_CHAR* pLastKey =
nullptr;
1631 for (
int n = 0; iKeyVal != section.end(); ++iKeyVal, ++
n)
1633 if (!pLastKey || IsLess(pLastKey, iKeyVal->first.pItem))
1635 a_names.push_back(iKeyVal->first);
1636 pLastKey = iKeyVal->first.pItem;
1643 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1645 const char* a_pszFile)
const
1648 #if __STDC_WANT_SECURE_LIB__
1649 fopen_s(&fp, a_pszFile,
"wb");
1651 fp =
fopen(a_pszFile,
"wb");
1659 #ifdef SI_HAS_WIDE_FILE
1660 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1665 FILE* fp = _wfopen(a_pwszFile, L
"wb");
1670 #else // SI_CONVERT_ICU
1672 u_austrncpy(szFile, a_pwszFile,
sizeof(szFile));
1673 return SaveFile(szFile);
1676 #endif // SI_HAS_WIDE_FILE
1678 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1680 FILE* a_pFile)
const
1683 return Save(writer);
1686 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1694 GetAllSections(oSections);
1695 #if (defined(_MSC_VER) && _MSC_VER <= 1200)
1702 bool bNeedNewLine =
false;
1705 if (!OutputMultiLineText(a_oOutput, convert, m_pFileComment))
1709 bNeedNewLine =
true;
1714 for (; iSection != oSections.end(); ++iSection)
1717 if (iSection->pComment)
1730 bNeedNewLine =
false;
1737 bNeedNewLine =
false;
1741 if (*iSection->pItem)
1747 a_oOutput.
Write(
"[");
1749 a_oOutput.
Write(
"]");
1755 GetAllKeys(iSection->pItem, oKeys);
1756 #if (defined(_MSC_VER) && _MSC_VER <= 1200)
1764 for (; iKey != oKeys.end(); ++iKey)
1768 GetAllValues(iSection->pItem, iKey->pItem, oValues);
1774 if (!OutputMultiLineText(a_oOutput, convert, iKey->pComment))
1781 for (; iValue != oValues.end(); ++iValue)
1795 a_oOutput.
Write(
"=");
1796 if (m_bAllowMultiLine && IsMultiLineData(iValue->pItem))
1802 if (!OutputMultiLineText(a_oOutput, convert, iValue->pItem))
1806 a_oOutput.
Write(
"SI-END-OF-MULTILINE-TEXT");
1816 bNeedNewLine =
true;
1822 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1825 const SI_CHAR* a_pText)
const
1827 const SI_CHAR* pEndOfLine;
1828 SI_CHAR cEndOfLineChar = *a_pText;
1829 while (cEndOfLineChar)
1832 pEndOfLine = a_pText;
1833 for (; *pEndOfLine && *pEndOfLine !=
'\n'; ++pEndOfLine)
1835 cEndOfLineChar = *pEndOfLine;
1838 *
const_cast<SI_CHAR*
>(pEndOfLine) = 0;
1843 *
const_cast<SI_CHAR*
>(pEndOfLine) = cEndOfLineChar;
1844 a_pText += (pEndOfLine - a_pText) + 1;
1851 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1853 const SI_CHAR* a_pSection,
const SI_CHAR* a_pKey,
bool a_bRemoveEmpty)
1861 if (iSection == m_data.end())
1870 if (iKeyVal == iSection->second.end())
1879 iDelete = iKeyVal++;
1881 DeleteString(iDelete->first.pItem);
1882 DeleteString(iDelete->second);
1883 iSection->second.erase(iDelete);
1884 }
while (iKeyVal != iSection->second.end() &&
1885 !IsLess(a_pKey, iKeyVal->first.pItem));
1890 if (!a_bRemoveEmpty || !iSection->second.empty())
1900 for (; iKeyVal != iSection->second.end(); ++iKeyVal)
1902 DeleteString(iKeyVal->first.pItem);
1903 DeleteString(iKeyVal->second);
1908 DeleteString(iSection->first.pItem);
1909 m_data.erase(iSection);
1914 template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1916 const SI_CHAR* a_pString)
1921 if (a_pString < m_pData || a_pString >= m_pData + m_uDataLen)
1924 for (; i != m_strings.end(); ++i)
1926 if (a_pString == i->pItem)
1928 delete[]
const_cast<SI_CHAR*
>(i->pItem);
1945 template <
class SI_CHAR>
1948 bool operator()(
const SI_CHAR* pLeft,
const SI_CHAR* pRight)
const
1951 for (; *pLeft && *pRight; ++pLeft, ++pRight)
1953 cmp = (long)*pLeft - (
long)*pRight;
1959 return *pRight != 0;
1969 template <
class SI_CHAR>
1974 return (ch < 'A' || ch >
'Z') ? ch : (ch -
'A' +
'a');
1976 bool operator()(
const SI_CHAR* pLeft,
const SI_CHAR* pRight)
const
1979 for (; *pLeft && *pRight; ++pLeft, ++pRight)
1987 return *pRight != 0;
1994 template <
class SI_CHAR>
2018 const char* a_pInputData,
size_t a_uInputDataLen)
2021 SI_ASSERT(a_uInputDataLen != (
size_t)-1);
2024 return a_uInputDataLen;
2042 const char* a_pInputData,
size_t a_uInputDataLen,
2043 SI_CHAR* a_pOutputData,
size_t a_uOutputDataSize)
2046 if (a_uInputDataLen > a_uOutputDataSize)
2050 memcpy(a_pOutputData, a_pInputData, a_uInputDataLen);
2068 return strlen((
const char*)a_pInputData) + 1;
2085 const SI_CHAR* a_pInputData,
char* a_pOutputData,
2086 size_t a_uOutputDataSize)
2089 size_t uInputLen = strlen((
const char*)a_pInputData) + 1;
2090 if (uInputLen > a_uOutputDataSize)
2096 memcpy(a_pOutputData, a_pInputData, uInputLen);
2119 const char* a_pInputData,
size_t a_uInputDataLen)
override
2121 SI_ASSERT(a_uInputDataLen != (
size_t)-1);
2122 return do_parse(a_pInputData, a_uInputDataLen,
nullptr);
2126 const char* a_pInputData,
size_t a_uInputDataLen,
char* a_pOutputData,
2127 size_t a_uOutputDataSize)
override
2129 this->
do_parse(a_pInputData, a_uInputDataLen, a_pOutputData);
2145 while (expr.size() > 5)
2147 auto p = expr.find(
"$env{");
2148 if (
p != std::string::npos)
2150 auto pend = expr.find(
"}",
p);
2151 if (pend == std::string::npos)
2153 "Line %u: Expected closing `}` near: `%s`",
2155 const auto substr = expr.substr(
p + 5, pend -
p - 5);
2157 auto env_val = ::getenv(substr.c_str());
2159 new_expr += expr.substr(pend + 1);
2160 new_expr.swap(expr);
2162 else if ((
p = expr.find(
"$eval{")) != std::string::npos)
2164 auto pend = expr.find(
"}",
p);
2165 if (pend == std::string::npos)
2167 "Line %u: Expected closing `}` near: `%s`",
2170 const auto substr = expr.substr(
p + 6, pend -
p - 6);
2178 new_expr += expr.substr(pend + 1);
2179 new_expr.swap(expr);
2191 if (!var_name.empty())
2194 if (!var_value.empty())
2204 size_t do_parse(
const char* in_str,
const size_t in_len,
char* out_str)
2207 size_t out_len = 0, i = 0;
2210 const char c = in_str[i];
2216 if (
c ==
'\\' && i < in_len - 1 &&
2217 (in_str[i + 1] ==
'\r' || in_str[i + 1] ==
'\n'))
2221 if (i < in_len - 2 && in_str[i + 1] ==
'\r' &&
2222 in_str[i + 2] ==
'\n')
2227 else if (in_str[i + 1] ==
'\r' || in_str[i + 1] ==
'\n')
2234 throw std::runtime_error(
2235 "MRPT_IniFileParser: parse error, shouldn't reach "
2242 if (in_len > i + 7 && !::strncmp(in_str + i,
"@define", 7))
2247 bool in_var_name =
false, done_var_name =
false;
2248 while (i < in_len && in_str[i] !=
'\r' && in_str[i] !=
'\n')
2250 const char ch = in_str[i];
2252 if (ch !=
' ' && ch !=
'\t')
2255 if (!in_var_name && !done_var_name)
2265 in_var_name =
false;
2266 done_var_name =
true;
2284 if (in_len > i + 4 && in_str[i] ==
'$' && in_str[i + 1] ==
'{')
2289 bool end_ok =
false;
2290 while (i < in_len && in_str[i] !=
'\n' && in_str[i] !=
'\r')
2292 const char ch = in_str[i];
2304 "Line %u: Expected closing `}` near: `%s`",
2311 "Line %u: Unknown variable `${%s}`", pc.
line_count,
2316 for (
const char ch : str_out)
2318 if (out_str) out_str[out_len] = ch;
2325 if (in_len > i + 7 && !strncmp(in_str + i,
"$eval{", 6))
2329 bool end_ok =
false;
2330 while (i < in_len && in_str[i] !=
'\n' && in_str[i] !=
'\r')
2332 const char ch = in_str[i];
2344 "Line %u: Expected closing `}` near: `%s`",
2350 for (
const char ch :
res)
2352 if (out_str) out_str[out_len] = ch;
2359 if (in_len > i + 6 && !strncmp(in_str + i,
"$env{", 5))
2363 bool end_ok =
false;
2364 while (i < in_len && in_str[i] !=
'\n' && in_str[i] !=
'\r')
2366 const char ch = in_str[i];
2378 "Line %u: Expected closing `}` near: `%s`",
2384 for (
const char ch :
res)
2386 if (out_str) out_str[out_len] = ch;
2395 out_str[out_len] =
c;
2418 #define CSimpleIni CSimpleIniW
2419 #define CSimpleIniCase CSimpleIniCaseW
2420 #define SI_NEWLINE SI_NEWLINE_W
2422 #define CSimpleIni CSimpleIniA
2423 #define CSimpleIniCase CSimpleIniCaseA
2424 #define SI_NEWLINE SI_NEWLINE_A
2431 #endif // INCLUDED_SimpleIni_h