00001
00002 #include "Core/precomp.h"
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053 #ifdef __WIN32__
00054 # ifdef _MSC_VER
00055
00056 # pragma warning(disable: 4201)
00057 # endif // VC++
00058
00059 # include <windows.h>
00060 #endif // WIN32
00061
00062 #ifdef __unix__
00063 # include <sys/param.h>
00064 # include <sys/stat.h>
00065 # include <unistd.h>
00066 # define MAX_PATH MAXPATHLEN
00067 #endif
00068
00069 #include <fcntl.h>
00070 #include <sys/types.h>
00071 #include <iostream>
00072 #include <fstream.h>
00073 #include <string.h>
00074 #include <cctype>
00075 #include <stdio.h>
00076 #include <stdlib.h>
00077 #include <stdarg.h>
00078 #include <assert.h>
00079
00080
00081 #include "appconf.h"
00082
00083
00084
00085
00086
00087 #if APPCONF_USE_GETTEXT
00088 # include <libintl.h>
00089 # define _(x) dgettext(APPCONF_DOMAIN,x)
00090 #else
00091 # define _(x) (x)
00092 #endif
00093
00094 using namespace std;
00095
00096 #ifndef __WXWIN__
00097
00098
00099
00100 #ifndef LogInfo
00101 # define LogInfo LogError
00102 #endif
00103
00104
00105 #ifndef LogWarning
00106 # define LogWarning LogError
00107 #endif
00108
00109
00110
00111 void LogError(const char *pszFormat, ...)
00112 {
00113 char szBuf[1025];
00114
00115 va_list argptr;
00116 va_start(argptr, pszFormat);
00117 vsprintf(szBuf, pszFormat, argptr);
00118 va_end(argptr);
00119
00120 strcat(szBuf, "\n");
00121 fputs(szBuf, stderr);
00122 }
00123
00124 #endif
00125
00126 #ifdef __WIN32__
00127
00128 const char *SysError()
00129 {
00130 static char s_szBuf[1024];
00131
00132
00133 LPVOID lpMsgBuf;
00134 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
00135 NULL, GetLastError(),
00136 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
00137 (LPTSTR)&lpMsgBuf,
00138 0, NULL);
00139
00140
00141 strncpy(s_szBuf, (const char *)lpMsgBuf, sizeof(s_szBuf)/sizeof(char));
00142 LocalFree(lpMsgBuf);
00143
00144
00145 s_szBuf[0] = (char)tolower(s_szBuf[0]);
00146 size_t len = strlen(s_szBuf);
00147 if ( (len > 0) && (s_szBuf[len - 1] == '\n') )
00148 s_szBuf[len - 1] = '\0';
00149
00150 return s_szBuf;
00151 }
00152
00153 #endif
00154
00155
00156
00157
00158 inline size_t Strlen(const char *pc) { return pc == NULL ? 0 : strlen(pc); }
00159 inline Bool IsValid(char c) { return isalnum(c) || strchr("_/-!.*%", c); }
00160 inline Bool IsCSym (char c) { return isalnum(c) || ( c == '_'); }
00161 inline size_t Min(size_t n1, size_t n2) { return n1 < n2 ? n1 : n2; }
00162
00163 #define SIZE(array) (sizeof(array)/sizeof(array[0]))
00164
00165 #if APPCONF_CASE_SENSITIVE
00166 # define StrCmp(s1,s2) strcmp((s1),(s2))
00167 #else
00168 # ifdef __unix__
00169 extern "C" int strcasecmp(const char *s1, const char *s2);
00170 # define StrCmp(s1,s2) strcasecmp((s1),(s2))
00171 # else
00172 # ifdef _MSC_VER
00173 # define StrCmp(s1,s2) _stricmp((s1),(s2))
00174 # else
00175 # error "Please define 'stricmp' function for your compiler."
00176 # endif // compilers
00177 # endif // strcasecmp/strcimp
00178 #endif
00179
00180
00181 char *ExpandEnvVars(const char *psz)
00182 {
00183 char *szNewValue = new char[strlen(psz)+1];
00184 strcpy(szNewValue, psz);
00185 return szNewValue;
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323 }
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333 BaseConfig::BaseConfig()
00334 {
00335 m_szCurrentPath = NULL;
00336 m_bRecordDefaults = FALSE;
00337 }
00338
00339 BaseConfig::~BaseConfig()
00340 {
00341 if ( m_szCurrentPath != NULL )
00342 delete [] m_szCurrentPath;
00343 }
00344
00345 void
00346 BaseConfig::recordDefaults(Bool enable)
00347 {
00348 m_bRecordDefaults = enable;
00349 }
00350
00351
00352
00353
00354
00355 Bool
00356 BaseConfig::writeEntry(const char *szKey, long int Value)
00357 {
00358 char buffer[APPCONF_STRBUFLEN];
00359 sprintf(buffer, "%ld", Value);
00360 return writeEntry(szKey,buffer);
00361 }
00362
00363 Bool
00364 BaseConfig::writeEntry(const char *szKey, double Value)
00365 {
00366 char buffer[APPCONF_STRBUFLEN];
00367 sprintf(buffer,"%g", Value);
00368 return writeEntry(szKey,buffer);
00369 }
00370
00371 long int
00372 BaseConfig::readEntry(const char *szKey, long int Default) const
00373 {
00374 const char *cptr = readEntry(szKey,(const char *)NULL);
00375 if(cptr)
00376 return atol(cptr);
00377 else
00378 {
00379 if(m_bRecordDefaults)
00380 ((BaseConfig *)this)->writeEntry(szKey,Default);
00381 return Default;
00382 }
00383 }
00384
00385 double
00386 BaseConfig::readEntry(const char *szKey, double Default) const
00387 {
00388 const char *cptr = readEntry(szKey,(const char *)NULL);
00389 if(cptr)
00390 return atof(cptr);
00391 else
00392 {
00393 if(m_bRecordDefaults)
00394 ((BaseConfig *)this)->writeEntry(szKey,Default);
00395 return Default;
00396 }
00397 }
00398
00399
00400
00401
00402
00403
00404
00405
00406 char *BaseConfig::normalizePath(const char *szStartPath, const char *szPath)
00407 {
00408 char *szNormPath;
00409
00410
00411 #define COMPONENTS_INITIAL (10)
00412
00413 char **aszPathComponents;
00414 size_t nComponents = 0,
00415 nMaxComponents;
00416
00417 aszPathComponents = new char *[nMaxComponents = COMPONENTS_INITIAL];
00418
00419 const char *pcStart;
00420 const char *pcIn;
00421
00422
00423 size_t len = Strlen(szStartPath);
00424 size_t nOldLen = len + Strlen(szPath) + 1;
00425 szNormPath = new char[nOldLen + 1];
00426 strcpy(szNormPath, szStartPath);
00427 szNormPath[len++] = APPCONF_PATH_SEPARATOR;
00428 szNormPath[len] = '\0';
00429 strcat(szNormPath, szPath);
00430
00431
00432 Bool bEnd = FALSE;
00433 for ( pcStart = pcIn = szNormPath; !bEnd; pcIn++ ) {
00434 if ( *pcIn == APPCONF_PATH_SEPARATOR || *pcIn == '\0' ) {
00435 if ( *pcIn == '\0' )
00436 bEnd = TRUE;
00437
00438
00439 if ( *pcStart == '.' ) {
00440 if ( pcIn == pcStart + 1 ) {
00441
00442 pcStart = pcIn + 1;
00443 continue;
00444 }
00445 else if ( (pcIn == pcStart + 2) && (*(pcStart + 1) == '.') ) {
00446
00447 if ( nComponents > 0 ) {
00448 delete [] aszPathComponents[--nComponents];
00449 }
00450 else {
00451 LogWarning(_("extra '..' in the path '%s'."), szPath);
00452 }
00453
00454 pcStart = pcIn + 1;
00455 continue;
00456 }
00457 }
00458 else if ( pcIn == pcStart ) {
00459 pcStart = pcIn + 1;
00460 continue;
00461 }
00462
00463
00464
00465
00466 if ( nComponents == nMaxComponents ) {
00467
00468 char **aszOld = aszPathComponents;
00469 nMaxComponents += COMPONENTS_INITIAL;
00470 aszPathComponents = new char *[nMaxComponents];
00471
00472
00473 memmove(aszPathComponents, aszOld,
00474 sizeof(aszPathComponents[0]) * nComponents);
00475
00476
00477 delete [] aszOld;
00478 }
00479
00480
00481 aszPathComponents[nComponents] = new char[pcIn - pcStart + 1];
00482 strncpy(aszPathComponents[nComponents], pcStart, pcIn - pcStart);
00483 aszPathComponents[nComponents][pcIn - pcStart] = '\0';
00484 nComponents++;
00485
00486 pcStart = pcIn + 1;
00487 }
00488 }
00489
00490 if ( nComponents == 0 ) {
00491
00492 szNormPath[0] = '\0';
00493 }
00494 else {
00495
00496 len = 0;
00497 for ( size_t n = 0; n < nComponents; n++ ) {
00498
00499 if ( len != 0 ) {
00500 szNormPath[len++] = APPCONF_PATH_SEPARATOR;
00501 }
00502 szNormPath[len] = '\0';
00503
00504
00505 strcat(szNormPath, aszPathComponents[n]);
00506
00507
00508 len += strlen(aszPathComponents[n]);
00509
00510
00511 delete [] aszPathComponents[n];
00512 }
00513 }
00514
00515 delete [] aszPathComponents;
00516
00517 return szNormPath;
00518 }
00519
00520 void BaseConfig::changeCurrentPath(const char *szPath)
00521 {
00522
00523 if ( Strlen(szPath) == 0 ) {
00524 if ( m_szCurrentPath != NULL ) {
00525 delete [] m_szCurrentPath;
00526 m_szCurrentPath = NULL;
00527 }
00528 }
00529 else {
00530 char *szNormPath;
00531
00532
00533 if ( *szPath == APPCONF_PATH_SEPARATOR )
00534 szNormPath = normalizePath("", szPath + 1);
00535 else
00536 szNormPath = normalizePath(m_szCurrentPath ? m_szCurrentPath : "", szPath);
00537
00538 size_t len = Strlen(szNormPath);
00539 if ( m_szCurrentPath == NULL || len > strlen(m_szCurrentPath) ) {
00540
00541 if ( m_szCurrentPath != NULL )
00542 delete [] m_szCurrentPath;
00543 m_szCurrentPath = new char[len + 1];
00544 }
00545
00546
00547 strcpy(m_szCurrentPath, szNormPath);
00548
00549 delete [] szNormPath;
00550 }
00551 }
00552
00553 void BaseConfig::setCurrentPath(const char *szPath)
00554 {
00555 changeCurrentPath();
00556 changeCurrentPath(szPath);
00557 }
00558
00559 const char *BaseConfig::getCurrentPath() const
00560 {
00561 return m_szCurrentPath == NULL ? "" : m_szCurrentPath;
00562 }
00563
00564
00565
00566
00567
00568
00569 char *BaseConfig::filterOut(const char *szValue)
00570 {
00571
00572 Bool bDoQuote = isspace(*szValue) || (*szValue == '"');
00573
00574
00575 size_t len = Strlen(szValue);
00576
00577 const char *pcIn = szValue;
00578 while ( *pcIn ) {
00579 switch ( *pcIn++ ) {
00580 case '"':
00581 if ( !bDoQuote )
00582 break;
00583
00584
00585 case '\n':
00586 case '\t':
00587 case '\\':
00588
00589 len++;
00590 break;
00591 }
00592 }
00593
00594 if ( bDoQuote )
00595 len += 2;
00596
00597 char *szBuf = new char[len + 1];
00598 char *pcOut = szBuf;
00599
00600 if ( bDoQuote )
00601 *pcOut++ = '"';
00602
00603 char c;
00604 for ( pcIn = szValue; *pcIn != '\0'; pcIn++ ) {
00605 switch ( *pcIn ) {
00606 case '\n':
00607 c = 'n';
00608 break;
00609
00610 case '\t':
00611 c = 't';
00612 break;
00613
00614 case '\\':
00615 c = '\\';
00616 break;
00617
00618 case '"':
00619 if ( bDoQuote )
00620 c = '"';
00621
00622
00623 default:
00624 *pcOut++ = *pcIn;
00625 continue;
00626 }
00627
00628
00629 *pcOut++ = '\\';
00630 *pcOut++ = c;
00631 }
00632
00633 if ( bDoQuote )
00634 *pcOut++ = '"';
00635
00636 *pcOut = '\0';
00637
00638 return szBuf;
00639 }
00640
00641
00642 char *BaseConfig::filterIn(const char *szValue)
00643 {
00644
00645 char *szBuf = new char[Strlen(szValue) + 1];
00646
00647 const char *pcIn = szValue;
00648 char *pcOut = szBuf;
00649
00650 Bool bQuoted = *pcIn == '"';
00651 if ( bQuoted )
00652 pcIn++;
00653
00654 while ( *pcIn != '\0' ) {
00655 switch ( *pcIn ) {
00656 case '\\':
00657 switch ( *++pcIn ) {
00658 case 'n':
00659 *pcOut++ = '\n';
00660 break;
00661
00662 case 't':
00663 *pcOut++ = '\t';
00664 break;
00665
00666 case '\\':
00667 *pcOut++ = '\\';
00668 break;
00669
00670 case '"':
00671 default:
00672
00673 *pcOut++ = *pcIn;
00674 }
00675 break;
00676
00677 case '"':
00678 if ( bQuoted ) {
00679 if ( *(pcIn + 1) != '\0' ) {
00680 LogWarning(_("invalid string '%s' in configuration file."), szValue);
00681 }
00682 break;
00683 }
00684
00685
00686 default:
00687 *pcOut++ = *pcIn;
00688 }
00689
00690 pcIn++;
00691 }
00692
00693 *pcOut = '\0';
00694
00695 return szBuf;
00696 }
00697
00698
00699
00700
00701 BaseConfig::Enumerator::Enumerator(size_t nCount, Bool bOwnsStrings)
00702 {
00703 m_bOwnsStrings = bOwnsStrings;
00704 m_aszData = new char *[nCount];
00705 m_nCount = 0;
00706 }
00707
00708
00709 BaseConfig::Enumerator::~Enumerator()
00710 {
00711 if ( m_bOwnsStrings ) {
00712 for ( size_t n = 0; n < m_nCount; n++ )
00713 delete [] m_aszData[n];
00714 }
00715
00716 delete [] m_aszData;
00717 }
00718
00719 void BaseConfig::Enumerator::AddString(char *sz)
00720 {
00721 m_aszData[m_nCount++] = sz;
00722 }
00723
00724 void BaseConfig::Enumerator::AddString(const char *sz)
00725 {
00726 assert( !m_bOwnsStrings );
00727
00728
00729 m_aszData[m_nCount++] = (char *)sz;
00730 }
00731
00732
00733 void BaseConfig::Enumerator::MakeUnique()
00734 {
00735 char **aszUnique = new char *[m_nCount];
00736 size_t nUnique = 0;
00737
00738 Bool bUnique;
00739 for ( size_t n = 0; n < m_nCount; n++ ) {
00740 bUnique = TRUE;
00741 for ( size_t n2 = n + 1; n2 < m_nCount; n2++ ) {
00742 if ( StrCmp(m_aszData[n], m_aszData[n2]) == 0 ) {
00743 bUnique = FALSE;
00744 break;
00745 }
00746 }
00747
00748 if ( bUnique )
00749 aszUnique[nUnique++] = m_aszData[n];
00750 else if ( m_bOwnsStrings )
00751 delete [] m_aszData[n];
00752 }
00753
00754 delete [] m_aszData;
00755 m_aszData = aszUnique;
00756 m_nCount = nUnique;
00757 }
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768 FileConfig::ConfigEntry::ConfigEntry(ConfigGroup *pParent,
00769 ConfigEntry *pNext,
00770 const char *szName)
00771 {
00772 m_pParent = pParent;
00773 m_pNext = pNext;
00774 m_szExpValue =
00775 m_szValue =
00776 m_szComment = NULL;
00777 m_bDirty =
00778 m_bLocal = FALSE;
00779
00780
00781 if ( *szName == APPCONF_IMMUTABLE_PREFIX ) {
00782 m_bImmutable = TRUE;
00783 szName++;
00784 }
00785 else
00786 m_bImmutable = FALSE;
00787
00788 m_szName = new char[Strlen(szName) + 1];
00789 strcpy(m_szName, szName);
00790 }
00791
00792
00793 FileConfig::ConfigEntry::~ConfigEntry()
00794 {
00795 if ( m_szName != NULL )
00796 delete [] m_szName;
00797
00798 if ( m_szValue != NULL )
00799 delete [] m_szValue;
00800
00801 if ( m_szComment != NULL )
00802 delete [] m_szComment;
00803
00804 if ( m_szExpValue != NULL )
00805 delete [] m_szExpValue;
00806 }
00807
00808
00809 void FileConfig::ConfigEntry::SetValue(const char *szValue,
00810 Bool bLocal, Bool bFromFile)
00811 {
00812 if ( m_szExpValue != NULL ) {
00813 delete [] m_szExpValue;
00814 m_szExpValue = NULL;
00815 }
00816
00817 if ( m_szValue != NULL ) {
00818
00819
00820 if ( m_bImmutable ) {
00821 LogWarning(_("attempt to change an immutable entry '%s' ignored."),
00822 m_szName);
00823 return;
00824 }
00825
00826 delete [] m_szValue;
00827 }
00828
00829
00830
00831 if ( !m_bImmutable && !bFromFile )
00832 SetDirty();
00833
00834 m_bLocal = bLocal;
00835 if ( bLocal ) {
00836
00837 SetDirty();
00838 }
00839
00840 if ( szValue != NULL )
00841 {
00842 m_szValue = new char[Strlen(szValue) + 1];
00843 strcpy(m_szValue, szValue);
00844 }
00845 else
00846 {
00847 m_szValue = NULL;
00848 SetDirty(FALSE);
00849 }
00850 }
00851
00852
00853 void FileConfig::ConfigEntry::SetComment(char *szComment)
00854 {
00855 assert( m_szComment == NULL );
00856
00857
00858 m_szComment = szComment;
00859 }
00860
00861
00862 void FileConfig::ConfigEntry::SetDirty(Bool bDirty)
00863 {
00864
00865 m_bDirty = m_bLocal ? TRUE : bDirty;
00866 if ( m_bDirty )
00867 m_pParent->SetDirty();
00868 }
00869
00870 const char *FileConfig::ConfigEntry::ExpandedValue()
00871 {
00872 if ( m_szExpValue == NULL ) {
00873
00874 m_szExpValue = ExpandEnvVars(m_szValue);
00875 }
00876
00877 return m_szExpValue;
00878 }
00879
00880
00881
00882
00883
00884
00885
00886
00887 FileConfig::ConfigGroup::ConfigGroup(ConfigGroup *pParent,
00888 ConfigGroup *pNext,
00889 const char *szName)
00890 {
00891 m_pParent = pParent;
00892 m_pNext = pNext;
00893 m_pEntries =
00894 m_pLastEntry = NULL;
00895 m_pSubgroups =
00896 m_pLastGroup = NULL;
00897 m_bDirty = FALSE;
00898
00899 m_szComment = NULL;
00900 m_szName = new char[Strlen(szName) + 1];
00901 strcpy(m_szName, szName); }
00902
00903 FileConfig::ConfigGroup::~ConfigGroup()
00904 {
00905
00906 ConfigEntry *pEntry, *pNextEntry;
00907 for ( pEntry = m_pEntries; pEntry != NULL; pEntry = pNextEntry ) {
00908 pNextEntry = pEntry->Next();
00909 delete pEntry;
00910 }
00911
00912
00913 ConfigGroup *pGroup, *pNextGroup;
00914 for ( pGroup = m_pSubgroups; pGroup != NULL; pGroup = pNextGroup ) {
00915 pNextGroup = pGroup->Next();
00916 delete pGroup;
00917 }
00918
00919 if ( m_szName != NULL )
00920 delete [] m_szName;
00921 }
00922
00923
00924
00925
00926 FileConfig::ConfigGroup *
00927 FileConfig::ConfigGroup::FindSubgroup(const char *szName) const
00928 {
00929 ConfigGroup *pGroup;
00930 for ( pGroup = m_pSubgroups; pGroup != NULL; pGroup = pGroup->Next() ) {
00931 if ( !StrCmp(pGroup->Name(), szName) )
00932 return pGroup;
00933 }
00934
00935 return NULL;
00936 }
00937
00938 FileConfig::ConfigEntry *
00939 FileConfig::ConfigGroup::FindEntry(const char *szName) const
00940 {
00941 ConfigEntry *pEntry;
00942 for ( pEntry = m_pEntries; pEntry != NULL; pEntry = pEntry->Next() ) {
00943 if ( !StrCmp(pEntry->Name(), szName) )
00944 return pEntry;
00945 }
00946
00947 return NULL;
00948 }
00949
00950
00951
00952
00953
00954 FileConfig::ConfigGroup *FileConfig::ConfigGroup::AddSubgroup(const char *szName)
00955 {
00956 ConfigGroup *pGroup = new ConfigGroup(this, NULL, szName);
00957
00958 if ( m_pSubgroups == NULL ) {
00959 m_pSubgroups =
00960 m_pLastGroup = pGroup;
00961 }
00962 else {
00963 m_pLastGroup = m_pLastGroup->m_pNext = pGroup;
00964 }
00965
00966 return pGroup;
00967 }
00968
00969
00970 FileConfig::ConfigEntry *FileConfig::ConfigGroup::AddEntry(const char *szName)
00971 {
00972 ConfigEntry *pEntry = new ConfigEntry(this, NULL, szName);
00973
00974 if ( m_pEntries == NULL ) {
00975 m_pEntries =
00976 m_pLastEntry = pEntry;
00977 }
00978 else {
00979 m_pLastEntry->SetNext(pEntry);
00980 m_pLastEntry = pEntry;
00981 }
00982
00983 return pEntry;
00984 }
00985
00986
00987
00988
00989 Bool FileConfig::ConfigGroup::DeleteSubgroup(const char *szName)
00990 {
00991 ConfigGroup *pGroup, *pPrevGroup = NULL;
00992 for ( pGroup = Subgroup(); pGroup != NULL; pGroup = pGroup->Next() ) {
00993 if ( StrCmp(pGroup->Name(), szName) == 0 ) {
00994 break;
00995 }
00996
00997 pPrevGroup = pGroup;
00998 }
00999
01000 if ( pGroup == NULL )
01001 return FALSE;
01002
01003
01004 if ( pPrevGroup == NULL ) {
01005 m_pSubgroups = pGroup->Next();
01006 }
01007 else {
01008 pPrevGroup->m_pNext = pGroup->Next();
01009 }
01010
01011
01012 if ( pGroup->Next() == NULL ) {
01013 m_pLastGroup = pPrevGroup == NULL ? m_pSubgroups : pPrevGroup;
01014 }
01015
01016
01017
01018 assert( pGroup->Entries() == NULL && pGroup->Subgroup() == NULL );
01019 delete pGroup;
01020
01021 return TRUE;
01022 }
01023
01024 Bool FileConfig::ConfigGroup::DeleteEntry(const char *szName)
01025 {
01026 ConfigEntry *pEntry, *pPrevEntry = NULL;
01027 for ( pEntry = Entries(); pEntry != NULL; pEntry = pEntry->Next() ) {
01028 if ( StrCmp(pEntry->Name(), szName) == 0 ) {
01029 break;
01030 }
01031
01032 pPrevEntry = pEntry;
01033 }
01034
01035 if ( pEntry == NULL )
01036 return FALSE;
01037
01038
01039 if ( pPrevEntry == NULL ) {
01040 m_pEntries = pEntry->Next();
01041 }
01042 else {
01043 pPrevEntry->SetNext(pEntry->Next());
01044 }
01045
01046
01047 if ( pEntry->Next() == NULL ) {
01048 m_pLastEntry = pPrevEntry == NULL ? m_pEntries : pPrevEntry;
01049 }
01050
01051
01052 delete pEntry;
01053
01054 m_pParent->SetDirty();
01055
01056 return TRUE;
01057 }
01058
01059
01060 Bool FileConfig::DeleteIfEmpty()
01061 {
01062
01063 if ( m_pCurGroup->Entries() != NULL || m_pCurGroup->Subgroup() != NULL )
01064 return FALSE;
01065
01066 if ( m_pCurGroup->Parent() == NULL ) {
01067
01068
01069 m_pCurGroup->SetDirty(FALSE);
01070 }
01071 else {
01072
01073 const char *szName = m_pCurGroup->Name();
01074 m_pCurGroup = m_pCurGroup->Parent();
01075 m_pCurGroup->DeleteSubgroup(szName);
01076 }
01077
01078
01079 DeleteIfEmpty();
01080
01081 return TRUE;
01082 }
01083
01084
01085
01086
01087
01088 char *FileConfig::ConfigGroup::FullName() const
01089 {
01090 char *szFullName;
01091 if ( m_pParent == NULL ) {
01092
01093 return NULL;
01094 }
01095 else {
01096 char *pParentFullName = m_pParent->FullName();
01097 if ( pParentFullName == NULL ) {
01098 szFullName = new char[Strlen(m_szName) + 1];
01099 strcpy(szFullName, m_szName);
01100 }
01101 else {
01102 size_t len = Strlen(pParentFullName);
01103 szFullName = new char[len + Strlen(m_szName) + 2];
01104 strcpy(szFullName, pParentFullName);
01105 szFullName[len] = APPCONF_PATH_SEPARATOR;
01106 szFullName[len + 1] = '\0';
01107 strcat(szFullName, m_szName);
01108 delete [] pParentFullName;
01109 }
01110 }
01111
01112 return szFullName;
01113 }
01114
01115
01116
01117 void FileConfig::ConfigGroup::SetDirty(Bool bDirty)
01118 {
01119 m_bDirty = bDirty;
01120 if ( bDirty ) {
01121 if ( m_pParent != NULL )
01122 m_pParent->SetDirty();
01123 }
01124 else {
01125 ConfigEntry *pEntry;
01126 for ( pEntry = Entries(); pEntry != NULL; pEntry = pEntry->Next() )
01127 pEntry->SetDirty(FALSE);
01128
01129 ConfigGroup *pGroup;
01130 for ( pGroup = Subgroup(); pGroup != NULL; pGroup = pGroup->Next() )
01131 pGroup->SetDirty(FALSE);
01132 }
01133 }
01134
01135
01136 Bool FileConfig::ConfigGroup::flush(std::ostream *ostr)
01137 {
01138
01139 Bool bFirstDirty = TRUE;
01140 ConfigEntry *pEntry;
01141 for ( pEntry = Entries(); pEntry != NULL; pEntry = pEntry->Next() ) {
01142 if ( pEntry->IsDirty() && pEntry->Value()) {
01143 if ( bFirstDirty ) {
01144
01145 if ( Comment() != NULL ) {
01146 *ostr << Comment();
01147 }
01148
01149
01150 char *pName = FullName();
01151 if ( pName != NULL ) {
01152 *ostr << '[' << pName << ']';
01153 if ( pEntry->Comment() == NULL )
01154 *ostr << endl;
01155 delete [] pName;
01156 }
01157
01158
01159 bFirstDirty = FALSE;
01160 }
01161
01162
01163 if ( pEntry->Comment() != NULL ) {
01164 *ostr << pEntry->Comment();
01165 }
01166
01167 char *szFilteredValue = filterOut(pEntry->Value());
01168 *ostr << pEntry->Name() << " = " << szFilteredValue << endl;
01169 delete [] szFilteredValue;
01170
01171 pEntry->SetDirty(FALSE);
01172 }
01173 }
01174
01175
01176 ConfigGroup *pGroup;
01177 Bool bOk = TRUE;
01178 for ( pGroup = Subgroup(); pGroup != NULL; pGroup = pGroup->Next() ) {
01179 if ( pGroup->IsDirty() && !pGroup->flush(ostr) ) {
01180 bOk = FALSE;
01181 }
01182 }
01183
01184 return bOk;
01185 }
01186
01187
01188
01189
01190 void FileConfig::ConfigGroup::SetComment(char *szComment)
01191 {
01192 assert( m_szComment == NULL );
01193
01194 m_szComment = szComment;
01195 }
01196
01197
01198
01199
01200
01201
01202 void FileConfig::Init()
01203 {
01204
01205 m_pRootGroup = new ConfigGroup(NULL, NULL, "");
01206
01207 m_szComment = NULL;
01208 m_bOk = FALSE;
01209
01210 m_bExpandVariables = FALSE;
01211 }
01212
01213
01214 FileConfig::FileConfig(const char *szFileName, Bool bLocalOnly, Bool bUseSubDir)
01215 {
01216 Init();
01217
01218 m_bUseSubDir = bUseSubDir;
01219
01220 m_szFileName = new char[Strlen(szFileName) + 1];
01221 strcpy(m_szFileName, szFileName);
01222
01223
01224
01225 ifstream inpStream;
01226 if ( !bLocalOnly ) {
01227 m_szFullFileName = GlobalConfigFile();
01228 inpStream.open(m_szFullFileName, ios::in);
01229 if ( inpStream ) {
01230 m_bParsingLocal = FALSE;
01231 m_bOk = readStream(&inpStream);
01232 }
01233
01234 inpStream.close();
01235 inpStream.clear();
01236 }
01237
01238
01239
01240 m_szFullFileName = LocalConfigFile();
01241 if ( m_szFullFileName != NULL ) {
01242 inpStream.open(m_szFullFileName, ios::in);
01243 if ( inpStream ) {
01244 m_bParsingLocal = TRUE;
01245 if ( readStream(&inpStream) ) {
01246 m_bOk = TRUE;
01247 }
01248
01249 }
01250 }
01251
01252 m_pCurGroup = m_pRootGroup;
01253 BaseConfig::setCurrentPath("");
01254 }
01255
01256
01257 FileConfig::FileConfig(istream *iStream)
01258 {
01259 Init();
01260
01261 m_szFileName = NULL;
01262
01263 if ( iStream == NULL )
01264 return;
01265
01266 m_bParsingLocal = TRUE;
01267 m_bOk = readStream(iStream);
01268
01269 m_pCurGroup = m_pRootGroup;
01270 BaseConfig::setCurrentPath("");
01271 }
01272
01273 FileConfig::FileConfig(void)
01274 {
01275 Init();
01276 m_szFileName = NULL;
01277 }
01278
01279 void
01280 FileConfig::readFile(const char *szFileName)
01281 {
01282 ifstream inpStream;
01283
01284 Init();
01285
01286 m_szFileName = new char[Strlen(szFileName) + 1];
01287 strcpy(m_szFileName, szFileName);
01288
01289 m_szFullFileName = m_szFileName;
01290 inpStream.open(m_szFullFileName, ios::in);
01291 if ( inpStream ) {
01292 m_bParsingLocal = TRUE;
01293 if ( readStream(&inpStream) ) {
01294 m_bOk = TRUE;
01295 }
01296 }
01297
01298 m_pCurGroup = m_pRootGroup;
01299 BaseConfig::setCurrentPath("");
01300 }
01301
01302
01303 FileConfig::~FileConfig()
01304 {
01305 if( m_szFileName != NULL )
01306 flush();
01307
01308 if ( m_szComment != NULL )
01309 delete [] m_szComment;
01310
01311 delete m_pRootGroup;
01312
01313 if ( m_szFileName != NULL )
01314 delete m_szFileName;
01315 }
01316
01317
01318
01319
01320
01321
01322 const char *FileConfig::GlobalConfigFile() const
01323 {
01324 static char s_szBuf[MAX_PATH];
01325
01326
01327 Bool bNoExt = strchr(m_szFileName, '.') == NULL;
01328
01329 #ifdef __unix__
01330 strcpy(s_szBuf, "/etc/");
01331 strcat(s_szBuf, m_szFileName);
01332 if ( bNoExt )
01333 strcat(s_szBuf, ".conf");
01334 #else // Windows
01335 char szWinDir[MAX_PATH];
01336 ::GetWindowsDirectory(szWinDir, MAX_PATH);
01337 strcpy(s_szBuf, szWinDir);
01338 strcat(s_szBuf, "\\");
01339 strcat(s_szBuf, m_szFileName);
01340 if ( bNoExt )
01341 strcat(s_szBuf, ".INI");
01342 #endif // UNIX/Win
01343
01344 return s_szBuf;
01345 }
01346
01347
01348 const char *FileConfig::LocalConfigFile() const
01349 {
01350 static char s_szBuf[MAX_PATH];
01351
01352 #ifdef __unix__
01353 const char *szHome = getenv("HOME");
01354 if ( szHome == NULL ) {
01355
01356 LogInfo(_("can't find user's HOME, looking for config file in current directory."));
01357 szHome = ".";
01358 }
01359 strcpy(s_szBuf, szHome);
01360 strcat(s_szBuf, "/.");
01361 strcat(s_szBuf, m_szFileName);
01362 if(m_bUseSubDir)
01363 {
01364 mkdir(s_szBuf, 0755);
01365
01366 strcat(s_szBuf, "/config");
01367 }
01368 #else // Windows
01369 #ifdef __WIN32__
01370 const char *szHome = getenv("HOMEDRIVE");
01371 if ( szHome == NULL )
01372 szHome = "";
01373 strcpy(s_szBuf, szHome);
01374 szHome = getenv("HOMEPATH");
01375 if ( szHome == NULL )
01376 strcpy(s_szBuf, ".");
01377 else
01378 strcat(s_szBuf, szHome);
01379 strcat(s_szBuf, m_szFileName);
01380 if ( strchr(m_szFileName, '.') == NULL )
01381 strcat(s_szBuf, ".INI");
01382 #else // Win16
01383
01384 if ( !bLocalOnly ) {
01385
01386 s_szBuf = NULL;
01387 }
01388 else {
01389 s_szBuf = GlobalConfigFile();
01390 }
01391 }
01392 #endif // WIN16/32
01393 #endif // UNIX/Win
01394
01395 return s_szBuf;
01396 }
01397
01398
01399
01400
01401
01402
01403 Bool FileConfig::readStream(istream *istr, ConfigGroup *pRootGroup)
01404 {
01405 char szBuf[APPCONF_STRBUFLEN];
01406
01407 m_pCurGroup = pRootGroup == NULL ? m_pRootGroup : pRootGroup;
01408
01409 m_uiLine = 1;
01410
01411 for (;;) {
01412 istr->getline(szBuf, APPCONF_STRBUFLEN, '\n');
01413 if ( istr->eof() ) {
01414
01415
01416 return parseLine(szBuf);
01417 }
01418
01419 if ( !istr->good() || !parseLine(szBuf) )
01420 return FALSE;
01421
01422 m_uiLine++;
01423 }
01424 }
01425
01426
01427 Bool FileConfig::parseLine(const char *psz)
01428 {
01429 size_t len;
01430
01431 const char *pStart = psz;
01432
01433
01434 while ( isspace(*psz) ) psz++;
01435
01436
01437 if ( *psz == '#' || *psz == ';' || *psz == '\0' ) {
01438 if ( *pStart != '\0' )
01439 AppendCommentLine(pStart);
01440
01441
01442 return TRUE;
01443 }
01444
01445 if ( *psz == '[' ) {
01446 const char *pEnd = ++psz;
01447
01448 while ( *pEnd != ']' ) {
01449 if ( IsValid(*pEnd) ) {
01450
01451 pEnd++;
01452 }
01453 else {
01454 if ( *pEnd != APPCONF_PATH_SEPARATOR ) {
01455 LogError(_("file '%s': unexpected character at line %d (missing ']'?)"),
01456 m_szFullFileName, m_uiLine);
01457 return FALSE;
01458 }
01459 }
01460 }
01461
01462 len = pEnd - psz;
01463 char *szGroup = new char[len + 2];
01464 szGroup[0] = APPCONF_PATH_SEPARATOR;
01465 szGroup[1] = '\0';
01466 strncat(szGroup, psz, len);
01467
01468
01469 setCurrentPath(szGroup);
01470
01471
01472 if ( m_szComment != NULL ) {
01473 m_pCurGroup->SetComment(m_szComment);
01474 m_szComment = NULL;
01475 }
01476
01477 delete [] szGroup;
01478
01479
01480 Bool bComment = FALSE;
01481 for ( pStart = ++pEnd ; *pEnd != '\0'; pEnd++ ) {
01482 switch ( *pEnd ) {
01483 case '#':
01484 case ';':
01485 bComment = TRUE;
01486 break;
01487
01488 case ' ':
01489 case '\t':
01490
01491 break;
01492
01493 default:
01494 if ( !bComment ) {
01495 LogWarning(_("file '%s', line %d: '%s' ignored after group header."),
01496 m_szFullFileName, m_uiLine, pEnd);
01497 return TRUE;
01498 }
01499 }
01500 }
01501
01502 if ( bComment ) {
01503 AppendCommentLine(pStart);
01504 }
01505 }
01506 else {
01507 const char *pEnd = psz;
01508 while ( IsValid(*pEnd) )
01509 pEnd++;
01510
01511 len = pEnd - psz;
01512 char *szKey = new char[len + 1];
01513 strncpy(szKey, psz, len + 1);
01514 szKey[len] = '\0';
01515
01516 while ( isspace(*pEnd) ) pEnd++;
01517
01518 if ( *pEnd++ != '=' ) {
01519 LogError(_("file '%s': expected '=' at line %d."),
01520 m_szFullFileName, m_uiLine);
01521 return FALSE;
01522 }
01523
01524 while ( isspace(*pEnd) ) pEnd++;
01525
01526 ConfigEntry *pEntry = m_pCurGroup->FindEntry(szKey);
01527
01528 if ( pEntry == NULL ) {
01529 pEntry = m_pCurGroup->AddEntry(szKey);
01530 }
01531
01532
01533
01534
01535
01536
01537
01538
01539
01540
01541
01542 if ( m_szComment != NULL ) {
01543 pEntry->SetComment(m_szComment);
01544 m_szComment = NULL;
01545 }
01546
01547 char *szUnfilteredValue = filterIn(pEnd);
01548 pEntry->SetValue(szUnfilteredValue, m_bParsingLocal, TRUE);
01549
01550 delete [] szUnfilteredValue;
01551 delete [] szKey;
01552 }
01553
01554 return TRUE;
01555 }
01556
01557
01558
01559
01560
01561 const char *FileConfig::readEntry(const char *szKey,
01562 const char *szDefault) const
01563 {
01564 ConfigEntry *pEntry = m_pCurGroup->FindEntry(szKey);
01565
01566 if ( pEntry != NULL ) {
01567 if ( m_bExpandVariables )
01568 return pEntry->ExpandedValue();
01569 else
01570 return pEntry->Value();
01571 }
01572
01573 if(m_bRecordDefaults)
01574 ((FileConfig *)this)->writeEntry(szKey,szDefault);
01575
01576
01577 return szDefault;
01578 }
01579
01580
01581
01582
01583
01584
01585 void FileConfig::changeCurrentPath(const char *szPath)
01586 {
01587
01588 BaseConfig::changeCurrentPath(szPath);
01589 szPath = getCurrentPath();
01590
01591 m_pCurGroup = m_pRootGroup;
01592
01593
01594 if ( *szPath == '\0' )
01595 return;
01596
01597 char *szGroupName = NULL;
01598 size_t len = 0;
01599
01600 const char *pBegin = szPath;
01601 const char *pEnd = pBegin + 1;
01602
01603 do{
01604 while ( *pEnd != '\0' && *pEnd != APPCONF_PATH_SEPARATOR )
01605 pEnd++;
01606
01607 if ( (unsigned)(pEnd - pBegin) + 1 > len ) {
01608
01609 len = pEnd - pBegin + 1;
01610
01611
01612 if ( szGroupName != NULL )
01613 delete [] szGroupName;
01614
01615 szGroupName = new char[len];
01616 }
01617
01618 strncpy(szGroupName, pBegin, len);
01619 szGroupName[len - 1] = '\0';
01620
01621 ConfigGroup *pGroup = m_pCurGroup->FindSubgroup(szGroupName);
01622
01623 if ( pGroup == NULL ) {
01624
01625 m_pCurGroup = m_pCurGroup->AddSubgroup(szGroupName);
01626 }
01627 else {
01628 m_pCurGroup = pGroup;
01629 }
01630
01631 if ( *pEnd == APPCONF_PATH_SEPARATOR ) {
01632 pBegin = ++pEnd;
01633 }
01634 }while ( *pEnd != '\0' );
01635
01636 if ( szGroupName != NULL )
01637 delete [] szGroupName;
01638 }
01639
01640
01641 Bool FileConfig::writeEntry(const char *szKey, const char *szValue)
01642 {
01643 ConfigEntry *pEntry = m_pCurGroup->FindEntry(szKey);
01644 if ( pEntry == NULL ) {
01645 pEntry = m_pCurGroup->AddEntry(szKey);
01646 }
01647
01648 pEntry->SetValue(szValue);
01649
01650 return TRUE;
01651 }
01652
01653
01654 Bool FileConfig::deleteEntry(const char *szKey)
01655 {
01656 Bool bDeleted = m_pCurGroup->DeleteEntry(szKey);
01657
01658 DeleteIfEmpty();
01659
01660 return bDeleted;
01661 }
01662
01663
01664
01665
01666
01667 Bool FileConfig::flush(Bool bCurrentOnly)
01668 {
01669 ConfigGroup *pRootGroup = bCurrentOnly ? m_pCurGroup : m_pRootGroup;
01670
01671 if ( m_pRootGroup->IsDirty() ) {
01672 fstream outStream(LocalConfigFile(), ios::out);
01673
01674 Bool bOk = pRootGroup->flush(&outStream);
01675
01676
01677
01678 if ( m_szComment != NULL ) {
01679 outStream << m_szComment;
01680 }
01681
01682 outStream.sync();
01683
01684 return bOk;
01685 }
01686 else
01687 return TRUE;
01688 }
01689
01690 Bool FileConfig::flush(std::ostream *oStream, Bool bCurrentOnly)
01691 {
01692 ConfigGroup *pRootGroup = bCurrentOnly ? m_pCurGroup : m_pRootGroup;
01693
01694 if ( m_pRootGroup->IsDirty() ) {
01695
01696 Bool bOk = pRootGroup->flush(oStream);
01697
01698
01699
01700 if ( m_szComment != NULL ) {
01701 *oStream << m_szComment;
01702 }
01703
01704 return bOk;
01705 }
01706 else
01707 return TRUE;
01708 }
01709
01710
01711
01712
01713
01714
01715 void FileConfig::AppendCommentLine(const char *szComment)
01716 {
01717 if ( !m_bParsingLocal )
01718 return;
01719
01720 size_t len = Strlen(m_szComment) + strlen(szComment) + 1;
01721
01722 char *szNewComment = new char[len + 1];
01723 if ( m_szComment == NULL ) {
01724 szNewComment[0] = '\0';
01725 }
01726 else {
01727 strcpy(szNewComment, m_szComment);
01728 delete [] m_szComment;
01729 }
01730 strcat(szNewComment, szComment);
01731 strcat(szNewComment, "\n");
01732
01733 m_szComment = szNewComment;
01734 }
01735
01736
01737
01738
01739
01740 BaseConfig::Enumerator *FileConfig::enumSubgroups() const
01741 {
01742 size_t nGroups = 0;
01743 ConfigGroup *pGroup = m_pCurGroup->Subgroup();
01744 while ( pGroup != NULL ) {
01745 nGroups++;
01746 pGroup = pGroup->Next();
01747 }
01748
01749 BaseConfig::Enumerator *pEnum = new Enumerator(nGroups, FALSE);
01750
01751 pGroup = m_pCurGroup->Subgroup();
01752 for ( size_t n = 0; n < nGroups; n++ ) {
01753 pEnum->AddString(pGroup->Name());
01754 pGroup = pGroup->Next();
01755 }
01756
01757 return pEnum;
01758 }
01759
01760 BaseConfig::Enumerator *FileConfig::enumEntries() const
01761 {
01762 size_t nEntries = 0;
01763 ConfigEntry *pEntry = m_pCurGroup->Entries();
01764 while ( pEntry != NULL ) {
01765 nEntries++;
01766 pEntry = pEntry->Next();
01767 }
01768
01769 BaseConfig::Enumerator *pEnum = new Enumerator(nEntries, FALSE);
01770
01771 pEntry = m_pCurGroup->Entries();
01772 for ( size_t n = 0; n < nEntries; n++ ) {
01773 pEnum->AddString(pEntry->Name());
01774 pEntry = pEntry->Next();
01775 }
01776
01777 return pEnum;
01778 }
01779
01780
01781
01782
01783 #ifdef __WIN32__
01784
01785
01786
01787
01788
01789
01790 RegistryConfig::RegistryConfig(const char *szRootKey)
01791 {
01792 static const char szPrefix[] = "Software";
01793
01794 char *szKey = new char[strlen(szPrefix) + Strlen(szRootKey) + 2];
01795 strcpy(szKey, szPrefix);
01796 strcat(szKey, "\\");
01797 strcat(szKey, szRootKey);
01798
01799
01800 LONG lRc = RegOpenKey(HKEY_LOCAL_MACHINE, szKey, &m_hGlobalRootKey);
01801 m_bOk = lRc == ERROR_SUCCESS;
01802 if ( !m_bOk )
01803 m_hGlobalRootKey = NULL;
01804
01805 m_hGlobalCurKey = m_hGlobalRootKey;
01806
01807
01808 lRc = RegCreateKey(HKEY_CURRENT_USER, szKey, &m_hLocalRootKey);
01809 m_hLocalCurKey = m_hLocalRootKey;
01810 if ( !m_bOk )
01811 m_bOk = lRc;
01812
01813 m_pLastRead = NULL;
01814
01815 delete [] szKey;
01816 }
01817
01818
01819 RegistryConfig::~RegistryConfig()
01820 {
01821 if ( m_pLastRead != NULL )
01822 delete [] m_pLastRead;
01823
01824 if ( m_hGlobalRootKey != NULL )
01825 RegCloseKey(m_hGlobalRootKey);
01826 if ( m_hLocalRootKey != NULL )
01827 RegCloseKey(m_hLocalRootKey);
01828
01829
01830 if ( m_hGlobalCurKey != NULL && m_hGlobalCurKey != m_hGlobalRootKey )
01831 RegCloseKey(m_hGlobalCurKey);
01832 if ( m_hLocalCurKey != NULL && m_hLocalCurKey != m_hLocalRootKey )
01833 RegCloseKey(m_hLocalCurKey);
01834 }
01835
01836
01837
01838
01839
01840
01841
01842 const char *RegistryConfig::ReadValue(void *hKey, const char *szValue) const
01843 {
01844
01845 DWORD dwSize;
01846 LONG lRc = RegQueryValueEx(hKey, szValue, 0, NULL, NULL, &dwSize);
01847
01848 if ( lRc != ERROR_SUCCESS )
01849 return NULL;
01850
01851 char *szBuffer = new char[dwSize];
01852 DWORD dwType;
01853 lRc = RegQueryValueEx(hKey, szValue, 0, &dwType,
01854 (unsigned char *)szBuffer, &dwSize);
01855
01856 if ( lRc != ERROR_SUCCESS ) {
01857
01858 LogWarning(_("can't query the value '%s' (%s)."), szValue, SysError());
01859
01860 return NULL;
01861 }
01862
01863
01864 if ( dwType == REG_EXPAND_SZ ) {
01865
01866 DWORD dwLen = ExpandEnvironmentStrings(szBuffer, NULL, 0);
01867
01868
01869 char *szBufferExp = new char[dwLen + 1];
01870 ExpandEnvironmentStrings(szBuffer, szBufferExp, dwLen + 1);
01871
01872
01873 delete [] szBuffer;
01874 szBuffer = szBufferExp;
01875 }
01876
01877
01878 if ( m_pLastRead != NULL )
01879 delete [] m_pLastRead;
01880
01881
01882 ((RegistryConfig *)this)->m_pLastRead = filterIn((const char *)szBuffer);
01883 delete [] szBuffer;
01884
01885 return m_pLastRead;
01886 }
01887
01888
01889
01890 const char *RegistryConfig::readEntry(const char *szKey,
01891 const char *szDefault) const
01892 {
01893 const char *pRetValue = ReadValue(m_hLocalCurKey, szKey);
01894
01895
01896 if ( pRetValue == NULL && m_hGlobalCurKey != NULL )
01897 pRetValue = ReadValue(m_hGlobalCurKey, szKey);
01898
01899 if(pRetValue != NULL)
01900 return pRetValue;
01901 else
01902 {
01903 if(m_bRecordDefaults)
01904 writeEntry(szKey, szDefault);
01905 return szDefault;
01906 }
01907 }
01908
01909
01910
01911 Bool RegistryConfig::writeEntry(const char *szKey, const char *szValue)
01912 {
01913 char *szFiltered = filterOut(szValue);
01914
01915 long lRc = RegSetValueEx(m_hLocalCurKey, szKey, 0, REG_SZ,
01916 (unsigned char *)szFiltered,
01917 Strlen(szFiltered) + 1);
01918
01919 delete [] szFiltered;
01920
01921 return lRc == ERROR_SUCCESS;
01922 }
01923
01924
01925 Bool RegistryConfig::deleteEntry(const char *szKey)
01926 {
01927 Bool bDeleted = RegDeleteValue(m_hLocalCurKey, szKey) == ERROR_SUCCESS;
01928 if ( !bDeleted ) {
01929
01930 LogWarning(_("can't delete entry '%s': %s"), szKey, SysError());
01931 }
01932
01933
01934
01935
01936 while ( KeyIsEmpty(m_hLocalCurKey) ) {
01937
01938 const char *szPath = getCurrentPath();
01939 const char *szKeyName = strrchr(szPath, APPCONF_PATH_SEPARATOR);
01940 if ( szKeyName == NULL )
01941 szKeyName = szPath;
01942 else
01943 szKeyName++;
01944
01945
01946 char *aszSubkey = new char[strlen(szKeyName) + 1];
01947 strcpy(aszSubkey, szKeyName);
01948
01949
01950 if ( *szKeyName != '\0' ) {
01951 changeCurrentPath("..");
01952 if ( RegDeleteKey(m_hLocalCurKey, aszSubkey) != ERROR_SUCCESS )
01953 LogWarning(_("can't delete key '%s': %s"), aszSubkey, SysError());
01954 }
01955
01956 delete [] aszSubkey;
01957 }
01958
01959 return bDeleted;
01960 }
01961
01962
01963
01964
01965
01966
01967
01968
01969
01970 BaseConfig::Enumerator *RegistryConfig::enumSubgroups() const
01971 {
01972 DWORD dwKeysLocal, dwKeysGlobal,
01973 dwKeyLenLocal, dwKeyLenGlobal;
01974
01975 long lRc = RegQueryInfoKey(m_hLocalCurKey, NULL, NULL, NULL,
01976 &dwKeysLocal, &dwKeyLenLocal,
01977 NULL, NULL, NULL, NULL, NULL, NULL);
01978
01979 assert( lRc == ERROR_SUCCESS );
01980
01981 if ( m_hGlobalCurKey == NULL ) {
01982
01983 dwKeysGlobal = dwKeyLenGlobal = 0;
01984 }
01985 else {
01986 lRc = RegQueryInfoKey(m_hGlobalCurKey, NULL, NULL, NULL, &dwKeysGlobal,
01987 &dwKeyLenGlobal, NULL, NULL, NULL, NULL, NULL, NULL);
01988
01989 assert( lRc == ERROR_SUCCESS );
01990 }
01991
01992 DWORD dwKeys = dwKeysLocal + dwKeysGlobal;
01993 DWORD dwKeyLen = max(dwKeyLenLocal, dwKeyLenGlobal);
01994
01995 BaseConfig::Enumerator *pEnum = new Enumerator((size_t)dwKeys, TRUE);
01996
01997 char *szKey;
01998 HKEY hKey = m_hGlobalCurKey;
01999 for ( DWORD dwKey = 0; dwKeys > 0; dwKey++, dwKeys-- ) {
02000 if ( dwKeys == dwKeysLocal ) {
02001
02002 hKey = m_hLocalCurKey;
02003 dwKey = 0;
02004 }
02005
02006 szKey = new char[dwKeyLen + 1];
02007 if ( RegEnumKey(hKey, dwKey, szKey, dwKeyLen + 1) != ERROR_SUCCESS ) {
02008 delete [] szKey;
02009 break;
02010 }
02011
02012 pEnum->AddString(szKey);
02013 }
02014
02015 pEnum->MakeUnique();
02016
02017 return pEnum;
02018 }
02019
02020 BaseConfig::Enumerator *RegistryConfig::enumEntries() const
02021 {
02022 DWORD dwEntriesLocal, dwEntriesGlobal,
02023 dwEntryLenLocal, dwEntryLenGlobal;
02024
02025 long lRc = RegQueryInfoKey(m_hLocalCurKey, NULL, NULL, NULL,
02026 NULL, NULL, NULL,
02027 &dwEntriesLocal, &dwEntryLenLocal,
02028 NULL, NULL, NULL);
02029
02030 assert( lRc == ERROR_SUCCESS );
02031
02032 if ( m_hGlobalCurKey == NULL ) {
02033
02034 dwEntriesGlobal = dwEntryLenGlobal = 0;
02035 }
02036 else {
02037 lRc = RegQueryInfoKey(m_hGlobalCurKey,
02038 NULL, NULL, NULL,
02039 NULL, NULL, NULL,
02040 &dwEntriesGlobal,
02041 &dwEntryLenGlobal,
02042 NULL, NULL, NULL);
02043
02044 assert( lRc == ERROR_SUCCESS );
02045 }
02046
02047 DWORD dwEntries = dwEntriesLocal + dwEntriesGlobal;
02048 DWORD dwEntryLen = max(dwEntryLenLocal, dwEntryLenGlobal);
02049
02050 BaseConfig::Enumerator *pEnum = new Enumerator((size_t)dwEntries, TRUE);
02051
02052 char *szVal;
02053 DWORD dwLen;
02054 HKEY hKey = m_hGlobalCurKey;
02055 for ( DWORD dwEntry = 0; dwEntries > 0; dwEntry++, dwEntries-- ) {
02056 if ( dwEntries == dwEntriesLocal ) {
02057
02058 hKey = m_hLocalCurKey;
02059 dwEntry = 0;
02060 }
02061
02062 dwLen = dwEntryLen + 1;
02063 szVal = new char [dwLen];
02064 lRc = RegEnumValue(hKey, dwEntry, szVal, &dwLen, 0, NULL, NULL, NULL);
02065 if ( lRc != ERROR_SUCCESS ) {
02066 delete [] szVal;
02067 break;
02068 }
02069
02070 pEnum->AddString(szVal);
02071 }
02072
02073 pEnum->MakeUnique();
02074
02075 return pEnum;
02076 }
02077
02078
02079
02080
02081
02082
02083 void RegistryConfig::changeCurrentPath(const char *szPath)
02084 {
02085
02086 BaseConfig::changeCurrentPath(szPath);
02087 szPath = getCurrentPath();
02088
02089
02090 if ( *szPath == '\0' ) {
02091 if ( m_hLocalCurKey != m_hLocalRootKey ) {
02092 RegCloseKey(m_hLocalCurKey);
02093 m_hLocalCurKey = m_hLocalRootKey;
02094 }
02095
02096 if ( m_hGlobalCurKey != m_hGlobalRootKey ) {
02097 RegCloseKey(m_hGlobalCurKey);
02098 m_hGlobalCurKey = m_hGlobalRootKey;
02099 }
02100
02101 return;
02102 }
02103
02104 char *szRegPath = new char[Strlen(szPath) + 1];
02105 strcpy(szRegPath, szPath);
02106
02107
02108 char *pcSeparator = szRegPath;
02109 while ( pcSeparator != NULL ) {
02110 pcSeparator = strchr(pcSeparator, APPCONF_PATH_SEPARATOR);
02111 if ( pcSeparator != NULL )
02112 *pcSeparator = '\\';
02113 }
02114
02115 HKEY hOldKey = m_hLocalCurKey;
02116
02117 if ( RegCreateKey(m_hLocalRootKey, szRegPath,
02118 &m_hLocalCurKey) == ERROR_SUCCESS ) {
02119
02120
02121 if ( (m_hLocalCurKey != hOldKey) && (hOldKey != m_hLocalRootKey) )
02122 RegCloseKey(hOldKey);
02123 }
02124 else {
02125 LogWarning(_("can not open key '%s' (%s)."), szPath, SysError());
02126 }
02127
02128 if ( m_hGlobalCurKey != 0 ) {
02129 hOldKey = m_hGlobalCurKey;
02130 if ( RegOpenKey(m_hGlobalRootKey, szRegPath,
02131 &m_hGlobalCurKey) == ERROR_SUCCESS ) {
02132 if ( (m_hGlobalCurKey != hOldKey) && (hOldKey != m_hGlobalRootKey) )
02133 RegCloseKey(hOldKey);
02134 }
02135 else {
02136
02137 if ( m_hGlobalCurKey != m_hGlobalRootKey )
02138 RegCloseKey(m_hGlobalCurKey);
02139 m_hGlobalCurKey = NULL;
02140 }
02141 }
02142
02143 delete [] szRegPath;
02144 }
02145
02146
02147
02148
02149 Bool RegistryConfig::KeyIsEmpty(void *hKey)
02150 {
02151 DWORD dwKeys, dwValues;
02152 long lRc = RegQueryInfoKey(hKey, NULL, NULL, NULL, &dwKeys, NULL, NULL,
02153 &dwValues, NULL, NULL, NULL, NULL);
02154
02155 return (lRc == ERROR_SUCCESS) && (dwValues == 0) && (dwKeys == 0);
02156 }
02157
02158 #endif // WIN32