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 41 #endif // 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 220 #endif // 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 340 #endif // SI_HAS_WIDE_FILE 353 #ifdef SI_SUPPORT_IOSTREAMS 361 std::istream & a_istream
363 #endif // SI_SUPPORT_IOSTREAMS 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
470 #endif // SI_SUPPORT_IOSTREAMS 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,
719 inline bool IsSpace(SI_CHAR ch)
const {
720 return (ch ==
' ' || ch ==
'\t' || ch ==
'\r' || ch ==
'\n');
724 inline bool IsComment(SI_CHAR ch)
const {
725 return (ch ==
';' || ch ==
'#');
730 inline void SkipNewLine(SI_CHAR *& a_pData)
const {
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");
884 #else // SI_CONVERT_ICU 886 u_austrncpy(szFile, a_pwszFile,
sizeof(szFile));
887 return LoadFile(szFile);
890 #endif // SI_HAS_WIDE_FILE 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);
1004 #endif // SI_SUPPORT_IOSTREAMS 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");
1653 #else // SI_CONVERT_ICU 1655 u_austrncpy(szFile, a_pwszFile,
sizeof(szFile));
1656 return SaveFile(szFile);
1659 #endif // SI_HAS_WIDE_FILE 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 2308 #endif // INCLUDED_SimpleIni_h Converter(const Converter &rhs)
Converter & operator=(const Converter &rhs)
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".
OutputWriter & operator=(const OutputWriter &)
SI_CHAR locase(SI_CHAR ch) const
FILE BASE_IMPEXP * fopen(const char *fileName, const char *mode) MRPT_NO_THROWS
An OS-independent version of fopen.
FileWriter & operator=(const FileWriter &)
std::map< std::string, std::string > defined_vars
int m_nOrder
Next order value, used to ensure sections and keys are output in the same order that they are loaded/...
Null conversion class for MBCS/UTF-8 to char (or equivalent).
StringWriter(std::string &a_string)
int GetSectionSize(const SI_CHAR *a_pSection) const
Query the number of keys in a specific section.
CSimpleIniTempl< char, SI_GenericNoCase< char >, SI_ConvertA< char > > CSimpleIniA
bool IsSpace(SI_CHAR ch) const
Is the supplied character a whitespace character?
bool operator()(const Entry &lhs, const Entry &rhs) const
#define MRPT_OVERRIDE
C++11 "override" for virtuals:
int BASE_IMPEXP void BASE_IMPEXP fclose(FILE *f)
An OS-independent version of fclose.
OutputWriter class to write the INI data to an ostream.
Entry & operator=(const Entry &rhs)
bool m_bAllowMultiKey
Are multiple values permitted for the same key?
std::multimap< Entry, const SI_CHAR *, typename Entry::KeyOrder > TKeyVal
map keys to values
bool IsMultiKey() const
Get the storage format of the INI data.
bool operator()(const Entry &lhs, const Entry &rhs) const
bool IsMultiLineTag(const SI_CHAR *a_pData) const
std::map< std::string, double > defined_vars_values
void SetMultiLine(bool a_bAllowMultiLine=true)
Should data values be permitted to span multiple lines in the file.
interface definition for the OutputWriter object to pass to Save() in order to output the INI file da...
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.
void SkipNewLine(SI_CHAR *&a_pData) const
Skip over a newline character (or characters) for either DOS or UNIX.
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.
void DeleteString(const SI_CHAR *a_pString)
Delete a string from the copied strings buffer if necessary.
const Scalar * const_iterator
A wrapper of exprtk runtime expression compiler: it takes a string representing an expression (from a...
CSimpleIniTempl< char, SI_GenericCase< char >, SI_ConvertA< char > > CSimpleIniCaseA
SI_Error LoadFile(const char *a_pszFile)
Load an INI file from disk into memory.
Entry(const SI_CHAR *a_pszItem=NULL, int a_nOrder=0)
bool m_bAllowMultiLine
Are data values permitted to span multiple lines?
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.
size_t SizeToStore(const SI_CHAR *a_pInputData)
Calculate the number of char required by the storage format of this data.
~CSimpleIniTempl()
Destructor.
void SetMultiKey(bool a_bAllowMultiKey=true)
Should multiple identical keys be permitted in the file.
MRPT custom INI file parser to allow minimal file preprocessing:
size_t do_parse(const char *in_str, const size_t in_len, char *out_str)
Shared code for the two virtual methods.
bool ConvertToStore(const SI_CHAR *a_pszString)
bool GetAllKeys(const SI_CHAR *a_pSection, TNamesDepend &a_names) const
Retrieve all unique key names in a section.
CSimpleIniTempl< char, SI_GenericNoCase< char >, MRPT_IniFileParser > MRPT_CSimpleIni
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.
bool operator<(const CArray< T, N > &x, const CArray< T, N > &y)
void Write(const char *a_pBuf) MRPT_OVERRIDE
double eval() const
Evaluates the current value of the precompiled formula.
TNamesDepend m_strings
This vector stores allocated memory for copies of strings that have been supplied after the file load...
Converter GetConverter() const
Return a conversion object to convert text to the same encoding as is used by the Save()...
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.
Strict less ordering by name of key only.
bool operator>(const CArray< T, N > &x, const CArray< T, N > &y)
void GetAllSections(TNamesDepend &a_names) const
Retrieve all section names.
SI_Error Load(std::istream &a_istream)
Load INI file data from an istream.
bool operator()(const SI_CHAR *pLeft, const SI_CHAR *pRight) const
File error (see errno for detail error)
std::string BASE_IMPEXP format(const char *fmt,...) MRPT_printf_format_check(1
A std::string version of C sprintf.
GLsizei const GLchar ** string
An existing value was updated.
SI_ConvertA & operator=(const SI_ConvertA &rhs)
Characterset conversion utility class to convert strings to the same format as is used for the storag...
void Write(const char *a_pBuf)
CSimpleIniTempl(bool a_bMultiKey=false, bool a_bMultiLine=false)
Default constructor.
SI_ConvertA(const SI_ConvertA &rhs)
bool IsMultiLineData(const SI_CHAR *a_pData) const
SI_CHAR * m_pData
Copy of the INI file data in our character format.
bool operator()(const SI_CHAR *pLeft, const SI_CHAR *pRight) const
TSection m_data
Parsed INI data.
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...
SI_Error SaveFile(const char *a_pszFile) const
Save an INI file from memory to disk.
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.
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.
Generic ASCII case-insensitive less than comparison.
bool IsNewLineChar(SI_CHAR a_c) const
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
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.
MRPT_IniFileParser(const MRPT_IniFileParser &rhs)
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.
size_t m_uDataLen
Length of the data that we have stored.
SI_Error FindFileComment(SI_CHAR *&a_pData, bool a_bCopyStrings)
Parse the data looking for a file comment and store it if found.
virtual void Write(const char *a_pBuf)=0
bool OutputMultiLineText(OutputWriter &a_oOutput, Converter &a_oConverter, const SI_CHAR *a_pText) const
A new value was inserted.
const TKeyVal * GetSection(const SI_CHAR *a_pSection) const
Retrieve all key and value pairs for a section.
OutputWriter class to write the INI data to a file.
Generic case-sensitive less than comparison.
std::list< Entry > TNamesDepend
set of dependent string pointers.
bool GetAllValues(const SI_CHAR *a_pSection, const SI_CHAR *a_pKey, TNamesDepend &a_values) const
Retrieve all values for a specific key.
void Write(const char *a_pBuf) MRPT_OVERRIDE
void parse_process_var_define(ParseContext &pc, const std::string &var_name, const std::string &var_value)
const SI_CHAR * m_pFileComment
File comment for this data, if one exists.
StreamWriter & operator=(const StreamWriter &)
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...
Strict less ordering by order, and then name of key.
std::string BASE_IMPEXP trim(const std::string &str)
Removes leading and trailing spaces.
void Reset()
Deallocate all memory stored by this object.
MRPT_IniFileParser & operator=(const MRPT_IniFileParser &rhs)
typedef void(APIENTRYP PFNGLBLENDCOLORPROC)(GLclampf red
SI_Error Save(OutputWriter &a_oOutput) const
Save the INI data.
SI_Error CopyString(const SI_CHAR *&a_pString)
Make a copy of the supplied string, replacing the original pointer.
bool IsMultiLine() const
Query the status of multi-line data.
StreamWriter(std::ostream &a_ostream)
std::string parse_process_var_eval(const ParseContext &pc, std::string expr)
bool LoadMultiLineText(SI_CHAR *&a_pData, const SI_CHAR *&a_pVal, const SI_CHAR *a_pTagName, bool a_bAllowBlankLinesInComment=false) const
bool IsComment(SI_CHAR ch) const
Does the supplied character start a comment line?
OutputWriter class to write the INI data to a string.
std::map< Entry, TKeyVal, typename Entry::KeyOrder > TSection
map sections to key/value map
bool IsLess(const SI_CHAR *a_pLeft, const SI_CHAR *a_pRight) const
Internal use of our string comparison function.
StringWriter & operator=(const StringWriter &)