?? simpleini.h
字號:
return true;
}
++a_pData;
}
// check for suffix
if (IsSpace(*--a_pData)) {
return true;
}
return false;
}
template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
bool
CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::IsNewLineChar(
SI_CHAR a_c
) const
{
return (a_c == '\n' || a_c == '\r');
}
template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
bool
CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::LoadMultiLineText(
SI_CHAR *& a_pData,
const SI_CHAR *& a_pVal,
const SI_CHAR * a_pTagName,
bool a_bAllowBlankLinesInComment
) const
{
// we modify this data to strip all newlines down to a single '\n'
// character. This means that on Windows we need to strip out some
// characters which will make the data shorter.
// i.e. LINE1-LINE1\r\nLINE2-LINE2\0 will become
// LINE1-LINE1\nLINE2-LINE2\0
// The pDataLine entry is the pointer to the location in memory that
// the current line needs to start to run following the existing one.
// This may be the same as pCurrLine in which case no move is needed.
SI_CHAR * pDataLine = a_pData;
SI_CHAR * pCurrLine;
// value starts at the current line
a_pVal = a_pData;
// find the end tag. This tag must start in column 1 and be
// followed by a newline. No whitespace removal is done while
// searching for this tag.
SI_CHAR cEndOfLineChar = *a_pData;
for(;;) {
// if we are loading comments then we need a comment character as
// the first character on every line
if (!a_pTagName && !IsComment(*a_pData)) {
// if we aren't allowing blank lines then we're done
if (!a_bAllowBlankLinesInComment) {
break;
}
// if we are allowing blank lines then we only include them
// in this comment if another comment follows, so read ahead
// to find out.
SI_CHAR * pCurr = a_pData;
int nNewLines = 0;
while (IsSpace(*pCurr)) {
if (IsNewLineChar(*pCurr)) {
++nNewLines;
SkipNewLine(pCurr);
}
else {
++pCurr;
}
}
// we have a comment, add the blank lines to the output
// and continue processing from here
if (IsComment(*pCurr)) {
for (; nNewLines > 0; --nNewLines) *pDataLine++ = '\n';
a_pData = pCurr;
continue;
}
// the comment ends here
break;
}
// find the end of this line
pCurrLine = a_pData;
while (*a_pData && !IsNewLineChar(*a_pData)) ++a_pData;
// move this line down to the location that it should be if necessary
if (pDataLine < pCurrLine) {
size_t nLen = (size_t) (a_pData - pCurrLine);
memmove(pDataLine, pCurrLine, nLen * sizeof(SI_CHAR));
pDataLine[nLen] = '\0';
}
// end the line with a NULL
cEndOfLineChar = *a_pData;
*a_pData = 0;
// if are looking for a tag then do the check now. This is done before
// checking for end of the data, so that if we have the tag at the end
// of the data then the tag is removed correctly.
if (a_pTagName &&
(!IsLess(pDataLine, a_pTagName) && !IsLess(a_pTagName, pDataLine)))
{
break;
}
// if we are at the end of the data then we just automatically end
// this entry and return the current data.
if (!cEndOfLineChar) {
return true;
}
// otherwise we need to process this newline to ensure that it consists
// of just a single \n character.
pDataLine += (a_pData - pCurrLine);
*a_pData = cEndOfLineChar;
SkipNewLine(a_pData);
*pDataLine++ = '\n';
}
// if we didn't find a comment at all then return false
if (a_pVal == a_pData) {
a_pVal = NULL;
return false;
}
// the data (which ends at the end of the last line) needs to be
// null-terminated BEFORE before the newline character(s). If the
// user wants a new line in the multi-line data then they need to
// add an empty line before the tag.
*--pDataLine = '\0';
// if looking for a tag and if we aren't at the end of the data,
// then move a_pData to the start of the next line.
if (a_pTagName && cEndOfLineChar) {
SI_ASSERT(IsNewLineChar(cEndOfLineChar));
*a_pData = cEndOfLineChar;
SkipNewLine(a_pData);
}
return true;
}
template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
SI_Error
CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::CopyString(
const SI_CHAR *& a_pString
)
{
size_t uLen = 0;
if (sizeof(SI_CHAR) == sizeof(char)) {
uLen = strlen((const char *)a_pString);
}
else if (sizeof(SI_CHAR) == sizeof(wchar_t)) {
uLen = wcslen((const wchar_t *)a_pString);
}
else {
for ( ; a_pString[uLen]; ++uLen) /*loop*/ ;
}
++uLen; // NULL character
SI_CHAR * pCopy = new SI_CHAR[uLen];
if (!pCopy) {
return SI_NOMEM;
}
memcpy(pCopy, a_pString, sizeof(SI_CHAR)*uLen);
m_strings.push_back(pCopy);
a_pString = pCopy;
return SI_OK;
}
template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
SI_Error
CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::AddEntry(
const SI_CHAR * a_pSection,
const SI_CHAR * a_pKey,
const SI_CHAR * a_pValue,
const SI_CHAR * a_pComment,
bool a_bCopyStrings
)
{
SI_Error rc;
bool bInserted = false;
SI_ASSERT(!a_pComment || IsComment(*a_pComment));
// if we are copying strings then make a copy of the comment now
// because we will need it when we add the entry.
if (a_bCopyStrings && a_pComment) {
rc = CopyString(a_pComment);
if (rc < 0) return rc;
}
// check for existence of the section first if we need string copies
typename TSection::iterator iSection = m_data.end();
if (a_bCopyStrings) {
iSection = m_data.find(a_pSection);
if (iSection == m_data.end()) {
// if the section doesn't exist then we need a copy as the
// string needs to last beyond the end of this function
// because we will be inserting the section next
rc = CopyString(a_pSection);
if (rc < 0) return rc;
}
}
// create the section entry
if (iSection == m_data.end()) {
Entry oKey(a_pSection, ++m_nOrder);
if (a_pComment && (!a_pKey || !a_pValue)) {
oKey.pComment = a_pComment;
}
typename TSection::value_type oEntry(oKey, TKeyVal());
typedef typename TSection::iterator SectionIterator;
std::pair<SectionIterator,bool> i =
m_data.insert(oEntry);
iSection = i.first;
bInserted = true;
}
if (!a_pKey || !a_pValue) {
// section only entries are specified with pItem and pVal as NULL
return bInserted ? SI_INSERTED : SI_UPDATED;
}
// check for existence of the key
TKeyVal & keyval = iSection->second;
typename TKeyVal::iterator iKey = keyval.find(a_pKey);
// make string copies if necessary
if (a_bCopyStrings) {
if (m_bAllowMultiKey || iKey == keyval.end()) {
// if the key doesn't exist then we need a copy as the
// string needs to last beyond the end of this function
// because we will be inserting the key next
rc = CopyString(a_pKey);
if (rc < 0) return rc;
}
// we always need a copy of the value
rc = CopyString(a_pValue);
if (rc < 0) return rc;
}
// create the key entry
if (iKey == keyval.end() || m_bAllowMultiKey) {
Entry oKey(a_pKey, ++m_nOrder);
if (a_pComment) {
oKey.pComment = a_pComment;
}
typename TKeyVal::value_type oEntry(oKey, NULL);
iKey = keyval.insert(oEntry);
bInserted = true;
}
iKey->second = a_pValue;
return bInserted ? SI_INSERTED : SI_UPDATED;
}
template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
const SI_CHAR *
CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::GetValue(
const SI_CHAR * a_pSection,
const SI_CHAR * a_pKey,
const SI_CHAR * a_pDefault,
bool * a_pHasMultiple
) const
{
if (a_pHasMultiple) {
*a_pHasMultiple = false;
}
if (!a_pSection || !a_pKey) {
return a_pDefault;
}
typename TSection::const_iterator iSection = m_data.find(a_pSection);
if (iSection == m_data.end()) {
return a_pDefault;
}
typename TKeyVal::const_iterator iKeyVal = iSection->second.find(a_pKey);
if (iKeyVal == iSection->second.end()) {
return a_pDefault;
}
// check for multiple entries with the same key
if (m_bAllowMultiKey && a_pHasMultiple) {
typename TKeyVal::const_iterator iTemp = iKeyVal;
if (++iTemp != iSection->second.end()) {
if (!IsLess(a_pKey, iTemp->first.pItem)) {
*a_pHasMultiple = true;
}
}
}
return iKeyVal->second;
}
template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
bool
CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::GetAllValues(
const SI_CHAR * a_pSection,
const SI_CHAR * a_pKey,
TNamesDepend & a_values
) const
{
if (!a_pSection || !a_pKey) {
return false;
}
typename TSection::const_iterator iSection = m_data.find(a_pSection);
if (iSection == m_data.end()) {
return false;
}
typename TKeyVal::const_iterator iKeyVal = iSection->second.find(a_pKey);
if (iKeyVal == iSection->second.end()) {
return false;
}
// insert all values for this key
a_values.push_back(iKeyVal->second);
if (m_bAllowMultiKey) {
++iKeyVal;
while (iKeyVal != iSection->second.end() && !IsLess(a_pKey, iKeyVal->first.pItem)) {
a_values.push_back(Entry(iKeyVal->second, iKeyVal->first.nOrder));
++iKeyVal;
}
}
return true;
}
template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
int
CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::GetSectionSize(
const SI_CHAR * a_pSection
) const
{
if (!a_pSection) {
return -1;
}
typename TSection::const_iterator iSection = m_data.find(a_pSection);
if (iSection == m_data.end()) {
return -1;
}
const TKeyVal & section = iSection->second;
// if multi-key isn't permitted then the section size is
// the number of keys that we have.
if (!m_bAllowMultiKey || section.empty()) {
return (int) section.size();
}
// otherwise we need to count them
int nCount = 0;
const SI_CHAR * pLastKey = NULL;
typename TKeyVal::const_iterator iKeyVal = section.begin();
for (int n = 0; iKeyVal != section.end(); ++iKeyVal, ++n) {
if (!pLastKey || IsLess(pLastKey, iKeyVal->first.pItem)) {
++nCount;
pLastKey = iKeyVal->first.pItem;
}
}
return nCount;
}
template<class SI_CHAR, class
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -