Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / tools / source / generic / config.cxx
blobb2eb546c0ef75b3116f2ec390c77f2612c56b0e3
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 ImplKeyData* pKey;
209 ImplGroupData* pPrevGroup = nullptr;
210 ImplGroupData* pGroup = nullptr;
211 i = 0;
212 while ( i < nLen )
214 // Ctrl+Z
215 if ( pBuf[i] == 0x1A )
216 break;
218 // Remove spaces and tabs
219 while ( (pBuf[i] == ' ') || (pBuf[i] == '\t') )
220 i++;
222 // remember line-starts
223 nStart = i;
224 pLine = pBuf+i;
226 // search line-endings
227 while ( (i < nLen) && pBuf[i] && (pBuf[i] != '\r') && (pBuf[i] != '\n') &&
228 (pBuf[i] != 0x1A) )
229 i++;
231 nLineLen = i-nStart;
233 // if Line-ending is found, continue once
234 if ( (i+1 < nLen) &&
235 (pBuf[i] != pBuf[i+1]) &&
236 ((pBuf[i+1] == '\r') || (pBuf[i+1] == '\n')) )
237 i++;
238 i++;
240 // evaluate line
241 if ( *pLine == '[' )
243 pGroup = new ImplGroupData;
244 pGroup->mpNext = nullptr;
245 pGroup->mpFirstKey = nullptr;
246 pGroup->mnEmptyLines = 0;
247 if ( pPrevGroup )
248 pPrevGroup->mpNext = pGroup;
249 else
250 pData->mpFirstGroup = pGroup;
251 pPrevGroup = pGroup;
252 pPrevKey = nullptr;
253 pKey = nullptr;
255 // filter group names
256 pLine++;
257 nLineLen--;
258 // remove spaces and tabs
259 while ( (*pLine == ' ') || (*pLine == '\t') )
261 nLineLen--;
262 pLine++;
264 nNameLen = 0;
265 while ( (nNameLen < nLineLen) && (pLine[nNameLen] != ']') )
266 nNameLen++;
267 if ( nNameLen )
269 while ( (pLine[nNameLen-1] == ' ') || (pLine[nNameLen-1] == '\t') )
270 nNameLen--;
272 pGroup->maGroupName = makeOString(pLine, nNameLen);
274 else
276 if ( nLineLen )
278 // If no group exists yet, add to default
279 if ( !pGroup )
281 pGroup = new ImplGroupData;
282 pGroup->mpNext = nullptr;
283 pGroup->mpFirstKey = nullptr;
284 pGroup->mnEmptyLines = 0;
285 pData->mpFirstGroup = pGroup;
286 pPrevGroup = pGroup;
287 pPrevKey = nullptr;
290 // if empty line, append it
291 if ( pPrevKey )
293 while ( pGroup->mnEmptyLines )
295 pKey = new ImplKeyData;
296 pKey->mbIsComment = true;
297 pPrevKey->mpNext = pKey;
298 pPrevKey = pKey;
299 pGroup->mnEmptyLines--;
303 // Generate new key
304 pKey = new ImplKeyData;
305 pKey->mpNext = nullptr;
306 if ( pPrevKey )
307 pPrevKey->mpNext = pKey;
308 else
309 pGroup->mpFirstKey = pKey;
310 pPrevKey = pKey;
311 if ( pLine[0] == ';' )
313 pKey->maValue = makeOString(pLine, nLineLen);
314 pKey->mbIsComment = true;
316 else
318 pKey->mbIsComment = false;
319 nNameLen = 0;
320 while ( (nNameLen < nLineLen) && (pLine[nNameLen] != '=') )
321 nNameLen++;
322 nKeyLen = nNameLen;
323 // Remove spaces and tabs
324 if ( nNameLen )
326 while ( (pLine[nNameLen-1] == ' ') || (pLine[nNameLen-1] == '\t') )
327 nNameLen--;
329 pKey->maKey = makeOString(pLine, nNameLen);
330 nKeyLen++;
331 if ( nKeyLen < nLineLen )
333 pLine += nKeyLen;
334 nLineLen -= nKeyLen;
335 // Remove spaces and tabs
336 while ( (*pLine == ' ') || (*pLine == '\t') )
338 nLineLen--;
339 pLine++;
341 if ( nLineLen )
343 while ( (pLine[nLineLen-1] == ' ') || (pLine[nLineLen-1] == '\t') )
344 nLineLen--;
345 pKey->maValue = makeOString(pLine, nLineLen);
350 else
352 // Spaces are counted and appended only after key generation,
353 // as we want to store spaces even after adding new keys
354 if ( pGroup )
355 pGroup->mnEmptyLines++;
361 static std::unique_ptr<sal_uInt8[]> ImplGetConfigBuffer( const ImplConfigData* pData, sal_uInt32& rLen )
363 std::unique_ptr<sal_uInt8[]> pWriteBuf;
364 sal_uInt8* pBuf;
365 sal_uInt8 aLineEndBuf[2] = {0, 0};
366 ImplKeyData* pKey;
367 ImplGroupData* pGroup;
368 sal_uInt32 nBufLen;
369 sal_uInt32 nValueLen;
370 sal_uInt32 nKeyLen;
371 sal_uInt32 nLineEndLen;
373 aLineEndBuf[0] = '\r';
374 aLineEndBuf[1] = '\n';
375 nLineEndLen = 2;
377 nBufLen = 0;
378 pGroup = pData->mpFirstGroup;
379 while ( pGroup )
381 // Don't write empty groups
382 if ( pGroup->mpFirstKey )
384 nBufLen += pGroup->maGroupName.getLength() + nLineEndLen + 2;
385 pKey = pGroup->mpFirstKey;
386 while ( pKey )
388 nValueLen = pKey->maValue.getLength();
389 if ( pKey->mbIsComment )
390 nBufLen += nValueLen + nLineEndLen;
391 else
392 nBufLen += pKey->maKey.getLength() + nValueLen + nLineEndLen + 1;
394 pKey = pKey->mpNext;
397 // Write empty lines after each group
398 if ( !pGroup->mnEmptyLines )
399 pGroup->mnEmptyLines = 1;
400 nBufLen += nLineEndLen * pGroup->mnEmptyLines;
403 pGroup = pGroup->mpNext;
406 // Output buffer length
407 rLen = nBufLen;
408 if ( !nBufLen )
410 pWriteBuf.reset(new sal_uInt8[nLineEndLen]);
411 pWriteBuf[0] = aLineEndBuf[0];
412 if ( nLineEndLen == 2 )
413 pWriteBuf[1] = aLineEndBuf[1];
414 return pWriteBuf;
417 // Allocate new write buffer (caller frees it)
418 pWriteBuf.reset(new sal_uInt8[nBufLen]);
420 // fill buffer
421 pBuf = pWriteBuf.get();
422 pGroup = pData->mpFirstGroup;
423 while ( pGroup )
425 // Don't write empty groups
426 if ( pGroup->mpFirstKey )
428 *pBuf = '['; pBuf++;
429 memcpy( pBuf, pGroup->maGroupName.getStr(), pGroup->maGroupName.getLength() );
430 pBuf += pGroup->maGroupName.getLength();
431 *pBuf = ']'; pBuf++;
432 *pBuf = aLineEndBuf[0]; pBuf++;
433 if ( nLineEndLen == 2 )
435 *pBuf = aLineEndBuf[1]; pBuf++;
437 pKey = pGroup->mpFirstKey;
438 while ( pKey )
440 nValueLen = pKey->maValue.getLength();
441 if ( pKey->mbIsComment )
443 if ( nValueLen )
445 memcpy( pBuf, pKey->maValue.getStr(), nValueLen );
446 pBuf += nValueLen;
448 *pBuf = aLineEndBuf[0]; pBuf++;
449 if ( nLineEndLen == 2 )
451 *pBuf = aLineEndBuf[1]; pBuf++;
454 else
456 nKeyLen = pKey->maKey.getLength();
457 memcpy( pBuf, pKey->maKey.getStr(), nKeyLen );
458 pBuf += nKeyLen;
459 *pBuf = '='; pBuf++;
460 memcpy( pBuf, pKey->maValue.getStr(), nValueLen );
461 pBuf += nValueLen;
462 *pBuf = aLineEndBuf[0]; pBuf++;
463 if ( nLineEndLen == 2 )
465 *pBuf = aLineEndBuf[1]; pBuf++;
469 pKey = pKey->mpNext;
472 // Store empty line after each group
473 sal_uInt16 nEmptyLines = pGroup->mnEmptyLines;
474 while ( nEmptyLines )
476 *pBuf = aLineEndBuf[0]; pBuf++;
477 if ( nLineEndLen == 2 )
479 *pBuf = aLineEndBuf[1]; pBuf++;
481 nEmptyLines--;
485 pGroup = pGroup->mpNext;
488 return pWriteBuf;
491 static void ImplReadConfig( ImplConfigData* pData )
493 sal_uInt32 nTimeStamp = 0;
494 sal_uInt64 nRead = 0;
495 bool bRead = false;
496 bool bIsUTF8BOM = false;
497 std::unique_ptr<sal_uInt8[]> pBuf = ImplSysReadConfig( pData->maFileName, nRead, bRead, bIsUTF8BOM, nTimeStamp );
499 // Read config list from buffer
500 if ( pBuf )
502 ImplMakeConfigList( pData, pBuf.get(), nRead );
503 pBuf.reset();
505 pData->mnTimeStamp = nTimeStamp;
506 pData->mbModified = false;
507 if ( bRead )
508 pData->mbRead = true;
509 if ( bIsUTF8BOM )
510 pData->mbIsUTF8BOM = true;
513 static void ImplWriteConfig( ImplConfigData* pData )
515 SAL_WARN_IF( pData->mnTimeStamp != ImplSysGetConfigTimeStamp( pData->maFileName ),
516 "tools.generic", "Config overwrites modified configfile: " << pData->maFileName );
518 // Read config list from buffer
519 sal_uInt32 nBufLen;
520 std::unique_ptr<sal_uInt8[]> pBuf = ImplGetConfigBuffer( pData, nBufLen );
521 if ( pBuf )
523 if ( ImplSysWriteConfig( pData->maFileName, pBuf.get(), nBufLen, pData->mbIsUTF8BOM, pData->mnTimeStamp ) )
524 pData->mbModified = false;
526 else
527 pData->mbModified = false;
530 static void ImplDeleteConfigData( ImplConfigData* pData )
532 ImplKeyData* pTempKey;
533 ImplKeyData* pKey;
534 ImplGroupData* pTempGroup;
535 ImplGroupData* pGroup = pData->mpFirstGroup;
536 while ( pGroup )
538 pTempGroup = pGroup->mpNext;
540 // remove all keys
541 pKey = pGroup->mpFirstKey;
542 while ( pKey )
544 pTempKey = pKey->mpNext;
545 delete pKey;
546 pKey = pTempKey;
549 // remove group and continue
550 delete pGroup;
551 pGroup = pTempGroup;
554 pData->mpFirstGroup = nullptr;
557 static std::unique_ptr<ImplConfigData> ImplGetConfigData( const OUString& rFileName )
559 std::unique_ptr<ImplConfigData> pData(new ImplConfigData);
560 pData->maFileName = rFileName;
561 pData->mpFirstGroup = nullptr;
562 pData->mnDataUpdateId = 0;
563 pData->mbRead = false;
564 pData->mbIsUTF8BOM = false;
565 ImplReadConfig( pData.get() );
567 return pData;
570 bool Config::ImplUpdateConfig() const
572 // Re-read file if timestamp differs
573 if ( mpData->mnTimeStamp != ImplSysGetConfigTimeStamp( maFileName ) )
575 ImplDeleteConfigData( mpData.get() );
576 ImplReadConfig( mpData.get() );
577 mpData->mnDataUpdateId++;
578 return true;
580 else
581 return false;
584 ImplGroupData* Config::ImplGetGroup() const
586 if ( !mpActGroup || (mnDataUpdateId != mpData->mnDataUpdateId) )
588 ImplGroupData* pPrevGroup = nullptr;
589 ImplGroupData* pGroup = mpData->mpFirstGroup;
590 while ( pGroup )
592 if ( pGroup->maGroupName.equalsIgnoreAsciiCase(maGroupName) )
593 break;
595 pPrevGroup = pGroup;
596 pGroup = pGroup->mpNext;
599 // Add group if not exists
600 if ( !pGroup )
602 pGroup = new ImplGroupData;
603 pGroup->mpNext = nullptr;
604 pGroup->mpFirstKey = nullptr;
605 pGroup->mnEmptyLines = 1;
606 if ( pPrevGroup )
607 pPrevGroup->mpNext = pGroup;
608 else
609 mpData->mpFirstGroup = pGroup;
612 // Always inherit group names and update cache members
613 pGroup->maGroupName = maGroupName;
614 const_cast<Config*>(this)->mnDataUpdateId = mpData->mnDataUpdateId;
615 const_cast<Config*>(this)->mpActGroup = pGroup;
618 return mpActGroup;
621 Config::Config( const OUString& rFileName )
623 // Initialize config data
624 maFileName = toUncPath( rFileName );
625 mpData = ImplGetConfigData( maFileName );
626 mpActGroup = nullptr;
627 mnDataUpdateId = 0;
629 SAL_INFO("tools.generic", "Config::Config( " << maFileName << " )");
632 Config::~Config()
634 SAL_INFO("tools.generic", "Config::~Config()" );
636 Flush();
637 ImplDeleteConfigData( mpData.get() );
640 void Config::SetGroup(const OString& rGroup)
642 // If group is to be reset, it needs to be updated on next call
643 if ( maGroupName != rGroup )
645 maGroupName = rGroup;
646 mnDataUpdateId = mpData->mnDataUpdateId-1;
650 void Config::DeleteGroup(std::string_view rGroup)
652 // Update config data if necessary
653 if ( !mpData->mbRead )
655 ImplUpdateConfig();
656 mpData->mbRead = true;
659 ImplGroupData* pPrevGroup = nullptr;
660 ImplGroupData* pGroup = mpData->mpFirstGroup;
661 while ( pGroup )
663 if ( pGroup->maGroupName.equalsIgnoreAsciiCase(rGroup) )
664 break;
666 pPrevGroup = pGroup;
667 pGroup = pGroup->mpNext;
670 if ( !pGroup )
671 return;
673 // Remove all keys
674 ImplKeyData* pTempKey;
675 ImplKeyData* pKey = pGroup->mpFirstKey;
676 while ( pKey )
678 pTempKey = pKey->mpNext;
679 delete pKey;
680 pKey = pTempKey;
683 // Rewire pointers and remove group
684 if ( pPrevGroup )
685 pPrevGroup->mpNext = pGroup->mpNext;
686 else
687 mpData->mpFirstGroup = pGroup->mpNext;
688 delete pGroup;
690 // Rewrite config data
691 mpData->mbModified = true;
693 mnDataUpdateId = mpData->mnDataUpdateId;
694 mpData->mnDataUpdateId++;
697 OString Config::GetGroupName(sal_uInt16 nGroup) const
699 ImplGroupData* pGroup = mpData->mpFirstGroup;
700 sal_uInt16 nGroupCount = 0;
701 OString aGroupName;
702 while ( pGroup )
704 if ( nGroup == nGroupCount )
706 aGroupName = pGroup->maGroupName;
707 break;
710 nGroupCount++;
711 pGroup = pGroup->mpNext;
714 return aGroupName;
717 sal_uInt16 Config::GetGroupCount() const
719 ImplGroupData* pGroup = mpData->mpFirstGroup;
720 sal_uInt16 nGroupCount = 0;
721 while ( pGroup )
723 nGroupCount++;
724 pGroup = pGroup->mpNext;
727 return nGroupCount;
730 bool Config::HasGroup(std::string_view rGroup) const
732 ImplGroupData* pGroup = mpData->mpFirstGroup;
733 bool bRet = false;
735 while( pGroup )
737 if( pGroup->maGroupName.equalsIgnoreAsciiCase(rGroup) )
739 bRet = true;
740 break;
743 pGroup = pGroup->mpNext;
746 return bRet;
749 OString Config::ReadKey(const OString& rKey) const
751 return ReadKey(rKey, OString());
754 OString Config::ReadKey(const OString& rKey, const OString& rDefault) const
756 SAL_INFO("tools.generic", "Config::ReadKey( " << rKey << " ) from " << GetGroup()
757 << " in " << maFileName);
759 // Search key, return value if found
760 ImplGroupData* pGroup = ImplGetGroup();
761 if ( pGroup )
763 ImplKeyData* pKey = pGroup->mpFirstKey;
764 while ( pKey )
766 if ( !pKey->mbIsComment && pKey->maKey.equalsIgnoreAsciiCase(rKey) )
767 return pKey->maValue;
769 pKey = pKey->mpNext;
773 return rDefault;
776 void Config::WriteKey(const OString& rKey, const OString& rStr)
778 SAL_INFO("tools.generic", "Config::WriteKey( " << rKey << ", " << rStr << " ) to "
779 << GetGroup() << " in " << maFileName);
781 // Update config data if necessary
782 if ( !mpData->mbRead )
784 ImplUpdateConfig();
785 mpData->mbRead = true;
788 // Search key and update value if found
789 ImplGroupData* pGroup = ImplGetGroup();
790 if ( !pGroup )
791 return;
793 ImplKeyData* pPrevKey = nullptr;
794 ImplKeyData* pKey = pGroup->mpFirstKey;
795 while ( pKey )
797 if ( !pKey->mbIsComment && pKey->maKey.equalsIgnoreAsciiCase(rKey) )
798 break;
800 pPrevKey = pKey;
801 pKey = pKey->mpNext;
804 bool bNewValue;
805 if ( !pKey )
807 pKey = new ImplKeyData;
808 pKey->mpNext = nullptr;
809 pKey->maKey = rKey;
810 pKey->mbIsComment = false;
811 if ( pPrevKey )
812 pPrevKey->mpNext = pKey;
813 else
814 pGroup->mpFirstKey = pKey;
815 bNewValue = true;
817 else
818 bNewValue = pKey->maValue != rStr;
820 if ( bNewValue )
822 pKey->maValue = rStr;
824 mpData->mbModified = true;
828 void Config::DeleteKey(std::string_view rKey)
830 // Update config data if necessary
831 if ( !mpData->mbRead )
833 ImplUpdateConfig();
834 mpData->mbRead = true;
837 // Search key and update value
838 ImplGroupData* pGroup = ImplGetGroup();
839 if ( !pGroup )
840 return;
842 ImplKeyData* pPrevKey = nullptr;
843 ImplKeyData* pKey = pGroup->mpFirstKey;
844 while ( pKey )
846 if ( !pKey->mbIsComment && pKey->maKey.equalsIgnoreAsciiCase(rKey) )
847 break;
849 pPrevKey = pKey;
850 pKey = pKey->mpNext;
853 if ( pKey )
855 // Rewire group pointers and delete
856 if ( pPrevKey )
857 pPrevKey->mpNext = pKey->mpNext;
858 else
859 pGroup->mpFirstKey = pKey->mpNext;
860 delete pKey;
862 mpData->mbModified = true;
866 sal_uInt16 Config::GetKeyCount() const
868 SAL_INFO("tools.generic", "Config::GetKeyCount() from " << GetGroup() << " in " << maFileName);
870 // Search key and update value
871 sal_uInt16 nCount = 0;
872 ImplGroupData* pGroup = ImplGetGroup();
873 if ( pGroup )
875 ImplKeyData* pKey = pGroup->mpFirstKey;
876 while ( pKey )
878 if ( !pKey->mbIsComment )
879 nCount++;
881 pKey = pKey->mpNext;
885 return nCount;
888 OString Config::GetKeyName(sal_uInt16 nKey) const
890 SAL_INFO("tools.generic", "Config::GetKeyName( " << OString::number(static_cast<sal_Int32>(nKey))
891 << " ) from " << GetGroup() << " in " << maFileName);
893 // search key and return name if found
894 ImplGroupData* pGroup = ImplGetGroup();
895 if ( pGroup )
897 ImplKeyData* pKey = pGroup->mpFirstKey;
898 while ( pKey )
900 if ( !pKey->mbIsComment )
902 if ( !nKey )
903 return pKey->maKey;
904 nKey--;
907 pKey = pKey->mpNext;
911 return OString();
914 OString Config::ReadKey(sal_uInt16 nKey) const
916 SAL_INFO("tools.generic", "Config::ReadKey( " << OString::number(static_cast<sal_Int32>(nKey))
917 << " ) from " << GetGroup() << " in " << maFileName);
919 // Search key and return value if found
920 ImplGroupData* pGroup = ImplGetGroup();
921 if ( pGroup )
923 ImplKeyData* pKey = pGroup->mpFirstKey;
924 while ( pKey )
926 if ( !pKey->mbIsComment )
928 if ( !nKey )
929 return pKey->maValue;
930 nKey--;
933 pKey = pKey->mpNext;
937 return OString();
940 void Config::Flush()
942 if ( mpData->mbModified )
943 ImplWriteConfig( mpData.get() );
946 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */