00001
00002
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 #include <ncbi_pch.hpp>
00037 #include <corelib/ncbireg.hpp>
00038 #include <corelib/env_reg.hpp>
00039 #include <corelib/metareg.hpp>
00040 #include <corelib/ncbiapp.hpp>
00041 #include <corelib/ncbimtx.hpp>
00042 #include <corelib/error_codes.hpp>
00043
00044 #include <algorithm>
00045 #include <set>
00046
00047
00048 #define NCBI_USE_ERRCODE_X Corelib_Reg
00049
00050
00051 BEGIN_NCBI_SCOPE
00052
00053 typedef CRegistryReadGuard TReadGuard;
00054 typedef CRegistryWriteGuard TWriteGuard;
00055
00056
00057
00058 inline bool s_IsNameSectionSymbol(char ch, IRegistry::TFlags flags)
00059 {
00060 return (isalnum((unsigned char) ch)
00061 || ch == '_' || ch == '-' || ch == '.' || ch == '/'
00062 || ((flags & IRegistry::fInternalSpaces) && ch == ' '));
00063 }
00064
00065
00066
00067 static bool s_IsNameSection(const string& str, IRegistry::TFlags flags)
00068 {
00069 if (str.empty()) {
00070 return false;
00071 }
00072
00073 ITERATE (string, it, str) {
00074 if (!s_IsNameSectionSymbol(*it, flags)) {
00075 return false;
00076 }
00077 }
00078 return true;
00079 }
00080
00081
00082
00083 static const string s_ConvertComment(const string& comment,
00084 bool is_file_comment = false)
00085 {
00086 if ( !comment.length() )
00087 return kEmptyStr;
00088
00089 string x_comment;
00090 const char c_comment = is_file_comment ? '#' : ';';
00091
00092 SIZE_TYPE endl_pos = 0;
00093 for (SIZE_TYPE beg = 0; beg < comment.length();
00094 beg = endl_pos + 1) {
00095 SIZE_TYPE pos = comment.find_first_not_of(" \t", beg);
00096 endl_pos = comment.find_first_of("\n", beg);
00097 if (endl_pos == NPOS) {
00098 endl_pos = comment.length();
00099 }
00100 if (((pos != NPOS && comment[pos] != c_comment) ||
00101 (pos == NPOS && endl_pos == comment.length())) &&
00102 (is_file_comment || beg != endl_pos) ) {
00103 x_comment += c_comment;
00104 }
00105 x_comment.append(comment, beg, endl_pos - beg);
00106 x_comment += '\n';
00107 }
00108 return x_comment;
00109 }
00110
00111
00112
00113 static bool s_WriteComment(CNcbiOstream& os, const string& comment)
00114 {
00115 if (!comment.length())
00116 return true;
00117
00118 if (strcmp(Endl(), "\n") == 0) {
00119 os << comment;
00120 } else {
00121 ITERATE(string, i, comment) {
00122 if (*i == '\n') {
00123 os << Endl();
00124 } else {
00125 os << *i;
00126 }
00127 }
00128 }
00129 return os.good();
00130 }
00131
00132
00133 inline bool s_Backslashed(const string& s, SIZE_TYPE pos)
00134 {
00135 if (pos == 0) {
00136 return false;
00137 }
00138 SIZE_TYPE last_non_bs = s.find_last_not_of("\\", pos - 1);
00139 return (pos - last_non_bs) % 2 == 0;
00140 }
00141
00142 inline string s_FlatKey(const string& section, const string& name)
00143 {
00144 return section + '#' + name;
00145 }
00146
00147
00148
00149
00150
00151
00152 bool IRegistry::Empty(TFlags flags) const
00153 {
00154 x_CheckFlags("IRegistry::Empty", flags, fLayerFlags);
00155 if ( !(flags & fTPFlags) ) {
00156 flags |= fTPFlags;
00157 }
00158 TReadGuard LOCK(*this);
00159 return x_Empty(flags);
00160 }
00161
00162
00163 bool IRegistry::Modified(TFlags flags) const
00164 {
00165 x_CheckFlags("IRegistry::Modified", flags, fLayerFlags);
00166 if ( !(flags & fTransient) ) {
00167 flags |= fPersistent;
00168 }
00169 TReadGuard LOCK(*this);
00170 return x_Modified(flags);
00171 }
00172
00173
00174 void IRegistry::SetModifiedFlag(bool modified, TFlags flags)
00175 {
00176 x_CheckFlags("IRegistry::SetModifiedFlag", flags, fLayerFlags);
00177 if ( !(flags & fTransient) ) {
00178 flags |= fPersistent;
00179 }
00180 TReadGuard LOCK(*this);
00181 x_SetModifiedFlag(modified, flags);
00182 }
00183
00184
00185
00186 bool IRegistry::Write(CNcbiOstream& os, TFlags flags) const
00187 {
00188 x_CheckFlags("IRegistry::Write", flags,
00189 (TFlags)fLayerFlags | fInternalSpaces | fCountCleared);
00190 if ( !(flags & fTransient) ) {
00191 flags |= fPersistent;
00192 }
00193 if ( !(flags & fNotJustCore) ) {
00194 flags |= fJustCore;
00195 }
00196 TReadGuard LOCK(*this);
00197
00198
00199 if ( !s_WriteComment(os, GetComment(kEmptyStr, kEmptyStr, flags)) )
00200 return false;
00201
00202 list<string> sections;
00203 EnumerateSections(§ions, flags);
00204
00205 ITERATE (list<string>, section, sections) {
00206 if ( !s_WriteComment(os, GetComment(*section, kEmptyStr, flags)) ) {
00207 return false;
00208 }
00209 os << '[' << *section << ']' << Endl();
00210 if ( !os ) {
00211 return false;
00212 }
00213 list<string> entries;
00214 EnumerateEntries(*section, &entries, flags);
00215 ITERATE (list<string>, entry, entries) {
00216 s_WriteComment(os, GetComment(*section, *entry, flags));
00217
00218
00219
00220 os << *entry << " = \""
00221 << Printable(Get(*section, *entry, flags)) << "\""
00222 << Endl();
00223 if ( !os ) {
00224 return false;
00225 }
00226 }
00227 }
00228
00229
00230
00231 if (Modified(flags & fLayerFlags)) {
00232 const_cast<IRegistry*>(this)->SetModifiedFlag
00233 (false, flags & fLayerFlags);
00234 }
00235
00236 return true;
00237 }
00238
00239
00240 const string& IRegistry::Get(const string& section, const string& name,
00241 TFlags flags) const
00242 {
00243 x_CheckFlags("IRegistry::Get", flags,
00244 (TFlags)fLayerFlags | fInternalSpaces);
00245 if ( !(flags & fTPFlags) ) {
00246 flags |= fTPFlags;
00247 }
00248 string clean_section = NStr::TruncateSpaces(section);
00249 if ( !s_IsNameSection(clean_section, flags) ) {
00250 _TRACE("IRegistry::Get: bad section name \""
00251 << NStr::PrintableString(section) << '\"');
00252 return kEmptyStr;
00253 }
00254 string clean_name = NStr::TruncateSpaces(name);
00255 if ( !s_IsNameSection(clean_name, flags) ) {
00256 _TRACE("IRegistry::Get: bad entry name \""
00257 << NStr::PrintableString(name) << '\"');
00258 return kEmptyStr;
00259 }
00260 TReadGuard LOCK(*this);
00261 return x_Get(clean_section, clean_name, flags);
00262 }
00263
00264
00265 bool IRegistry::HasEntry(const string& section, const string& name,
00266 TFlags flags) const
00267 {
00268 x_CheckFlags("IRegistry::HasEntry", flags,
00269 (TFlags)fLayerFlags | fInternalSpaces | fCountCleared);
00270 if ( !(flags & fTPFlags) ) {
00271 flags |= fTPFlags;
00272 }
00273 string clean_section = NStr::TruncateSpaces(section);
00274 if ( !s_IsNameSection(clean_section, flags) ) {
00275 _TRACE("IRegistry::HasEntry: bad section name \""
00276 << NStr::PrintableString(section) << '\"');
00277 return false;
00278 }
00279 string clean_name = NStr::TruncateSpaces(name);
00280 if ( !clean_name.empty() && !s_IsNameSection(clean_name, flags) ) {
00281 _TRACE("IRegistry::HasEntry: bad entry name \""
00282 << NStr::PrintableString(name) << '\"');
00283 return false;
00284 }
00285 TReadGuard LOCK(*this);
00286 return x_HasEntry(clean_section, clean_name, flags);
00287 }
00288
00289
00290 string IRegistry::GetString(const string& section, const string& name,
00291 const string& default_value, TFlags flags) const
00292 {
00293 const string& value = Get(section, name, flags);
00294 return value.empty() ? default_value : value;
00295 }
00296
00297
00298 int IRegistry::GetInt(const string& section, const string& name,
00299 int default_value, TFlags flags, EErrAction err_action)
00300 const
00301 {
00302 const string& value = Get(section, name, flags);
00303 if (value.empty()) {
00304 return default_value;
00305 }
00306
00307 try {
00308 return NStr::StringToInt(value);
00309 } catch (CStringException& ex) {
00310 if (err_action == eReturn) {
00311 return default_value;
00312 }
00313
00314 string msg = "IRegistry::GetInt(): [" + section + ']' + name;
00315
00316 if (err_action == eThrow) {
00317 NCBI_RETHROW_SAME(ex, msg);
00318 } else if (err_action == eErrPost) {
00319 ERR_POST_X(1, ex.what() << msg);
00320 }
00321
00322 return default_value;
00323 }
00324 }
00325
00326
00327 bool IRegistry::GetBool(const string& section, const string& name,
00328 bool default_value, TFlags flags,
00329 EErrAction err_action) const
00330 {
00331 const string& value = Get(section, name, flags);
00332 if (value.empty()) {
00333 return default_value;
00334 }
00335
00336 try {
00337 return NStr::StringToBool(value);
00338 } catch (CStringException& ex) {
00339 if (err_action == eReturn) {
00340 return default_value;
00341 }
00342
00343 string msg = "IRegistry::GetBool(): [" + section + ']' + name;
00344
00345 if (err_action == eThrow) {
00346 NCBI_RETHROW_SAME(ex, msg);
00347 } else if (err_action == eErrPost) {
00348 ERR_POST_X(2, ex.what() << msg);
00349 }
00350
00351 return default_value;
00352 }
00353 }
00354
00355
00356 double IRegistry::GetDouble(const string& section, const string& name,
00357 double default_value, TFlags flags,
00358 EErrAction err_action) const
00359 {
00360 const string& value = Get(section, name, flags);
00361 if (value.empty()) {
00362 return default_value;
00363 }
00364
00365 try {
00366 return NStr::StringToDouble(value);
00367 } catch (CStringException& ex) {
00368 if (err_action == eReturn) {
00369 return default_value;
00370 }
00371
00372 string msg = "IRegistry::GetDouble()";
00373 msg += " Reg entry:" + section + ":" + name;
00374
00375 if (err_action == eThrow) {
00376 NCBI_RETHROW_SAME(ex, msg);
00377 } else if (err_action == eErrPost) {
00378 ERR_POST_X(3, ex.what() << msg);
00379 }
00380
00381 return default_value;
00382 }
00383 }
00384
00385
00386 const string& IRegistry::GetComment(const string& section, const string& name,
00387 TFlags flags) const
00388 {
00389 x_CheckFlags("IRegistry::GetComment", flags,
00390 (TFlags)fLayerFlags | fInternalSpaces);
00391 string clean_section = NStr::TruncateSpaces(section);
00392 if ( !clean_section.empty() && !s_IsNameSection(clean_section, flags) ) {
00393 _TRACE("IRegistry::GetComment: bad section name \""
00394 << NStr::PrintableString(section) << '\"');
00395 return kEmptyStr;
00396 }
00397 string clean_name = NStr::TruncateSpaces(name);
00398 if ( !clean_name.empty() && !s_IsNameSection(clean_name, flags) ) {
00399 _TRACE("IRegistry::GetComment: bad entry name \""
00400 << NStr::PrintableString(name) << '\"');
00401 return kEmptyStr;
00402 }
00403 TReadGuard LOCK(*this);
00404 return x_GetComment(clean_section, clean_name, flags);
00405 }
00406
00407
00408 void IRegistry::EnumerateSections(list<string>* sections, TFlags flags) const
00409 {
00410 x_CheckFlags("IRegistry::EnumerateSections", flags,
00411 (TFlags)fLayerFlags | fInternalSpaces | fCountCleared);
00412 if ( !(flags & fTPFlags) ) {
00413 flags |= fTPFlags;
00414 }
00415 _ASSERT(sections);
00416 sections->clear();
00417 TReadGuard LOCK(*this);
00418 x_Enumerate(kEmptyStr, *sections, flags);
00419 }
00420
00421
00422 void IRegistry::EnumerateEntries(const string& section, list<string>* entries,
00423 TFlags flags) const
00424 {
00425 x_CheckFlags("IRegistry::EnumerateEntries", flags,
00426 (TFlags)fLayerFlags | fInternalSpaces | fCountCleared);
00427 if ( !(flags & fTPFlags) ) {
00428 flags |= fTPFlags;
00429 }
00430 _ASSERT(entries);
00431 entries->clear();
00432 string clean_section = NStr::TruncateSpaces(section);
00433 if ( !clean_section.empty() && !s_IsNameSection(clean_section, flags) ) {
00434 _TRACE("IRegistry::EnumerateEntries: bad section name \""
00435 << NStr::PrintableString(section) << '\"');
00436 return;
00437 }
00438 TReadGuard LOCK(*this);
00439 x_Enumerate(clean_section, *entries, flags);
00440 }
00441
00442
00443 void IRegistry::ReadLock (void)
00444 {
00445 x_ChildLockAction(&IRegistry::ReadLock);
00446 m_Lock.ReadLock();
00447 }
00448
00449
00450 void IRegistry::WriteLock(void)
00451 {
00452 x_ChildLockAction(&IRegistry::WriteLock);
00453 m_Lock.WriteLock();
00454 }
00455
00456
00457 void IRegistry::Unlock(void)
00458 {
00459 m_Lock.Unlock();
00460 x_ChildLockAction(&IRegistry::Unlock);
00461 }
00462
00463
00464 void IRegistry::x_CheckFlags(const string& _DEBUG_ARG(func),
00465 TFlags& flags, TFlags allowed)
00466 {
00467 if (flags & ~allowed)
00468 _TRACE(func << "(): extra flags passed: "
00469 << resetiosflags(IOS_BASE::basefield)
00470 << setiosflags(IOS_BASE::hex | IOS_BASE::showbase)
00471 << flags);
00472 flags &= allowed;
00473 }
00474
00475
00476
00477
00478
00479
00480 IRegistry::TFlags IRWRegistry::AssessImpact(TFlags flags, EOperation op)
00481 {
00482
00483 flags &= fLayerFlags | fTPFlags;
00484 switch (op) {
00485 case eClear:
00486 return flags;
00487 case eRead:
00488 case eSet:
00489 return ((flags & fTransient) ? fTransient : fPersistent) | fJustCore;
00490 default:
00491 _TROUBLE;
00492 return flags;
00493 }
00494 }
00495
00496 void IRWRegistry::Clear(TFlags flags)
00497 {
00498 x_CheckFlags("IRWRegistry::Clear", flags,
00499 (TFlags)fLayerFlags | fInternalSpaces);
00500 TWriteGuard LOCK(*this);
00501 if ( (flags & fPersistent) && !x_Empty(fPersistent) ) {
00502 x_SetModifiedFlag(true, flags & ~fTransient);
00503 }
00504 if ( (flags & fTransient) && !x_Empty(fTransient) ) {
00505 x_SetModifiedFlag(true, flags & ~fPersistent);
00506 }
00507 x_Clear(flags);
00508 }
00509
00510
00511 IRWRegistry* IRWRegistry::Read(CNcbiIstream& is, TFlags flags)
00512 {
00513 x_CheckFlags("IRWRegistry::Read", flags,
00514 fTransient | fNoOverride | fIgnoreErrors | fInternalSpaces
00515 | fWithNcbirc | fJustCore | fCountCleared);
00516 return x_Read(is, flags);
00517 }
00518
00519
00520 IRWRegistry* IRWRegistry::x_Read(CNcbiIstream& is, TFlags flags)
00521 {
00522
00523 TFlags layer = (flags & fTransient) ? fTransient : fPersistent;
00524 TFlags impact = layer | fJustCore;
00525 bool non_modifying = Empty(impact) && !Modified(impact);
00526 bool ignore_errors = (flags & fIgnoreErrors) > 0;
00527
00528
00529 flags = (flags & ~fTPFlags & ~fIgnoreErrors) | layer;
00530
00531 string str;
00532 SIZE_TYPE line;
00533 string section;
00534 string comment;
00535
00536 for (line = 1; NcbiGetlineEOL(is, str); ++line) {
00537 try {
00538 SIZE_TYPE len = str.length();
00539 SIZE_TYPE beg = 0;
00540
00541 while (beg < len && isspace((unsigned char) str[beg])) {
00542 ++beg;
00543 }
00544 if (beg == len) {
00545 comment += str;
00546 comment += '\n';
00547 continue;
00548 }
00549
00550 switch (str[beg]) {
00551
00552 case '#': {
00553 SetComment(GetComment() + str + '\n');
00554 break;
00555 }
00556
00557 case ';': {
00558 comment += str;
00559 comment += '\n';
00560 break;
00561 }
00562
00563 case '[': {
00564 ++beg;
00565 SIZE_TYPE end = str.find_first_of(']', beg + 1);
00566 if (end == NPOS) {
00567 NCBI_THROW2(CRegistryException, eSection,
00568 "Invalid registry section(']' is missing): `"
00569 + str + "'", line);
00570 }
00571 section = NStr::TruncateSpaces(str.substr(beg, end - beg));
00572 if (section.empty()) {
00573 NCBI_THROW2(CRegistryException, eSection,
00574 "Unnamed registry section: `" + str + "'",
00575 line);
00576 } else if ( !s_IsNameSection(section, flags) ) {
00577 NCBI_THROW2(CRegistryException, eSection,
00578 "Invalid registry section name: `"
00579 + str + "'", line);
00580 }
00581
00582 if ( !comment.empty() ) {
00583 SetComment(GetComment(section) + comment, section);
00584 comment.erase();
00585 }
00586 break;
00587 }
00588
00589 default: {
00590 string name, value;
00591 if ( !NStr::SplitInTwo(str, "=", name, value) ) {
00592 NCBI_THROW2(CRegistryException, eEntry,
00593 "Invalid registry entry format: '" + str + "'",
00594 line);
00595 }
00596 NStr::TruncateSpacesInPlace(name);
00597 if ( !s_IsNameSection(name, flags) ) {
00598 NCBI_THROW2(CRegistryException, eEntry,
00599 "Invalid registry entry name: '" + str + "'",
00600 line);
00601 }
00602
00603 NStr::TruncateSpacesInPlace(value);
00604 #if 0 // historic behavior; could inappropriately expose entries in lower layers
00605 if (value.empty()) {
00606 if ( !(flags & fNoOverride) ) {
00607 Set(section, name, kEmptyStr, flags, comment);
00608 comment.erase();
00609 }
00610 break;
00611 }
00612 #endif
00613
00614 string cont;
00615 while (s_Backslashed(value, value.size())
00616 && NcbiGetlineEOL(is, cont)) {
00617 ++line;
00618 value[value.size() - 1] = '\n';
00619 value += NStr::TruncateSpaces(cont);
00620 str += 'n' + cont;
00621 }
00622
00623
00624
00625 beg = 0;
00626 SIZE_TYPE end = value.size();
00627 for (SIZE_TYPE pos = value.find('\"');
00628 pos < end && pos != NPOS;
00629 pos = value.find('\"', pos + 1)) {
00630 if (s_Backslashed(value, pos)) {
00631 continue;
00632 } else if (pos == beg) {
00633 ++beg;
00634 } else if (pos == end - 1) {
00635 --end;
00636 } else {
00637 NCBI_THROW2(CRegistryException, eValue,
00638 "Single(unescaped) '\"' in the middle "
00639 "of registry value: '" + str + "'",
00640 line);
00641 }
00642 }
00643
00644 try {
00645 value = NStr::ParseEscapes(value.substr(beg, end - beg));
00646 } catch (CStringException&) {
00647 NCBI_THROW2(CRegistryException, eValue,
00648 "Badly placed '\\' in the registry value: '"
00649 + str + "'", line);
00650
00651 }
00652 TFlags set_flags = flags;
00653 if (NStr::EqualNocase(section, "NCBI")
00654 && NStr::EqualNocase(name, ".Inherits")
00655 && HasEntry(section, name, flags)) {
00656 const string& old_value = Get(section, name, flags);
00657 if (flags & fNoOverride) {
00658 value = old_value + ' ' + value;
00659 set_flags &= ~fNoOverride;
00660 } else {
00661 value += ' ';
00662 value += old_value;
00663 }
00664 }
00665 Set(section, name, value, set_flags, comment);
00666 comment.erase();
00667 }
00668 }
00669 } catch (exception& e) {
00670 if (ignore_errors) {
00671 ERR_POST_X(4, e.what());
00672 } else {
00673 throw;
00674 }
00675 }
00676 }
00677
00678 if ( !is.eof() ) {
00679 NCBI_THROW2(CRegistryException, eErr,
00680 "Error in reading the registry: '" + str + "'", line);
00681 }
00682
00683 if ( non_modifying ) {
00684 SetModifiedFlag(false, impact);
00685 }
00686
00687 return NULL;
00688 }
00689
00690
00691 bool IRWRegistry::Set(const string& section, const string& name,
00692 const string& value, TFlags flags,
00693 const string& comment)
00694 {
00695 x_CheckFlags("IRWRegistry::Set", flags,
00696 fPersistent | fNoOverride | fTruncate | fInternalSpaces
00697 | fCountCleared);
00698 string clean_section = NStr::TruncateSpaces(section);
00699 if ( !s_IsNameSection(clean_section, flags) ) {
00700 _TRACE("IRWRegistry::Set: bad section name \""
00701 << NStr::PrintableString(section) << '\"');
00702 return false;
00703 }
00704 string clean_name = NStr::TruncateSpaces(name);
00705 if ( !s_IsNameSection(clean_name, flags) ) {
00706 _TRACE("IRWRegistry::Set: bad entry name \""
00707 << NStr::PrintableString(name) << '\"');
00708 return false;
00709 }
00710 SIZE_TYPE beg = 0, end = value.size();
00711 if (flags & fTruncate) {
00712
00713 beg = value.find_first_not_of(" \r\t\v");
00714 end = value.find_last_not_of (" \r\t\v");
00715 if (beg == NPOS) {
00716 _ASSERT(end == NPOS);
00717 beg = 1;
00718 end = 0;
00719 }
00720 }
00721 TWriteGuard LOCK(*this);
00722 if (x_Set(clean_section, clean_name, value.substr(beg, end - beg + 1),
00723 flags, s_ConvertComment(comment, section.empty()))) {
00724 x_SetModifiedFlag(true, flags);
00725 return true;
00726 } else {
00727 return false;
00728 }
00729 }
00730
00731
00732 bool IRWRegistry::SetComment(const string& comment, const string& section,
00733 const string& name, TFlags flags)
00734 {
00735 x_CheckFlags("IRWRegistry::SetComment", flags,
00736 fTransient | fNoOverride | fInternalSpaces);
00737 string clean_section = NStr::TruncateSpaces(section);
00738 if ( !clean_section.empty() && !s_IsNameSection(clean_section, flags) ) {
00739 _TRACE("IRWRegistry::SetComment: bad section name \""
00740 << NStr::PrintableString(section) << '\"');
00741 return false;
00742 }
00743 string clean_name = NStr::TruncateSpaces(name);
00744 if ( !clean_name.empty() && !s_IsNameSection(clean_name, flags) ) {
00745 _TRACE("IRWRegistry::SetComment: bad entry name \""
00746 << NStr::PrintableString(name) << '\"');
00747 return false;
00748 }
00749 TWriteGuard LOCK(*this);
00750 if (x_SetComment(s_ConvertComment(comment, section.empty()),
00751 clean_section, clean_name, flags)) {
00752 x_SetModifiedFlag(true, fPersistent);
00753 return true;
00754 } else {
00755 return false;
00756 }
00757 }
00758
00759
00760 bool IRWRegistry::MaybeSet(string& target, const string& value, TFlags flags)
00761 {
00762 if (target.empty()) {
00763 target = value;
00764 return !value.empty();
00765 } else if ( !(flags & fNoOverride) ) {
00766 target = value;
00767 return true;
00768 } else {
00769 return false;
00770 }
00771 }
00772
00773
00774
00775
00776
00777
00778 bool CMemoryRegistry::x_Empty(TFlags) const
00779 {
00780 TReadGuard LOCK(*this);
00781 return m_Sections.empty() && m_RegistryComment.empty();
00782 }
00783
00784
00785 const string& CMemoryRegistry::x_Get(const string& section, const string& name,
00786 TFlags) const
00787 {
00788 TSections::const_iterator sit = m_Sections.find(section);
00789 if (sit == m_Sections.end()) {
00790 return kEmptyStr;
00791 }
00792 const TEntries& entries = sit->second.entries;
00793 TEntries::const_iterator eit = entries.find(name);
00794 return (eit == entries.end()) ? kEmptyStr : eit->second.value;
00795 }
00796
00797 bool CMemoryRegistry::x_HasEntry(const string& section, const string& name,
00798 TFlags flags) const
00799 {
00800 TSections::const_iterator sit = m_Sections.find(section);
00801 if (sit == m_Sections.end()) {
00802 return false;
00803 } else if (name.empty()) {
00804 return ((flags & fCountCleared) != 0) || !sit->second.cleared;
00805 }
00806 const TEntries& entries = sit->second.entries;
00807 TEntries::const_iterator eit = entries.find(name);
00808 if (eit == entries.end()) {
00809 return false;
00810 } else if ((flags & fCountCleared) != 0) {
00811 return true;
00812 } else {
00813 return !eit->second.value.empty();
00814 }
00815 }
00816
00817
00818 const string& CMemoryRegistry::x_GetComment(const string& section,
00819 const string& name,
00820 TFlags) const
00821 {
00822 if (section.empty()) {
00823 return m_RegistryComment;
00824 }
00825 TSections::const_iterator sit = m_Sections.find(section);
00826 if (sit == m_Sections.end()) {
00827 return kEmptyStr;
00828 } else if (name.empty()) {
00829 return sit->second.comment;
00830 }
00831 const TEntries& entries = sit->second.entries;
00832 TEntries::const_iterator eit = entries.find(name);
00833 return (eit == entries.end()) ? kEmptyStr : eit->second.comment;
00834 }
00835
00836
00837 void CMemoryRegistry::x_Enumerate(const string& section, list<string>& entries,
00838 TFlags flags) const
00839 {
00840 if (section.empty()) {
00841 ITERATE (TSections, it, m_Sections) {
00842 if (s_IsNameSection(it->first, flags)
00843 && HasEntry(it->first, kEmptyStr, flags)) {
00844 entries.push_back(it->first);
00845 }
00846 }
00847 } else {
00848 TSections::const_iterator sit = m_Sections.find(section);
00849 if (sit != m_Sections.end()) {
00850 ITERATE (TEntries, it, sit->second.entries) {
00851 if (s_IsNameSection(it->first, flags)
00852 && ((flags & fCountCleared) != 0
00853 || !it->second.value.empty() )) {
00854 entries.push_back(it->first);
00855 }
00856 }
00857 }
00858 }
00859 }
00860
00861
00862 void CMemoryRegistry::x_Clear(TFlags)
00863 {
00864 m_RegistryComment.erase();
00865 m_Sections.clear();
00866 }
00867
00868 bool CMemoryRegistry::x_Set(const string& section, const string& name,
00869 const string& value, TFlags flags,
00870 const string& comment)
00871 {
00872 _TRACE(this << ": [" << section << ']' << name << " = " << value);
00873 #if 0 // historic behavior; could inappropriately expose entries in lower layers
00874 if (value.empty()) {
00875 if (flags & fNoOverride) {
00876 return false;
00877 }
00878
00879 TSections::iterator sit = m_Sections.find(section);
00880 if (sit == m_Sections.end()) {
00881 return false;
00882 }
00883 TEntries& entries = sit->second.entries;
00884 TEntries::iterator eit = entries.find(name);
00885 if (eit == entries.end()) {
00886 return false;
00887 } else {
00888 entries.erase(eit);
00889 if (entries.empty() && sit->second.comment.empty()) {
00890 m_Sections.erase(sit);
00891 }
00892 return true;
00893 }
00894 } else
00895 #endif
00896 {
00897 TSections::iterator sit = m_Sections.find(section);
00898 if (sit == m_Sections.end()) {
00899 sit = m_Sections.insert(make_pair(section, SSection())).first;
00900 sit->second.cleared = false;
00901 }
00902 SEntry& entry = sit->second.entries[name];
00903 #if 0
00904 if (entry.value == value) {
00905 if (entry.comment != comment) {
00906 return MaybeSet(entry.comment, comment, flags);
00907 }
00908 return false;
00909 }
00910 #endif
00911 if ( !value.empty() ) {
00912 sit->second.cleared = false;
00913 } else if ( !entry.value.empty() ) {
00914 _ASSERT( !sit->second.cleared );
00915 bool cleared = true;
00916 ITERATE (TEntries, eit, sit->second.entries) {
00917 if (&eit->second != &entry && !eit->second.value.empty() ) {
00918 cleared = false;
00919 break;
00920 }
00921 }
00922 sit->second.cleared = cleared;
00923 }
00924 if (MaybeSet(entry.value, value, flags)) {
00925 MaybeSet(entry.comment, comment, flags);
00926 return true;
00927 }
00928 return false;
00929 }
00930 }
00931
00932
00933 bool CMemoryRegistry::x_SetComment(const string& comment,
00934 const string& section, const string& name,
00935 TFlags flags)
00936 {
00937 if (comment.empty() && (flags & fNoOverride)) {
00938 return false;
00939 }
00940 if (section.empty()) {
00941 return MaybeSet(m_RegistryComment, comment, flags);
00942 }
00943 TSections::iterator sit = m_Sections.find(section);
00944 if (sit == m_Sections.end()) {
00945 if (comment.empty()) {
00946 return false;
00947 } else {
00948 sit = m_Sections.insert(make_pair(section, SSection())).first;
00949 sit->second.cleared = false;
00950 }
00951 }
00952 TEntries& entries = sit->second.entries;
00953 if (name.empty()) {
00954 if (comment.empty() && entries.empty()) {
00955 m_Sections.erase(sit);
00956 return true;
00957 } else {
00958 return MaybeSet(sit->second.comment, comment, flags);
00959 }
00960 }
00961 TEntries::iterator eit = entries.find(name);
00962 if (eit == entries.end()) {
00963 return false;
00964 } else {
00965 return MaybeSet(eit->second.comment, comment, flags);
00966 }
00967 }
00968
00969
00970
00971
00972
00973
00974 void CCompoundRegistry::Add(const IRegistry& reg, TPriority prio,
00975 const string& name)
00976 {
00977
00978 IRegistry& nc_reg = const_cast<IRegistry&>(reg);
00979
00980 m_PriorityMap.insert(TPriorityMap::value_type
00981 (prio, CRef<IRegistry>(&nc_reg)));
00982 if (name.size()) {
00983 CRef<IRegistry>& preg = m_NameMap[name];
00984 if (preg) {
00985 NCBI_THROW2(CRegistryException, eErr,
00986 "CCompoundRegistry::Add: name " + name
00987 + " already in use", 0);
00988 } else {
00989 preg.Reset(&nc_reg);
00990 }
00991 }
00992 }
00993
00994
00995 void CCompoundRegistry::Remove(const IRegistry& reg)
00996 {
00997 NON_CONST_ITERATE (TNameMap, it, m_NameMap) {
00998 if (it->second == ®) {
00999 m_NameMap.erase(it);
01000 break;
01001 }
01002 }
01003 NON_CONST_ITERATE (TPriorityMap, it, m_PriorityMap) {
01004 if (it->second == ®) {
01005 m_PriorityMap.erase(it);
01006 return;
01007 }
01008 }
01009
01010 NCBI_THROW2(CRegistryException, eErr,
01011 "CCompoundRegistry::Remove:"
01012 " reg is not a (direct) subregistry of this.", 0);
01013 }
01014
01015
01016 CConstRef<IRegistry> CCompoundRegistry::FindByName(const string& name) const
01017 {
01018 TNameMap::const_iterator it = m_NameMap.find(name);
01019 return it == m_NameMap.end() ? CConstRef<IRegistry>() : it->second;
01020 }
01021
01022
01023 CConstRef<IRegistry> CCompoundRegistry::FindByContents(const string& section,
01024 const string& entry,
01025 TFlags flags) const
01026 {
01027 TFlags has_entry_flags = (flags | fCountCleared) & ~fJustCore;
01028 REVERSE_ITERATE(TPriorityMap, it, m_PriorityMap) {
01029 if (it->second->HasEntry(section, entry, has_entry_flags)) {
01030 return it->second;
01031 }
01032 }
01033 return null;
01034 }
01035
01036
01037 bool CCompoundRegistry::x_Empty(TFlags flags) const
01038 {
01039 REVERSE_ITERATE (TPriorityMap, it, m_PriorityMap) {
01040 if ((flags & fJustCore) && (it->first < m_CoreCutoff)) {
01041 break;
01042 }
01043 if ( !it->second->Empty(flags & ~fJustCore) ) {
01044 return false;
01045 }
01046 }
01047 return true;
01048 }
01049
01050
01051 bool CCompoundRegistry::x_Modified(TFlags flags) const
01052 {
01053 REVERSE_ITERATE (TPriorityMap, it, m_PriorityMap) {
01054 if ((flags & fJustCore) && (it->first < m_CoreCutoff)) {
01055 break;
01056 }
01057 if ( it->second->Modified(flags & ~fJustCore) ) {
01058 return true;
01059 }
01060 }
01061 return false;
01062 }
01063
01064
01065 void CCompoundRegistry::x_SetModifiedFlag(bool modified, TFlags flags)
01066 {
01067 _ASSERT( !modified );
01068 for (TPriorityMap::reverse_iterator it = m_PriorityMap.rbegin();
01069 it != m_PriorityMap.rend(); ++it) {
01070 if ((flags & fJustCore) && (it->first < m_CoreCutoff)) {
01071 break;
01072 }
01073 it->second->SetModifiedFlag(modified, flags & ~fJustCore);
01074 }
01075 }
01076
01077
01078 const string& CCompoundRegistry::x_Get(const string& section,
01079 const string& name,
01080 TFlags flags) const
01081 {
01082 CConstRef<IRegistry> reg = FindByContents(section, name,
01083 flags & ~fJustCore);
01084 return reg ? reg->Get(section, name, flags & ~fJustCore) : kEmptyStr;
01085 }
01086
01087
01088 bool CCompoundRegistry::x_HasEntry(const string& section, const string& name,
01089 TFlags flags) const
01090 {
01091 return FindByContents(section, name, flags).NotEmpty();
01092 }
01093
01094
01095 const string& CCompoundRegistry::x_GetComment(const string& section,
01096 const string& name, TFlags flags)
01097 const
01098 {
01099 if ( m_PriorityMap.empty() ) {
01100 return kEmptyStr;
01101 }
01102
01103 CConstRef<IRegistry> reg;
01104 if (section.empty()) {
01105 reg = m_PriorityMap.rbegin()->second;
01106 } else {
01107 reg = FindByContents(section, name, flags);
01108 }
01109 return reg ? reg->GetComment(section, name, flags & ~fJustCore)
01110 : kEmptyStr;
01111 }
01112
01113
01114 void CCompoundRegistry::x_Enumerate(const string& section,
01115 list<string>& entries, TFlags flags) const
01116 {
01117 set<string> accum;
01118 REVERSE_ITERATE (TPriorityMap, it, m_PriorityMap) {
01119 if ((flags & fJustCore) && (it->first < m_CoreCutoff)) {
01120 break;
01121 }
01122 list<string> tmp;
01123 it->second->EnumerateEntries(section, &tmp, flags & ~fJustCore);
01124 ITERATE (list<string>, it2, tmp) {
01125 accum.insert(*it2);
01126 }
01127 }
01128 ITERATE (set<string>, it, accum) {
01129 entries.push_back(*it);
01130 }
01131 }
01132
01133
01134 void CCompoundRegistry::x_ChildLockAction(FLockAction action)
01135 {
01136 NON_CONST_ITERATE (TPriorityMap, it, m_PriorityMap) {
01137 ((*it->second).*action)();
01138 }
01139 }
01140
01141
01142
01143
01144
01145
01146 CTwoLayerRegistry::CTwoLayerRegistry(IRWRegistry* persistent)
01147 : m_Transient(CRegRef(new CMemoryRegistry)),
01148 m_Persistent(CRegRef(persistent ? persistent : new CMemoryRegistry))
01149 {
01150 }
01151
01152
01153 bool CTwoLayerRegistry::x_Empty(TFlags flags) const
01154 {
01155
01156 if (flags & fTransient && !m_Transient->Empty(flags | fTPFlags) ) {
01157 return false;
01158 } else if (flags & fPersistent
01159 && !m_Persistent->Empty(flags | fTPFlags) ) {
01160 return false;
01161 } else {
01162 return true;
01163 }
01164 }
01165
01166
01167 bool CTwoLayerRegistry::x_Modified(TFlags flags) const
01168 {
01169 if (flags & fTransient && m_Transient->Modified(flags | fTPFlags)) {
01170 return true;
01171 } else if (flags & fPersistent
01172 && m_Persistent->Modified(flags | fTPFlags)) {
01173 return true;
01174 } else {
01175 return false;
01176 }
01177 }
01178
01179
01180 void CTwoLayerRegistry::x_SetModifiedFlag(bool modified, TFlags flags)
01181 {
01182 if (flags & fTransient) {
01183 m_Transient->SetModifiedFlag(modified, flags | fTPFlags);
01184 }
01185 if (flags & fPersistent) {
01186 m_Persistent->SetModifiedFlag(modified, flags | fTPFlags);
01187 }
01188 }
01189
01190
01191 const string& CTwoLayerRegistry::x_Get(const string& section,
01192 const string& name, TFlags flags) const
01193 {
01194 if (flags & fTransient) {
01195 const string& result = m_Transient->Get(section, name,
01196 flags & ~fTPFlags);
01197 if ( !result.empty() || !(flags & fPersistent) ) {
01198 return result;
01199 }
01200 }
01201 return m_Persistent->Get(section, name, flags & ~fTPFlags);
01202 }
01203
01204
01205 bool CTwoLayerRegistry::x_HasEntry(const string& section, const string& name,
01206 TFlags flags) const
01207 {
01208 return (((flags & fTransient)
01209 && m_Transient->HasEntry(section, name, flags & ~fTPFlags)) ||
01210 ((flags & fPersistent)
01211 && m_Persistent->HasEntry(section, name, flags & ~fTPFlags)));
01212 }
01213
01214
01215 const string& CTwoLayerRegistry::x_GetComment(const string& section,
01216 const string& name,
01217 TFlags flags) const
01218 {
01219 if (flags & fTransient) {
01220 const string& result = m_Transient->GetComment(section, name,
01221 flags & ~fTPFlags);
01222 if ( !result.empty() || !(flags & fPersistent) ) {
01223 return result;
01224 }
01225 }
01226 return m_Persistent->GetComment(section, name, flags & ~fTPFlags);
01227 }
01228
01229
01230 void CTwoLayerRegistry::x_Enumerate(const string& section,
01231 list<string>& entries, TFlags flags) const
01232 {
01233 switch (flags & fTPFlags) {
01234 case fTransient:
01235 m_Transient->EnumerateEntries(section, &entries, flags | fTPFlags);
01236 break;
01237 case fPersistent:
01238 m_Persistent->EnumerateEntries(section, &entries, flags | fTPFlags);
01239 break;
01240 case fTPFlags:
01241 {
01242 list<string> tl, pl;
01243 m_Transient ->EnumerateEntries(section, &tl, flags | fTPFlags);
01244 m_Persistent->EnumerateEntries(section, &pl, flags | fTPFlags);
01245 set_union(pl.begin(), pl.end(), tl.begin(), tl.end(),
01246 back_inserter(entries), PNocase());
01247 break;
01248 }
01249 default:
01250 _TROUBLE;
01251 }
01252 }
01253
01254
01255 void CTwoLayerRegistry::x_ChildLockAction(FLockAction action)
01256 {
01257 ((*m_Transient).*action)();
01258 ((*m_Persistent).*action)();
01259 }
01260
01261
01262 void CTwoLayerRegistry::x_Clear(TFlags flags)
01263 {
01264 if (flags & fTransient) {
01265 m_Transient->Clear(flags | fTPFlags);
01266 }
01267 if (flags & fPersistent) {
01268 m_Persistent->Clear(flags | fTPFlags);
01269 }
01270 }
01271
01272
01273 bool CTwoLayerRegistry::x_Set(const string& section, const string& name,
01274 const string& value, TFlags flags,
01275 const string& comment)
01276 {
01277 if (flags & fPersistent) {
01278 return m_Persistent->Set(section, name, value, flags & ~fTPFlags,
01279 comment);
01280 } else {
01281 return m_Transient->Set(section, name, value, flags & ~fTPFlags,
01282 comment);
01283 }
01284 }
01285
01286
01287 bool CTwoLayerRegistry::x_SetComment(const string& comment,
01288 const string& section, const string& name,
01289 TFlags flags)
01290 {
01291 if (flags & fTransient) {
01292 return m_Transient->SetComment(comment, section, name,
01293 flags & ~fTPFlags);
01294 } else {
01295 return m_Persistent->SetComment(comment, section, name,
01296 flags & ~fTPFlags);
01297 }
01298 }
01299
01300
01301
01302
01303
01304
01305
01306
01307
01308 const char* CNcbiRegistry::sm_EnvRegName = ".env";
01309 const char* CNcbiRegistry::sm_FileRegName = ".file";
01310 const char* CNcbiRegistry::sm_OverrideRegName = ".overrides";
01311 const char* CNcbiRegistry::sm_SysRegName = ".ncbirc";
01312
01313 inline
01314 void CNcbiRegistry::x_Init(void)
01315 {
01316 CNcbiApplication* app = CNcbiApplication::Instance();
01317 if (app) {
01318 m_EnvRegistry.Reset(new CEnvironmentRegistry(app->SetEnvironment()));
01319 } else {
01320 m_EnvRegistry.Reset(new CEnvironmentRegistry);
01321 }
01322 x_Add(*m_EnvRegistry, ePriority_Environment, sm_EnvRegName);
01323
01324 m_FileRegistry.Reset(new CTwoLayerRegistry);
01325 x_Add(*m_FileRegistry, ePriority_File, sm_FileRegName);
01326
01327 m_SysRegistry.Reset(new CTwoLayerRegistry);
01328 x_Add(*m_SysRegistry, ePriority_Default - 1, sm_SysRegName);
01329
01330 const char* override_path = getenv("NCBI_CONFIG_OVERRIDES");
01331 if (override_path && *override_path) {
01332 m_OverrideRegistry.Reset(new CCompoundRWRegistry);
01333 CMetaRegistry::SEntry entry
01334 = CMetaRegistry::Load(override_path, CMetaRegistry::eName_AsIs,
01335 0, 0, m_OverrideRegistry.GetPointer());
01336 if (entry.registry) {
01337 if (entry.registry != m_OverrideRegistry) {
01338 ERR_POST_X(5, Warning << "Resetting m_OverrideRegistry");
01339 m_OverrideRegistry.Reset(entry.registry);
01340 }
01341 x_Add(*m_OverrideRegistry, ePriority_Overrides, sm_OverrideRegName);
01342 } else {
01343 ERR_POST_ONCE(Warning
01344 << "NCBI_CONFIG_OVERRIDES names nonexistent file "
01345 << override_path);
01346 m_OverrideRegistry.Reset();
01347 }
01348 }
01349 }
01350
01351
01352 CNcbiRegistry::CNcbiRegistry(void)
01353 : m_RuntimeOverrideCount(0)
01354 {
01355 x_Init();
01356 }
01357
01358
01359 CNcbiRegistry::CNcbiRegistry(CNcbiIstream& is, TFlags flags)
01360 : m_RuntimeOverrideCount(0)
01361 {
01362 x_CheckFlags("CNcbiRegistry::CNcbiRegistry", flags,
01363 fTransient | fInternalSpaces | fWithNcbirc);
01364 x_Init();
01365 m_FileRegistry->Read(is, flags & ~fWithNcbirc);
01366 IncludeNcbircIfAllowed(flags);
01367 }
01368
01369
01370 CNcbiRegistry::~CNcbiRegistry()
01371 {
01372 }
01373
01374
01375 bool CNcbiRegistry::IncludeNcbircIfAllowed(TFlags flags)
01376 {
01377 if (flags & fWithNcbirc) {
01378 flags &= ~fWithNcbirc;
01379 } else {
01380 return false;
01381 }
01382
01383 if (getenv("NCBI_DONT_USE_NCBIRC")) {
01384 return false;
01385 }
01386
01387 if (HasEntry("NCBI", "DONT_USE_NCBIRC")) {
01388 return false;
01389 }
01390
01391 try {
01392 CMetaRegistry::SEntry entry
01393 = CMetaRegistry::Load("ncbi", CMetaRegistry::eName_RcOrIni,
01394 0, flags, m_SysRegistry.GetPointer());
01395 if (entry.registry && entry.registry != m_SysRegistry) {
01396 ERR_POST_X(5, Warning << "Resetting m_SysRegistry");
01397 m_SysRegistry.Reset(entry.registry);
01398 }
01399 } catch (CRegistryException& e) {
01400 ERR_POST_X(6, Critical << "CNcbiRegistry: "
01401 "Syntax error in system-wide configuration file: "
01402 << e.what());
01403 return false;
01404 }
01405
01406 if ( !m_SysRegistry->Empty() ) {
01407 return true;
01408 }
01409
01410 return false;
01411 }
01412
01413
01414 void CNcbiRegistry::x_Clear(TFlags flags)
01415 {
01416 CCompoundRWRegistry::x_Clear(flags);
01417 m_FileRegistry->Clear(flags);
01418 }
01419
01420
01421 IRWRegistry* CNcbiRegistry::x_Read(CNcbiIstream& is, TFlags flags)
01422 {
01423
01424
01425
01426 if (FindByName(sm_MainRegName)->Empty() && m_FileRegistry->Empty()) {
01427 m_FileRegistry->Read(is, flags);
01428 LoadBaseRegistries(flags);
01429 IncludeNcbircIfAllowed(flags);
01430 return NULL;
01431 } else if ((flags & fNoOverride) == 0) {
01432 CRef<CCompoundRWRegistry> crwreg(new CCompoundRWRegistry);
01433 crwreg->Read(is, flags);
01434 ++m_RuntimeOverrideCount;
01435 x_Add(*crwreg, ePriority_RuntimeOverrides + m_RuntimeOverrideCount,
01436 sm_OverrideRegName + NStr::IntToString(m_RuntimeOverrideCount));
01437 return crwreg.GetPointer();
01438 } else {
01439
01440
01441 return CCompoundRWRegistry::x_Read(is, flags);
01442 }
01443 }
01444
01445
01446
01447
01448
01449
01450 const char* CCompoundRWRegistry::sm_MainRegName = ".main";
01451 const char* CCompoundRWRegistry::sm_BaseRegNamePrefix = ".base:";
01452
01453
01454 CCompoundRWRegistry::CCompoundRWRegistry(void)
01455 : m_MainRegistry(new CTwoLayerRegistry),
01456 m_AllRegistries(new CCompoundRegistry)
01457 {
01458 x_Add(*m_MainRegistry, CCompoundRegistry::ePriority_Max - 1,
01459 sm_MainRegName);
01460 }
01461
01462
01463 CCompoundRWRegistry::~CCompoundRWRegistry()
01464 {
01465 }
01466
01467
01468 CCompoundRWRegistry::TPriority CCompoundRWRegistry::GetCoreCutoff(void) const
01469 {
01470 return m_AllRegistries->GetCoreCutoff();
01471 }
01472
01473
01474 void CCompoundRWRegistry::SetCoreCutoff(TPriority prio)
01475 {
01476 m_AllRegistries->SetCoreCutoff(prio);
01477 }
01478
01479
01480 void CCompoundRWRegistry::Add(const IRegistry& reg, TPriority prio,
01481 const string& name)
01482 {
01483 if (name.size() > 1 && name[0] == '.') {
01484 NCBI_THROW2(CRegistryException, eErr,
01485 "The sub-registry name " + name + " is reserved.", 0);
01486 }
01487 if (prio > ePriority_MaxUser) {
01488 ERR_POST_X(7, Warning
01489 << "Reserved priority value automatically downgraded.");
01490 prio = ePriority_MaxUser;
01491 }
01492 x_Add(reg, prio, name);
01493 }
01494
01495
01496 void CCompoundRWRegistry::Remove(const IRegistry& reg)
01497 {
01498 if (® == m_MainRegistry.GetPointer()) {
01499 NCBI_THROW2(CRegistryException, eErr,
01500 "The primary portion of the registry may not be removed.",
01501 0);
01502 } else {
01503 m_AllRegistries->Remove(reg);
01504 }
01505 }
01506
01507
01508 CConstRef<IRegistry> CCompoundRWRegistry::FindByName(const string& name) const
01509 {
01510 return m_AllRegistries->FindByName(name);
01511 }
01512
01513
01514 CConstRef<IRegistry> CCompoundRWRegistry::FindByContents(const string& section,
01515 const string& entry,
01516 TFlags flags) const
01517 {
01518 return m_AllRegistries->FindByContents(section, entry, flags);
01519 }
01520
01521
01522 bool CCompoundRWRegistry::LoadBaseRegistries(TFlags flags, int metareg_flags)
01523 {
01524 if (flags & fJustCore) {
01525 return false;
01526 }
01527
01528 list<string> names;
01529 {{
01530 string s = m_MainRegistry->Get("NCBI", ".Inherits");
01531 if (s.empty()) {
01532 if (dynamic_cast<CNcbiRegistry*>(this) != NULL) {
01533 _TRACE("LoadBaseRegistries(" << this
01534 << "): trying file registry");
01535 s = FindByName(CNcbiRegistry::sm_FileRegName)
01536 ->Get("NCBI", ".Inherits");
01537 }
01538 if (s.empty()) {
01539 return false;
01540 }
01541 }
01542 _TRACE("LoadBaseRegistries(" << this << "): using " << s);
01543 NStr::Split(s, ", ", names);
01544 }}
01545
01546 typedef pair<string, CRef<IRWRegistry> > TNewBase;
01547 typedef vector<TNewBase> TNewBases;
01548 TNewBases bases;
01549 SIZE_TYPE initial_num_bases = m_BaseRegNames.size();
01550
01551 ITERATE (list<string>, it, names) {
01552 if (m_BaseRegNames.find(*it) != m_BaseRegNames.end()) {
01553 continue;
01554 }
01555 CMetaRegistry::ENameStyle style
01556 = ((it->find('.') == NPOS)
01557 ? CMetaRegistry::eName_Ini : CMetaRegistry::eName_AsIs);
01558 CRef<CCompoundRWRegistry> reg2(new CCompoundRWRegistry);
01559 CMetaRegistry::SEntry entry2
01560 = CMetaRegistry::Load(*it, style, metareg_flags, flags,
01561 reg2.GetPointer());
01562 if (entry2.registry) {
01563 m_BaseRegNames.insert(*it);
01564 bases.push_back(TNewBase(*it, entry2.registry));
01565 }
01566 }
01567
01568 for (SIZE_TYPE i = 0; i < bases.size(); ++i) {
01569 x_Add(*bases[i].second, ePriority_MaxUser - initial_num_bases - i,
01570 sm_BaseRegNamePrefix + bases[i].first);
01571 }
01572
01573 return !bases.empty();
01574 }
01575
01576
01577 bool CCompoundRWRegistry::x_Empty(TFlags flags) const
01578 {
01579 return m_AllRegistries->Empty(flags);
01580 }
01581
01582
01583 bool CCompoundRWRegistry::x_Modified(TFlags flags) const
01584 {
01585 return m_AllRegistries->Modified(flags);
01586 }
01587
01588
01589 void CCompoundRWRegistry::x_SetModifiedFlag(bool modified, TFlags flags)
01590 {
01591 if (modified) {
01592 m_MainRegistry->SetModifiedFlag(modified, flags);
01593 } else {
01594
01595 m_AllRegistries->SetModifiedFlag(modified, flags);
01596 }
01597 }
01598
01599
01600 const string& CCompoundRWRegistry::x_Get(const string& section,
01601 const string& name,
01602 TFlags flags) const
01603 {
01604 TClearedEntries::const_iterator it
01605 = m_ClearedEntries.find(s_FlatKey(section, name));
01606 if (it != m_ClearedEntries.end()) {
01607 flags &= ~it->second;
01608 if ( !(flags & ~fJustCore) ) {
01609 return kEmptyStr;
01610 }
01611 }
01612 return m_AllRegistries->Get(section, name, flags);
01613 }
01614
01615
01616 bool CCompoundRWRegistry::x_HasEntry(const string& section, const string& name,
01617 TFlags flags) const
01618 {
01619 TClearedEntries::const_iterator it
01620 = m_ClearedEntries.find(s_FlatKey(section, name));
01621 if (it != m_ClearedEntries.end()) {
01622 if ((flags & fCountCleared) && (flags & it->second)) {
01623 return true;
01624 }
01625 flags &= ~it->second;
01626 if ( !(flags & ~fJustCore) ) {
01627 return false;
01628 }
01629 }
01630 return m_AllRegistries->HasEntry(section, name, flags);
01631 }
01632
01633
01634 const string& CCompoundRWRegistry::x_GetComment(const string& section,
01635 const string& name,
01636 TFlags flags) const
01637 {
01638 return m_AllRegistries->GetComment(section, name, flags);
01639 }
01640
01641
01642 void CCompoundRWRegistry::x_Enumerate(const string& section,
01643 list<string>& entries,
01644 TFlags flags) const
01645 {
01646 set<string> accum;
01647 REVERSE_ITERATE (CCompoundRegistry::TPriorityMap, it,
01648 m_AllRegistries->m_PriorityMap) {
01649 if ((flags & fJustCore) && (it->first < GetCoreCutoff())) {
01650 break;
01651 }
01652 list<string> tmp;
01653 it->second->EnumerateEntries(section, &tmp, flags & ~fJustCore);
01654 ITERATE (list<string>, it2, tmp) {
01655
01656 TClearedEntries::const_iterator ceci
01657 = (flags & fCountCleared) ? m_ClearedEntries.end()
01658 : m_ClearedEntries.find(s_FlatKey(section, *it2));
01659 if (ceci == m_ClearedEntries.end()
01660 || (flags & ~fJustCore & ~ceci->second)) {
01661 accum.insert(*it2);
01662 }
01663 }
01664 }
01665 ITERATE (set<string>, it, accum) {
01666 entries.push_back(*it);
01667 }
01668 }
01669
01670
01671 void CCompoundRWRegistry::x_ChildLockAction(FLockAction action)
01672 {
01673 ((*m_AllRegistries).*action)();
01674 }
01675
01676
01677 void CCompoundRWRegistry::x_Clear(TFlags flags)
01678 {
01679 m_MainRegistry->Clear(flags);
01680
01681 ITERATE (set<string>, it, m_BaseRegNames) {
01682 Remove(*FindByName(sm_BaseRegNamePrefix + *it));
01683 }
01684 m_BaseRegNames.clear();
01685 }
01686
01687
01688 bool CCompoundRWRegistry::x_Set(const string& section, const string& name,
01689 const string& value, TFlags flags,
01690 const string& comment)
01691 {
01692 TFlags flags2 = (flags & fPersistent) ? flags : (flags | fTransient);
01693 flags2 &= fLayerFlags;
01694 _TRACE('[' << section << ']' << name << " = " << value);
01695 if ((flags & fNoOverride) && HasEntry(section, name, flags)) {
01696 return false;
01697 }
01698 if (value.empty()) {
01699 bool was_empty = Get(section, name, flags).empty();
01700 m_MainRegistry->Set(section, name, value, flags, comment);
01701 m_ClearedEntries[s_FlatKey(section, name)] |= flags2;
01702 return !was_empty;
01703 } else {
01704 TClearedEntries::iterator it
01705 = m_ClearedEntries.find(s_FlatKey(section, name));
01706 if (it != m_ClearedEntries.end()) {
01707 if ((it->second &= ~flags2) == 0) {
01708 m_ClearedEntries.erase(it);
01709 }
01710 }
01711 }
01712 return m_MainRegistry->Set(section, name, value, flags, comment);
01713 }
01714
01715
01716 bool CCompoundRWRegistry::x_SetComment(const string& comment,
01717 const string& section,
01718 const string& name, TFlags flags)
01719 {
01720 return m_MainRegistry->SetComment(comment, section, name, flags);
01721 }
01722
01723
01724 IRWRegistry* CCompoundRWRegistry::x_Read(CNcbiIstream& in, TFlags flags)
01725 {
01726 TFlags lbr_flags = flags;
01727 if ((flags & fNoOverride) == 0 && !Empty(fPersistent) ) {
01728 lbr_flags |= fOverride;
01729 } else {
01730 lbr_flags &= ~fOverride;
01731 }
01732 IRWRegistry::x_Read(in, flags);
01733 LoadBaseRegistries(lbr_flags);
01734 return NULL;
01735 }
01736
01737
01738 void CCompoundRWRegistry::x_Add(const IRegistry& reg, TPriority prio,
01739 const string& name)
01740 {
01741 m_AllRegistries->Add(reg, prio, name);
01742 }
01743
01744
01745
01746
01747
01748
01749 const char* CRegistryException::GetErrCodeString(void) const
01750 {
01751 switch (GetErrCode()) {
01752 case eSection: return "eSection";
01753 case eEntry: return "eEntry";
01754 case eValue: return "eValue";
01755 case eErr: return "eErr";
01756 default: return CException::GetErrCodeString();
01757 }
01758 }
01759
01760
01761 END_NCBI_SCOPE
01762
01763