cid#1607171 Data race condition
[LibreOffice.git] / tools / source / generic / config.cxx
blob9fa470b854ba77f0cdc4d0959fc37f95b554f246
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 namespace {
34 struct ImplKeyData
36 ImplKeyData* mpNext;
37 OString maKey;
38 OString maValue;
39 bool mbIsComment;
44 struct ImplGroupData
46 ImplGroupData* mpNext;
47 ImplKeyData* mpFirstKey;
48 OString maGroupName;
49 sal_uInt16 mnEmptyLines;
52 struct ImplConfigData
54 ImplGroupData* mpFirstGroup;
55 OUString maFileName;
56 sal_uInt32 mnDataUpdateId;
57 sal_uInt32 mnTimeStamp;
58 bool mbModified;
59 bool mbRead;
60 bool mbIsUTF8BOM;
63 static OUString toUncPath( const OUString& rPath )
65 OUString aFileURL;
67 // check if rFileName is already a URL; if not make it so
68 if( rPath.startsWith( "file://"))
70 aFileURL = rPath;
72 else if( ::osl::FileBase::getFileURLFromSystemPath( rPath, aFileURL ) != ::osl::FileBase::E_None )
74 aFileURL = rPath;
76 return aFileURL;
79 static sal_uInt32 ImplSysGetConfigTimeStamp( const OUString& rFileName )
81 sal_uInt32 nTimeStamp = 0;
82 ::osl::DirectoryItem aItem;
83 ::osl::FileStatus aStatus( osl_FileStatus_Mask_ModifyTime );
85 if( ::osl::DirectoryItem::get( rFileName, aItem ) == ::osl::FileBase::E_None &&
86 aItem.getFileStatus( aStatus ) == ::osl::FileBase::E_None )
88 nTimeStamp = aStatus.getModifyTime().Seconds;
91 return nTimeStamp;
94 static std::unique_ptr<sal_uInt8[]> ImplSysReadConfig( const OUString& rFileName,
95 sal_uInt64& rRead, bool& rbRead, bool& rbIsUTF8BOM, sal_uInt32& rTimeStamp )
97 std::unique_ptr<sal_uInt8[]> pBuf;
98 ::osl::File aFile( rFileName );
100 if( aFile.open( osl_File_OpenFlag_Read ) == ::osl::FileBase::E_None )
102 sal_uInt64 nPos = 0;
103 if( aFile.getSize( nPos ) == ::osl::FileBase::E_None )
105 if (nPos > SAL_MAX_SIZE) {
106 aFile.close();
107 return nullptr;
109 pBuf.reset(new sal_uInt8[static_cast< std::size_t >(nPos)]);
110 sal_uInt64 nRead = 0;
111 if( aFile.read( pBuf.get(), nPos, nRead ) == ::osl::FileBase::E_None && nRead == nPos )
113 //skip the byte-order-mark 0xEF 0xBB 0xBF, if it was UTF8 files
114 unsigned char const BOM[3] = {0xEF, 0xBB, 0xBF};
115 if (nRead > 2 && memcmp(pBuf.get(), BOM, 3) == 0)
117 nRead -= 3;
118 memmove(pBuf.get(), pBuf.get() + 3, sal::static_int_cast<std::size_t>(nRead * sizeof(sal_uInt8)) );
119 rbIsUTF8BOM = true;
122 rTimeStamp = ImplSysGetConfigTimeStamp( rFileName );
123 rbRead = true;
124 rRead = nRead;
126 else
128 pBuf.reset();
131 aFile.close();
134 return pBuf;
137 static bool ImplSysWriteConfig( const OUString& rFileName,
138 const sal_uInt8* pBuf, sal_uInt32 nBufLen, bool rbIsUTF8BOM, sal_uInt32& rTimeStamp )
140 bool bSuccess = false;
141 bool bUTF8BOMSuccess = false;
143 ::osl::File aFile( rFileName );
144 ::osl::FileBase::RC eError = aFile.open( osl_File_OpenFlag_Write | osl_File_OpenFlag_Create );
145 if( eError != ::osl::FileBase::E_None )
146 eError = aFile.open( osl_File_OpenFlag_Write );
147 if( eError == ::osl::FileBase::E_None )
149 // truncate
150 aFile.setSize( 0 );
151 sal_uInt64 nWritten;
153 //write the byte-order-mark 0xEF 0xBB 0xBF first , if it was UTF8 files
154 if ( rbIsUTF8BOM )
156 unsigned char const BOM[3] = {0xEF, 0xBB, 0xBF};
157 sal_uInt64 nUTF8BOMWritten;
158 if( aFile.write( BOM, 3, nUTF8BOMWritten ) == ::osl::FileBase::E_None && 3 == nUTF8BOMWritten )
160 bUTF8BOMSuccess = true;
164 if( aFile.write( pBuf, nBufLen, nWritten ) == ::osl::FileBase::E_None && nWritten == nBufLen )
166 bSuccess = true;
168 if ( rbIsUTF8BOM ? bSuccess && bUTF8BOMSuccess : bSuccess )
170 rTimeStamp = ImplSysGetConfigTimeStamp( rFileName );
174 return rbIsUTF8BOM ? bSuccess && bUTF8BOMSuccess : bSuccess;
177 namespace {
178 OString makeOString(const sal_uInt8* p, sal_uInt64 n)
180 if (n > SAL_MAX_INT32)
182 #ifdef _WIN32
183 abort();
184 #else
185 ::std::abort(); //TODO: handle this gracefully
186 #endif
188 return OString(
189 reinterpret_cast< char const * >(p),
190 sal::static_int_cast< sal_Int32 >(n));
194 static void ImplMakeConfigList( ImplConfigData* pData,
195 const sal_uInt8* pBuf, sal_uInt64 nLen )
197 if ( !nLen )
198 return;
200 // Parse buffer and build config list
201 sal_uInt64 nStart;
202 sal_uInt64 nLineLen;
203 sal_uInt64 nNameLen;
204 sal_uInt64 nKeyLen;
205 sal_uInt64 i;
206 const sal_uInt8* pLine;
207 ImplKeyData* pPrevKey = nullptr;
208 ImplGroupData* pPrevGroup = nullptr;
209 ImplGroupData* pGroup = nullptr;
210 i = 0;
211 while ( i < nLen )
213 // Ctrl+Z
214 if ( pBuf[i] == 0x1A )
215 break;
217 // Remove spaces and tabs
218 while ( (pBuf[i] == ' ') || (pBuf[i] == '\t') )
219 i++;
221 // remember line-starts
222 nStart = i;
223 pLine = pBuf+i;
225 // search line-endings
226 while ( (i < nLen) && pBuf[i] && (pBuf[i] != '\r') && (pBuf[i] != '\n') &&
227 (pBuf[i] != 0x1A) )
228 i++;
230 nLineLen = i-nStart;
232 // if Line-ending is found, continue once
233 if ( (i+1 < nLen) &&
234 (pBuf[i] != pBuf[i+1]) &&
235 ((pBuf[i+1] == '\r') || (pBuf[i+1] == '\n')) )
236 i++;
237 i++;
239 // evaluate line
240 if ( *pLine == '[' )
242 pGroup = new ImplGroupData;
243 pGroup->mpNext = nullptr;
244 pGroup->mpFirstKey = nullptr;
245 pGroup->mnEmptyLines = 0;
246 if ( pPrevGroup )
247 pPrevGroup->mpNext = pGroup;
248 else
249 pData->mpFirstGroup = pGroup;
250 pPrevGroup = pGroup;
251 pPrevKey = nullptr;
253 // filter group names
254 pLine++;
255 assert(nLineLen > 0);
256 nLineLen--;
257 // remove spaces and tabs
258 while ( nLineLen > 0 && (*pLine == ' ' || *pLine == '\t') )
260 nLineLen--;
261 pLine++;
263 nNameLen = 0;
264 while ( (nNameLen < nLineLen) && (pLine[nNameLen] != ']') )
265 nNameLen++;
266 while ( nNameLen > 0 && (pLine[nNameLen-1] == ' ' || pLine[nNameLen-1] == '\t') )
267 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 ImplKeyData* pKey = new ImplKeyData;
292 pKey->mbIsComment = true;
293 pPrevKey->mpNext = pKey;
294 pPrevKey = pKey;
295 pGroup->mnEmptyLines--;
299 // Generate new key
300 ImplKeyData* 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 while ( nNameLen > 0 && (pLine[nNameLen-1] == ' ' || pLine[nNameLen-1] == '\t') )
321 nNameLen--;
322 pKey->maKey = makeOString(pLine, nNameLen);
323 nKeyLen++;
324 if ( nKeyLen < nLineLen )
326 pLine += nKeyLen;
327 nLineLen -= nKeyLen;
328 // Remove spaces and tabs
329 while ( (*pLine == ' ') || (*pLine == '\t') )
331 nLineLen--;
332 pLine++;
334 if ( nLineLen )
336 while ( (pLine[nLineLen-1] == ' ') || (pLine[nLineLen-1] == '\t') )
337 nLineLen--;
338 pKey->maValue = makeOString(pLine, nLineLen);
343 else
345 // Spaces are counted and appended only after key generation,
346 // as we want to store spaces even after adding new keys
347 if ( pGroup )
348 pGroup->mnEmptyLines++;
354 static std::unique_ptr<sal_uInt8[]> ImplGetConfigBuffer( const ImplConfigData* pData, sal_uInt32& rLen )
356 std::unique_ptr<sal_uInt8[]> pWriteBuf;
357 sal_uInt8* pBuf;
358 sal_uInt8 aLineEndBuf[2] = {0, 0};
359 ImplKeyData* pKey;
360 ImplGroupData* pGroup;
361 sal_uInt32 nBufLen;
362 sal_uInt32 nValueLen;
363 sal_uInt32 nKeyLen;
364 sal_uInt32 nLineEndLen;
366 aLineEndBuf[0] = '\r';
367 aLineEndBuf[1] = '\n';
368 nLineEndLen = 2;
370 nBufLen = 0;
371 pGroup = pData->mpFirstGroup;
372 while ( pGroup )
374 // Don't write empty groups
375 if ( pGroup->mpFirstKey )
377 nBufLen += pGroup->maGroupName.getLength() + nLineEndLen + 2;
378 pKey = pGroup->mpFirstKey;
379 while ( pKey )
381 nValueLen = pKey->maValue.getLength();
382 if ( pKey->mbIsComment )
383 nBufLen += nValueLen + nLineEndLen;
384 else
385 nBufLen += pKey->maKey.getLength() + nValueLen + nLineEndLen + 1;
387 pKey = pKey->mpNext;
390 // Write empty lines after each group
391 if ( !pGroup->mnEmptyLines )
392 pGroup->mnEmptyLines = 1;
393 nBufLen += nLineEndLen * pGroup->mnEmptyLines;
396 pGroup = pGroup->mpNext;
399 // Output buffer length
400 rLen = nBufLen;
401 if ( !nBufLen )
403 pWriteBuf.reset(new sal_uInt8[nLineEndLen]);
404 pWriteBuf[0] = aLineEndBuf[0];
405 if ( nLineEndLen == 2 )
406 pWriteBuf[1] = aLineEndBuf[1];
407 return pWriteBuf;
410 // Allocate new write buffer (caller frees it)
411 pWriteBuf.reset(new sal_uInt8[nBufLen]);
413 // fill buffer
414 pBuf = pWriteBuf.get();
415 pGroup = pData->mpFirstGroup;
416 while ( pGroup )
418 // Don't write empty groups
419 if ( pGroup->mpFirstKey )
421 *pBuf = '['; pBuf++;
422 memcpy( pBuf, pGroup->maGroupName.getStr(), pGroup->maGroupName.getLength() );
423 pBuf += pGroup->maGroupName.getLength();
424 *pBuf = ']'; pBuf++;
425 *pBuf = aLineEndBuf[0]; pBuf++;
426 if ( nLineEndLen == 2 )
428 *pBuf = aLineEndBuf[1]; pBuf++;
430 pKey = pGroup->mpFirstKey;
431 while ( pKey )
433 nValueLen = pKey->maValue.getLength();
434 if ( pKey->mbIsComment )
436 if ( nValueLen )
438 memcpy( pBuf, pKey->maValue.getStr(), nValueLen );
439 pBuf += nValueLen;
441 *pBuf = aLineEndBuf[0]; pBuf++;
442 if ( nLineEndLen == 2 )
444 *pBuf = aLineEndBuf[1]; pBuf++;
447 else
449 nKeyLen = pKey->maKey.getLength();
450 memcpy( pBuf, pKey->maKey.getStr(), nKeyLen );
451 pBuf += nKeyLen;
452 *pBuf = '='; pBuf++;
453 memcpy( pBuf, pKey->maValue.getStr(), nValueLen );
454 pBuf += nValueLen;
455 *pBuf = aLineEndBuf[0]; pBuf++;
456 if ( nLineEndLen == 2 )
458 *pBuf = aLineEndBuf[1]; pBuf++;
462 pKey = pKey->mpNext;
465 // Store empty line after each group
466 sal_uInt16 nEmptyLines = pGroup->mnEmptyLines;
467 while ( nEmptyLines )
469 *pBuf = aLineEndBuf[0]; pBuf++;
470 if ( nLineEndLen == 2 )
472 *pBuf = aLineEndBuf[1]; pBuf++;
474 nEmptyLines--;
478 pGroup = pGroup->mpNext;
481 return pWriteBuf;
484 static void ImplReadConfig( ImplConfigData* pData )
486 sal_uInt32 nTimeStamp = 0;
487 sal_uInt64 nRead = 0;
488 bool bRead = false;
489 bool bIsUTF8BOM = false;
490 std::unique_ptr<sal_uInt8[]> pBuf = ImplSysReadConfig( pData->maFileName, nRead, bRead, bIsUTF8BOM, nTimeStamp );
492 // Read config list from buffer
493 if ( pBuf )
495 ImplMakeConfigList( pData, pBuf.get(), nRead );
496 pBuf.reset();
498 pData->mnTimeStamp = nTimeStamp;
499 pData->mbModified = false;
500 if ( bRead )
501 pData->mbRead = true;
502 if ( bIsUTF8BOM )
503 pData->mbIsUTF8BOM = true;
506 static void ImplWriteConfig( ImplConfigData* pData )
508 SAL_WARN_IF( pData->mnTimeStamp != ImplSysGetConfigTimeStamp( pData->maFileName ),
509 "tools.generic", "Config overwrites modified configfile: " << pData->maFileName );
511 // Read config list from buffer
512 sal_uInt32 nBufLen;
513 std::unique_ptr<sal_uInt8[]> pBuf = ImplGetConfigBuffer( pData, nBufLen );
514 if ( pBuf )
516 if ( ImplSysWriteConfig( pData->maFileName, pBuf.get(), nBufLen, pData->mbIsUTF8BOM, pData->mnTimeStamp ) )
517 pData->mbModified = false;
519 else
520 pData->mbModified = false;
523 static void ImplDeleteConfigData( ImplConfigData* pData )
525 ImplKeyData* pTempKey;
526 ImplKeyData* pKey;
527 ImplGroupData* pTempGroup;
528 ImplGroupData* pGroup = pData->mpFirstGroup;
529 while ( pGroup )
531 pTempGroup = pGroup->mpNext;
533 // remove all keys
534 pKey = pGroup->mpFirstKey;
535 while ( pKey )
537 pTempKey = pKey->mpNext;
538 delete pKey;
539 pKey = pTempKey;
542 // remove group and continue
543 delete pGroup;
544 pGroup = pTempGroup;
547 pData->mpFirstGroup = nullptr;
550 static std::unique_ptr<ImplConfigData> ImplGetConfigData( const OUString& rFileName )
552 std::unique_ptr<ImplConfigData> pData(new ImplConfigData);
553 pData->maFileName = rFileName;
554 pData->mpFirstGroup = nullptr;
555 pData->mnDataUpdateId = 0;
556 pData->mbRead = false;
557 pData->mbIsUTF8BOM = false;
558 ImplReadConfig( pData.get() );
560 return pData;
563 bool Config::ImplUpdateConfig() const
565 // Re-read file if timestamp differs
566 if ( mpData->mnTimeStamp != ImplSysGetConfigTimeStamp( maFileName ) )
568 ImplDeleteConfigData( mpData.get() );
569 ImplReadConfig( mpData.get() );
570 mpData->mnDataUpdateId++;
571 return true;
573 else
574 return false;
577 ImplGroupData* Config::ImplGetGroup() const
579 if ( !mpActGroup || (mnDataUpdateId != mpData->mnDataUpdateId) )
581 ImplGroupData* pPrevGroup = nullptr;
582 ImplGroupData* pGroup = mpData->mpFirstGroup;
583 while ( pGroup )
585 if ( pGroup->maGroupName.equalsIgnoreAsciiCase(maGroupName) )
586 break;
588 pPrevGroup = pGroup;
589 pGroup = pGroup->mpNext;
592 // Add group if not exists
593 if ( !pGroup )
595 pGroup = new ImplGroupData;
596 pGroup->mpNext = nullptr;
597 pGroup->mpFirstKey = nullptr;
598 pGroup->mnEmptyLines = 1;
599 if ( pPrevGroup )
600 pPrevGroup->mpNext = pGroup;
601 else
602 mpData->mpFirstGroup = pGroup;
605 // Always inherit group names and update cache members
606 pGroup->maGroupName = maGroupName;
607 const_cast<Config*>(this)->mnDataUpdateId = mpData->mnDataUpdateId;
608 const_cast<Config*>(this)->mpActGroup = pGroup;
611 return mpActGroup;
614 Config::Config( const OUString& rFileName )
616 // Initialize config data
617 maFileName = toUncPath( rFileName );
618 mpData = ImplGetConfigData( maFileName );
619 mpActGroup = nullptr;
620 mnDataUpdateId = 0;
622 SAL_INFO("tools.generic", "Config::Config( " << maFileName << " )");
625 Config::~Config()
627 SAL_INFO("tools.generic", "Config::~Config()" );
629 Flush();
630 ImplDeleteConfigData( mpData.get() );
633 void Config::SetGroup(const OString& rGroup)
635 // If group is to be reset, it needs to be updated on next call
636 if ( maGroupName != rGroup )
638 maGroupName = rGroup;
639 mnDataUpdateId = mpData->mnDataUpdateId-1;
643 void Config::DeleteGroup(std::string_view rGroup)
645 // Update config data if necessary
646 if ( !mpData->mbRead )
648 ImplUpdateConfig();
649 mpData->mbRead = true;
652 ImplGroupData* pPrevGroup = nullptr;
653 ImplGroupData* pGroup = mpData->mpFirstGroup;
654 while ( pGroup )
656 if ( pGroup->maGroupName.equalsIgnoreAsciiCase(rGroup) )
657 break;
659 pPrevGroup = pGroup;
660 pGroup = pGroup->mpNext;
663 if ( !pGroup )
664 return;
666 // Remove all keys
667 ImplKeyData* pTempKey;
668 ImplKeyData* pKey = pGroup->mpFirstKey;
669 while ( pKey )
671 pTempKey = pKey->mpNext;
672 delete pKey;
673 pKey = pTempKey;
676 // Rewire pointers and remove group
677 if ( pPrevGroup )
678 pPrevGroup->mpNext = pGroup->mpNext;
679 else
680 mpData->mpFirstGroup = pGroup->mpNext;
681 delete pGroup;
683 // Rewrite config data
684 mpData->mbModified = true;
686 mnDataUpdateId = mpData->mnDataUpdateId;
687 mpData->mnDataUpdateId++;
690 OString Config::GetGroupName(sal_uInt16 nGroup) const
692 ImplGroupData* pGroup = mpData->mpFirstGroup;
693 sal_uInt16 nGroupCount = 0;
694 OString aGroupName;
695 while ( pGroup )
697 if ( nGroup == nGroupCount )
699 aGroupName = pGroup->maGroupName;
700 break;
703 nGroupCount++;
704 pGroup = pGroup->mpNext;
707 return aGroupName;
710 sal_uInt16 Config::GetGroupCount() const
712 ImplGroupData* pGroup = mpData->mpFirstGroup;
713 sal_uInt16 nGroupCount = 0;
714 while ( pGroup )
716 nGroupCount++;
717 pGroup = pGroup->mpNext;
720 return nGroupCount;
723 bool Config::HasGroup(std::string_view rGroup) const
725 ImplGroupData* pGroup = mpData->mpFirstGroup;
726 bool bRet = false;
728 while( pGroup )
730 if( pGroup->maGroupName.equalsIgnoreAsciiCase(rGroup) )
732 bRet = true;
733 break;
736 pGroup = pGroup->mpNext;
739 return bRet;
742 OString Config::ReadKey(const OString& rKey) const
744 return ReadKey(rKey, OString());
747 OString Config::ReadKey(const OString& rKey, const OString& rDefault) const
749 SAL_INFO("tools.generic", "Config::ReadKey( " << rKey << " ) from " << GetGroup()
750 << " in " << maFileName);
752 // Search key, return value if found
753 ImplGroupData* pGroup = ImplGetGroup();
754 if ( pGroup )
756 ImplKeyData* pKey = pGroup->mpFirstKey;
757 while ( pKey )
759 if ( !pKey->mbIsComment && pKey->maKey.equalsIgnoreAsciiCase(rKey) )
760 return pKey->maValue;
762 pKey = pKey->mpNext;
766 return rDefault;
769 void Config::WriteKey(const OString& rKey, const OString& rStr)
771 SAL_INFO("tools.generic", "Config::WriteKey( " << rKey << ", " << rStr << " ) to "
772 << GetGroup() << " in " << maFileName);
774 // Update config data if necessary
775 if ( !mpData->mbRead )
777 ImplUpdateConfig();
778 mpData->mbRead = true;
781 // Search key and update value if found
782 ImplGroupData* pGroup = ImplGetGroup();
783 if ( !pGroup )
784 return;
786 ImplKeyData* pPrevKey = nullptr;
787 ImplKeyData* pKey = pGroup->mpFirstKey;
788 while ( pKey )
790 if ( !pKey->mbIsComment && pKey->maKey.equalsIgnoreAsciiCase(rKey) )
791 break;
793 pPrevKey = pKey;
794 pKey = pKey->mpNext;
797 bool bNewValue;
798 if ( !pKey )
800 pKey = new ImplKeyData;
801 pKey->mpNext = nullptr;
802 pKey->maKey = rKey;
803 pKey->mbIsComment = false;
804 if ( pPrevKey )
805 pPrevKey->mpNext = pKey;
806 else
807 pGroup->mpFirstKey = pKey;
808 bNewValue = true;
810 else
811 bNewValue = pKey->maValue != rStr;
813 if ( bNewValue )
815 pKey->maValue = rStr;
817 mpData->mbModified = true;
821 void Config::DeleteKey(std::string_view rKey)
823 // Update config data if necessary
824 if ( !mpData->mbRead )
826 ImplUpdateConfig();
827 mpData->mbRead = true;
830 // Search key and update value
831 ImplGroupData* pGroup = ImplGetGroup();
832 if ( !pGroup )
833 return;
835 ImplKeyData* pPrevKey = nullptr;
836 ImplKeyData* pKey = pGroup->mpFirstKey;
837 while ( pKey )
839 if ( !pKey->mbIsComment && pKey->maKey.equalsIgnoreAsciiCase(rKey) )
840 break;
842 pPrevKey = pKey;
843 pKey = pKey->mpNext;
846 if ( pKey )
848 // Rewire group pointers and delete
849 if ( pPrevKey )
850 pPrevKey->mpNext = pKey->mpNext;
851 else
852 pGroup->mpFirstKey = pKey->mpNext;
853 delete pKey;
855 mpData->mbModified = true;
859 sal_uInt16 Config::GetKeyCount() const
861 SAL_INFO("tools.generic", "Config::GetKeyCount() from " << GetGroup() << " in " << maFileName);
863 // Search key and update value
864 sal_uInt16 nCount = 0;
865 ImplGroupData* pGroup = ImplGetGroup();
866 if ( pGroup )
868 ImplKeyData* pKey = pGroup->mpFirstKey;
869 while ( pKey )
871 if ( !pKey->mbIsComment )
872 nCount++;
874 pKey = pKey->mpNext;
878 return nCount;
881 OString Config::GetKeyName(sal_uInt16 nKey) const
883 SAL_INFO("tools.generic", "Config::GetKeyName( " << OString::number(static_cast<sal_Int32>(nKey))
884 << " ) from " << GetGroup() << " in " << maFileName);
886 // search key and return name if found
887 ImplGroupData* pGroup = ImplGetGroup();
888 if ( pGroup )
890 ImplKeyData* pKey = pGroup->mpFirstKey;
891 while ( pKey )
893 if ( !pKey->mbIsComment )
895 if ( !nKey )
896 return pKey->maKey;
897 nKey--;
900 pKey = pKey->mpNext;
904 return OString();
907 OString Config::ReadKey(sal_uInt16 nKey) const
909 SAL_INFO("tools.generic", "Config::ReadKey( " << OString::number(static_cast<sal_Int32>(nKey))
910 << " ) from " << GetGroup() << " in " << maFileName);
912 // Search key and return value if found
913 ImplGroupData* pGroup = ImplGetGroup();
914 if ( pGroup )
916 ImplKeyData* pKey = pGroup->mpFirstKey;
917 while ( pKey )
919 if ( !pKey->mbIsComment )
921 if ( !nKey )
922 return pKey->maValue;
923 nKey--;
926 pKey = pKey->mpNext;
930 return OString();
933 void Config::Flush()
935 if ( mpData->mbModified )
936 ImplWriteConfig( mpData.get() );
939 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */