Bump version to 6.4-15
[LibreOffice.git] / tools / source / generic / config.cxx
blobfe760decf852ecd9831cc1a8cbe2c6c25862400e
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <cstddef>
21 #include <cstdlib>
22 #include <string.h>
24 #ifdef _WIN32
25 #include <stdlib.h>
26 #endif
28 #include <osl/file.hxx>
29 #include <tools/config.hxx>
30 #include <sal/log.hxx>
32 struct ImplKeyData
34 ImplKeyData* mpNext;
35 OString maKey;
36 OString maValue;
37 bool mbIsComment;
40 struct ImplGroupData
42 ImplGroupData* mpNext;
43 ImplKeyData* mpFirstKey;
44 OString maGroupName;
45 sal_uInt16 mnEmptyLines;
48 struct ImplConfigData
50 ImplGroupData* mpFirstGroup;
51 OUString maFileName;
52 sal_uInt32 mnDataUpdateId;
53 sal_uInt32 mnTimeStamp;
54 bool mbModified;
55 bool mbRead;
56 bool mbIsUTF8BOM;
59 static OUString toUncPath( const OUString& rPath )
61 OUString aFileURL;
63 // check if rFileName is already a URL; if not make it so
64 if( rPath.startsWith( "file://"))
66 aFileURL = rPath;
68 else if( ::osl::FileBase::getFileURLFromSystemPath( rPath, aFileURL ) != ::osl::FileBase::E_None )
70 aFileURL = rPath;
72 return aFileURL;
75 static sal_uInt32 ImplSysGetConfigTimeStamp( const OUString& rFileName )
77 sal_uInt32 nTimeStamp = 0;
78 ::osl::DirectoryItem aItem;
79 ::osl::FileStatus aStatus( osl_FileStatus_Mask_ModifyTime );
81 if( ::osl::DirectoryItem::get( rFileName, aItem ) == ::osl::FileBase::E_None &&
82 aItem.getFileStatus( aStatus ) == ::osl::FileBase::E_None )
84 nTimeStamp = aStatus.getModifyTime().Seconds;
87 return nTimeStamp;
90 static std::unique_ptr<sal_uInt8[]> ImplSysReadConfig( const OUString& rFileName,
91 sal_uInt64& rRead, bool& rbRead, bool& rbIsUTF8BOM, sal_uInt32& rTimeStamp )
93 std::unique_ptr<sal_uInt8[]> pBuf;
94 ::osl::File aFile( rFileName );
96 if( aFile.open( osl_File_OpenFlag_Read ) == ::osl::FileBase::E_None )
98 sal_uInt64 nPos = 0;
99 if( aFile.getSize( nPos ) == ::osl::FileBase::E_None )
101 if (nPos > SAL_MAX_SIZE) {
102 aFile.close();
103 return nullptr;
105 pBuf.reset(new sal_uInt8[static_cast< std::size_t >(nPos)]);
106 sal_uInt64 nRead = 0;
107 if( aFile.read( pBuf.get(), nPos, nRead ) == ::osl::FileBase::E_None && nRead == nPos )
109 //skip the byte-order-mark 0xEF 0xBB 0xBF, if it was UTF8 files
110 unsigned char const BOM[3] = {0xEF, 0xBB, 0xBF};
111 if (nRead > 2 && memcmp(pBuf.get(), BOM, 3) == 0)
113 nRead -= 3;
114 memmove(pBuf.get(), pBuf.get() + 3, sal::static_int_cast<std::size_t>(nRead * sizeof(sal_uInt8)) );
115 rbIsUTF8BOM = true;
118 rTimeStamp = ImplSysGetConfigTimeStamp( rFileName );
119 rbRead = true;
120 rRead = nRead;
122 else
124 pBuf.reset();
127 aFile.close();
130 return pBuf;
133 static bool ImplSysWriteConfig( const OUString& rFileName,
134 const sal_uInt8* pBuf, sal_uInt32 nBufLen, bool rbIsUTF8BOM, sal_uInt32& rTimeStamp )
136 bool bSuccess = false;
137 bool bUTF8BOMSuccess = false;
139 ::osl::File aFile( rFileName );
140 ::osl::FileBase::RC eError = aFile.open( osl_File_OpenFlag_Write | osl_File_OpenFlag_Create );
141 if( eError != ::osl::FileBase::E_None )
142 eError = aFile.open( osl_File_OpenFlag_Write );
143 if( eError == ::osl::FileBase::E_None )
145 // truncate
146 aFile.setSize( 0 );
147 sal_uInt64 nWritten;
149 //write the byte-order-mark 0xEF 0xBB 0xBF first , if it was UTF8 files
150 if ( rbIsUTF8BOM )
152 unsigned char const BOM[3] = {0xEF, 0xBB, 0xBF};
153 sal_uInt64 nUTF8BOMWritten;
154 if( aFile.write( BOM, 3, nUTF8BOMWritten ) == ::osl::FileBase::E_None && 3 == nUTF8BOMWritten )
156 bUTF8BOMSuccess = true;
160 if( aFile.write( pBuf, nBufLen, nWritten ) == ::osl::FileBase::E_None && nWritten == nBufLen )
162 bSuccess = true;
164 if ( rbIsUTF8BOM ? bSuccess && bUTF8BOMSuccess : bSuccess )
166 rTimeStamp = ImplSysGetConfigTimeStamp( rFileName );
170 return rbIsUTF8BOM ? bSuccess && bUTF8BOMSuccess : bSuccess;
173 namespace {
174 OString makeOString(const sal_uInt8* p, sal_uInt64 n)
176 if (n > SAL_MAX_INT32)
178 #ifdef _WIN32
179 abort();
180 #else
181 ::std::abort(); //TODO: handle this gracefully
182 #endif
184 return OString(
185 reinterpret_cast< char const * >(p),
186 sal::static_int_cast< sal_Int32 >(n));
190 static void ImplMakeConfigList( ImplConfigData* pData,
191 const sal_uInt8* pBuf, sal_uInt64 nLen )
193 if ( !nLen )
194 return;
196 // Parse buffer and build config list
197 sal_uInt64 nStart;
198 sal_uInt64 nLineLen;
199 sal_uInt64 nNameLen;
200 sal_uInt64 nKeyLen;
201 sal_uInt64 i;
202 const sal_uInt8* pLine;
203 ImplKeyData* pPrevKey = nullptr;
204 ImplKeyData* pKey;
205 ImplGroupData* pPrevGroup = nullptr;
206 ImplGroupData* pGroup = nullptr;
207 i = 0;
208 while ( i < nLen )
210 // Ctrl+Z
211 if ( pBuf[i] == 0x1A )
212 break;
214 // Remove spaces and tabs
215 while ( (pBuf[i] == ' ') || (pBuf[i] == '\t') )
216 i++;
218 // remember line-starts
219 nStart = i;
220 pLine = pBuf+i;
222 // search line-endings
223 while ( (i < nLen) && pBuf[i] && (pBuf[i] != '\r') && (pBuf[i] != '\n') &&
224 (pBuf[i] != 0x1A) )
225 i++;
227 nLineLen = i-nStart;
229 // if Line-ending is found, continue once
230 if ( (i+1 < nLen) &&
231 (pBuf[i] != pBuf[i+1]) &&
232 ((pBuf[i+1] == '\r') || (pBuf[i+1] == '\n')) )
233 i++;
234 i++;
236 // evaluate line
237 if ( *pLine == '[' )
239 pGroup = new ImplGroupData;
240 pGroup->mpNext = nullptr;
241 pGroup->mpFirstKey = nullptr;
242 pGroup->mnEmptyLines = 0;
243 if ( pPrevGroup )
244 pPrevGroup->mpNext = pGroup;
245 else
246 pData->mpFirstGroup = pGroup;
247 pPrevGroup = pGroup;
248 pPrevKey = nullptr;
249 pKey = nullptr;
251 // filter group names
252 pLine++;
253 nLineLen--;
254 // remove spaces and tabs
255 while ( (*pLine == ' ') || (*pLine == '\t') )
257 nLineLen--;
258 pLine++;
260 nNameLen = 0;
261 while ( (nNameLen < nLineLen) && (pLine[nNameLen] != ']') )
262 nNameLen++;
263 if ( nNameLen )
265 while ( (pLine[nNameLen-1] == ' ') || (pLine[nNameLen-1] == '\t') )
266 nNameLen--;
268 pGroup->maGroupName = makeOString(pLine, nNameLen);
270 else
272 if ( nLineLen )
274 // If no group exists yet, add to default
275 if ( !pGroup )
277 pGroup = new ImplGroupData;
278 pGroup->mpNext = nullptr;
279 pGroup->mpFirstKey = nullptr;
280 pGroup->mnEmptyLines = 0;
281 pData->mpFirstGroup = pGroup;
282 pPrevGroup = pGroup;
283 pPrevKey = nullptr;
286 // if empty line, append it
287 if ( pPrevKey )
289 while ( pGroup->mnEmptyLines )
291 pKey = new ImplKeyData;
292 pKey->mbIsComment = true;
293 pPrevKey->mpNext = pKey;
294 pPrevKey = pKey;
295 pGroup->mnEmptyLines--;
299 // Generate new key
300 pKey = new ImplKeyData;
301 pKey->mpNext = nullptr;
302 if ( pPrevKey )
303 pPrevKey->mpNext = pKey;
304 else
305 pGroup->mpFirstKey = pKey;
306 pPrevKey = pKey;
307 if ( pLine[0] == ';' )
309 pKey->maValue = makeOString(pLine, nLineLen);
310 pKey->mbIsComment = true;
312 else
314 pKey->mbIsComment = false;
315 nNameLen = 0;
316 while ( (nNameLen < nLineLen) && (pLine[nNameLen] != '=') )
317 nNameLen++;
318 nKeyLen = nNameLen;
319 // Remove spaces and tabs
320 if ( nNameLen )
322 while ( (pLine[nNameLen-1] == ' ') || (pLine[nNameLen-1] == '\t') )
323 nNameLen--;
325 pKey->maKey = makeOString(pLine, nNameLen);
326 nKeyLen++;
327 if ( nKeyLen < nLineLen )
329 pLine += nKeyLen;
330 nLineLen -= nKeyLen;
331 // Remove spaces and tabs
332 while ( (*pLine == ' ') || (*pLine == '\t') )
334 nLineLen--;
335 pLine++;
337 if ( nLineLen )
339 while ( (pLine[nLineLen-1] == ' ') || (pLine[nLineLen-1] == '\t') )
340 nLineLen--;
341 pKey->maValue = makeOString(pLine, nLineLen);
346 else
348 // Spaces are counted and appended only after key generation,
349 // as we want to store spaces even after adding new keys
350 if ( pGroup )
351 pGroup->mnEmptyLines++;
357 static std::unique_ptr<sal_uInt8[]> ImplGetConfigBuffer( const ImplConfigData* pData, sal_uInt32& rLen )
359 std::unique_ptr<sal_uInt8[]> pWriteBuf;
360 sal_uInt8* pBuf;
361 sal_uInt8 aLineEndBuf[2] = {0, 0};
362 ImplKeyData* pKey;
363 ImplGroupData* pGroup;
364 sal_uInt32 nBufLen;
365 sal_uInt32 nValueLen;
366 sal_uInt32 nKeyLen;
367 sal_uInt32 nLineEndLen;
369 aLineEndBuf[0] = '\r';
370 aLineEndBuf[1] = '\n';
371 nLineEndLen = 2;
373 nBufLen = 0;
374 pGroup = pData->mpFirstGroup;
375 while ( pGroup )
377 // Don't write empty groups
378 if ( pGroup->mpFirstKey )
380 nBufLen += pGroup->maGroupName.getLength() + nLineEndLen + 2;
381 pKey = pGroup->mpFirstKey;
382 while ( pKey )
384 nValueLen = pKey->maValue.getLength();
385 if ( pKey->mbIsComment )
386 nBufLen += nValueLen + nLineEndLen;
387 else
388 nBufLen += pKey->maKey.getLength() + nValueLen + nLineEndLen + 1;
390 pKey = pKey->mpNext;
393 // Write empty lines after each group
394 if ( !pGroup->mnEmptyLines )
395 pGroup->mnEmptyLines = 1;
396 nBufLen += nLineEndLen * pGroup->mnEmptyLines;
399 pGroup = pGroup->mpNext;
402 // Output buffer length
403 rLen = nBufLen;
404 if ( !nBufLen )
406 pWriteBuf.reset(new sal_uInt8[nLineEndLen]);
407 pWriteBuf[0] = aLineEndBuf[0];
408 if ( nLineEndLen == 2 )
409 pWriteBuf[1] = aLineEndBuf[1];
410 return pWriteBuf;
413 // Allocate new write buffer (caller frees it)
414 pWriteBuf.reset(new sal_uInt8[nBufLen]);
416 // fill buffer
417 pBuf = pWriteBuf.get();
418 pGroup = pData->mpFirstGroup;
419 while ( pGroup )
421 // Don't write empty groups
422 if ( pGroup->mpFirstKey )
424 *pBuf = '['; pBuf++;
425 memcpy( pBuf, pGroup->maGroupName.getStr(), pGroup->maGroupName.getLength() );
426 pBuf += pGroup->maGroupName.getLength();
427 *pBuf = ']'; pBuf++;
428 *pBuf = aLineEndBuf[0]; pBuf++;
429 if ( nLineEndLen == 2 )
431 *pBuf = aLineEndBuf[1]; pBuf++;
433 pKey = pGroup->mpFirstKey;
434 while ( pKey )
436 nValueLen = pKey->maValue.getLength();
437 if ( pKey->mbIsComment )
439 if ( nValueLen )
441 memcpy( pBuf, pKey->maValue.getStr(), nValueLen );
442 pBuf += nValueLen;
444 *pBuf = aLineEndBuf[0]; pBuf++;
445 if ( nLineEndLen == 2 )
447 *pBuf = aLineEndBuf[1]; pBuf++;
450 else
452 nKeyLen = pKey->maKey.getLength();
453 memcpy( pBuf, pKey->maKey.getStr(), nKeyLen );
454 pBuf += nKeyLen;
455 *pBuf = '='; pBuf++;
456 memcpy( pBuf, pKey->maValue.getStr(), nValueLen );
457 pBuf += nValueLen;
458 *pBuf = aLineEndBuf[0]; pBuf++;
459 if ( nLineEndLen == 2 )
461 *pBuf = aLineEndBuf[1]; pBuf++;
465 pKey = pKey->mpNext;
468 // Store empty line after each group
469 sal_uInt16 nEmptyLines = pGroup->mnEmptyLines;
470 while ( nEmptyLines )
472 *pBuf = aLineEndBuf[0]; pBuf++;
473 if ( nLineEndLen == 2 )
475 *pBuf = aLineEndBuf[1]; pBuf++;
477 nEmptyLines--;
481 pGroup = pGroup->mpNext;
484 return pWriteBuf;
487 static void ImplReadConfig( ImplConfigData* pData )
489 sal_uInt32 nTimeStamp = 0;
490 sal_uInt64 nRead = 0;
491 bool bRead = false;
492 bool bIsUTF8BOM = false;
493 std::unique_ptr<sal_uInt8[]> pBuf = ImplSysReadConfig( pData->maFileName, nRead, bRead, bIsUTF8BOM, nTimeStamp );
495 // Read config list from buffer
496 if ( pBuf )
498 ImplMakeConfigList( pData, pBuf.get(), nRead );
499 pBuf.reset();
501 pData->mnTimeStamp = nTimeStamp;
502 pData->mbModified = false;
503 if ( bRead )
504 pData->mbRead = true;
505 if ( bIsUTF8BOM )
506 pData->mbIsUTF8BOM = true;
509 static void ImplWriteConfig( ImplConfigData* pData )
511 SAL_WARN_IF( pData->mnTimeStamp != ImplSysGetConfigTimeStamp( pData->maFileName ),
512 "tools.generic", "Config overwrites modified configfile: " << pData->maFileName );
514 // Read config list from buffer
515 sal_uInt32 nBufLen;
516 std::unique_ptr<sal_uInt8[]> pBuf = ImplGetConfigBuffer( pData, nBufLen );
517 if ( pBuf )
519 if ( ImplSysWriteConfig( pData->maFileName, pBuf.get(), nBufLen, pData->mbIsUTF8BOM, pData->mnTimeStamp ) )
520 pData->mbModified = false;
522 else
523 pData->mbModified = false;
526 static void ImplDeleteConfigData( ImplConfigData* pData )
528 ImplKeyData* pTempKey;
529 ImplKeyData* pKey;
530 ImplGroupData* pTempGroup;
531 ImplGroupData* pGroup = pData->mpFirstGroup;
532 while ( pGroup )
534 pTempGroup = pGroup->mpNext;
536 // remove all keys
537 pKey = pGroup->mpFirstKey;
538 while ( pKey )
540 pTempKey = pKey->mpNext;
541 delete pKey;
542 pKey = pTempKey;
545 // remove group and continue
546 delete pGroup;
547 pGroup = pTempGroup;
550 pData->mpFirstGroup = nullptr;
553 static std::unique_ptr<ImplConfigData> ImplGetConfigData( const OUString& rFileName )
555 std::unique_ptr<ImplConfigData> pData(new ImplConfigData);
556 pData->maFileName = rFileName;
557 pData->mpFirstGroup = nullptr;
558 pData->mnDataUpdateId = 0;
559 pData->mbRead = false;
560 pData->mbIsUTF8BOM = false;
561 ImplReadConfig( pData.get() );
563 return pData;
566 bool Config::ImplUpdateConfig() const
568 // Re-read file if timestamp differs
569 if ( mpData->mnTimeStamp != ImplSysGetConfigTimeStamp( maFileName ) )
571 ImplDeleteConfigData( mpData.get() );
572 ImplReadConfig( mpData.get() );
573 mpData->mnDataUpdateId++;
574 return true;
576 else
577 return false;
580 ImplGroupData* Config::ImplGetGroup() const
582 if ( !mpActGroup || (mnDataUpdateId != mpData->mnDataUpdateId) )
584 ImplGroupData* pPrevGroup = nullptr;
585 ImplGroupData* pGroup = mpData->mpFirstGroup;
586 while ( pGroup )
588 if ( pGroup->maGroupName.equalsIgnoreAsciiCase(maGroupName) )
589 break;
591 pPrevGroup = pGroup;
592 pGroup = pGroup->mpNext;
595 // Add group if not exists
596 if ( !pGroup )
598 pGroup = new ImplGroupData;
599 pGroup->mpNext = nullptr;
600 pGroup->mpFirstKey = nullptr;
601 pGroup->mnEmptyLines = 1;
602 if ( pPrevGroup )
603 pPrevGroup->mpNext = pGroup;
604 else
605 mpData->mpFirstGroup = pGroup;
608 // Always inherit group names and update cache members
609 pGroup->maGroupName = maGroupName;
610 const_cast<Config*>(this)->mnDataUpdateId = mpData->mnDataUpdateId;
611 const_cast<Config*>(this)->mpActGroup = pGroup;
614 return mpActGroup;
617 Config::Config( const OUString& rFileName )
619 // Initialize config data
620 maFileName = toUncPath( rFileName );
621 mpData = ImplGetConfigData( maFileName );
622 mpActGroup = nullptr;
623 mnDataUpdateId = 0;
625 SAL_INFO("tools.generic", "Config::Config( " << maFileName << " )");
628 Config::~Config()
630 SAL_INFO("tools.generic", "Config::~Config()" );
632 Flush();
633 ImplDeleteConfigData( mpData.get() );
636 void Config::SetGroup(const OString& rGroup)
638 // If group is to be reset, it needs to be updated on next call
639 if ( maGroupName != rGroup )
641 maGroupName = rGroup;
642 mnDataUpdateId = mpData->mnDataUpdateId-1;
646 void Config::DeleteGroup(const OString& rGroup)
648 // Update config data if necessary
649 if ( !mpData->mbRead )
651 ImplUpdateConfig();
652 mpData->mbRead = true;
655 ImplGroupData* pPrevGroup = nullptr;
656 ImplGroupData* pGroup = mpData->mpFirstGroup;
657 while ( pGroup )
659 if ( pGroup->maGroupName.equalsIgnoreAsciiCase(rGroup) )
660 break;
662 pPrevGroup = pGroup;
663 pGroup = pGroup->mpNext;
666 if ( pGroup )
668 // Remove all keys
669 ImplKeyData* pTempKey;
670 ImplKeyData* pKey = pGroup->mpFirstKey;
671 while ( pKey )
673 pTempKey = pKey->mpNext;
674 delete pKey;
675 pKey = pTempKey;
678 // Rewire pointers and remove group
679 if ( pPrevGroup )
680 pPrevGroup->mpNext = pGroup->mpNext;
681 else
682 mpData->mpFirstGroup = pGroup->mpNext;
683 delete pGroup;
685 // Rewrite config data
686 mpData->mbModified = true;
688 mnDataUpdateId = mpData->mnDataUpdateId;
689 mpData->mnDataUpdateId++;
693 OString Config::GetGroupName(sal_uInt16 nGroup) const
695 ImplGroupData* pGroup = mpData->mpFirstGroup;
696 sal_uInt16 nGroupCount = 0;
697 OString aGroupName;
698 while ( pGroup )
700 if ( nGroup == nGroupCount )
702 aGroupName = pGroup->maGroupName;
703 break;
706 nGroupCount++;
707 pGroup = pGroup->mpNext;
710 return aGroupName;
713 sal_uInt16 Config::GetGroupCount() const
715 ImplGroupData* pGroup = mpData->mpFirstGroup;
716 sal_uInt16 nGroupCount = 0;
717 while ( pGroup )
719 nGroupCount++;
720 pGroup = pGroup->mpNext;
723 return nGroupCount;
726 bool Config::HasGroup(const OString& rGroup) const
728 ImplGroupData* pGroup = mpData->mpFirstGroup;
729 bool bRet = false;
731 while( pGroup )
733 if( pGroup->maGroupName.equalsIgnoreAsciiCase(rGroup) )
735 bRet = true;
736 break;
739 pGroup = pGroup->mpNext;
742 return bRet;
745 OString Config::ReadKey(const OString& rKey) const
747 return ReadKey(rKey, OString());
750 OString Config::ReadKey(const OString& rKey, const OString& rDefault) const
752 SAL_INFO("tools.generic", "Config::ReadKey( " << rKey << " ) from " << GetGroup()
753 << " in " << maFileName);
755 // Search key, return value if found
756 ImplGroupData* pGroup = ImplGetGroup();
757 if ( pGroup )
759 ImplKeyData* pKey = pGroup->mpFirstKey;
760 while ( pKey )
762 if ( !pKey->mbIsComment && pKey->maKey.equalsIgnoreAsciiCase(rKey) )
763 return pKey->maValue;
765 pKey = pKey->mpNext;
769 return rDefault;
772 void Config::WriteKey(const OString& rKey, const OString& rStr)
774 SAL_INFO("tools.generic", "Config::WriteKey( " << rKey << ", " << rStr << " ) to "
775 << GetGroup() << " in " << maFileName);
777 // Update config data if necessary
778 if ( !mpData->mbRead )
780 ImplUpdateConfig();
781 mpData->mbRead = true;
784 // Search key and update value if found
785 ImplGroupData* pGroup = ImplGetGroup();
786 if ( pGroup )
788 ImplKeyData* pPrevKey = nullptr;
789 ImplKeyData* pKey = pGroup->mpFirstKey;
790 while ( pKey )
792 if ( !pKey->mbIsComment && pKey->maKey.equalsIgnoreAsciiCase(rKey) )
793 break;
795 pPrevKey = pKey;
796 pKey = pKey->mpNext;
799 bool bNewValue;
800 if ( !pKey )
802 pKey = new ImplKeyData;
803 pKey->mpNext = nullptr;
804 pKey->maKey = rKey;
805 pKey->mbIsComment = false;
806 if ( pPrevKey )
807 pPrevKey->mpNext = pKey;
808 else
809 pGroup->mpFirstKey = pKey;
810 bNewValue = true;
812 else
813 bNewValue = pKey->maValue != rStr;
815 if ( bNewValue )
817 pKey->maValue = rStr;
819 mpData->mbModified = true;
824 void Config::DeleteKey(const OString& rKey)
826 // Update config data if necessary
827 if ( !mpData->mbRead )
829 ImplUpdateConfig();
830 mpData->mbRead = true;
833 // Search key and update value
834 ImplGroupData* pGroup = ImplGetGroup();
835 if ( pGroup )
837 ImplKeyData* pPrevKey = nullptr;
838 ImplKeyData* pKey = pGroup->mpFirstKey;
839 while ( pKey )
841 if ( !pKey->mbIsComment && pKey->maKey.equalsIgnoreAsciiCase(rKey) )
842 break;
844 pPrevKey = pKey;
845 pKey = pKey->mpNext;
848 if ( pKey )
850 // Rewire group pointers and delete
851 if ( pPrevKey )
852 pPrevKey->mpNext = pKey->mpNext;
853 else
854 pGroup->mpFirstKey = pKey->mpNext;
855 delete pKey;
857 mpData->mbModified = true;
862 sal_uInt16 Config::GetKeyCount() const
864 SAL_INFO("tools.generic", "Config::GetKeyCount() from " << GetGroup() << " in " << maFileName);
866 // Search key and update value
867 sal_uInt16 nCount = 0;
868 ImplGroupData* pGroup = ImplGetGroup();
869 if ( pGroup )
871 ImplKeyData* pKey = pGroup->mpFirstKey;
872 while ( pKey )
874 if ( !pKey->mbIsComment )
875 nCount++;
877 pKey = pKey->mpNext;
881 return nCount;
884 OString Config::GetKeyName(sal_uInt16 nKey) const
886 SAL_INFO("tools.generic", "Config::GetKeyName( " << OString::number(static_cast<sal_Int32>(nKey))
887 << " ) from " << GetGroup() << " in " << maFileName);
889 // search key and return name if found
890 ImplGroupData* pGroup = ImplGetGroup();
891 if ( pGroup )
893 ImplKeyData* pKey = pGroup->mpFirstKey;
894 while ( pKey )
896 if ( !pKey->mbIsComment )
898 if ( !nKey )
899 return pKey->maKey;
900 nKey--;
903 pKey = pKey->mpNext;
907 return OString();
910 OString Config::ReadKey(sal_uInt16 nKey) const
912 SAL_INFO("tools.generic", "Config::ReadKey( " << OString::number(static_cast<sal_Int32>(nKey))
913 << " ) from " << GetGroup() << " in " << maFileName);
915 // Search key and return value if found
916 ImplGroupData* pGroup = ImplGetGroup();
917 if ( pGroup )
919 ImplKeyData* pKey = pGroup->mpFirstKey;
920 while ( pKey )
922 if ( !pKey->mbIsComment )
924 if ( !nKey )
925 return pKey->maValue;
926 nKey--;
929 pKey = pKey->mpNext;
933 return OString();
936 void Config::Flush()
938 if ( mpData->mbModified )
939 ImplWriteConfig( mpData.get() );
942 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */