lok: vcl: fix multiple floatwin removal case more robustly.
[LibreOffice.git] / sal / osl / unx / profile.cxx
bloba986dfd0d41f1fba049e2f3dd6cc88a117884513
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 "system.hxx"
21 #include "readwrite_helper.hxx"
22 #include "file_url.hxx"
23 #include "unixerrnostring.hxx"
25 #include <osl/diagnose.h>
26 #include <osl/profile.h>
27 #include <osl/process.h>
28 #include <osl/thread.h>
29 #include <rtl/alloc.h>
30 #include <sal/log.hxx>
32 #define LINES_INI 32
33 #define LINES_ADD 10
34 #define SECTIONS_INI 5
35 #define SECTIONS_ADD 3
36 #define ENTRIES_INI 5
37 #define ENTRIES_ADD 3
39 #define STR_INI_BOOLYES "yes"
40 #define STR_INI_BOOLON "on"
41 #define STR_INI_BOOLONE "1"
42 #define STR_INI_BOOLNO "no"
43 #define STR_INI_BOOLOFF "off"
44 #define STR_INI_BOOLZERO "0"
46 #define FLG_USER 0x00FF
47 #define FLG_AUTOOPEN 0x0100
48 #define FLG_MODIFIED 0x0200
50 #define DEFAULT_PMODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
52 typedef time_t osl_TStamp;
54 enum osl_TLockMode
56 un_lock, read_lock, write_lock
59 struct osl_TFile
61 int m_Handle;
62 sal_Char* m_pReadPtr;
63 sal_Char m_ReadBuf[512];
64 sal_Char* m_pWriteBuf;
65 sal_uInt32 m_nWriteBufLen;
66 sal_uInt32 m_nWriteBufFree;
69 struct osl_TProfileEntry
71 sal_uInt32 m_Line;
72 sal_uInt32 m_Offset;
73 sal_uInt32 m_Len;
76 struct osl_TProfileSection
78 sal_uInt32 m_Line;
79 sal_uInt32 m_Offset;
80 sal_uInt32 m_Len;
81 sal_uInt32 m_NoEntries;
82 sal_uInt32 m_MaxEntries;
83 osl_TProfileEntry* m_Entries;
86 /* Profile-data structure hidden behind oslProfile: */
87 struct osl_TProfileImpl
89 sal_uInt32 m_Flags;
90 osl_TFile* m_pFile;
91 osl_TStamp m_Stamp;
92 sal_Char m_FileName[PATH_MAX + 1];
93 sal_uInt32 m_NoLines;
94 sal_uInt32 m_MaxLines;
95 sal_uInt32 m_NoSections;
96 sal_uInt32 m_MaxSections;
97 sal_Char** m_Lines;
98 osl_TProfileSection* m_Sections;
99 pthread_mutex_t m_AccessLock;
100 bool m_bIsValid;
103 static osl_TFile* openFileImpl(const sal_Char* pszFilename, oslProfileOption ProfileFlags);
104 static osl_TStamp closeFileImpl(osl_TFile* pFile, oslProfileOption Flags);
105 static bool OslProfile_lockFile(const osl_TFile* pFile, osl_TLockMode eMode);
106 static bool OslProfile_rewindFile(osl_TFile* pFile, bool bTruncate);
107 static osl_TStamp OslProfile_getFileStamp(osl_TFile* pFile);
109 static sal_Char* OslProfile_getLine(osl_TFile* pFile);
110 static bool OslProfile_putLine(osl_TFile* pFile, const sal_Char *pszLine);
111 static sal_Char* stripBlanks(sal_Char* String, sal_uInt32* pLen);
112 static sal_Char* addLine(osl_TProfileImpl* pProfile, const sal_Char* Line);
113 static sal_Char* insertLine(osl_TProfileImpl* pProfile, const sal_Char* Line, sal_uInt32 LineNo);
114 static void removeLine(osl_TProfileImpl* pProfile, sal_uInt32 LineNo);
115 static void setEntry(osl_TProfileImpl* pProfile, osl_TProfileSection* pSection,
116 sal_uInt32 NoEntry, sal_uInt32 Line,
117 sal_Char* Entry, sal_uInt32 Len);
118 static bool addEntry(osl_TProfileImpl* pProfile, osl_TProfileSection *pSection,
119 int Line, sal_Char* Entry, sal_uInt32 Len);
120 static void removeEntry(osl_TProfileSection *pSection, sal_uInt32 NoEntry);
121 static bool addSection(osl_TProfileImpl* pProfile, int Line, const sal_Char* Section, sal_uInt32 Len);
122 static void removeSection(osl_TProfileImpl* pProfile, osl_TProfileSection *pSection);
123 static osl_TProfileSection* findEntry(osl_TProfileImpl* pProfile, const sal_Char* Section,
124 const sal_Char* Entry, sal_uInt32 *pNoEntry);
125 static bool loadProfile(osl_TFile* pFile, osl_TProfileImpl* pProfile);
126 static bool storeProfile(osl_TProfileImpl* pProfile, bool bCleanup);
127 static osl_TProfileImpl* acquireProfile(oslProfile Profile, bool bWriteable);
128 static bool releaseProfile(osl_TProfileImpl* pProfile);
130 static bool writeProfileImpl (osl_TFile* pFile);
131 static osl_TFile* osl_openTmpProfileImpl(osl_TProfileImpl*);
132 static bool osl_ProfileSwapProfileNames(osl_TProfileImpl*);
133 static void osl_ProfileGenerateExtension(const sal_Char* pszFileName, const sal_Char* pszExtension, sal_Char* pszTmpName, int BufferMaxLen);
134 static oslProfile osl_psz_openProfile(const sal_Char *pszProfileName, oslProfileOption Flags);
136 oslProfile SAL_CALL osl_openProfile(rtl_uString *ustrProfileName, oslProfileOption Options)
138 char profilePath[PATH_MAX] = "";
139 return
140 (ustrProfileName == nullptr
141 || ustrProfileName->buffer[0] == 0
142 || (FileURLToPath(profilePath, PATH_MAX, ustrProfileName)
143 == osl_File_E_None))
144 ? osl_psz_openProfile(profilePath, Options)
145 : nullptr;
148 static oslProfile osl_psz_openProfile(const sal_Char *pszProfileName, oslProfileOption Flags)
150 osl_TFile* pFile;
151 osl_TProfileImpl* pProfile;
152 bool bRet = false;
154 if ( ( pFile = openFileImpl(pszProfileName, Flags ) ) == nullptr )
156 return nullptr;
159 pProfile = static_cast<osl_TProfileImpl*>(calloc(1, sizeof(osl_TProfileImpl)));
161 if ( pProfile == nullptr )
163 closeFileImpl(pFile, Flags);
164 return nullptr;
167 pProfile->m_Flags = Flags & FLG_USER;
169 if ( Flags & ( osl_Profile_READLOCK | osl_Profile_WRITELOCK | osl_Profile_FLUSHWRITE ) )
171 pProfile->m_pFile = pFile;
174 pthread_mutex_init(&(pProfile->m_AccessLock),PTHREAD_MUTEXATTR_DEFAULT);
175 pProfile->m_bIsValid = true;
177 pProfile->m_Stamp = OslProfile_getFileStamp(pFile);
178 bRet=loadProfile(pFile, pProfile);
179 bRet &= realpath(pszProfileName, pProfile->m_FileName) != nullptr;
180 SAL_WARN_IF(!bRet, "sal.osl", "realpath(pszProfileName, pProfile->m_FileName) != NULL ==> false");
182 if (pProfile->m_pFile == nullptr)
183 closeFileImpl(pFile,pProfile->m_Flags);
185 // coverity[leaked_storage] - pFile is not leaked
186 return pProfile;
189 sal_Bool SAL_CALL osl_closeProfile(oslProfile Profile)
191 osl_TProfileImpl* pProfile = static_cast<osl_TProfileImpl*>(Profile);
192 osl_TProfileImpl* pTmpProfile;
194 if ( Profile == nullptr )
196 return false;
199 pthread_mutex_lock(&(pProfile->m_AccessLock));
201 if ( !pProfile->m_bIsValid )
203 SAL_WARN("sal.osl", "!pProfile->m_bIsValid");
204 pthread_mutex_unlock(&(pProfile->m_AccessLock));
206 return false;
209 pProfile->m_bIsValid = false;
211 if ( ! ( pProfile->m_Flags & osl_Profile_READLOCK ) && ( pProfile->m_Flags & FLG_MODIFIED ) )
213 pTmpProfile = acquireProfile(Profile, true);
215 if ( pTmpProfile != nullptr )
217 bool bRet = storeProfile(pTmpProfile, true);
218 SAL_WARN_IF(!bRet, "sal.osl", "storeProfile(pTmpProfile, true) ==> false");
221 else
223 pTmpProfile = acquireProfile(Profile, false);
226 if ( pTmpProfile == nullptr )
228 pthread_mutex_unlock(&(pProfile->m_AccessLock));
230 SAL_INFO("sal.osl", "Out osl_closeProfile [pProfile==0]");
231 return false;
234 pProfile = pTmpProfile;
236 if (pProfile->m_pFile != nullptr)
237 closeFileImpl(pProfile->m_pFile,pProfile->m_Flags);
239 pProfile->m_pFile = nullptr;
240 pProfile->m_FileName[0] = '\0';
242 /* release whole profile data types memory */
243 if ( pProfile->m_NoLines > 0)
245 unsigned int idx=0;
246 if ( pProfile->m_Lines != nullptr )
248 for ( idx = 0 ; idx < pProfile->m_NoLines ; ++idx)
250 if ( pProfile->m_Lines[idx] != nullptr )
252 free(pProfile->m_Lines[idx]);
253 pProfile->m_Lines[idx]=nullptr;
256 free(pProfile->m_Lines);
257 pProfile->m_Lines=nullptr;
259 if ( pProfile->m_Sections != nullptr )
261 /*osl_TProfileSection* pSections=pProfile->m_Sections;*/
262 for ( idx = 0 ; idx < pProfile->m_NoSections ; ++idx )
264 if ( pProfile->m_Sections[idx].m_Entries != nullptr )
266 free(pProfile->m_Sections[idx].m_Entries);
267 pProfile->m_Sections[idx].m_Entries=nullptr;
270 free(pProfile->m_Sections);
271 pProfile->m_Sections=nullptr;
275 pthread_mutex_unlock(&(pProfile->m_AccessLock));
277 pthread_mutex_destroy(&(pProfile->m_AccessLock));
279 free(pProfile);
281 return true;
284 sal_Bool SAL_CALL osl_flushProfile(oslProfile Profile)
286 osl_TProfileImpl* pProfile = static_cast<osl_TProfileImpl*>(Profile);
287 osl_TFile* pFile;
288 bool bRet = false;
290 if ( pProfile == nullptr )
292 return false;
295 pthread_mutex_lock(&(pProfile->m_AccessLock));
297 if ( !pProfile->m_bIsValid )
299 SAL_WARN_IF(!pProfile->m_bIsValid, "sal.osl", "!pProfile->m_bIsValid");
300 pthread_mutex_unlock(&(pProfile->m_AccessLock));
301 return false;
304 pFile = pProfile->m_pFile;
305 if ( !( pFile != nullptr && pFile->m_Handle >= 0 ) )
307 pthread_mutex_unlock(&(pProfile->m_AccessLock));
309 return false;
312 if ( pProfile->m_Flags & FLG_MODIFIED )
314 bRet = storeProfile(pProfile, false);
315 SAL_WARN_IF(!bRet, "sal.osl", "storeProfile(pProfile, false) ==> false");
318 pthread_mutex_unlock(&(pProfile->m_AccessLock));
319 return bRet;
322 static bool writeProfileImpl(osl_TFile* pFile)
324 if ( !( pFile != nullptr && pFile->m_Handle >= 0 ) || ( pFile->m_pWriteBuf == nullptr ) )
326 return false;
329 SAL_WARN_IF(
330 (strlen(pFile->m_pWriteBuf)
331 != pFile->m_nWriteBufLen - pFile->m_nWriteBufFree),
332 "sal.osl",
333 strlen(pFile->m_pWriteBuf) << " != "
334 << (pFile->m_nWriteBufLen - pFile->m_nWriteBufFree));
336 if ( !safeWrite(pFile->m_Handle, pFile->m_pWriteBuf, pFile->m_nWriteBufLen - pFile->m_nWriteBufFree) )
338 SAL_INFO("sal.osl", "write failed: " << UnixErrnoString(errno));
339 return false;
342 free(pFile->m_pWriteBuf);
343 pFile->m_pWriteBuf=nullptr;
344 pFile->m_nWriteBufLen=0;
345 pFile->m_nWriteBufFree=0;
347 return true;
350 sal_Bool SAL_CALL osl_readProfileString(oslProfile Profile,
351 const sal_Char* pszSection,
352 const sal_Char* pszEntry,
353 sal_Char* pszString,
354 sal_uInt32 MaxLen,
355 const sal_Char* pszDefault)
357 sal_uInt32 NoEntry;
358 sal_Char* pStr=nullptr;
359 osl_TProfileImpl* pProfile=nullptr;
360 osl_TProfileImpl* pTmpProfile=nullptr;
361 bool bRet = false;
363 pTmpProfile = static_cast<osl_TProfileImpl*>(Profile);
365 if ( pTmpProfile == nullptr )
367 return false;
370 pthread_mutex_lock(&(pTmpProfile->m_AccessLock));
372 if ( !pTmpProfile->m_bIsValid )
374 pthread_mutex_unlock(&(pTmpProfile->m_AccessLock));
376 return false;
379 pProfile = acquireProfile(Profile, false);
381 if ( pProfile == nullptr )
383 pthread_mutex_unlock(&(pTmpProfile->m_AccessLock));
385 return false;
388 if (! (pProfile->m_Flags & osl_Profile_SYSTEM))
390 osl_TProfileSection* pSec;
391 if (((pSec = findEntry(pProfile, pszSection, pszEntry, &NoEntry)) != nullptr) &&
392 (NoEntry < pSec->m_NoEntries) &&
393 ((pStr = strchr(pProfile->m_Lines[pSec->m_Entries[NoEntry].m_Line],
394 '=')) != nullptr))
396 pStr++;
398 else
400 pStr=const_cast<sal_Char*>(pszDefault);
403 if ( pStr != nullptr )
405 pStr = stripBlanks(pStr, nullptr);
406 MaxLen = (MaxLen - 1 < strlen(pStr)) ? (MaxLen - 1) : strlen(pStr);
407 pStr = stripBlanks(pStr, &MaxLen);
408 strncpy(pszString, pStr, MaxLen);
409 pszString[MaxLen] = '\0';
412 else
413 { /* not implemented */ }
415 bRet=releaseProfile(pProfile);
416 SAL_WARN_IF(!bRet, "sal.osl", "releaseProfile(pProfile) ==> false");
418 if ( pStr == nullptr )
420 pthread_mutex_unlock(&(pTmpProfile->m_AccessLock));
422 return false;
425 pthread_mutex_unlock(&(pTmpProfile->m_AccessLock));
427 return true;
430 sal_Bool SAL_CALL osl_readProfileBool(oslProfile Profile,
431 const sal_Char* pszSection,
432 const sal_Char* pszEntry,
433 sal_Bool Default)
435 sal_Char Line[32];
436 Line[0] = '\0';
438 if (osl_readProfileString(Profile, pszSection, pszEntry, Line, sizeof(Line), ""))
440 if ((strcasecmp(Line, STR_INI_BOOLYES) == 0) ||
441 (strcasecmp(Line, STR_INI_BOOLON) == 0) ||
442 (strcasecmp(Line, STR_INI_BOOLONE) == 0))
443 Default = true;
444 else
445 if ((strcasecmp(Line, STR_INI_BOOLNO) == 0) ||
446 (strcasecmp(Line, STR_INI_BOOLOFF) == 0) ||
447 (strcasecmp(Line, STR_INI_BOOLZERO) == 0))
448 Default = false;
451 return Default;
454 sal_uInt32 SAL_CALL osl_readProfileIdent(oslProfile Profile,
455 const sal_Char* pszSection,
456 const sal_Char* pszEntry,
457 sal_uInt32 FirstId,
458 const sal_Char* Strings[],
459 sal_uInt32 Default)
461 sal_uInt32 i;
462 sal_Char Line[256];
463 Line[0] = '\0';
465 if (osl_readProfileString(Profile, pszSection, pszEntry, Line, sizeof(Line), ""))
467 i = 0;
468 while (Strings[i] != nullptr)
470 if (strcasecmp(Line, Strings[i]) == 0)
472 Default = i + FirstId;
473 break;
475 i++;
479 return Default;
482 sal_Bool SAL_CALL osl_writeProfileString(oslProfile Profile,
483 const sal_Char* pszSection,
484 const sal_Char* pszEntry,
485 const sal_Char* pszString)
487 sal_uInt32 i;
488 bool bRet = false;
489 sal_uInt32 NoEntry;
490 sal_Char* pStr;
491 sal_Char* Line = nullptr;
492 osl_TProfileSection* pSec;
493 osl_TProfileImpl* pProfile = nullptr;
494 osl_TProfileImpl* pTmpProfile = nullptr;
496 pTmpProfile = static_cast<osl_TProfileImpl*>(Profile);
498 if ( pTmpProfile == nullptr )
500 return false;
503 pthread_mutex_lock(&(pTmpProfile->m_AccessLock));
505 if ( !pTmpProfile->m_bIsValid )
507 SAL_WARN_IF(!pTmpProfile->m_bIsValid, "sal.osl", "!pTmpProfile->m_bIsValid");
508 pthread_mutex_unlock(&(pTmpProfile->m_AccessLock));
510 return false;
513 pProfile=acquireProfile(Profile, true);
515 if (pProfile == nullptr)
517 pthread_mutex_unlock(&(pTmpProfile->m_AccessLock));
519 return false;
522 Line = static_cast<sal_Char*>(malloc(strlen(pszEntry)+strlen(pszString)+48));
524 if (! (pProfile->m_Flags & osl_Profile_SYSTEM))
526 if ((pSec = findEntry(pProfile, pszSection, pszEntry, &NoEntry)) == nullptr)
528 Line[0] = '\0';
529 addLine(pProfile, Line);
531 Line[0] = '[';
532 strcpy(&Line[1], pszSection);
533 Line[1 + strlen(pszSection)] = ']';
534 Line[2 + strlen(pszSection)] = '\0';
536 if (((pStr = addLine(pProfile, Line)) == nullptr) ||
537 (! addSection(pProfile, pProfile->m_NoLines - 1, &pStr[1], strlen(pszSection))))
539 bRet=releaseProfile(pProfile);
540 SAL_WARN_IF(!bRet, "sal.osl", "releaseProfile(pProfile) ==> false");
542 pthread_mutex_unlock(&(pTmpProfile->m_AccessLock));
544 free(Line);
545 return false;
548 pSec = &pProfile->m_Sections[pProfile->m_NoSections - 1];
549 NoEntry = pSec->m_NoEntries;
552 Line[0] = '\0';
553 strcpy(&Line[0], pszEntry);
554 Line[0 + strlen(pszEntry)] = '=';
555 strcpy(&Line[1 + strlen(pszEntry)], pszString);
557 if (NoEntry >= pSec->m_NoEntries)
559 if (pSec->m_NoEntries > 0)
560 i = pSec->m_Entries[pSec->m_NoEntries - 1].m_Line + 1;
561 else
562 i = pSec->m_Line + 1;
564 if (((pStr = insertLine(pProfile, Line, i)) == nullptr) ||
565 (! addEntry(pProfile, pSec, i, pStr, strlen(pszEntry))))
567 bRet=releaseProfile(pProfile);
568 SAL_WARN_IF(!bRet, "sal.osl", "releaseProfile(pProfile) ==> false");
570 pthread_mutex_unlock(&(pTmpProfile->m_AccessLock));
571 free(Line);
573 return false;
576 pProfile->m_Flags |= FLG_MODIFIED;
578 else
580 i = pSec->m_Entries[NoEntry].m_Line;
581 free(pProfile->m_Lines[i]);
582 pProfile->m_Lines[i] = strdup(Line);
583 setEntry(pProfile, pSec, NoEntry, i, pProfile->m_Lines[i], strlen(pszEntry));
585 pProfile->m_Flags |= FLG_MODIFIED;
588 else {
589 /* not implemented */
592 bRet = releaseProfile(pProfile);
593 SAL_WARN_IF(!bRet, "sal.osl", "releaseProfile(pProfile) ==> false");
595 pthread_mutex_unlock(&(pTmpProfile->m_AccessLock));
596 if ( Line!= nullptr )
598 free(Line);
601 return bRet;
604 sal_Bool SAL_CALL osl_writeProfileBool(oslProfile Profile,
605 const sal_Char* pszSection,
606 const sal_Char* pszEntry,
607 sal_Bool Value)
609 bool bRet = false;
611 if (Value)
612 bRet=osl_writeProfileString(Profile, pszSection, pszEntry, STR_INI_BOOLONE);
613 else
614 bRet=osl_writeProfileString(Profile, pszSection, pszEntry, STR_INI_BOOLZERO);
616 return bRet;
619 sal_Bool SAL_CALL osl_writeProfileIdent(oslProfile Profile,
620 const sal_Char* pszSection,
621 const sal_Char* pszEntry,
622 sal_uInt32 FirstId,
623 const sal_Char* Strings[],
624 sal_uInt32 Value)
626 int i, n = 0;
627 bool bRet = false;
629 while (Strings[n] != nullptr)
630 ++n;
632 if ((i = Value - FirstId) >= n)
633 bRet = false;
634 else
635 bRet = osl_writeProfileString(Profile, pszSection, pszEntry, Strings[i]);
637 return bRet;
640 sal_Bool SAL_CALL osl_removeProfileEntry(oslProfile Profile,
641 const sal_Char *pszSection,
642 const sal_Char *pszEntry)
644 sal_uInt32 NoEntry;
645 osl_TProfileImpl* pProfile = nullptr;
646 osl_TProfileImpl* pTmpProfile = nullptr;
647 bool bRet = false;
649 pTmpProfile = static_cast<osl_TProfileImpl*>(Profile);
651 if ( pTmpProfile == nullptr )
653 return false;
656 pthread_mutex_lock(&(pTmpProfile->m_AccessLock));
658 if ( !pTmpProfile->m_bIsValid )
660 SAL_WARN_IF(!pTmpProfile->m_bIsValid, "sal.osl", "!pTmpProfile->m_bIsValid");
661 pthread_mutex_unlock(&(pTmpProfile->m_AccessLock));
662 return false;
665 pProfile = acquireProfile(Profile, true);
667 if (pProfile == nullptr)
669 pthread_mutex_unlock(&(pTmpProfile->m_AccessLock));
671 return false;
674 if (! (pProfile->m_Flags & osl_Profile_SYSTEM))
676 osl_TProfileSection* pSec;
677 if (((pSec = findEntry(pProfile, pszSection, pszEntry, &NoEntry)) != nullptr) &&
678 (NoEntry < pSec->m_NoEntries))
680 removeLine(pProfile, pSec->m_Entries[NoEntry].m_Line);
681 removeEntry(pSec, NoEntry);
682 if (pSec->m_NoEntries == 0)
684 removeLine(pProfile, pSec->m_Line);
686 /* remove any empty separation line */
687 if ((pSec->m_Line > 0) && (pProfile->m_Lines[pSec->m_Line - 1][0] == '\0'))
688 removeLine(pProfile, pSec->m_Line - 1);
690 removeSection(pProfile, pSec);
693 pProfile->m_Flags |= FLG_MODIFIED;
696 else
697 { /* not implemented */ }
699 bRet = releaseProfile(pProfile);
700 SAL_WARN_IF(!bRet, "sal.osl", "releaseProfile(pProfile) ==> false");
702 pthread_mutex_unlock(&(pTmpProfile->m_AccessLock));
704 return bRet;
707 sal_uInt32 SAL_CALL osl_getProfileSectionEntries(oslProfile Profile,
708 const sal_Char *pszSection,
709 sal_Char* pszBuffer,
710 sal_uInt32 MaxLen)
712 sal_uInt32 i, n = 0;
713 sal_uInt32 NoEntry;
714 osl_TProfileImpl* pProfile = nullptr;
715 osl_TProfileImpl* pTmpProfile = nullptr;
716 bool bRet = false;
718 pTmpProfile = static_cast<osl_TProfileImpl*>(Profile);
720 if ( pTmpProfile == nullptr )
722 return 0;
726 pthread_mutex_lock(&(pTmpProfile->m_AccessLock));
728 if ( !pTmpProfile->m_bIsValid )
730 SAL_WARN_IF(!pTmpProfile->m_bIsValid, "sal.osl", "!pTmpProfile->m_bIsValid");
732 pthread_mutex_unlock(&(pTmpProfile->m_AccessLock));
734 return 0;
737 pProfile = acquireProfile(Profile, false);
739 if (pProfile == nullptr)
741 pthread_mutex_unlock(&(pTmpProfile->m_AccessLock));
743 return 0;
746 if (! (pProfile->m_Flags & osl_Profile_SYSTEM))
748 osl_TProfileSection* pSec;
749 if ((pSec = findEntry(pProfile, pszSection, "", &NoEntry)) != nullptr)
751 if (MaxLen != 0)
753 for (i = 0; i < pSec->m_NoEntries; i++)
755 if ((n + pSec->m_Entries[i].m_Len + 1) < MaxLen)
757 strncpy(&pszBuffer[n], &pProfile->m_Lines[pSec->m_Entries[i].m_Line]
758 [pSec->m_Entries[i].m_Offset], pSec->m_Entries[i].m_Len);
759 n += pSec->m_Entries[i].m_Len;
760 pszBuffer[n++] = '\0';
762 else
763 break;
767 pszBuffer[n++] = '\0';
769 else
771 for (i = 0; i < pSec->m_NoEntries; i++)
772 n += pSec->m_Entries[i].m_Len + 1;
774 n += 1;
777 else
778 n = 0;
780 else {
781 /* not implemented */
784 bRet=releaseProfile(pProfile);
785 SAL_WARN_IF(!bRet, "sal.osl", "releaseProfile(pProfile) ==> false");
787 pthread_mutex_unlock(&(pTmpProfile->m_AccessLock));
789 return n;
792 sal_uInt32 SAL_CALL osl_getProfileSections(oslProfile Profile,
793 sal_Char* pszBuffer,
794 sal_uInt32 MaxLen)
796 sal_uInt32 i, n = 0;
797 osl_TProfileImpl* pProfile = nullptr;
798 osl_TProfileImpl* pTmpProfile = nullptr;
799 bool bRet = false;
801 pTmpProfile = static_cast<osl_TProfileImpl*>(Profile);
803 if ( pTmpProfile == nullptr )
805 return 0;
808 pthread_mutex_lock(&(pTmpProfile->m_AccessLock));
810 if ( !pTmpProfile->m_bIsValid )
812 SAL_WARN_IF(!pTmpProfile->m_bIsValid, "sal.osl", "!pTmpProfile->m_bIsValid");
813 pthread_mutex_unlock(&(pTmpProfile->m_AccessLock));
815 return 0;
818 pProfile = acquireProfile(Profile, false);
820 if (pProfile == nullptr)
822 pthread_mutex_unlock(&(pTmpProfile->m_AccessLock));
824 return 0;
827 if (! (pProfile->m_Flags & osl_Profile_SYSTEM))
829 if (MaxLen != 0)
831 for (i = 0; i < pProfile->m_NoSections; i++)
833 osl_TProfileSection* pSec = &pProfile->m_Sections[i];
835 if ((n + pSec->m_Len + 1) < MaxLen)
837 strncpy(&pszBuffer[n], &pProfile->m_Lines[pSec->m_Line][pSec->m_Offset],
838 pSec->m_Len);
839 n += pSec->m_Len;
840 pszBuffer[n++] = '\0';
842 else
843 break;
846 pszBuffer[n++] = '\0';
848 else
850 for (i = 0; i < pProfile->m_NoSections; i++)
851 n += pProfile->m_Sections[i].m_Len + 1;
853 n += 1;
856 else
857 { /* not implemented */ }
859 bRet=releaseProfile(pProfile);
860 SAL_WARN_IF(!bRet, "sal.osl", "releaseProfile(pProfile) ==> false");
862 pthread_mutex_unlock(&(pTmpProfile->m_AccessLock));
864 return n;
867 static osl_TStamp OslProfile_getFileStamp(osl_TFile* pFile)
869 struct stat status;
871 if ( (pFile->m_Handle < 0) || (fstat(pFile->m_Handle, &status) < 0) )
873 return 0;
876 return status.st_mtime;
879 static bool OslProfile_lockFile(const osl_TFile* pFile, osl_TLockMode eMode)
881 struct flock lock;
882 /* boring hack, but initializers for static vars must be constant */
883 static bool bIsInitialized = false;
884 static bool bLockingDisabled;
886 if ( !bIsInitialized )
888 sal_Char* pEnvValue;
889 pEnvValue = getenv( "STAR_PROFILE_LOCKING_DISABLED" );
891 bLockingDisabled = pEnvValue != nullptr;
893 bIsInitialized = true;
896 if (pFile->m_Handle < 0)
898 return false;
901 if ( bLockingDisabled )
903 return true;
906 lock.l_start = 0;
907 lock.l_whence = SEEK_SET;
908 lock.l_len = 0;
910 switch (eMode)
912 case un_lock:
913 lock.l_type = F_UNLCK;
914 break;
916 case read_lock:
917 lock.l_type = F_RDLCK;
918 break;
920 case write_lock:
921 lock.l_type = F_WRLCK;
922 break;
925 #ifndef MACOSX
926 if ( fcntl(pFile->m_Handle, F_SETLKW, &lock) == -1 )
927 #else
928 /* Mac OSX will return ENOTSUP for webdav drives so we should ignore it */
929 if ( fcntl(pFile->m_Handle, F_SETLKW, &lock) == -1 && errno != ENOTSUP )
930 #endif
932 SAL_INFO("sal.osl", "fcntl failed: " << UnixErrnoString(errno));
933 return false;
936 return true;
939 static osl_TFile* openFileImpl(const sal_Char* pszFilename, oslProfileOption ProfileFlags )
941 int Flags;
942 osl_TFile* pFile = static_cast<osl_TFile*>(calloc(1, sizeof(osl_TFile)));
943 bool bWriteable = false;
945 if ( ProfileFlags & ( osl_Profile_WRITELOCK | osl_Profile_FLUSHWRITE ) )
947 bWriteable = true;
950 if (! bWriteable)
952 pFile->m_Handle = open(pszFilename, O_RDONLY);
954 if (pFile->m_Handle == -1)
956 int e = errno;
957 SAL_INFO("sal.file", "open(" << pszFilename << ",O_RDONLY): " << UnixErrnoString(e));
959 else
960 SAL_INFO("sal.file", "open(" << pszFilename << ",O_RDONLY) => " << pFile->m_Handle);
962 /* mfe: argghh!!! do not check if the file could be opened */
963 /* default mode expects it that way!!! */
965 else
967 if (((pFile->m_Handle = open(pszFilename, O_RDWR | O_CREAT | O_EXCL, DEFAULT_PMODE)) < 0) &&
968 ((pFile->m_Handle = open(pszFilename, O_RDWR)) < 0))
970 int e = errno;
971 SAL_INFO("sal.file", "open(" << pszFilename << ",...): " << UnixErrnoString(e));
972 free(pFile);
973 return nullptr;
975 else
976 SAL_INFO("sal.file", "open(" << pszFilename << ",...) => " << pFile->m_Handle);
979 /* set close-on-exec flag */
980 if ((Flags = fcntl(pFile->m_Handle, F_GETFD, 0)) != -1)
982 Flags |= FD_CLOEXEC;
983 int e = fcntl(pFile->m_Handle, F_SETFD, Flags);
984 SAL_INFO_IF(
985 e != 0, "sal.osl",
986 "fcntl to set FD_CLOEXEC failed for " << pszFilename);
989 pFile->m_pWriteBuf=nullptr;
990 pFile->m_nWriteBufFree=0;
991 pFile->m_nWriteBufLen=0;
993 if ( ProfileFlags & (osl_Profile_WRITELOCK | osl_Profile_READLOCK ) )
995 OslProfile_lockFile(pFile, bWriteable ? write_lock : read_lock);
998 return pFile;
1001 static osl_TStamp closeFileImpl(osl_TFile* pFile, oslProfileOption Flags)
1003 osl_TStamp stamp = 0;
1005 if ( pFile == nullptr )
1007 return stamp;
1010 if ( pFile->m_Handle >= 0 )
1012 stamp = OslProfile_getFileStamp(pFile);
1014 if ( Flags & (osl_Profile_WRITELOCK | osl_Profile_READLOCK ) )
1016 OslProfile_lockFile(pFile, un_lock);
1019 close(pFile->m_Handle);
1020 SAL_INFO("sal.file", "close(" << pFile->m_Handle << ")");
1021 pFile->m_Handle = -1;
1024 if ( pFile->m_pWriteBuf )
1026 free(pFile->m_pWriteBuf);
1029 free(pFile);
1031 return stamp;
1034 static bool OslProfile_rewindFile(osl_TFile* pFile, bool bTruncate)
1036 bool bRet = true;
1038 if (pFile->m_Handle >= 0)
1040 pFile->m_pReadPtr = pFile->m_ReadBuf + sizeof(pFile->m_ReadBuf);
1042 bRet = (lseek(pFile->m_Handle, SEEK_SET, 0L) == 0);
1044 if (bTruncate)
1046 bRet &= (ftruncate(pFile->m_Handle, 0L) == 0);
1051 return bRet;
1054 static sal_Char* OslProfile_getLine(osl_TFile* pFile)
1056 int Max, Free, nLineBytes = 0;
1057 sal_Char* pChr;
1058 sal_Char* pLine = nullptr;
1059 sal_Char* pNewLine;
1061 if ( pFile == nullptr )
1063 return nullptr;
1066 if (pFile->m_Handle < 0)
1067 return nullptr;
1071 int Bytes = sizeof(pFile->m_ReadBuf) - (pFile->m_pReadPtr - pFile->m_ReadBuf);
1073 if (Bytes <= 1)
1075 /* refill buffer */
1076 memcpy(pFile->m_ReadBuf, pFile->m_pReadPtr, Bytes);
1077 pFile->m_pReadPtr = pFile->m_ReadBuf;
1079 Free = sizeof(pFile->m_ReadBuf) - Bytes;
1081 if ((Max = read(pFile->m_Handle, &pFile->m_ReadBuf[Bytes], Free)) < 0)
1083 SAL_INFO("sal.osl", "read failed: " << UnixErrnoString(errno));
1085 if( pLine )
1086 free( pLine );
1087 pLine = nullptr;
1088 break;
1091 if (Max < Free)
1093 if ((Max == 0) && ! pLine)
1094 break;
1096 pFile->m_ReadBuf[Bytes + Max] = '\0';
1100 for (pChr = pFile->m_pReadPtr;
1101 (*pChr != '\n') && (*pChr != '\r') && (*pChr != '\0') &&
1102 (pChr < (pFile->m_ReadBuf + sizeof(pFile->m_ReadBuf) - 1));
1103 pChr++);
1105 Max = pChr - pFile->m_pReadPtr;
1106 pNewLine = static_cast<sal_Char*>(malloc( nLineBytes + Max + 1 ));
1107 if( pLine )
1109 memcpy( pNewLine, pLine, nLineBytes );
1110 free( pLine );
1112 memcpy(pNewLine+nLineBytes, pFile->m_pReadPtr, Max);
1113 nLineBytes += Max;
1114 pNewLine[ nLineBytes ] = 0;
1115 pLine = pNewLine;
1117 if (pChr < (pFile->m_ReadBuf + sizeof(pFile->m_ReadBuf) - 1))
1119 if (*pChr != '\0')
1121 if ((pChr[0] == '\r') && (pChr[1] == '\n'))
1122 pChr += 2;
1123 else
1124 pChr += 1;
1127 if ((pChr < (pFile->m_ReadBuf + sizeof(pFile->m_ReadBuf))) &&
1128 (*pChr == '\0'))
1129 pChr = pFile->m_ReadBuf + sizeof(pFile->m_ReadBuf);
1131 /* setting Max to -1 indicates terminating read loop */
1132 Max = -1;
1135 pFile->m_pReadPtr = pChr;
1137 while (Max > 0) ;
1139 return pLine;
1142 static bool OslProfile_putLine(osl_TFile* pFile, const sal_Char *pszLine)
1144 unsigned int Len = strlen(pszLine);
1146 if ( pFile == nullptr || pFile->m_Handle < 0 )
1148 return false;
1151 if ( pFile->m_pWriteBuf == nullptr )
1153 pFile->m_pWriteBuf = static_cast<sal_Char*>(malloc(Len+3));
1154 pFile->m_nWriteBufLen = Len+3;
1155 pFile->m_nWriteBufFree = Len+3;
1157 else
1159 if ( pFile->m_nWriteBufFree <= Len + 3 )
1161 sal_Char* pTmp;
1163 pTmp=static_cast<sal_Char*>(realloc(pFile->m_pWriteBuf,( ( pFile->m_nWriteBufLen + Len ) * 2) ));
1164 if ( pTmp == nullptr )
1166 return false;
1168 pFile->m_pWriteBuf = pTmp;
1169 pFile->m_nWriteBufFree = pFile->m_nWriteBufFree + pFile->m_nWriteBufLen + ( 2 * Len );
1170 pFile->m_nWriteBufLen = ( pFile->m_nWriteBufLen + Len ) * 2;
1171 memset( (pFile->m_pWriteBuf) + ( pFile->m_nWriteBufLen - pFile->m_nWriteBufFree ), 0, pFile->m_nWriteBufFree);
1175 memcpy(pFile->m_pWriteBuf + ( pFile->m_nWriteBufLen - pFile->m_nWriteBufFree ),pszLine,Len+1);
1176 pFile->m_pWriteBuf[pFile->m_nWriteBufLen - pFile->m_nWriteBufFree + Len]='\n';
1177 pFile->m_pWriteBuf[pFile->m_nWriteBufLen - pFile->m_nWriteBufFree + Len + 1]='\0';
1179 pFile->m_nWriteBufFree-=Len+1;
1181 return true;
1184 static sal_Char* stripBlanks(sal_Char* String, sal_uInt32* pLen)
1186 if ( ( pLen != nullptr ) && ( *pLen != 0 ) )
1188 while ((String[*pLen - 1] == ' ') || (String[*pLen - 1] == '\t'))
1189 (*pLen)--;
1191 while ( (*String == ' ') || (*String == '\t') )
1193 String++;
1194 (*pLen)--;
1197 else
1198 while ( (*String == ' ') || (*String == '\t') )
1199 String++;
1201 return String;
1204 static sal_Char* addLine(osl_TProfileImpl* pProfile, const sal_Char* Line)
1206 if (pProfile->m_NoLines >= pProfile->m_MaxLines)
1208 if (pProfile->m_Lines == nullptr)
1210 pProfile->m_MaxLines = LINES_INI;
1211 pProfile->m_Lines = static_cast<sal_Char **>(calloc(pProfile->m_MaxLines, sizeof(sal_Char *)));
1213 else
1215 unsigned int idx=0;
1216 unsigned int oldmax=pProfile->m_MaxLines;
1218 pProfile->m_MaxLines += LINES_ADD;
1219 pProfile->m_Lines = static_cast<sal_Char **>(realloc(pProfile->m_Lines,
1220 pProfile->m_MaxLines * sizeof(sal_Char *)));
1221 for ( idx = oldmax ; idx < pProfile->m_MaxLines ; ++idx )
1223 pProfile->m_Lines[idx]=nullptr;
1227 if (pProfile->m_Lines == nullptr)
1229 pProfile->m_NoLines = 0;
1230 pProfile->m_MaxLines = 0;
1231 return nullptr;
1234 if ( pProfile->m_Lines[pProfile->m_NoLines] != nullptr )
1236 free(pProfile->m_Lines[pProfile->m_NoLines]);
1238 pProfile->m_Lines[pProfile->m_NoLines++] = strdup(Line);
1240 return pProfile->m_Lines[pProfile->m_NoLines - 1];
1243 static sal_Char* insertLine(osl_TProfileImpl* pProfile, const sal_Char* Line, sal_uInt32 LineNo)
1245 if (pProfile->m_NoLines >= pProfile->m_MaxLines)
1247 if (pProfile->m_Lines == nullptr)
1249 pProfile->m_MaxLines = LINES_INI;
1250 pProfile->m_Lines = static_cast<sal_Char **>(calloc(pProfile->m_MaxLines, sizeof(sal_Char *)));
1252 else
1254 pProfile->m_MaxLines += LINES_ADD;
1255 pProfile->m_Lines = static_cast<sal_Char **>(realloc(pProfile->m_Lines,
1256 pProfile->m_MaxLines * sizeof(sal_Char *)));
1258 memset(&pProfile->m_Lines[pProfile->m_NoLines],
1260 (pProfile->m_MaxLines - pProfile->m_NoLines - 1) * sizeof(sal_Char*));
1263 if (pProfile->m_Lines == nullptr)
1265 pProfile->m_NoLines = 0;
1266 pProfile->m_MaxLines = 0;
1267 return nullptr;
1271 LineNo = std::min(LineNo, pProfile->m_NoLines);
1273 if (LineNo < pProfile->m_NoLines)
1275 sal_uInt32 i, n;
1277 memmove(&pProfile->m_Lines[LineNo + 1], &pProfile->m_Lines[LineNo],
1278 (pProfile->m_NoLines - LineNo) * sizeof(sal_Char *));
1280 /* adjust line references */
1281 for (i = 0; i < pProfile->m_NoSections; i++)
1283 osl_TProfileSection* pSec = &pProfile->m_Sections[i];
1285 if (pSec->m_Line >= LineNo)
1286 pSec->m_Line++;
1288 for (n = 0; n < pSec->m_NoEntries; n++)
1289 if (pSec->m_Entries[n].m_Line >= LineNo)
1290 pSec->m_Entries[n].m_Line++;
1294 pProfile->m_NoLines++;
1296 pProfile->m_Lines[LineNo] = strdup(Line);
1298 return pProfile->m_Lines[LineNo];
1301 static void removeLine(osl_TProfileImpl* pProfile, sal_uInt32 LineNo)
1303 if (LineNo < pProfile->m_NoLines)
1305 free(pProfile->m_Lines[LineNo]);
1306 pProfile->m_Lines[LineNo]=nullptr;
1307 if (pProfile->m_NoLines - LineNo > 1)
1309 sal_uInt32 i, n;
1311 memmove(&pProfile->m_Lines[LineNo], &pProfile->m_Lines[LineNo + 1],
1312 (pProfile->m_NoLines - LineNo - 1) * sizeof(sal_Char *));
1314 memset(&pProfile->m_Lines[pProfile->m_NoLines - 1],
1316 (pProfile->m_MaxLines - pProfile->m_NoLines) * sizeof(sal_Char*));
1318 /* adjust line references */
1319 for (i = 0; i < pProfile->m_NoSections; i++)
1321 osl_TProfileSection* pSec = &pProfile->m_Sections[i];
1323 if (pSec->m_Line > LineNo)
1324 pSec->m_Line--;
1326 for (n = 0; n < pSec->m_NoEntries; n++)
1327 if (pSec->m_Entries[n].m_Line > LineNo)
1328 pSec->m_Entries[n].m_Line--;
1331 else
1333 pProfile->m_Lines[LineNo] = nullptr;
1336 pProfile->m_NoLines--;
1340 static void setEntry(osl_TProfileImpl* pProfile, osl_TProfileSection* pSection,
1341 sal_uInt32 NoEntry, sal_uInt32 Line,
1342 sal_Char* Entry, sal_uInt32 Len)
1344 Entry = stripBlanks(Entry, &Len);
1345 pSection->m_Entries[NoEntry].m_Line = Line;
1346 pSection->m_Entries[NoEntry].m_Offset = Entry - pProfile->m_Lines[Line];
1347 pSection->m_Entries[NoEntry].m_Len = Len;
1350 static bool addEntry(osl_TProfileImpl* pProfile,
1351 osl_TProfileSection *pSection,
1352 int Line, sal_Char* Entry,
1353 sal_uInt32 Len)
1355 if (pSection != nullptr)
1357 if (pSection->m_NoEntries >= pSection->m_MaxEntries)
1359 if (pSection->m_Entries == nullptr)
1361 pSection->m_MaxEntries = ENTRIES_INI;
1362 pSection->m_Entries = static_cast<osl_TProfileEntry *>(malloc(
1363 pSection->m_MaxEntries * sizeof(osl_TProfileEntry)));
1365 else
1367 pSection->m_MaxEntries += ENTRIES_ADD;
1368 pSection->m_Entries = static_cast<osl_TProfileEntry *>(realloc(pSection->m_Entries,
1369 pSection->m_MaxEntries * sizeof(osl_TProfileEntry)));
1372 if (pSection->m_Entries == nullptr)
1374 pSection->m_NoEntries = 0;
1375 pSection->m_MaxEntries = 0;
1376 return false;
1380 pSection->m_NoEntries++;
1382 Entry = stripBlanks(Entry, &Len);
1383 setEntry(pProfile, pSection, pSection->m_NoEntries - 1, Line,
1384 Entry, Len);
1386 return true;
1389 return false;
1392 static void removeEntry(osl_TProfileSection *pSection, sal_uInt32 NoEntry)
1394 if (NoEntry < pSection->m_NoEntries)
1396 if (pSection->m_NoEntries - NoEntry > 1)
1398 memmove(&pSection->m_Entries[NoEntry],
1399 &pSection->m_Entries[NoEntry + 1],
1400 (pSection->m_NoEntries - NoEntry - 1) * sizeof(osl_TProfileEntry));
1401 pSection->m_Entries[pSection->m_NoEntries - 1].m_Line=0;
1402 pSection->m_Entries[pSection->m_NoEntries - 1].m_Offset=0;
1403 pSection->m_Entries[pSection->m_NoEntries - 1].m_Len=0;
1406 pSection->m_NoEntries--;
1411 static bool addSection(osl_TProfileImpl* pProfile, int Line, const sal_Char* Section, sal_uInt32 Len)
1413 if (pProfile->m_NoSections >= pProfile->m_MaxSections)
1415 if (pProfile->m_Sections == nullptr)
1417 pProfile->m_MaxSections = SECTIONS_INI;
1418 pProfile->m_Sections = static_cast<osl_TProfileSection *>(calloc(pProfile->m_MaxSections, sizeof(osl_TProfileSection)));
1420 else
1422 unsigned int idx=0;
1423 unsigned int oldmax=pProfile->m_MaxSections;
1425 pProfile->m_MaxSections += SECTIONS_ADD;
1426 pProfile->m_Sections = static_cast<osl_TProfileSection *>(realloc(pProfile->m_Sections,
1427 pProfile->m_MaxSections * sizeof(osl_TProfileSection)));
1428 for ( idx = oldmax ; idx < pProfile->m_MaxSections ; ++idx )
1430 pProfile->m_Sections[idx].m_Entries=nullptr;
1434 if (pProfile->m_Sections == nullptr)
1436 pProfile->m_NoSections = 0;
1437 pProfile->m_MaxSections = 0;
1438 return false;
1442 pProfile->m_NoSections++;
1444 if ( pProfile->m_Sections[(pProfile->m_NoSections) - 1].m_Entries != nullptr )
1446 free(pProfile->m_Sections[(pProfile->m_NoSections) - 1].m_Entries);
1448 pProfile->m_Sections[pProfile->m_NoSections - 1].m_Entries = nullptr;
1449 pProfile->m_Sections[pProfile->m_NoSections - 1].m_NoEntries = 0;
1450 pProfile->m_Sections[pProfile->m_NoSections - 1].m_MaxEntries = 0;
1452 pProfile->m_Sections[pProfile->m_NoSections - 1].m_Line = Line;
1453 pProfile->m_Sections[pProfile->m_NoSections - 1].m_Offset = Section - pProfile->m_Lines[Line];
1454 pProfile->m_Sections[pProfile->m_NoSections - 1].m_Len = Len;
1456 return true;
1459 static void removeSection(osl_TProfileImpl* pProfile, osl_TProfileSection *pSection)
1461 sal_uInt32 Section;
1463 if ((Section = pSection - pProfile->m_Sections) < pProfile->m_NoSections)
1465 free (pSection->m_Entries);
1466 pSection->m_Entries=nullptr;
1467 if (pProfile->m_NoSections - Section > 1)
1469 memmove(&pProfile->m_Sections[Section], &pProfile->m_Sections[Section + 1],
1470 (pProfile->m_NoSections - Section - 1) * sizeof(osl_TProfileSection));
1472 memset(&pProfile->m_Sections[pProfile->m_NoSections - 1],
1474 (pProfile->m_MaxSections - pProfile->m_NoSections) * sizeof(osl_TProfileSection));
1475 pProfile->m_Sections[pProfile->m_NoSections - 1].m_Entries = nullptr;
1477 else
1479 pSection->m_Entries = nullptr;
1482 pProfile->m_NoSections--;
1486 static osl_TProfileSection* findEntry(osl_TProfileImpl* pProfile,
1487 const sal_Char* Section,
1488 const sal_Char* Entry,
1489 sal_uInt32 *pNoEntry)
1491 static sal_uInt32 Sect = 0;
1492 sal_uInt32 i, n;
1493 sal_uInt32 Len;
1494 osl_TProfileSection* pSec=nullptr;
1496 Len = strlen(Section);
1498 n = Sect;
1500 for (i = 0; i < pProfile->m_NoSections; i++)
1502 n %= pProfile->m_NoSections;
1503 pSec = &pProfile->m_Sections[n];
1504 if ((Len == pSec->m_Len) &&
1505 (strncasecmp(Section, &pProfile->m_Lines[pSec->m_Line][pSec->m_Offset], pSec->m_Len)
1506 == 0))
1507 break;
1508 n++;
1511 Sect = n;
1513 if (i < pProfile->m_NoSections)
1515 Len = strlen(Entry);
1517 *pNoEntry = pSec->m_NoEntries;
1519 for (i = 0; i < pSec->m_NoEntries; i++)
1521 const sal_Char* pStr = &pProfile->m_Lines[pSec->m_Entries[i].m_Line]
1522 [pSec->m_Entries[i].m_Offset];
1523 if ((Len == pSec->m_Entries[i].m_Len) &&
1524 (strncasecmp(Entry, pStr, pSec->m_Entries[i].m_Len)
1525 == 0))
1527 *pNoEntry = i;
1528 break;
1532 else
1533 pSec = nullptr;
1535 return pSec;
1538 static bool loadProfile(osl_TFile* pFile, osl_TProfileImpl* pProfile)
1540 sal_uInt32 i;
1541 sal_Char* pStr;
1542 sal_Char* pChar;
1544 sal_Char* pLine;
1546 if ( !pFile )
1548 return false;
1551 if ( !pProfile )
1553 return false;
1556 pProfile->m_NoLines = 0;
1557 pProfile->m_NoSections = 0;
1559 OSL_VERIFY(OslProfile_rewindFile(pFile, false));
1561 while ( ( pLine=OslProfile_getLine(pFile) ) != nullptr )
1563 sal_Char* bWasAdded = addLine( pProfile, pLine );
1564 free( pLine );
1565 SAL_WARN_IF(!bWasAdded, "sal.osl", "addLine( pProfile, pLine ) ==> false");
1566 if ( ! bWasAdded )
1567 return false;
1570 for (i = 0; i < pProfile->m_NoLines; i++)
1572 pStr = stripBlanks(pProfile->m_Lines[i], nullptr);
1574 if ((*pStr == '\0') || (*pStr == ';'))
1575 continue;
1577 if ((*pStr != '[') || ((pChar = strrchr(pStr, ']')) == nullptr) ||
1578 ((pChar - pStr) <= 2))
1580 /* insert entry */
1582 if (pProfile->m_NoSections < 1)
1583 continue;
1585 if ((pChar = strchr(pStr, '=')) == nullptr)
1586 pChar = pStr + strlen(pStr);
1588 if (! addEntry(pProfile, &pProfile->m_Sections[pProfile->m_NoSections - 1],
1589 i, pStr, pChar - pStr))
1591 SAL_WARN("sal.osl", "Adding entry => false");
1592 continue;
1596 else
1598 /* new section */
1600 if (! addSection(pProfile, i, pStr + 1, pChar - pStr - 1))
1602 SAL_WARN("sal.osl", "Adding section => false");
1603 continue;
1609 return true;
1612 static bool storeProfile(osl_TProfileImpl* pProfile, bool bCleanup)
1614 if (pProfile->m_Lines != nullptr)
1616 if (pProfile->m_Flags & FLG_MODIFIED)
1618 sal_uInt32 i;
1620 osl_TFile* pTmpFile = osl_openTmpProfileImpl(pProfile);
1622 if ( pTmpFile == nullptr )
1624 return false;
1627 OSL_VERIFY(OslProfile_rewindFile(pTmpFile, true));
1629 for ( i = 0 ; i < pProfile->m_NoLines ; i++ )
1631 OSL_VERIFY(OslProfile_putLine(pTmpFile, pProfile->m_Lines[i]));
1634 if ( ! writeProfileImpl(pTmpFile) )
1636 if ( pTmpFile->m_pWriteBuf != nullptr )
1638 free(pTmpFile->m_pWriteBuf);
1641 pTmpFile->m_pWriteBuf=nullptr;
1642 pTmpFile->m_nWriteBufLen=0;
1643 pTmpFile->m_nWriteBufFree=0;
1645 closeFileImpl(pTmpFile,pProfile->m_Flags);
1647 return false;
1650 pProfile->m_Flags &= ~FLG_MODIFIED;
1652 closeFileImpl(pProfile->m_pFile,pProfile->m_Flags);
1653 closeFileImpl(pTmpFile,pProfile->m_Flags);
1655 osl_ProfileSwapProfileNames(pProfile);
1657 pProfile->m_pFile = openFileImpl(pProfile->m_FileName,pProfile->m_Flags);
1661 if (bCleanup)
1663 while (pProfile->m_NoLines > 0)
1664 removeLine(pProfile, pProfile->m_NoLines - 1);
1666 free(pProfile->m_Lines);
1667 pProfile->m_Lines = nullptr;
1668 pProfile->m_NoLines = 0;
1669 pProfile->m_MaxLines = 0;
1671 while (pProfile->m_NoSections > 0)
1672 removeSection(pProfile, &pProfile->m_Sections[pProfile->m_NoSections - 1]);
1674 free(pProfile->m_Sections);
1675 pProfile->m_Sections = nullptr;
1676 pProfile->m_NoSections = 0;
1677 pProfile->m_MaxSections = 0;
1681 return true;
1684 static osl_TFile* osl_openTmpProfileImpl(osl_TProfileImpl* pProfile)
1686 osl_TFile* pFile=nullptr;
1687 sal_Char const * const pszExtension = "tmp";
1688 sal_Char pszTmpName[PATH_MAX];
1689 oslProfileOption PFlags=0;
1691 pszTmpName[0] = '\0';
1693 /* generate tmp profilename */
1694 osl_ProfileGenerateExtension(pProfile->m_FileName, pszExtension, pszTmpName, PATH_MAX);
1696 if ( pszTmpName[0] == 0 )
1698 return nullptr;
1701 if ( ! ( pProfile->m_Flags & osl_Profile_READLOCK ) )
1703 PFlags |= osl_Profile_WRITELOCK;
1706 /* open this file */
1707 pFile = openFileImpl(pszTmpName,pProfile->m_Flags | PFlags);
1709 /* return new pFile */
1710 return pFile;
1713 static bool osl_ProfileSwapProfileNames(osl_TProfileImpl* pProfile)
1715 sal_Char pszBakFile[PATH_MAX];
1716 sal_Char pszTmpFile[PATH_MAX];
1718 pszBakFile[0] = '\0';
1719 pszTmpFile[0] = '\0';
1721 osl_ProfileGenerateExtension(pProfile->m_FileName, "bak", pszBakFile, PATH_MAX);
1722 osl_ProfileGenerateExtension(pProfile->m_FileName, "tmp", pszTmpFile, PATH_MAX);
1724 /* unlink bak */
1725 unlink( pszBakFile );
1727 // Rename ini -> bak, then tmp -> ini:
1728 bool result = rename( pProfile->m_FileName, pszBakFile ) == 0;
1729 if (!result)
1731 int e = errno;
1732 SAL_INFO("sal.file", "rename(" << pProfile->m_FileName << "," << pszBakFile << "): " << UnixErrnoString(e));
1734 else
1736 SAL_INFO("sal.file", "rename(" << pProfile->m_FileName << "," << pszBakFile << "): OK");
1737 result = rename( pszTmpFile, pProfile->m_FileName ) == 0;
1738 if (!result)
1740 int e = errno;
1741 SAL_INFO("sal.file", "rename(" << pszTmpFile << "," << pProfile->m_FileName << "): " << UnixErrnoString(e));
1743 else
1745 SAL_INFO("sal.file", "rename(" << pszTmpFile << "," << pProfile->m_FileName << "): OK");
1748 return result;
1751 static void osl_ProfileGenerateExtension(const sal_Char* pszFileName, const sal_Char* pszExtension, sal_Char* pszTmpName, int BufferMaxLen)
1753 sal_Char* cursor = pszTmpName;
1754 int len;
1756 /* concatenate filename + "." + extension, limited to the size of the
1757 * output buffer; in case of overrun, data is truncated at the end...
1758 * and the result is always 0-terminated.
1760 len = strlen(pszFileName);
1761 if(len < BufferMaxLen)
1763 memcpy(cursor, pszFileName, len);
1764 cursor += len;
1765 BufferMaxLen -= len;
1767 else
1769 memcpy(cursor, pszFileName, BufferMaxLen - 1);
1770 cursor += BufferMaxLen - 1;
1771 BufferMaxLen = 1;
1773 if(BufferMaxLen > 1)
1775 *cursor++ = '.';
1776 BufferMaxLen -= 1;
1778 len = strlen(pszExtension);
1779 if(len < BufferMaxLen)
1781 memcpy(cursor, pszExtension, len);
1782 cursor += len;
1784 else
1786 memcpy(cursor, pszExtension, BufferMaxLen - 1);
1787 cursor += BufferMaxLen - 1;
1789 *cursor = 0;
1792 static osl_TProfileImpl* acquireProfile(oslProfile Profile, bool bWriteable)
1794 osl_TProfileImpl* pProfile = static_cast<osl_TProfileImpl*>(Profile);
1795 oslProfileOption PFlags=0;
1797 if ( bWriteable )
1799 PFlags = osl_Profile_DEFAULT | osl_Profile_WRITELOCK;
1801 else
1803 PFlags = osl_Profile_DEFAULT;
1806 if (pProfile == nullptr)
1808 if ( ( pProfile = static_cast<osl_TProfileImpl*>(osl_openProfile(nullptr, PFlags )) ) != nullptr )
1810 pProfile->m_Flags |= FLG_AUTOOPEN;
1813 else
1815 if (! (pProfile->m_Flags & osl_Profile_SYSTEM))
1817 if (! (pProfile->m_Flags & (osl_Profile_READLOCK | osl_Profile_WRITELOCK | osl_Profile_FLUSHWRITE )))
1819 osl_TStamp Stamp;
1821 if (! (pProfile->m_pFile = openFileImpl(pProfile->m_FileName, pProfile->m_Flags | PFlags )))
1822 return nullptr;
1824 Stamp = OslProfile_getFileStamp(pProfile->m_pFile);
1826 if (memcmp(&Stamp, &(pProfile->m_Stamp), sizeof(osl_TStamp)))
1828 pProfile->m_Stamp = Stamp;
1829 bool bRet = loadProfile(pProfile->m_pFile, pProfile);
1830 SAL_WARN_IF(!bRet, "sal.osl", "loadProfile(pProfile->m_pFile, pProfile) ==> false");
1833 else
1835 /* A readlock file could not be written */
1836 if ((pProfile->m_Flags & osl_Profile_READLOCK) && bWriteable)
1838 return nullptr;
1844 return pProfile;
1847 static bool releaseProfile(osl_TProfileImpl* pProfile)
1849 if ( pProfile == nullptr )
1851 return false;
1854 if (pProfile->m_Flags & FLG_AUTOOPEN)
1856 return osl_closeProfile(static_cast<oslProfile>(pProfile));
1859 if (! (pProfile->m_Flags & (osl_Profile_READLOCK | osl_Profile_WRITELOCK | osl_Profile_FLUSHWRITE )))
1861 if (pProfile->m_Flags & FLG_MODIFIED)
1863 bool bRet = storeProfile(pProfile, false);
1864 SAL_WARN_IF(!bRet, "sal.osl", "storeProfile(pProfile, false) ==> false");
1867 closeFileImpl(pProfile->m_pFile,pProfile->m_Flags);
1868 pProfile->m_pFile = nullptr;
1871 return true;
1874 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */