10 #ifndef INCLUDED_SimpleIni_h
11 #define INCLUDED_SimpleIni_h
24 # pragma warning (disable: 4127 4503 4702 4786)
37 #define SI_SUPPORT_IOSTREAMS
39 #ifdef SI_SUPPORT_IOSTREAMS
45 # 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
109 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
119 Entry(
const SI_CHAR * a_pszItem = NULL,
int a_nOrder = 0)
132 #if (defined(_MSC_VER) && _MSC_VER <= 1200) || defined(__BORLANDC__)
134 bool operator<(
const Entry & rhs)
const {
return LoadOrder()(*
this, rhs); }
135 bool operator>(
const Entry & rhs)
const {
return LoadOrder()(rhs, *
this); }
139 struct KeyOrder : std::binary_function<Entry, Entry, bool> {
141 const static SI_STRLESS isLess = SI_STRLESS();
147 struct LoadOrder : std::binary_function<Entry, Entry, bool> {
158 typedef std::multimap<Entry,const SI_CHAR *,typename Entry::KeyOrder>
TKeyVal;
161 typedef std::map<Entry,TKeyVal,typename Entry::KeyOrder>
TSection;
175 virtual void Write(
const char * a_pBuf) = 0;
207 #ifdef SI_SUPPORT_IOSTREAMS
236 size_t uLen = this->SizeToStore(a_pszString);
237 if (uLen == (
size_t)(-1)) {
243 return SI_CONVERTER::ConvertToStore(
262 bool a_bMultiKey =
false,
263 bool a_bMultiLine =
false
327 const char * a_pszFile
330 #ifdef SI_HAS_WIDE_FILE
353 #ifdef SI_SUPPORT_IOSTREAMS
361 std::istream & a_istream
372 return Load(a_strData.c_str(), a_strData.size());
383 const char * a_pData,
400 const char * a_pszFile
403 #ifdef SI_HAS_WIDE_FILE
453 OutputWriter & a_oOutput
456 #ifdef SI_SUPPORT_IOSTREAMS
464 std::ostream & a_ostream
522 const SI_CHAR * a_pSection,
541 const SI_CHAR * a_pSection,
542 const SI_CHAR * a_pKey,
556 const SI_CHAR * a_pSection
574 const SI_CHAR * a_pSection
595 const SI_CHAR * a_pSection,
596 const SI_CHAR * a_pKey,
597 const SI_CHAR * a_pDefault = NULL,
598 bool * a_pHasMultiple = NULL
625 const SI_CHAR * a_pSection,
626 const SI_CHAR * a_pKey,
627 const SI_CHAR * a_pValue,
628 const SI_CHAR * a_pComment = NULL
631 return AddEntry(a_pSection, a_pKey, a_pValue, a_pComment,
true);
653 const SI_CHAR * a_pSection,
654 const SI_CHAR * a_pKey,
655 bool a_bRemoveEmpty =
false
688 const SI_CHAR *& a_pSection,
689 const SI_CHAR *& a_pKey,
690 const SI_CHAR *& a_pVal,
691 const SI_CHAR *& a_pComment
711 const SI_CHAR * a_pSection,
712 const SI_CHAR * a_pKey,
713 const SI_CHAR * a_pValue,
714 const SI_CHAR * a_pComment,
720 return (ch ==
' ' || ch ==
'\t' || ch ==
'\r' || ch ==
'\n');
725 return (ch ==
';' || ch ==
'#');
731 a_pData += (*a_pData ==
'\r' && *(a_pData+1) ==
'\n') ? 2 : 1;
741 bool IsLess(
const SI_CHAR * a_pLeft,
const SI_CHAR * a_pRight)
const {
742 const static SI_STRLESS isLess = SI_STRLESS();
743 return isLess(a_pLeft, a_pRight);
750 const SI_CHAR *& a_pVal,
751 const SI_CHAR * a_pTagName,
752 bool a_bAllowBlankLinesInComment =
false
757 OutputWriter & a_oOutput,
758 Converter & a_oConverter,
759 const SI_CHAR * a_pText
804 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
806 bool a_bAllowMultiKey,
807 bool a_bAllowMultiLine
811 , m_pFileComment(NULL)
812 , m_bAllowMultiKey(a_bAllowMultiKey)
813 , m_bAllowMultiLine(a_bAllowMultiLine)
817 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
823 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
831 m_pFileComment = NULL;
832 if (!m_data.empty()) {
833 m_data.erase(m_data.begin(), m_data.end());
837 if (!m_strings.empty()) {
839 for (; i != m_strings.end(); ++i) {
840 delete[]
const_cast<SI_CHAR*
>(i->pItem);
842 m_strings.erase(m_strings.begin(), m_strings.end());
846 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
849 const char * a_pszFile
853 #if __STDC_WANT_SECURE_LIB__
854 fopen_s(&fp, a_pszFile,
"rb");
856 fp =
fopen(a_pszFile,
"rb");
866 #ifdef SI_HAS_WIDE_FILE
867 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
875 #if __STDC_WANT_SECURE_LIB__
876 _wfopen_s(&fp, a_pwszFile, L
"rb");
878 fp = _wfopen(a_pwszFile, L
"rb");
886 u_austrncpy(szFile, a_pwszFile,
sizeof(szFile));
887 return LoadFile(szFile);
892 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
899 int retval = fseek(a_fpFile, 0,
SEEK_END);
903 long lSize = ftell(a_fpFile);
907 char * pData =
new char[lSize];
912 size_t uRead = fread(pData,
sizeof(
char), lSize, a_fpFile);
913 if (uRead != (
size_t) lSize) {
924 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
927 const char * a_pData,
931 SI_CONVERTER converter;
934 size_t uLen = converter.SizeFromStore(a_pData, a_uDataLen);
935 if (uLen == (
size_t)(-1)) {
941 SI_CHAR * pData =
new SI_CHAR[uLen+1];
945 memset(pData, 0,
sizeof(SI_CHAR)*(uLen+1));
948 if (!converter.ConvertFromStore(a_pData, a_uDataLen, pData, uLen)) {
954 const static SI_CHAR
empty = 0;
955 SI_CHAR * pWork = pData;
956 const SI_CHAR * pSection = &
empty;
957 const SI_CHAR * pItem = NULL;
958 const SI_CHAR * pVal = NULL;
959 const SI_CHAR * pComment = NULL;
963 bool bCopyStrings = (m_pData != NULL);
967 SI_Error rc = FindFileComment(pWork, bCopyStrings);
968 if (rc < 0)
return rc;
971 while (FindEntry(pWork, pSection, pItem, pVal, pComment)) {
972 rc = AddEntry(pSection, pItem, pVal, pComment, bCopyStrings);
973 if (rc < 0)
return rc;
988 #ifdef SI_SUPPORT_IOSTREAMS
989 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
992 std::istream & a_istream
998 a_istream.get(szBuf,
sizeof(szBuf),
'\0');
999 strData.append(szBuf);
1001 while (a_istream.good());
1002 return Load(strData);
1006 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1014 if (m_pFileComment) {
1020 if (!LoadMultiLineText(a_pData, m_pFileComment, NULL,
false)) {
1025 if (a_bCopyStrings) {
1026 SI_Error rc = CopyString(m_pFileComment);
1027 if (rc < 0)
return rc;
1033 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1037 const SI_CHAR *& a_pSection,
1038 const SI_CHAR *& a_pKey,
1039 const SI_CHAR *& a_pVal,
1040 const SI_CHAR *& a_pComment
1045 SI_CHAR * pTrail = NULL;
1048 while (*a_pData && IsSpace(*a_pData)) {
1057 if (IsComment(*a_pData)) {
1058 LoadMultiLineText(a_pData, a_pComment, NULL,
true);
1063 if (*a_pData ==
'[') {
1066 while (*a_pData && IsSpace(*a_pData)) {
1072 a_pSection = a_pData;
1073 while (*a_pData && *a_pData !=
']' && !IsNewLineChar(*a_pData)) {
1078 if (*a_pData !=
']') {
1083 pTrail = a_pData - 1;
1084 while (pTrail >= a_pSection && IsSpace(*pTrail)) {
1092 while (*a_pData && !IsNewLineChar(*a_pData)) {
1104 while (*a_pData && *a_pData !=
'=' && !IsNewLineChar(*a_pData)) {
1109 if (*a_pData !=
'=') {
1114 if (a_pKey == a_pData) {
1115 while (*a_pData && !IsNewLineChar(*a_pData)) {
1122 pTrail = a_pData - 1;
1123 while (pTrail >= a_pKey && IsSpace(*pTrail)) {
1131 while (*a_pData && !IsNewLineChar(*a_pData) && IsSpace(*a_pData)) {
1137 while (*a_pData && !IsNewLineChar(*a_pData)) {
1142 pTrail = a_pData - 1;
1144 SkipNewLine(a_pData);
1146 while (pTrail >= a_pVal && IsSpace(*pTrail)) {
1153 if (m_bAllowMultiLine && IsMultiLineTag(a_pVal)) {
1155 const SI_CHAR * pTagName = a_pVal + 3;
1156 return LoadMultiLineText(a_pData, a_pVal, pTagName);
1166 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1169 const SI_CHAR * a_pVal
1173 if (*a_pVal++ !=
'<')
return false;
1174 if (*a_pVal++ !=
'<')
return false;
1175 if (*a_pVal++ !=
'<')
return false;
1179 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1182 const SI_CHAR * a_pData
1196 if (IsSpace(*a_pData)) {
1202 if (IsNewLineChar(*a_pData)) {
1209 if (IsSpace(*--a_pData)) {
1216 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1222 return (a_c ==
'\n' || a_c ==
'\r');
1225 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1229 const SI_CHAR *& a_pVal,
1230 const SI_CHAR * a_pTagName,
1231 bool a_bAllowBlankLinesInComment
1242 SI_CHAR * pDataLine = a_pData;
1243 SI_CHAR * pCurrLine;
1251 SI_CHAR cEndOfLineChar = *a_pData;
1255 if (!a_pTagName && !IsComment(*a_pData)) {
1257 if (!a_bAllowBlankLinesInComment) {
1264 SI_CHAR * pCurr = a_pData;
1266 while (IsSpace(*pCurr)) {
1267 if (IsNewLineChar(*pCurr)) {
1278 if (IsComment(*pCurr)) {
1279 for (; nNewLines > 0; --nNewLines) *pDataLine++ =
'\n';
1289 pCurrLine = a_pData;
1290 while (*a_pData && !IsNewLineChar(*a_pData)) ++a_pData;
1293 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) {
1319 pDataLine += (a_pData - pCurrLine);
1320 *a_pData = cEndOfLineChar;
1321 SkipNewLine(a_pData);
1322 *pDataLine++ =
'\n';
1326 if (a_pVal == a_pData) {
1335 *--pDataLine =
'\0';
1339 if (a_pTagName && cEndOfLineChar) {
1340 SI_ASSERT(IsNewLineChar(cEndOfLineChar));
1341 *a_pData = cEndOfLineChar;
1342 SkipNewLine(a_pData);
1348 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1351 const SI_CHAR *& a_pString
1355 if (
sizeof(SI_CHAR) ==
sizeof(
char)) {
1356 uLen = strlen((
const char *)a_pString);
1358 else if (
sizeof(SI_CHAR) ==
sizeof(
wchar_t)) {
1359 uLen = wcslen((
const wchar_t *)a_pString);
1362 for ( ; a_pString[uLen]; ++uLen) ;
1365 SI_CHAR * pCopy =
new SI_CHAR[uLen];
1369 memcpy(pCopy, a_pString,
sizeof(SI_CHAR)*uLen);
1370 m_strings.push_back(pCopy);
1375 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1378 const SI_CHAR * a_pSection,
1379 const SI_CHAR * a_pKey,
1380 const SI_CHAR * a_pValue,
1381 const SI_CHAR * a_pComment,
1386 bool bInserted =
false;
1388 SI_ASSERT(!a_pComment || IsComment(*a_pComment));
1392 if (a_bCopyStrings && a_pComment) {
1393 rc = CopyString(a_pComment);
1394 if (rc < 0)
return rc;
1399 if (a_bCopyStrings) {
1400 iSection = m_data.find(a_pSection);
1401 if (iSection == m_data.end()) {
1405 rc = CopyString(a_pSection);
1406 if (rc < 0)
return rc;
1411 if (iSection == m_data.end()) {
1412 Entry oKey(a_pSection, ++m_nOrder);
1413 if (a_pComment && (!a_pKey || !a_pValue)) {
1416 typename TSection::value_type oEntry(oKey,
TKeyVal());
1418 std::pair<SectionIterator,bool> i =
1419 m_data.insert(oEntry);
1423 if (!a_pKey || !a_pValue) {
1429 TKeyVal & keyval = iSection->second;
1433 if (a_bCopyStrings) {
1434 if (m_bAllowMultiKey || iKey == keyval.end()) {
1438 rc = CopyString(a_pKey);
1439 if (rc < 0)
return rc;
1443 rc = CopyString(a_pValue);
1444 if (rc < 0)
return rc;
1448 if (iKey == keyval.end() || m_bAllowMultiKey) {
1449 Entry oKey(a_pKey, ++m_nOrder);
1453 typename TKeyVal::value_type oEntry(oKey,
static_cast<const char*
>(NULL));
1454 iKey = keyval.insert(oEntry);
1457 iKey->second = a_pValue;
1461 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1464 const SI_CHAR * a_pSection,
1465 const SI_CHAR * a_pKey,
1466 const SI_CHAR * a_pDefault,
1467 bool * a_pHasMultiple
1470 if (a_pHasMultiple) {
1471 *a_pHasMultiple =
false;
1473 if (!a_pSection || !a_pKey) {
1477 if (iSection == m_data.end()) {
1481 if (iKeyVal == iSection->second.end()) {
1486 if (m_bAllowMultiKey && a_pHasMultiple) {
1488 if (++iTemp != iSection->second.end()) {
1489 if (!IsLess(a_pKey, iTemp->first.pItem)) {
1490 *a_pHasMultiple =
true;
1495 return iKeyVal->second;
1498 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1501 const SI_CHAR * a_pSection,
1502 const SI_CHAR * a_pKey,
1506 if (!a_pSection || !a_pKey) {
1510 if (iSection == m_data.end()) {
1514 if (iKeyVal == iSection->second.end()) {
1519 a_values.push_back(iKeyVal->second);
1520 if (m_bAllowMultiKey) {
1522 while (iKeyVal != iSection->second.end() && !IsLess(a_pKey, iKeyVal->first.pItem)) {
1523 a_values.push_back(
Entry(iKeyVal->second, iKeyVal->first.nOrder));
1531 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1534 const SI_CHAR * a_pSection
1542 if (iSection == m_data.end()) {
1545 const TKeyVal & section = iSection->second;
1549 if (!m_bAllowMultiKey || section.empty()) {
1550 return (
int) section.size();
1555 const SI_CHAR * pLastKey = NULL;
1557 for (
int n = 0; iKeyVal != section.end(); ++iKeyVal, ++
n) {
1558 if (!pLastKey || IsLess(pLastKey, iKeyVal->first.pItem)) {
1560 pLastKey = iKeyVal->first.pItem;
1566 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1569 const SI_CHAR * a_pSection
1574 if (i != m_data.end()) {
1575 return &(i->second);
1581 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1588 for (
int n = 0; i != m_data.end(); ++i, ++
n ) {
1589 a_names.push_back(i->first);
1593 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1596 const SI_CHAR * a_pSection,
1605 if (iSection == m_data.end()) {
1609 const TKeyVal & section = iSection->second;
1610 const SI_CHAR * pLastKey = NULL;
1612 for (
int n = 0; iKeyVal != section.end(); ++iKeyVal, ++
n ) {
1613 if (!pLastKey || IsLess(pLastKey, iKeyVal->first.pItem)) {
1614 a_names.push_back(iKeyVal->first);
1615 pLastKey = iKeyVal->first.pItem;
1622 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1625 const char * a_pszFile
1629 #if __STDC_WANT_SECURE_LIB__
1630 fopen_s(&fp, a_pszFile,
"wb");
1632 fp =
fopen(a_pszFile,
"wb");
1640 #ifdef SI_HAS_WIDE_FILE
1641 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1648 FILE * fp = _wfopen(a_pwszFile, L
"wb");
1655 u_austrncpy(szFile, a_pwszFile,
sizeof(szFile));
1656 return SaveFile(szFile);
1661 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1668 return Save(writer);
1671 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1681 GetAllSections(oSections);
1682 #if (defined(_MSC_VER) && _MSC_VER <= 1200) || defined(__BORLANDC__)
1689 bool bNeedNewLine =
false;
1690 if (m_pFileComment) {
1691 if (!OutputMultiLineText(a_oOutput, convert, m_pFileComment)) {
1694 bNeedNewLine =
true;
1699 for ( ; iSection != oSections.end(); ++iSection ) {
1701 if (iSection->pComment) {
1711 bNeedNewLine =
false;
1717 bNeedNewLine =
false;
1721 if (*iSection->pItem) {
1725 a_oOutput.
Write(
"[");
1727 a_oOutput.
Write(
"]");
1733 GetAllKeys(iSection->pItem, oKeys);
1734 #if (defined(_MSC_VER) && _MSC_VER <= 1200) || defined(__BORLANDC__)
1742 for ( ; iKey != oKeys.end(); ++iKey) {
1745 GetAllValues(iSection->pItem, iKey->pItem, oValues);
1748 if (iKey->pComment) {
1750 if (!OutputMultiLineText(a_oOutput, convert, iKey->pComment)) {
1756 for ( ; iValue != oValues.end(); ++iValue) {
1767 a_oOutput.
Write(
"=");
1768 if (m_bAllowMultiLine && IsMultiLineData(iValue->pItem)) {
1772 if (!OutputMultiLineText(a_oOutput, convert, iValue->pItem)) {
1775 a_oOutput.
Write(
"SI-END-OF-MULTILINE-TEXT");
1784 bNeedNewLine =
true;
1790 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1795 const SI_CHAR * a_pText
1798 const SI_CHAR * pEndOfLine;
1799 SI_CHAR cEndOfLineChar = *a_pText;
1800 while (cEndOfLineChar) {
1802 pEndOfLine = a_pText;
1803 for (; *pEndOfLine && *pEndOfLine !=
'\n'; ++pEndOfLine) ;
1804 cEndOfLineChar = *pEndOfLine;
1807 *
const_cast<SI_CHAR*
>(pEndOfLine) = 0;
1811 *
const_cast<SI_CHAR*
>(pEndOfLine) = cEndOfLineChar;
1812 a_pText += (pEndOfLine - a_pText) + 1;
1819 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1822 const SI_CHAR * a_pSection,
1823 const SI_CHAR * a_pKey,
1832 if (iSection == m_data.end()) {
1839 if (iKeyVal == iSection->second.end()) {
1846 iDelete = iKeyVal++;
1848 DeleteString(iDelete->first.pItem);
1849 DeleteString(iDelete->second);
1850 iSection->second.erase(iDelete);
1852 while (iKeyVal != iSection->second.end()
1853 && !IsLess(a_pKey, iKeyVal->first.pItem));
1858 if (!a_bRemoveEmpty || !iSection->second.empty()) {
1866 for ( ; iKeyVal != iSection->second.end(); ++iKeyVal) {
1867 DeleteString(iKeyVal->first.pItem);
1868 DeleteString(iKeyVal->second);
1873 DeleteString(iSection->first.pItem);
1874 m_data.erase(iSection);
1879 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1882 const SI_CHAR * a_pString
1888 if (a_pString < m_pData || a_pString >= m_pData + m_uDataLen) {
1890 for (;i != m_strings.end(); ++i) {
1891 if (a_pString == i->pItem) {
1892 delete[]
const_cast<SI_CHAR*
>(i->pItem);
1909 template<
class SI_CHAR>
1911 bool operator()(
const SI_CHAR * pLeft,
const SI_CHAR * pRight)
const {
1913 for ( ;*pLeft && *pRight; ++pLeft, ++pRight) {
1914 cmp = (long) *pLeft - (
long) *pRight;
1919 return *pRight != 0;
1929 template<
class SI_CHAR>
1932 return (ch < 'A' || ch >
'Z') ? ch : (ch -
'A' +
'a');
1934 bool operator()(
const SI_CHAR * pLeft,
const SI_CHAR * pRight)
const {
1936 for ( ;*pLeft && *pRight; ++pLeft, ++pRight) {
1942 return *pRight != 0;
1949 template<
class SI_CHAR>
1974 const char * a_pInputData,
1975 size_t a_uInputDataLen)
1978 SI_ASSERT(a_uInputDataLen != (
size_t) -1);
1981 return a_uInputDataLen;
1998 const char * a_pInputData,
1999 size_t a_uInputDataLen,
2000 SI_CHAR * a_pOutputData,
2001 size_t a_uOutputDataSize)
2004 if (a_uInputDataLen > a_uOutputDataSize) {
2007 memcpy(a_pOutputData, a_pInputData, a_uInputDataLen);
2022 const SI_CHAR * a_pInputData)
2025 return strlen((
const char *)a_pInputData) + 1;
2042 const SI_CHAR * a_pInputData,
2043 char * a_pOutputData,
2044 size_t a_uOutputDataSize)
2047 size_t uInputLen = strlen((
const char *)a_pInputData) + 1;
2048 if (uInputLen > a_uOutputDataSize) {
2053 memcpy(a_pOutputData, a_pInputData, uInputLen);
2073 const char * a_pInputData,
2076 SI_ASSERT(a_uInputDataLen != (
size_t)-1);
2077 return do_parse(a_pInputData, a_uInputDataLen,
nullptr);
2081 const char * a_pInputData,
2082 size_t a_uInputDataLen,
2083 char * a_pOutputData,
2086 this->
do_parse(a_pInputData, a_uInputDataLen, a_pOutputData);
2102 while (expr.size()>6)
2104 auto p = expr.find(
"$eval{");
2105 if (
p == std::string::npos)
break;
2106 auto pend = expr.find(
"}",
p);
2107 if (pend == std::string::npos)
2108 throw std::runtime_error(
mrpt::format(
"Line %u: Expected closing `}` near: `%s`", pc.
line_count, expr.c_str()));
2110 const auto substr = expr.substr(
p + 6, pend -
p - 6);
2116 new_expr += expr.substr(pend+1);
2118 new_expr.swap(expr);
2125 if (!var_name.empty()) {
2127 if (!var_value.empty()) {
2135 const char * in_str,
2136 const size_t in_len,
2140 size_t out_len = 0, i = 0;
2143 const char c = in_str[i];
2148 if (
c ==
'\\' && i < in_len - 1 && (in_str[i + 1] ==
'\r' || in_str[i + 1] ==
'\n'))
2151 if (i < in_len - 2 && in_str[i + 1] ==
'\r' && in_str[i + 2] ==
'\n') {
2155 else if (in_str[i + 1] ==
'\r' || in_str[i + 1] ==
'\n') {
2160 throw std::runtime_error(
"MRPT_IniFileParser: parse error, shouldn't reach here!");
2166 if (in_len>i+7 && !::strncmp(in_str + i,
"@define",7))
2171 bool in_var_name =
false, done_var_name =
false;
2172 while (i < in_len && in_str[i] !=
'\r' && in_str[i] !=
'\n')
2174 const char c = in_str[i];
2176 if (
c !=
' ' &&
c !=
'\t')
2179 if (!in_var_name && !done_var_name) {
2187 in_var_name =
false;
2188 done_var_name =
true;
2194 if (done_var_name) {
2204 if (in_len>i + 4 && in_str[i]==
'$' && in_str[i+1] ==
'{')
2209 bool end_ok =
false;
2210 while (i < in_len && in_str[i]!=
'\n' && in_str[i]!=
'\r')
2212 const char ch = in_str[i];
2221 throw std::runtime_error(
mrpt::format(
"Line %u: Expected closing `}` near: `%s`", pc.
line_count,varname.c_str()));
2226 throw std::runtime_error(
mrpt::format(
"Line %u: Unknown variable `${%s}`", pc.
line_count,varname.c_str()));
2230 for (
const char ch : str_out)
2232 if (out_str) out_str[out_len] = ch;
2239 if (in_len>i + 7 && !strncmp(in_str+i,
"$eval{", 6))
2243 bool end_ok =
false;
2244 while (i < in_len && in_str[i] !=
'\n' && in_str[i] !=
'\r')
2246 const char ch = in_str[i];
2255 throw std::runtime_error(
mrpt::format(
"Line %u: Expected closing `}` near: `%s`", pc.
line_count, expr.c_str()));
2260 for (
const char ch :
res)
2262 if (out_str) out_str[out_len] = ch;
2270 out_str[out_len] =
c;
2287 typedef CSimpleIniTempl<char,
2295 # define CSimpleIni CSimpleIniW
2296 # define CSimpleIniCase CSimpleIniCaseW
2297 # define SI_NEWLINE SI_NEWLINE_W
2299 # define CSimpleIni CSimpleIniA
2300 # define CSimpleIniCase CSimpleIniCaseA
2301 # define SI_NEWLINE SI_NEWLINE_A
A wrapper of exprtk runtime expression compiler: it takes a string representing an expression (from a...
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.
double eval() const
Evaluates the current value of the precompiled formula.
Characterset conversion utility class to convert strings to the same format as is used for the storag...
bool ConvertToStore(const SI_CHAR *a_pszString)
Converter & operator=(const Converter &rhs)
Converter(const Converter &rhs)
OutputWriter class to write the INI data to a file.
void Write(const char *a_pBuf) MRPT_OVERRIDE
FileWriter(const FileWriter &)
FileWriter & operator=(const FileWriter &)
interface definition for the OutputWriter object to pass to Save() in order to output the INI file da...
OutputWriter & operator=(const OutputWriter &)
virtual void Write(const char *a_pBuf)=0
OutputWriter(const OutputWriter &)
OutputWriter class to write the INI data to an ostream.
StreamWriter(std::ostream &a_ostream)
StreamWriter & operator=(const StreamWriter &)
StreamWriter(const StreamWriter &)
void Write(const char *a_pBuf)
OutputWriter class to write the INI data to a string.
void Write(const char *a_pBuf) MRPT_OVERRIDE
StringWriter(std::string &a_string)
StringWriter & operator=(const StringWriter &)
StringWriter(const StringWriter &)
bool m_bAllowMultiKey
Are multiple values permitted for the same key?
const SI_CHAR * GetValue(const SI_CHAR *a_pSection, const SI_CHAR *a_pKey, const SI_CHAR *a_pDefault=NULL, bool *a_pHasMultiple=NULL) const
Retrieve the value for a specific key.
bool GetAllValues(const SI_CHAR *a_pSection, const SI_CHAR *a_pKey, TNamesDepend &a_values) const
Retrieve all values for a specific key.
int m_nOrder
Next order value, used to ensure sections and keys are output in the same order that they are loaded/...
CSimpleIniTempl(bool a_bMultiKey=false, bool a_bMultiLine=false)
Default constructor.
bool GetAllKeys(const SI_CHAR *a_pSection, TNamesDepend &a_names) const
Retrieve all unique key names in a section.
bool IsMultiKey() const
Get the storage format of the INI data.
TNamesDepend m_strings
This vector stores allocated memory for copies of strings that have been supplied after the file load...
SI_Error Save(OutputWriter &a_oOutput) const
Save the INI data.
bool IsMultiLine() const
Query the status of multi-line data.
SI_CHAR * m_pData
Copy of the INI file data in our character format.
SI_Error Save(std::string &a_sBuffer) const
Append the INI data to a string.
SI_Error Save(std::ostream &a_ostream) const
Save the INI data to an ostream.
bool LoadMultiLineText(SI_CHAR *&a_pData, const SI_CHAR *&a_pVal, const SI_CHAR *a_pTagName, bool a_bAllowBlankLinesInComment=false) const
void Reset()
Deallocate all memory stored by this object.
bool IsNewLineChar(SI_CHAR a_c) const
std::multimap< Entry, const SI_CHAR *, typename Entry::KeyOrder > TKeyVal
map keys to values
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.
SI_Error SetValue(const SI_CHAR *a_pSection, const SI_CHAR *a_pKey, const SI_CHAR *a_pValue, const SI_CHAR *a_pComment=NULL)
Add or update a section or value.
std::list< Entry > TNamesDepend
set of dependent string pointers.
bool m_bAllowMultiLine
Are data values permitted to span multiple lines?
void GetAllSections(TNamesDepend &a_names) const
Retrieve all section names.
bool IsLess(const SI_CHAR *a_pLeft, const SI_CHAR *a_pRight) const
Internal use of our string comparison function.
SI_Error SaveFile(const char *a_pszFile) const
Save an INI file from memory to disk.
bool IsSpace(SI_CHAR ch) const
Is the supplied character a whitespace character?
size_t m_uDataLen
Length of the data that we have stored.
SI_Error CopyString(const SI_CHAR *&a_pString)
Make a copy of the supplied string, replacing the original pointer.
void DeleteString(const SI_CHAR *a_pString)
Delete a string from the copied strings buffer if necessary.
TSection m_data
Parsed INI data.
SI_Error FindFileComment(SI_CHAR *&a_pData, bool a_bCopyStrings)
Parse the data looking for a file comment and store it if found.
bool IsComment(SI_CHAR ch) const
Does the supplied character start a comment line?
SI_Error Load(const std::string &a_strData)
Load INI file data direct from a std::string.
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.
bool IsMultiLineTag(const SI_CHAR *a_pData) const
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.
void SetMultiLine(bool a_bAllowMultiLine=true)
Should data values be permitted to span multiple lines in the file.
Converter GetConverter() const
Return a conversion object to convert text to the same encoding as is used by the Save(),...
void SkipNewLine(SI_CHAR *&a_pData) const
Skip over a newline character (or characters) for either DOS or UNIX.
bool IsMultiLineData(const SI_CHAR *a_pData) const
~CSimpleIniTempl()
Destructor.
SI_Error LoadFile(const char *a_pszFile)
Load an INI file from disk into memory.
const TKeyVal * GetSection(const SI_CHAR *a_pSection) const
Retrieve all key and value pairs for a section.
const SI_CHAR * m_pFileComment
File comment for this data, if one exists.
std::map< Entry, TKeyVal, typename Entry::KeyOrder > TSection
map sections to key/value map
SI_Error Load(std::istream &a_istream)
Load INI file data from an istream.
void SetMultiKey(bool a_bAllowMultiKey=true)
Should multiple identical keys be permitted in the file.
int GetSectionSize(const SI_CHAR *a_pSection) const
Query the number of keys in a specific section.
bool OutputMultiLineText(OutputWriter &a_oOutput, Converter &a_oConverter, const SI_CHAR *a_pText) const
Null conversion class for MBCS/UTF-8 to char (or equivalent).
size_t SizeToStore(const SI_CHAR *a_pInputData)
Calculate the number of char required by the storage format of this data.
SI_ConvertA(const SI_ConvertA &rhs)
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.
SI_ConvertA & operator=(const SI_ConvertA &rhs)
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.
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.
const Scalar * const_iterator
typedef void(APIENTRYP PFNGLBLENDCOLORPROC)(GLclampf red
GLsizei const GLchar ** string
void BASE_IMPEXP memcpy(void *dest, size_t destSize, const void *src, size_t copyCount) MRPT_NO_THROWS
An OS and compiler independent version of "memcpy".
FILE BASE_IMPEXP * fopen(const char *fileName, const char *mode) MRPT_NO_THROWS
An OS-independent version of fopen.
int BASE_IMPEXP void BASE_IMPEXP fclose(FILE *f)
An OS-independent version of fclose.
std::string BASE_IMPEXP trim(const std::string &str)
Removes leading and trailing spaces.
#define MRPT_OVERRIDE
C++11 "override" for virtuals:
CSimpleIniTempl< char, SI_GenericCase< char >, SI_ConvertA< char > > CSimpleIniCaseA
CSimpleIniTempl< char, SI_GenericNoCase< char >, SI_ConvertA< char > > CSimpleIniA
CSimpleIniTempl< char, SI_GenericNoCase< char >, MRPT_IniFileParser > MRPT_CSimpleIni
@ SI_NOMEM
Out of memory error.
@ SI_INSERTED
A new value was inserted.
@ SI_UPDATED
An existing value was updated.
@ SI_FAIL
Generic failure.
@ SI_FILE
File error (see errno for detail error)
bool operator>(const CArray< T, N > &x, const CArray< T, N > &y)
bool operator<(const CArray< T, N > &x, const CArray< T, N > &y)
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
std::string BASE_IMPEXP format(const char *fmt,...) MRPT_printf_format_check(1
A std::string version of C sprintf.
Strict less ordering by name of key only.
bool operator()(const Entry &lhs, const Entry &rhs) const
Strict less ordering by order, and then name of key.
bool operator()(const Entry &lhs, const Entry &rhs) const
Entry & operator=(const Entry &rhs)
Entry(const SI_CHAR *a_pszItem=NULL, int a_nOrder=0)
std::map< std::string, std::string > defined_vars
std::map< std::string, double > defined_vars_values
MRPT custom INI file parser to allow minimal file preprocessing:
void parse_process_var_define(ParseContext &pc, const std::string &var_name, const std::string &var_value)
virtual size_t SizeFromStore(const char *a_pInputData, size_t a_uInputDataLen) MRPT_OVERRIDE
Calculate the number of SI_CHAR required for converting the input from the storage format.
MRPT_IniFileParser(const MRPT_IniFileParser &rhs)
MRPT_IniFileParser & operator=(const MRPT_IniFileParser &rhs)
size_t do_parse(const char *in_str, const size_t in_len, char *out_str)
Shared code for the two virtual methods.
std::string parse_process_var_eval(const ParseContext &pc, std::string expr)
virtual bool ConvertFromStore(const char *a_pInputData, size_t a_uInputDataLen, char *a_pOutputData, size_t a_uOutputDataSize) MRPT_OVERRIDE
Convert the input string from the storage format to SI_CHAR.
Generic case-sensitive less than comparison.
bool operator()(const SI_CHAR *pLeft, const SI_CHAR *pRight) const
Generic ASCII case-insensitive less than comparison.
SI_CHAR locase(SI_CHAR ch) const
bool operator()(const SI_CHAR *pLeft, const SI_CHAR *pRight) const