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(m_Flags)))
00900 .first;
00901 sit->second.cleared = false;
00902 }
00903 SEntry& entry = sit->second.entries[name];
00904 #if 0
00905 if (entry.value == value) {
00906 if (entry.comment != comment) {
00907 return MaybeSet(entry.comment, comment, flags);
00908 }
00909 return false;
00910 }
00911 #endif
00912 if ( !value.empty() ) {
00913 sit->second.cleared = false;
00914 } else if ( !entry.value.empty() ) {
00915 _ASSERT( !sit->second.cleared );
00916 bool cleared = true;
00917 ITERATE (TEntries, eit, sit->second.entries) {
00918 if (&eit->second != &entry && !eit->second.value.empty() ) {
00919 cleared = false;
00920 break;
00921 }
00922 }
00923 sit->second.cleared = cleared;
00924 }
00925 if (MaybeSet(entry.value, value, flags)) {
00926 MaybeSet(entry.comment, comment, flags);
00927 return true;
00928 }
00929 return false;
00930 }
00931 }
00932
00933
00934 bool CMemoryRegistry::x_SetComment(const string& comment,
00935 const string& section, const string& name,
00936 TFlags flags)
00937 {
00938 if (comment.empty() && (flags & fNoOverride)) {
00939 return false;
00940 }
00941 if (section.empty()) {
00942 return MaybeSet(m_RegistryComment, comment, flags);
00943 }
00944 TSections::iterator sit = m_Sections.find(section);
00945 if (sit == m_Sections.end()) {
00946 if (comment.empty()) {
00947 return false;
00948 } else {
00949 sit = m_Sections.insert(make_pair(section, SSection(m_Flags)))
00950 .first;
00951 sit->second.cleared = false;
00952 }
00953 }
00954 TEntries& entries = sit->second.entries;
00955 if (name.empty()) {
00956 if (comment.empty() && entries.empty()) {
00957 m_Sections.erase(sit);
00958 return true;
00959 } else {
00960 return MaybeSet(sit->second.comment, comment, flags);
00961 }
00962 }
00963 TEntries::iterator eit = entries.find(name);
00964 if (eit == entries.end()) {
00965 return false;
00966 } else {
00967 return MaybeSet(eit->second.comment, comment, flags);
00968 }
00969 }
00970
00971
00972
00973
00974
00975
00976 void CCompoundRegistry::Add(const IRegistry& reg, TPriority prio,
00977 const string& name)
00978 {
00979
00980 IRegistry& nc_reg = const_cast<IRegistry&>(reg);
00981
00982 m_PriorityMap.insert(TPriorityMap::value_type
00983 (prio, CRef<IRegistry>(&nc_reg)));
00984 if (name.size()) {
00985 CRef<IRegistry>& preg = m_NameMap[name];
00986 if (preg) {
00987 NCBI_THROW2(CRegistryException, eErr,
00988 "CCompoundRegistry::Add: name " + name
00989 + " already in use", 0);
00990 } else {
00991 preg.Reset(&nc_reg);
00992 }
00993 }
00994 }
00995
00996
00997 void CCompoundRegistry::Remove(const IRegistry& reg)
00998 {
00999 NON_CONST_ITERATE (TNameMap, it, m_NameMap) {
01000 if (it->second == ®) {
01001 m_NameMap.erase(it);
01002 break;
01003 }
01004 }
01005 NON_CONST_ITERATE (TPriorityMap, it, m_PriorityMap) {
01006 if (it->second == ®) {
01007 m_PriorityMap.erase(it);
01008 return;
01009 }
01010 }
01011
01012 NCBI_THROW2(CRegistryException, eErr,
01013 "CCompoundRegistry::Remove:"
01014 " reg is not a (direct) subregistry of this.", 0);
01015 }
01016
01017
01018 CConstRef<IRegistry> CCompoundRegistry::FindByName(const string& name) const
01019 {
01020 TNameMap::const_iterator it = m_NameMap.find(name);
01021 return it == m_NameMap.end() ? CConstRef<IRegistry>() : it->second;
01022 }
01023
01024
01025 CConstRef<IRegistry> CCompoundRegistry::FindByContents(const string& section,
01026 const string& entry,
01027 TFlags flags) const
01028 {
01029 TFlags has_entry_flags = (flags | fCountCleared) & ~fJustCore;
01030 REVERSE_ITERATE(TPriorityMap, it, m_PriorityMap) {
01031 if (it->second->HasEntry(section, entry, has_entry_flags)) {
01032 return it->second;
01033 }
01034 }
01035 return null;
01036 }
01037
01038
01039 bool CCompoundRegistry::x_Empty(TFlags flags) const
01040 {
01041 REVERSE_ITERATE (TPriorityMap, it, m_PriorityMap) {
01042 if ((flags & fJustCore) && (it->first < m_CoreCutoff)) {
01043 break;
01044 }
01045 if ( !it->second->Empty(flags & ~fJustCore) ) {
01046 return false;
01047 }
01048 }
01049 return true;
01050 }
01051
01052
01053 bool CCompoundRegistry::x_Modified(TFlags flags) const
01054 {
01055 REVERSE_ITERATE (TPriorityMap, it, m_PriorityMap) {
01056 if ((flags & fJustCore) && (it->first < m_CoreCutoff)) {
01057 break;
01058 }
01059 if ( it->second->Modified(flags & ~fJustCore) ) {
01060 return true;
01061 }
01062 }
01063 return false;
01064 }
01065
01066
01067 void CCompoundRegistry::x_SetModifiedFlag(bool modified, TFlags flags)
01068 {
01069 _ASSERT( !modified );
01070 for (TPriorityMap::reverse_iterator it = m_PriorityMap.rbegin();
01071 it != m_PriorityMap.rend(); ++it) {
01072 if ((flags & fJustCore) && (it->first < m_CoreCutoff)) {
01073 break;
01074 }
01075 it->second->SetModifiedFlag(modified, flags & ~fJustCore);
01076 }
01077 }
01078
01079
01080 const string& CCompoundRegistry::x_Get(const string& section,
01081 const string& name,
01082 TFlags flags) const
01083 {
01084 CConstRef<IRegistry> reg = FindByContents(section, name,
01085 flags & ~fJustCore);
01086 return reg ? reg->Get(section, name, flags & ~fJustCore) : kEmptyStr;
01087 }
01088
01089
01090 bool CCompoundRegistry::x_HasEntry(const string& section, const string& name,
01091 TFlags flags) const
01092 {
01093 return FindByContents(section, name, flags).NotEmpty();
01094 }
01095
01096
01097 const string& CCompoundRegistry::x_GetComment(const string& section,
01098 const string& name, TFlags flags)
01099 const
01100 {
01101 if ( m_PriorityMap.empty() ) {
01102 return kEmptyStr;
01103 }
01104
01105 CConstRef<IRegistry> reg;
01106 if (section.empty()) {
01107 reg = m_PriorityMap.rbegin()->second;
01108 } else {
01109 reg = FindByContents(section, name, flags);
01110 }
01111 return reg ? reg->GetComment(section, name, flags & ~fJustCore)
01112 : kEmptyStr;
01113 }
01114
01115
01116 void CCompoundRegistry::x_Enumerate(const string& section,
01117 list<string>& entries, TFlags flags) const
01118 {
01119 set<string> accum;
01120 REVERSE_ITERATE (TPriorityMap, it, m_PriorityMap) {
01121 if ((flags & fJustCore) && (it->first < m_CoreCutoff)) {
01122 break;
01123 }
01124 list<string> tmp;
01125 it->second->EnumerateEntries(section, &tmp, flags & ~fJustCore);
01126 ITERATE (list<string>, it2, tmp) {
01127 accum.insert(*it2);
01128 }
01129 }
01130 ITERATE (set<string>, it, accum) {
01131 entries.push_back(*it);
01132 }
01133 }
01134
01135
01136 void CCompoundRegistry::x_ChildLockAction(FLockAction action)
01137 {
01138 NON_CONST_ITERATE (TPriorityMap, it, m_PriorityMap) {
01139 ((*it->second).*action)();
01140 }
01141 }
01142
01143
01144
01145
01146
01147
01148 CTwoLayerRegistry::CTwoLayerRegistry(IRWRegistry* persistent, TFlags flags)
01149 : m_Transient(CRegRef(new CMemoryRegistry(flags))),
01150 m_Persistent(CRegRef(persistent ? persistent
01151 : new CMemoryRegistry(flags)))
01152 {
01153 }
01154
01155
01156 bool CTwoLayerRegistry::x_Empty(TFlags flags) const
01157 {
01158
01159 if (flags & fTransient && !m_Transient->Empty(flags | fTPFlags) ) {
01160 return false;
01161 } else if (flags & fPersistent
01162 && !m_Persistent->Empty(flags | fTPFlags) ) {
01163 return false;
01164 } else {
01165 return true;
01166 }
01167 }
01168
01169
01170 bool CTwoLayerRegistry::x_Modified(TFlags flags) const
01171 {
01172 if (flags & fTransient && m_Transient->Modified(flags | fTPFlags)) {
01173 return true;
01174 } else if (flags & fPersistent
01175 && m_Persistent->Modified(flags | fTPFlags)) {
01176 return true;
01177 } else {
01178 return false;
01179 }
01180 }
01181
01182
01183 void CTwoLayerRegistry::x_SetModifiedFlag(bool modified, TFlags flags)
01184 {
01185 if (flags & fTransient) {
01186 m_Transient->SetModifiedFlag(modified, flags | fTPFlags);
01187 }
01188 if (flags & fPersistent) {
01189 m_Persistent->SetModifiedFlag(modified, flags | fTPFlags);
01190 }
01191 }
01192
01193
01194 const string& CTwoLayerRegistry::x_Get(const string& section,
01195 const string& name, TFlags flags) const
01196 {
01197 if (flags & fTransient) {
01198 const string& result = m_Transient->Get(section, name,
01199 flags & ~fTPFlags);
01200 if ( !result.empty() || !(flags & fPersistent) ) {
01201 return result;
01202 }
01203 }
01204 return m_Persistent->Get(section, name, flags & ~fTPFlags);
01205 }
01206
01207
01208 bool CTwoLayerRegistry::x_HasEntry(const string& section, const string& name,
01209 TFlags flags) const
01210 {
01211 return (((flags & fTransient)
01212 && m_Transient->HasEntry(section, name, flags & ~fTPFlags)) ||
01213 ((flags & fPersistent)
01214 && m_Persistent->HasEntry(section, name, flags & ~fTPFlags)));
01215 }
01216
01217
01218 const string& CTwoLayerRegistry::x_GetComment(const string& section,
01219 const string& name,
01220 TFlags flags) const
01221 {
01222 if (flags & fTransient) {
01223 const string& result = m_Transient->GetComment(section, name,
01224 flags & ~fTPFlags);
01225 if ( !result.empty() || !(flags & fPersistent) ) {
01226 return result;
01227 }
01228 }
01229 return m_Persistent->GetComment(section, name, flags & ~fTPFlags);
01230 }
01231
01232
01233 void CTwoLayerRegistry::x_Enumerate(const string& section,
01234 list<string>& entries, TFlags flags) const
01235 {
01236 switch (flags & fTPFlags) {
01237 case fTransient:
01238 m_Transient->EnumerateEntries(section, &entries, flags | fTPFlags);
01239 break;
01240 case fPersistent:
01241 m_Persistent->EnumerateEntries(section, &entries, flags | fTPFlags);
01242 break;
01243 case fTPFlags:
01244 {
01245 list<string> tl, pl;
01246 m_Transient ->EnumerateEntries(section, &tl, flags | fTPFlags);
01247 m_Persistent->EnumerateEntries(section, &pl, flags | fTPFlags);
01248 set_union(pl.begin(), pl.end(), tl.begin(), tl.end(),
01249 back_inserter(entries), PNocase());
01250 break;
01251 }
01252 default:
01253 _TROUBLE;
01254 }
01255 }
01256
01257
01258 void CTwoLayerRegistry::x_ChildLockAction(FLockAction action)
01259 {
01260 ((*m_Transient).*action)();
01261 ((*m_Persistent).*action)();
01262 }
01263
01264
01265 void CTwoLayerRegistry::x_Clear(TFlags flags)
01266 {
01267 if (flags & fTransient) {
01268 m_Transient->Clear(flags | fTPFlags);
01269 }
01270 if (flags & fPersistent) {
01271 m_Persistent->Clear(flags | fTPFlags);
01272 }
01273 }
01274
01275
01276 bool CTwoLayerRegistry::x_Set(const string& section, const string& name,
01277 const string& value, TFlags flags,
01278 const string& comment)
01279 {
01280 if (flags & fPersistent) {
01281 return m_Persistent->Set(section, name, value, flags & ~fTPFlags,
01282 comment);
01283 } else {
01284 return m_Transient->Set(section, name, value, flags & ~fTPFlags,
01285 comment);
01286 }
01287 }
01288
01289
01290 bool CTwoLayerRegistry::x_SetComment(const string& comment,
01291 const string& section, const string& name,
01292 TFlags flags)
01293 {
01294 if (flags & fTransient) {
01295 return m_Transient->SetComment(comment, section, name,
01296 flags & ~fTPFlags);
01297 } else {
01298 return m_Persistent->SetComment(comment, section, name,
01299 flags & ~fTPFlags);
01300 }
01301 }
01302
01303
01304
01305
01306
01307
01308
01309
01310
01311 const char* CNcbiRegistry::sm_EnvRegName = ".env";
01312 const char* CNcbiRegistry::sm_FileRegName = ".file";
01313 const char* CNcbiRegistry::sm_OverrideRegName = ".overrides";
01314 const char* CNcbiRegistry::sm_SysRegName = ".ncbirc";
01315
01316 inline
01317 void CNcbiRegistry::x_Init(void)
01318 {
01319 CNcbiApplication* app = CNcbiApplication::Instance();
01320 TFlags cf = m_Flags & fCaseFlags;
01321 if (app) {
01322 m_EnvRegistry.Reset(new CEnvironmentRegistry(app->SetEnvironment(),
01323 eNoOwnership, cf));
01324 } else {
01325 m_EnvRegistry.Reset(new CEnvironmentRegistry(cf));
01326 }
01327 x_Add(*m_EnvRegistry, ePriority_Environment, sm_EnvRegName);
01328
01329 m_FileRegistry.Reset(new CTwoLayerRegistry(NULL, cf));
01330 x_Add(*m_FileRegistry, ePriority_File, sm_FileRegName);
01331
01332 m_SysRegistry.Reset(new CTwoLayerRegistry(NULL, cf));
01333 x_Add(*m_SysRegistry, ePriority_Default - 1, sm_SysRegName);
01334
01335 const char* override_path = getenv("NCBI_CONFIG_OVERRIDES");
01336 if (override_path && *override_path) {
01337 m_OverrideRegistry.Reset(new CCompoundRWRegistry(cf));
01338 CMetaRegistry::SEntry entry
01339 = CMetaRegistry::Load(override_path, CMetaRegistry::eName_AsIs,
01340 0, cf, m_OverrideRegistry.GetPointer());
01341 if (entry.registry) {
01342 if (entry.registry != m_OverrideRegistry) {
01343 ERR_POST_X(5, Warning << "Resetting m_OverrideRegistry");
01344 m_OverrideRegistry.Reset(entry.registry);
01345 }
01346 x_Add(*m_OverrideRegistry, ePriority_Overrides, sm_OverrideRegName);
01347 } else {
01348 ERR_POST_ONCE(Warning
01349 << "NCBI_CONFIG_OVERRIDES names nonexistent file "
01350 << override_path);
01351 m_OverrideRegistry.Reset();
01352 }
01353 }
01354 }
01355
01356
01357 CNcbiRegistry::CNcbiRegistry(TFlags flags)
01358 : m_RuntimeOverrideCount(0), m_Flags(flags)
01359 {
01360 x_Init();
01361 }
01362
01363
01364 CNcbiRegistry::CNcbiRegistry(CNcbiIstream& is, TFlags flags)
01365 : m_RuntimeOverrideCount(0), m_Flags(flags)
01366 {
01367 x_CheckFlags("CNcbiRegistry::CNcbiRegistry", flags,
01368 fTransient | fInternalSpaces | fWithNcbirc | fCaseFlags);
01369 x_Init();
01370 m_FileRegistry->Read(is, flags & ~(fWithNcbirc | fCaseFlags));
01371 IncludeNcbircIfAllowed(flags & ~fCaseFlags);
01372 }
01373
01374
01375 CNcbiRegistry::~CNcbiRegistry()
01376 {
01377 }
01378
01379
01380 bool CNcbiRegistry::IncludeNcbircIfAllowed(TFlags flags)
01381 {
01382 if (flags & fWithNcbirc) {
01383 flags &= ~fWithNcbirc;
01384 } else {
01385 return false;
01386 }
01387
01388 if (getenv("NCBI_DONT_USE_NCBIRC")) {
01389 return false;
01390 }
01391
01392 if (HasEntry("NCBI", "DONT_USE_NCBIRC")) {
01393 return false;
01394 }
01395
01396 try {
01397 CMetaRegistry::SEntry entry
01398 = CMetaRegistry::Load("ncbi", CMetaRegistry::eName_RcOrIni,
01399 0, flags, m_SysRegistry.GetPointer());
01400 if (entry.registry && entry.registry != m_SysRegistry) {
01401 ERR_POST_X(5, Warning << "Resetting m_SysRegistry");
01402 m_SysRegistry.Reset(entry.registry);
01403 }
01404 } catch (CRegistryException& e) {
01405 ERR_POST_X(6, Critical << "CNcbiRegistry: "
01406 "Syntax error in system-wide configuration file: "
01407 << e.what());
01408 return false;
01409 }
01410
01411 if ( !m_SysRegistry->Empty() ) {
01412 return true;
01413 }
01414
01415 return false;
01416 }
01417
01418
01419 void CNcbiRegistry::x_Clear(TFlags flags)
01420 {
01421 CCompoundRWRegistry::x_Clear(flags);
01422 m_FileRegistry->Clear(flags);
01423 }
01424
01425
01426 IRWRegistry* CNcbiRegistry::x_Read(CNcbiIstream& is, TFlags flags)
01427 {
01428
01429
01430
01431 CConstRef<IRegistry> main_reg(FindByName(sm_MainRegName));
01432 if (main_reg->Empty() && m_FileRegistry->Empty()) {
01433 m_FileRegistry->Read(is, flags);
01434 LoadBaseRegistries(flags);
01435 IncludeNcbircIfAllowed(flags);
01436 return NULL;
01437 } else if ((flags & fNoOverride) == 0) {
01438 CRef<CCompoundRWRegistry> crwreg
01439 (new CCompoundRWRegistry(m_Flags & fCaseFlags));
01440 crwreg->Read(is, flags);
01441
01442 IRWRegistry& nc_main_reg
01443 = dynamic_cast<IRWRegistry&>(const_cast<IRegistry&>(*main_reg));
01444 if ((flags & fTransient) == 0) {
01445 flags |= fPersistent;
01446 }
01447 list<string> sections;
01448 crwreg->EnumerateSections(§ions, flags | fCountCleared);
01449 ITERATE (list<string>, sit, sections) {
01450 list<string> entries;
01451 crwreg->EnumerateEntries(*sit, &entries, flags | fCountCleared);
01452 ITERATE (list<string>, eit, entries) {
01453
01454
01455
01456
01457
01458
01459 if (nc_main_reg.HasEntry(*sit, *eit, flags | fCountCleared)) {
01460 nc_main_reg.Set(*sit, *eit, crwreg->Get(*sit, *eit), flags);
01461 }
01462 }
01463 }
01464 ++m_RuntimeOverrideCount;
01465 x_Add(*crwreg, ePriority_RuntimeOverrides + m_RuntimeOverrideCount,
01466 sm_OverrideRegName + NStr::IntToString(m_RuntimeOverrideCount));
01467 return crwreg.GetPointer();
01468 } else {
01469
01470
01471 return CCompoundRWRegistry::x_Read(is, flags);
01472 }
01473 }
01474
01475
01476
01477
01478
01479
01480 const char* CCompoundRWRegistry::sm_MainRegName = ".main";
01481 const char* CCompoundRWRegistry::sm_BaseRegNamePrefix = ".base:";
01482
01483
01484 CCompoundRWRegistry::CCompoundRWRegistry(TFlags flags)
01485 : m_MainRegistry(new CTwoLayerRegistry),
01486 m_AllRegistries(new CCompoundRegistry),
01487 m_Flags(flags)
01488 {
01489 x_Add(*m_MainRegistry, CCompoundRegistry::ePriority_Max - 1,
01490 sm_MainRegName);
01491 }
01492
01493
01494 CCompoundRWRegistry::~CCompoundRWRegistry()
01495 {
01496 }
01497
01498
01499 CCompoundRWRegistry::TPriority CCompoundRWRegistry::GetCoreCutoff(void) const
01500 {
01501 return m_AllRegistries->GetCoreCutoff();
01502 }
01503
01504
01505 void CCompoundRWRegistry::SetCoreCutoff(TPriority prio)
01506 {
01507 m_AllRegistries->SetCoreCutoff(prio);
01508 }
01509
01510
01511 void CCompoundRWRegistry::Add(const IRegistry& reg, TPriority prio,
01512 const string& name)
01513 {
01514 if (name.size() > 1 && name[0] == '.') {
01515 NCBI_THROW2(CRegistryException, eErr,
01516 "The sub-registry name " + name + " is reserved.", 0);
01517 }
01518 if (prio > ePriority_MaxUser) {
01519 ERR_POST_X(7, Warning
01520 << "Reserved priority value automatically downgraded.");
01521 prio = ePriority_MaxUser;
01522 }
01523 x_Add(reg, prio, name);
01524 }
01525
01526
01527 void CCompoundRWRegistry::Remove(const IRegistry& reg)
01528 {
01529 if (® == m_MainRegistry.GetPointer()) {
01530 NCBI_THROW2(CRegistryException, eErr,
01531 "The primary portion of the registry may not be removed.",
01532 0);
01533 } else {
01534 m_AllRegistries->Remove(reg);
01535 }
01536 }
01537
01538
01539 CConstRef<IRegistry> CCompoundRWRegistry::FindByName(const string& name) const
01540 {
01541 return m_AllRegistries->FindByName(name);
01542 }
01543
01544
01545 CConstRef<IRegistry> CCompoundRWRegistry::FindByContents(const string& section,
01546 const string& entry,
01547 TFlags flags) const
01548 {
01549 return m_AllRegistries->FindByContents(section, entry, flags);
01550 }
01551
01552
01553 bool CCompoundRWRegistry::LoadBaseRegistries(TFlags flags, int metareg_flags)
01554 {
01555 if (flags & fJustCore) {
01556 return false;
01557 }
01558
01559 list<string> names;
01560 {{
01561 string s = m_MainRegistry->Get("NCBI", ".Inherits");
01562 if (s.empty()) {
01563 if (dynamic_cast<CNcbiRegistry*>(this) != NULL) {
01564 _TRACE("LoadBaseRegistries(" << this
01565 << "): trying file registry");
01566 s = FindByName(CNcbiRegistry::sm_FileRegName)
01567 ->Get("NCBI", ".Inherits");
01568 }
01569 if (s.empty()) {
01570 return false;
01571 }
01572 }
01573 _TRACE("LoadBaseRegistries(" << this << "): using " << s);
01574 NStr::Split(s, ", ", names);
01575 }}
01576
01577 typedef pair<string, CRef<IRWRegistry> > TNewBase;
01578 typedef vector<TNewBase> TNewBases;
01579 TNewBases bases;
01580 SIZE_TYPE initial_num_bases = m_BaseRegNames.size();
01581
01582 ITERATE (list<string>, it, names) {
01583 if (m_BaseRegNames.find(*it) != m_BaseRegNames.end()) {
01584 continue;
01585 }
01586 CMetaRegistry::ENameStyle style
01587 = ((it->find('.') == NPOS)
01588 ? CMetaRegistry::eName_Ini : CMetaRegistry::eName_AsIs);
01589 CRef<CCompoundRWRegistry> reg2
01590 (new CCompoundRWRegistry(m_Flags & fCaseFlags));
01591 CMetaRegistry::SEntry entry2
01592 = CMetaRegistry::Load(*it, style, metareg_flags, flags,
01593 reg2.GetPointer());
01594 if (entry2.registry) {
01595 m_BaseRegNames.insert(*it);
01596 bases.push_back(TNewBase(*it, entry2.registry));
01597 }
01598 }
01599
01600 for (SIZE_TYPE i = 0; i < bases.size(); ++i) {
01601 x_Add(*bases[i].second, ePriority_MaxUser - initial_num_bases - i,
01602 sm_BaseRegNamePrefix + bases[i].first);
01603 }
01604
01605 return !bases.empty();
01606 }
01607
01608
01609 bool CCompoundRWRegistry::x_Empty(TFlags flags) const
01610 {
01611 return m_AllRegistries->Empty(flags);
01612 }
01613
01614
01615 bool CCompoundRWRegistry::x_Modified(TFlags flags) const
01616 {
01617 return m_AllRegistries->Modified(flags);
01618 }
01619
01620
01621 void CCompoundRWRegistry::x_SetModifiedFlag(bool modified, TFlags flags)
01622 {
01623 if (modified) {
01624 m_MainRegistry->SetModifiedFlag(modified, flags);
01625 } else {
01626
01627 m_AllRegistries->SetModifiedFlag(modified, flags);
01628 }
01629 }
01630
01631
01632 const string& CCompoundRWRegistry::x_Get(const string& section,
01633 const string& name,
01634 TFlags flags) const
01635 {
01636 TClearedEntries::const_iterator it
01637 = m_ClearedEntries.find(s_FlatKey(section, name));
01638 if (it != m_ClearedEntries.end()) {
01639 flags &= ~it->second;
01640 if ( !(flags & ~fJustCore) ) {
01641 return kEmptyStr;
01642 }
01643 }
01644 return m_AllRegistries->Get(section, name, flags);
01645 }
01646
01647
01648 bool CCompoundRWRegistry::x_HasEntry(const string& section, const string& name,
01649 TFlags flags) const
01650 {
01651 TClearedEntries::const_iterator it
01652 = m_ClearedEntries.find(s_FlatKey(section, name));
01653 if (it != m_ClearedEntries.end()) {
01654 if ((flags & fCountCleared) && (flags & it->second)) {
01655 return true;
01656 }
01657 flags &= ~it->second;
01658 if ( !(flags & ~fJustCore) ) {
01659 return false;
01660 }
01661 }
01662 return m_AllRegistries->HasEntry(section, name, flags);
01663 }
01664
01665
01666 const string& CCompoundRWRegistry::x_GetComment(const string& section,
01667 const string& name,
01668 TFlags flags) const
01669 {
01670 return m_AllRegistries->GetComment(section, name, flags);
01671 }
01672
01673
01674 void CCompoundRWRegistry::x_Enumerate(const string& section,
01675 list<string>& entries,
01676 TFlags flags) const
01677 {
01678 set<string> accum;
01679 REVERSE_ITERATE (CCompoundRegistry::TPriorityMap, it,
01680 m_AllRegistries->m_PriorityMap) {
01681 if ((flags & fJustCore) && (it->first < GetCoreCutoff())) {
01682 break;
01683 }
01684 list<string> tmp;
01685 it->second->EnumerateEntries(section, &tmp, flags & ~fJustCore);
01686 ITERATE (list<string>, it2, tmp) {
01687
01688 TClearedEntries::const_iterator ceci
01689 = (flags & fCountCleared) ? m_ClearedEntries.end()
01690 : m_ClearedEntries.find(s_FlatKey(section, *it2));
01691 if (ceci == m_ClearedEntries.end()
01692 || (flags & ~fJustCore & ~ceci->second)) {
01693 accum.insert(*it2);
01694 }
01695 }
01696 }
01697 ITERATE (set<string>, it, accum) {
01698 entries.push_back(*it);
01699 }
01700 }
01701
01702
01703 void CCompoundRWRegistry::x_ChildLockAction(FLockAction action)
01704 {
01705 ((*m_AllRegistries).*action)();
01706 }
01707
01708
01709 void CCompoundRWRegistry::x_Clear(TFlags flags)
01710 {
01711 m_MainRegistry->Clear(flags);
01712
01713 ITERATE (set<string>, it, m_BaseRegNames) {
01714 Remove(*FindByName(sm_BaseRegNamePrefix + *it));
01715 }
01716 m_BaseRegNames.clear();
01717 }
01718
01719
01720 bool CCompoundRWRegistry::x_Set(const string& section, const string& name,
01721 const string& value, TFlags flags,
01722 const string& comment)
01723 {
01724 TFlags flags2 = (flags & fPersistent) ? flags : (flags | fTransient);
01725 flags2 &= fLayerFlags;
01726 _TRACE('[' << section << ']' << name << " = " << value);
01727 if ((flags & fNoOverride) && HasEntry(section, name, flags)) {
01728 return false;
01729 }
01730 if (value.empty()) {
01731 bool was_empty = Get(section, name, flags).empty();
01732 m_MainRegistry->Set(section, name, value, flags, comment);
01733 m_ClearedEntries[s_FlatKey(section, name)] |= flags2;
01734 return !was_empty;
01735 } else {
01736 TClearedEntries::iterator it
01737 = m_ClearedEntries.find(s_FlatKey(section, name));
01738 if (it != m_ClearedEntries.end()) {
01739 if ((it->second &= ~flags2) == 0) {
01740 m_ClearedEntries.erase(it);
01741 }
01742 }
01743 }
01744 return m_MainRegistry->Set(section, name, value, flags, comment);
01745 }
01746
01747
01748 bool CCompoundRWRegistry::x_SetComment(const string& comment,
01749 const string& section,
01750 const string& name, TFlags flags)
01751 {
01752 return m_MainRegistry->SetComment(comment, section, name, flags);
01753 }
01754
01755
01756 IRWRegistry* CCompoundRWRegistry::x_Read(CNcbiIstream& in, TFlags flags)
01757 {
01758 TFlags lbr_flags = flags;
01759 if ((flags & fNoOverride) == 0 && !Empty(fPersistent) ) {
01760 lbr_flags |= fOverride;
01761 } else {
01762 lbr_flags &= ~fOverride;
01763 }
01764 IRWRegistry::x_Read(in, flags);
01765 LoadBaseRegistries(lbr_flags);
01766 return NULL;
01767 }
01768
01769
01770 void CCompoundRWRegistry::x_Add(const IRegistry& reg, TPriority prio,
01771 const string& name)
01772 {
01773 m_AllRegistries->Add(reg, prio, name);
01774 }
01775
01776
01777
01778
01779
01780
01781 const char* CRegistryException::GetErrCodeString(void) const
01782 {
01783 switch (GetErrCode()) {
01784 case eSection: return "eSection";
01785 case eEntry: return "eEntry";
01786 case eValue: return "eValue";
01787 case eErr: return "eErr";
01788 default: return CException::GetErrCodeString();
01789 }
01790 }
01791
01792
01793 END_NCBI_SCOPE
01794
01795