NCBI C++ ToolKit
ncbireg.cpp
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* $Id: ncbireg.cpp 99267 2023-03-03 17:10:24Z ucko $
2  * ===========================================================================
3  *
4  * PUBLIC DOMAIN NOTICE
5  * National Center for Biotechnology Information
6  *
7  * This software/database is a "United States Government Work" under the
8  * terms of the United States Copyright Act. It was written as part of
9  * the author's official duties as a United States Government employee and
10  * thus cannot be copyrighted. This software/database is freely available
11  * to the public for use. The National Library of Medicine and the U.S.
12  * Government have not placed any restriction on its use or reproduction.
13  *
14  * Although all reasonable efforts have been taken to ensure the accuracy
15  * and reliability of the software and data, the NLM and the U.S.
16  * Government do not and cannot warrant the performance or results that
17  * may be obtained by using this software or data. The NLM and the U.S.
18  * Government disclaim all warranties, express or implied, including
19  * warranties of performance, merchantability or fitness for any particular
20  * purpose.
21  *
22  * Please cite the author in any work or product based on this material.
23  *
24  * ===========================================================================
25  *
26  * Authors: Denis Vakatov, Aaron Ucko
27  *
28  * File Description:
29  * Handle info in the NCBI configuration file(s):
30  * read and parse config. file
31  * search, edit, etc. in the retrieved configuration info
32  * dump info back to config. file
33  *
34  */
35 
36 #include <ncbi_pch.hpp>
37 #include <corelib/ncbireg.hpp>
38 #include <corelib/env_reg.hpp>
39 #include <corelib/metareg.hpp>
40 #include <corelib/ncbiapp_api.hpp>
41 #include <corelib/ncbimtx.hpp>
42 #include <corelib/error_codes.hpp>
44 #include "ncbisys.hpp"
45 
46 #include <algorithm>
47 #include <set>
48 
49 
50 #define NCBI_USE_ERRCODE_X Corelib_Reg
51 
52 
54 
57 
58 
59 // Valid symbols for a section/entry name
61 {
62  return (isalnum((unsigned char) ch)
63  || ch == '_' || ch == '-' || ch == '.' || ch == '/'
64  || ((flags & IRegistry::fInternalSpaces) && ch == ' '));
65 }
66 
67 
69 {
70  // Allow empty section name in case of fSectionlessEntries set
71  if (str.empty() && !(flags & IRegistry::fSectionlessEntries) ) {
72  return false;
73  }
74 
75  ITERATE (string, it, str) {
76  if (!s_IsNameSectionSymbol(*it, flags)) {
77  return false;
78  }
79  }
80  return true;
81 }
82 
83 
84 bool IRegistry::IsNameEntry(const string& str, TFlags flags)
85 {
87 }
88 
89 
90 // Convert "comment" from plain text to comment
91 static const string s_ConvertComment(const string& comment,
92  bool is_file_comment = false)
93 {
94  if ( !comment.length() )
95  return kEmptyStr;
96 
97  string x_comment;
98  const char c_comment = is_file_comment ? '#' : ';';
99 
100  SIZE_TYPE endl_pos = 0;
101  for (SIZE_TYPE beg = 0; beg < comment.length();
102  beg = endl_pos + 1) {
103  SIZE_TYPE pos = comment.find_first_not_of(" \t", beg);
104  endl_pos = comment.find_first_of("\n", beg);
105  if (endl_pos == NPOS) {
106  endl_pos = comment.length();
107  }
108  if (((pos != NPOS && comment[pos] != c_comment) ||
109  (pos == NPOS && endl_pos == comment.length())) &&
110  (is_file_comment || beg != endl_pos) ) {
111  x_comment += c_comment;
112  }
113  x_comment.append(comment, beg, endl_pos - beg);
114  x_comment += '\n';
115  }
116  return x_comment;
117 }
118 
119 
120 // Dump the comment to stream "os"
121 static bool s_WriteComment(CNcbiOstream& os, const string& comment)
122 {
123  if (!comment.length())
124  return true;
125 
126  if (strcmp(Endl(), "\n") == 0) {
127  os << comment;
128  } else {
129  ITERATE(string, i, comment) {
130  if (*i == '\n') {
131  os << Endl();
132  } else {
133  os << *i;
134  }
135  }
136  }
137  return os.good();
138 }
139 
140 // Does pos follow an odd number of backslashes?
141 inline bool s_Backslashed(const string& s, SIZE_TYPE pos)
142 {
143  if (pos == 0) {
144  return false;
145  }
146  SIZE_TYPE last_non_bs = s.find_last_not_of("\\", pos - 1);
147  return (pos - last_non_bs) % 2 == 0;
148 }
149 
150 inline string s_FlatKey(const string& section, const string& name)
151 {
152  return section + '#' + name;
153 }
154 
155 
156 //////////////////////////////////////////////////////////////////////
157 //
158 // IRegistry
159 
160 const char* IRegistry::sm_InSectionCommentName = "[]";
161 
163 {
164  x_CheckFlags("IRegistry::Empty", flags, fLayerFlags);
165  if ( !(flags & fTPFlags) ) {
166  flags |= fTPFlags;
167  }
168  TReadGuard LOCK(*this);
169  return x_Empty(flags);
170 }
171 
172 
174 {
175  x_CheckFlags("IRegistry::Modified", flags, fLayerFlags);
176  if ( !(flags & fTransient) ) {
177  flags |= fPersistent;
178  }
179  TReadGuard LOCK(*this);
180  return x_Modified(flags);
181 }
182 
183 
185 {
186  x_CheckFlags("IRegistry::SetModifiedFlag", flags, fLayerFlags);
187  if ( !(flags & fTransient) ) {
188  flags |= fPersistent;
189  }
190  TReadGuard LOCK(*this); // Treat the flag as semi-mutable
191  x_SetModifiedFlag(modified, flags);
192 }
193 
194 
195 // Somewhat inefficient, but that can't really be helped....
197 {
198  x_CheckFlags("IRegistry::Write", flags,
201 
202  if ( !(flags & fTransient) ) {
203  flags |= fPersistent;
204  }
205  if ( !(flags & fNotJustCore) ) {
206  flags |= fJustCore;
207  }
208  TReadGuard LOCK(*this);
209 
210  // Write file comment
211  if ( !s_WriteComment(os, GetComment(kEmptyStr, kEmptyStr, flags) + "\n") )
212  return false;
213 
214  list<string> sections;
215  EnumerateSections(&sections, flags);
216 
217  ITERATE (list<string>, section, sections) {
218  if ( !s_WriteComment(os, GetComment(*section, kEmptyStr, flags)) ) {
219  return false;
220  }
221  if(!(section->empty()))
222  os << '[' << *section << ']' << Endl();
223  if ( !os ) {
224  return false;
225  }
226  list<string> entries;
227  EnumerateEntries(*section, &entries, flags);
228  ITERATE (list<string>, entry, entries) {
229  s_WriteComment(os, GetComment(*section, *entry, flags));
230  // XXX - produces output that older versions can't handle
231  // when the value contains control characters other than
232  // CR (\r) or LF (\n).
233  os << *entry << " = \""
234  << Printable(Get(*section, *entry, flags)) << "\""
235  << Endl();
236  if ( !os ) {
237  return false;
238  }
239  }
240  // Make a line break between section entries and next section
241  // (or optional in-section comments)
242  os << Endl();
243  // Write in-section comment
244  list<string> in_section_comments;
245  EnumerateInSectionComments(*section, &in_section_comments, flags);
246  ITERATE(list<string>, comment, in_section_comments) {
247  s_WriteComment(os, *comment + "\n");
248  }
249  }
250 
251  // Clear the modified bit (checking it first so as to perform the
252  // const_cast<> only if absolutely necessary).
253  if (Modified(flags & fLayerFlags)) {
254  const_cast<IRegistry*>(this)->SetModifiedFlag
255  (false, flags & fLayerFlags);
256  }
257 
258  return true;
259 }
260 
261 
262 const string& IRegistry::Get(const string& section, const string& name,
263  TFlags flags) const
264 {
265  if (flags & fInternalCheckedAndLocked) return x_Get(section, name, flags);
266 
267  x_CheckFlags("IRegistry::Get", flags,
269 
270  if ( !(flags & fTPFlags) ) {
271  flags |= fTPFlags;
272  }
273  string clean_section = NStr::TruncateSpaces(section);
274  if ( !IsNameSection(clean_section, flags) ) {
275  _TRACE("IRegistry::Get: bad section name \""
276  << NStr::PrintableString(section) << '\"');
277  return kEmptyStr;
278  }
279  string clean_name = NStr::TruncateSpaces(name);
280  if ( !IsNameEntry(clean_name, flags) ) {
281  _TRACE("IRegistry::Get: bad entry name \""
282  << NStr::PrintableString(name) << '\"');
283  return kEmptyStr;
284  }
285  TReadGuard LOCK(*this);
286  return x_Get(clean_section, clean_name, flags | fInternalCheckedAndLocked);
287 }
288 
289 
290 bool IRegistry::HasEntry(const string& section, const string& name,
291  TFlags flags) const
292 {
293  if (flags & fInternalCheckedAndLocked) return x_HasEntry(section, name, flags);
294 
295  x_CheckFlags("IRegistry::HasEntry", flags,
298 
299  if ( !(flags & fTPFlags) ) {
300  flags |= fTPFlags;
301  }
302  string clean_section = NStr::TruncateSpaces(section);
303  if ( !IsNameSection(clean_section, flags) ) {
304  _TRACE("IRegistry::HasEntry: bad section name \""
305  << NStr::PrintableString(section) << '\"');
306  return false;
307  }
308  string clean_name = NStr::TruncateSpaces(name);
309  bool is_special_name = clean_name.empty() ||
310  clean_name == sm_InSectionCommentName;
311  if ( !is_special_name && !IsNameEntry(clean_name, flags) ) {
312  _TRACE("IRegistry::HasEntry: bad entry name \""
313  << NStr::PrintableString(name) << '\"');
314  return false;
315  }
316  TReadGuard LOCK(*this);
317  return x_HasEntry(clean_section, clean_name, flags | fInternalCheckedAndLocked);
318 }
319 
320 
321 string IRegistry::GetString(const string& section, const string& name,
322  const string& default_value, TFlags flags) const
323 {
324  const string& value = Get(section, name, flags);
325  return value.empty() ? default_value : value;
326 }
327 
328 
329 string IRegistry::GetEncryptedString(const string& section, const string& name,
330  TFlags flags, const string& password)
331  const
332 {
333  string clean_section = NStr::TruncateSpaces(section);
334  string clean_name = NStr::TruncateSpaces(name);
335  const string& raw_value = Get(clean_section, clean_name,
337 
338  if (CNcbiEncrypt::IsEncrypted(raw_value)) {
339  try {
340  if (password.empty()) {
341  return CNcbiEncrypt::Decrypt(raw_value);
342  } else {
343  return CNcbiEncrypt::Decrypt(raw_value, password);
344  }
345  } catch (CException& e) {
346  NCBI_RETHROW2(e, CRegistryException, eDecryptionFailed,
347  "Decryption failed for configuration value ["
348  + clean_section + "] " + clean_name + '.',
349  0);
350  }
351  } else if ( !raw_value.empty() && (flags & fPlaintextAllowed) == 0) {
352  NCBI_THROW2(CRegistryException, eUnencrypted,
353  "Configuration value for [" + clean_section + "] "
354  + clean_name + " should have been encrypted but wasn't.",
355  0);
356  } else {
357  return raw_value;
358  }
359 }
360 
361 
362 int IRegistry::GetInt(const string& section, const string& name,
363  int default_value, TFlags flags, EErrAction err_action)
364  const
365 {
366  const string& value = Get(section, name, flags);
367  if (value.empty()) {
368  return default_value;
369  }
370 
371  try {
372  return NStr::StringToInt(value);
373  } catch (CStringException& ex) {
374  if (err_action == eReturn) {
375  return default_value;
376  }
377 
378  string msg = "IRegistry::GetInt(): [" + section + ']' + name;
379 
380  if (err_action == eThrow) {
381  NCBI_RETHROW_SAME(ex, msg);
382  } else if (err_action == eErrPost) {
383  ERR_POST_X(1, ex.what() << msg);
384  }
385 
386  return default_value;
387  }
388 }
389 
390 
391 bool IRegistry::GetBool(const string& section, const string& name,
392  bool default_value, TFlags flags,
393  EErrAction err_action) const
394 {
395  const string& value = Get(section, name, flags);
396  if (value.empty()) {
397  return default_value;
398  }
399 
400  try {
401  return NStr::StringToBool(value);
402  } catch (CStringException& ex) {
403  if (err_action == eReturn) {
404  return default_value;
405  }
406 
407  string msg = "IRegistry::GetBool(): [" + section + ']' + name;
408 
409  if (err_action == eThrow) {
410  NCBI_RETHROW_SAME(ex, msg);
411  } else if (err_action == eErrPost) {
412  ERR_POST_X(2, ex.what() << msg);
413  }
414 
415  return default_value;
416  }
417 }
418 
419 
420 double IRegistry::GetDouble(const string& section, const string& name,
421  double default_value, TFlags flags,
422  EErrAction err_action) const
423 {
424  const string& value = Get(section, name, flags);
425  if (value.empty()) {
426  return default_value;
427  }
428 
429  try {
431  } catch (CStringException& ex) {
432  if (err_action == eReturn) {
433  return default_value;
434  }
435 
436  string msg = "IRegistry::GetDouble()";
437  msg += " Reg entry:" + section + ":" + name;
438 
439  if (err_action == eThrow) {
440  NCBI_RETHROW_SAME(ex, msg);
441  } else if (err_action == eErrPost) {
442  ERR_POST_X(3, ex.what() << msg);
443  }
444 
445  return default_value;
446  }
447 }
448 
449 
450 const string& IRegistry::GetComment(const string& section, const string& name,
451  TFlags flags) const
452 {
453  x_CheckFlags("IRegistry::GetComment", flags,
455  string clean_section = NStr::TruncateSpaces(section);
456  if ( !clean_section.empty() && !IsNameSection(clean_section, flags) ) {
457  _TRACE("IRegistry::GetComment: bad section name \""
458  << NStr::PrintableString(section) << '\"');
459  return kEmptyStr;
460  }
461  string clean_name = NStr::TruncateSpaces(name);
462  bool is_special_name = clean_name.empty() ||
463  clean_name == sm_InSectionCommentName;
464  if ( !is_special_name && !IsNameSection(clean_name, flags) ) {
465  _TRACE("IRegistry::GetComment: bad entry name \""
466  << NStr::PrintableString(name) << '\"');
467  return kEmptyStr;
468  }
469  TReadGuard LOCK(*this);
470  return x_GetComment(clean_section, clean_name, flags);
471 }
472 
473 
474 void IRegistry::EnumerateInSectionComments(const string& section,
475  list<string>* comments,
476  TFlags flags) const
477 {
478  x_CheckFlags("IRegistry::EnumerateInSectionComments", flags,
480 
481  if (!(flags & fTPFlags)) {
482  flags |= fTPFlags;
483  }
484  _ASSERT(comments);
485  comments->clear();
486  string clean_section = NStr::TruncateSpaces(section);
487  if (clean_section.empty() || !IsNameSection(clean_section, flags)) {
488  _TRACE("IRegistry::EnumerateInSectionComments: bad section name \""
489  << NStr::PrintableString(section) << '\"');
490  return;
491  }
492  TReadGuard LOCK(*this);
493  x_Enumerate(clean_section, *comments, flags | fInSectionComments);
494 }
495 
496 
497 void IRegistry::EnumerateSections(list<string>* sections, TFlags flags) const
498 {
499  // Should clear fSectionlessEntries if set
500  x_CheckFlags("IRegistry::EnumerateSections", flags,
503 
504  if ( !(flags & fTPFlags) ) {
505  flags |= fTPFlags;
506  }
507  _ASSERT(sections);
508  sections->clear();
509  TReadGuard LOCK(*this);
510  x_Enumerate(kEmptyStr, *sections, flags | fSections);
511 }
512 
513 
514 void IRegistry::EnumerateEntries(const string& section, list<string>* entries,
515  TFlags flags) const
516 {
517  x_CheckFlags("IRegistry::EnumerateEntries", flags,
520 
521  if ( !(flags & fTPFlags) ) {
522  flags |= fTPFlags;
523  }
524  _ASSERT(entries);
525  entries->clear();
526  string clean_section = NStr::TruncateSpaces(section);
527  if ( !clean_section.empty() && !IsNameSection(clean_section, flags) ) {
528  _TRACE("IRegistry::EnumerateEntries: bad section name \""
529  << NStr::PrintableString(section) << '\"');
530  return;
531  }
532  TReadGuard LOCK(*this);
533  x_Enumerate(clean_section, *entries, flags);
534 }
535 
536 
538 {
540  m_Lock.ReadLock();
541 }
542 
543 
545 {
547  m_Lock.WriteLock();
548 }
549 
550 
552 {
553  m_Lock.Unlock();
555 }
556 
557 
558 void IRegistry::x_CheckFlags(const string& _DEBUG_ARG(func),
559  TFlags& flags, TFlags allowed)
560 {
561  if (flags & ~allowed)
562  _TRACE(func << "(): extra flags passed: "
563  << resetiosflags(IOS_BASE::basefield)
564  << setiosflags(IOS_BASE::hex | IOS_BASE::showbase)
565  << flags);
566  flags &= allowed;
567 }
568 
569 
570 //////////////////////////////////////////////////////////////////////
571 //
572 // IRWRegistry
573 
575 {
576  // mask out irrelevant flags
578  switch (op) {
579  case eClear:
580  return flags;
581  case eRead:
582  case eSet:
583  return ((flags & fTransient) ? fTransient : fPersistent) | fJustCore;
584  default:
585  _TROUBLE;
586  return flags;
587  }
588 }
589 
591 {
592  x_CheckFlags("IRWRegistry::Clear", flags,
594  TWriteGuard LOCK(*this);
595  if ( (flags & fPersistent) && !x_Empty(fPersistent) ) {
597  }
598  if ( (flags & fTransient) && !x_Empty(fTransient) ) {
600  }
601  x_Clear(flags);
602 }
603 
604 
606  const string& path)
607 {
608  x_CheckFlags("IRWRegistry::Read", flags,
612 
613  if ( !is ) {
614  return NULL;
615  }
616 
617  // Ensure that x_Read gets a stream it can handle.
620  CStringUTF8 s;
621  ReadIntoUtf8(is, &s, ef);
622  CNcbiIstrstream iss(s);
623  return x_Read(iss, flags, path);
624  } else {
625  return x_Read(is, flags, path);
626  }
627 }
628 
629 
631  const string& path)
632 {
633  // Whether to consider this read to be (unconditionally) non-modifying
634  TFlags layer = (flags & fTransient) ? fTransient : fPersistent;
635  TFlags impact = layer | fJustCore;
636  bool was_empty = Empty(impact);
637  bool non_modifying = was_empty && !Modified(impact);
638  bool ignore_errors = (flags & fIgnoreErrors) > 0;
639 
640  // Adjust flags for Set() fSectionlessEntries must survive this change
641  flags = (flags & ~fTPFlags & ~fIgnoreErrors) | layer;
642 
643  string str; // the line being parsed
644  SIZE_TYPE line; // # of the line being parsed
645  string section(kEmptyStr); // current section name
646  string comment; // current comment
647  string in_path = path.empty() ? kEmptyStr : (" in " + path);
648  // To collect in-section comments we need a special container, because
649  // these comments may be multiline with line breaks in the middle
650  map<string, string> in_section_comments;
651 
652  for (line = 1; NcbiGetlineEOL(is, str); ++line) {
653  try {
654  SIZE_TYPE len = str.length();
655  SIZE_TYPE beg = 0;
656 
657  while (beg < len && isspace((unsigned char) str[beg])) {
658  ++beg;
659  }
660  // If this line is empty, all comments
661  // that have just been read go to the current section.
662  if (beg == len) {
663  if (!comment.empty() && !section.empty()) {
664  in_section_comments[section] += comment + "\n";
666  in_section_comments[section]), section,
668  comment.erase();
669  }
670  continue;
671  }
672 
673  switch (str[beg]) {
674 
675  case '#': { // file comment
676  SetComment(GetComment() + str + '\n');
677  break;
678  }
679 
680  case ';': { // section or entry comment
681  comment += str;
682  comment += '\n';
683  // If there is end of file next, all comments
684  // that have just been read go to the current section.
685  if (is.peek() == EOF && !section.empty()) {
686  SetComment(comment, section, sm_InSectionCommentName,
687  flags | fCountCleared);
688  comment.erase();
689  continue;
690  }
691  break;
692  }
693 
694  case '[': { // section name
695  ++beg;
696  SIZE_TYPE end = str.find_first_of(']', beg + 1);
697  if (end == NPOS) {
699  "Invalid registry section" + in_path
700  + " (']' is missing): `" + str + "'", line);
701  }
702  section = NStr::TruncateSpaces(str.substr(beg, end - beg));
703  if (section.empty()) {
705  "Unnamed registry section" + in_path + ": `"
706  + str + "'", line);
707  } else if ( !IsNameSection(section, flags) ) {
709  "Invalid registry section name" + in_path
710  + ": `" + str + "'", line);
711  }
712  // Unconditional, to ensure the section becomes known
713  // even if it has no comment or contents
714  SetComment(comment, section, kEmptyStr, flags | fCountCleared);
715  comment.erase();
716  break;
717  }
718 
719  default: { // regular entry
720  string name, value;
721  if ( !NStr::SplitInTwo(str, "=", name, value) ) {
723  "Invalid registry entry format" + in_path
724  + ": '" + str + "'", line);
725  }
727  if ( !IsNameEntry(name, flags) ) {
729  "Invalid registry entry name" + in_path + ": '"
730  + str + "'", line);
731  }
732 
734 #if 0 // historic behavior; could inappropriately expose entries in lower layers
735  if (value.empty()) {
736  if ( !(flags & fNoOverride) ) {
737  Set(section, name, kEmptyStr, flags, comment);
738  comment.erase();
739  }
740  break;
741  }
742 #endif
743  // read continuation lines, if any
744  string cont;
745  while (s_Backslashed(value, value.size())
746  && NcbiGetlineEOL(is, cont)) {
747  ++line;
748  value[value.size() - 1] = '\n';
749  value += NStr::TruncateSpaces(cont);
750  str += 'n' + cont; // for presentation in exceptions
751  }
752 
753  // Historically, " may appear unescaped at the beginning,
754  // end, both, or neither.
755  beg = 0;
756  SIZE_TYPE end = value.size();
757  for (SIZE_TYPE pos = value.find('\"');
758  pos < end && pos != NPOS;
759  pos = value.find('\"', pos + 1)) {
760  if (s_Backslashed(value, pos)) {
761  continue;
762  } else if (pos == beg) {
763  ++beg;
764  } else if (pos == end - 1) {
765  --end;
766  } else {
768  "Single(unescaped) '\"' in the middle "
769  "of registry value" + in_path + ": '"
770  + str + "'", line);
771  }
772  }
773 
774  try {
775  value = NStr::ParseEscapes(value.substr(beg, end - beg));
776  } catch (CStringException&) {
778  "Badly placed '\\' in the registry value"
779  + in_path + ": '" + str + "'", line);
780 
781  }
782  TFlags set_flags = flags & ~fJustCore;
783  if (NStr::EqualNocase(section, "NCBI")
784  && NStr::EqualNocase(name, ".Inherits")
785  && HasEntry(section, name, flags)) {
786  const string& old_value = Get(section, name, flags);
787  if (flags & fNoOverride) {
788  value = old_value + ' ' + value;
789  set_flags &= ~fNoOverride;
790  } else {
791  value += ' ';
792  value += old_value;
793  }
794  } else if (was_empty && HasEntry(section, name, flags)) {
796  << "Found multiple [" << section << "] "
797  << name << " settings" << in_path
798  << "; using the one from line " << line);
799  }
800  Set(section, name, value, set_flags, comment);
801  comment.erase();
802  }
803  }
804  } catch (exception& e) {
805  if (ignore_errors) {
806  ERR_POST_X(4, e.what());
807  } else {
808  throw;
809  }
810  }
811  }
812 
813  if ( !is.eof() ) {
814  ERR_POST_X(4, "Error reading the registry after line " << line
815  << in_path << ": " << str);
816  }
817 
818  if ( non_modifying ) {
819  SetModifiedFlag(false, impact);
820  }
821 
822  return NULL;
823 }
824 
825 
826 bool IRWRegistry::Set(const string& section, const string& name,
827  const string& value, TFlags flags,
828  const string& comment)
829 {
830  x_CheckFlags("IRWRegistry::Set", flags,
833  string clean_section = NStr::TruncateSpaces(section);
834  if ( !IsNameSection(clean_section, flags) ) {
835  _TRACE("IRWRegistry::Set: bad section name \""
836  << NStr::PrintableString(section) << '\"');
837  return false;
838  }
839  string clean_name = NStr::TruncateSpaces(name);
840  if ( !IsNameEntry(clean_name, flags) ) {
841  _TRACE("IRWRegistry::Set: bad entry name \""
842  << NStr::PrintableString(name) << '\"');
843  return false;
844  }
845  SIZE_TYPE beg = 0, end = value.size();
846  if (flags & fTruncate) {
847  // don't use TruncateSpaces, since newlines should stay
848  beg = value.find_first_not_of(" \r\t\v");
849  end = value.find_last_not_of (" \r\t\v");
850  if (beg == NPOS) {
851  _ASSERT(end == NPOS);
852  beg = 1;
853  end = 0;
854  }
855  }
856  TWriteGuard LOCK(*this);
857  if (x_Set(clean_section, clean_name, value.substr(beg, end - beg + 1),
858  flags, s_ConvertComment(comment, section.empty()))) {
859  x_SetModifiedFlag(true, flags);
860  return true;
861  } else {
862  return false;
863  }
864 }
865 
866 
867 bool IRWRegistry::Unset(const string& section, const string& name,
868  TFlags flags)
869 {
870  x_CheckFlags("IRWRegistry::Unset", flags,
871  static_cast<TFlags>(fTPFlags) | fCountCleared
873  string clean_section = NStr::TruncateSpaces(section);
874  if ( !IsNameSection(clean_section, flags) ) {
875  _TRACE("IRWRegistry::Unset: bad section name \""
876  << NStr::PrintableString(section) << '\"');
877  return false;
878  }
879  string clean_name = NStr::TruncateSpaces(name);
880  if ( !IsNameEntry(clean_name, flags) ) {
881  _TRACE("IRWRegistry::Unset: bad entry name \""
882  << NStr::PrintableString(name) << '\"');
883  return false;
884  }
885  TWriteGuard LOCK(*this);
886  if (x_Unset(clean_section, clean_name, flags)) {
887  x_SetModifiedFlag(true, flags);
888  return true;
889  } else {
890  return false;
891  }
892 }
893 
894 
895 bool IRWRegistry::SetComment(const string& comment, const string& section,
896  const string& name, TFlags flags)
897 {
898  x_CheckFlags("IRWRegistry::SetComment", flags,
900  string clean_section = NStr::TruncateSpaces(section);
901  if ( !clean_section.empty() && !IsNameSection(clean_section, flags) ) {
902  _TRACE("IRWRegistry::SetComment: bad section name \""
903  << NStr::PrintableString(section) << '\"');
904  return false;
905  }
906  string clean_name = NStr::TruncateSpaces(name);
907  bool is_special_name = clean_name.empty() ||
908  clean_name == sm_InSectionCommentName;
909  if ( !is_special_name && !IsNameEntry(clean_name, flags) ) {
910  _TRACE("IRWRegistry::SetComment: bad entry name \""
911  << NStr::PrintableString(name) << '\"');
912  return false;
913  }
914  TWriteGuard LOCK(*this);
915  if (x_SetComment(s_ConvertComment(comment, section.empty()),
916  clean_section, clean_name, flags)) {
918  return true;
919  } else {
920  return false;
921  }
922 }
923 
924 
925 bool IRWRegistry::MaybeSet(string& target, const string& value, TFlags flags)
926 {
927  if (target.empty()) {
928  target = value;
929  /* "return !value.empty()" was here before, which prevented to set
930  comments to empty values, but now empty string is
931  considered a value, not an unset variable, so we always return
932  true */
933  return true;
934  } else if ( !(flags & fNoOverride) ) {
935  target = value;
936  return true;
937  } else {
938  return false;
939  }
940 }
941 
942 
943 //////////////////////////////////////////////////////////////////////
944 //
945 // CMemoryRegistry
946 
948 {
949  TReadGuard LOCK(*this);
950  return m_Sections.empty() && m_RegistryComment.empty();
951 }
952 
953 
954 const string& CMemoryRegistry::x_Get(const string& section, const string& name,
955  TFlags) const
956 {
958  if (sit == m_Sections.end()) {
959  return kEmptyStr;
960  }
961  const TEntries& entries = sit->second.entries;
962  TEntries::const_iterator eit = entries.find(name);
963  return (eit == entries.end()) ? kEmptyStr : eit->second.value;
964 }
965 
966 bool CMemoryRegistry::x_HasEntry(const string& section, const string& name,
967  TFlags flags) const
968 {
970  if (sit == m_Sections.end()) {
971  return false;
972  } else if (name.empty()) {
973  return ((flags & fCountCleared) != 0) || !sit->second.cleared;
974  }
975  if (name == sm_InSectionCommentName) {
976  const string& inner_comment = sit->second.in_section_comment;
977  if (!inner_comment.empty()) {
978  return true;
979  } else {
980  return false;
981  }
982  }
983  const TEntries& entries = sit->second.entries;
984  TEntries::const_iterator eit = entries.find(name);
985  if (eit == entries.end()) {
986  return false;
987  } else if ((flags & fCountCleared) != 0) {
988  return true;
989  } else {
990  return !eit->second.value.empty();
991  }
992 }
993 
994 
995 const string& CMemoryRegistry::x_GetComment(const string& section,
996  const string& name,
997  TFlags) const
998 {
999  if (section.empty()) {
1000  return m_RegistryComment;
1001  }
1002  TSections::const_iterator sit = m_Sections.find(section);
1003  if (sit == m_Sections.end()) {
1004  return kEmptyStr;
1005  } else if (name.empty()) {
1006  return sit->second.comment;
1007  } else if (name == sm_InSectionCommentName) {
1008  return sit->second.in_section_comment;
1009  }
1010  const TEntries& entries = sit->second.entries;
1011  TEntries::const_iterator eit = entries.find(name);
1012  return (eit == entries.end()) ? kEmptyStr : eit->second.comment;
1013 }
1014 
1015 
1016 void CMemoryRegistry::x_Enumerate(const string& section, list<string>& entries,
1017  TFlags flags) const
1018 {
1019  if (section.empty() &&
1022  // Enumerate sections
1024  _TRACE("Deprecated call to x_Enumerate with empty section name, "
1025  " but with no fSections flag set");
1026 
1027  ITERATE (TSections, it, m_Sections) {
1028  if (IsNameSection(it->first, flags)
1029  && HasEntry(it->first, kEmptyStr, flags)) {
1030  entries.push_back(it->first);
1031  }
1032  }
1033  } else if (flags & IRegistry::fInSectionComments) {
1034  // Enumerate in-section comments
1035  string comment = x_GetComment(section, "[]", flags);
1036  if (!comment.empty()) {
1037  entries.push_back(comment);
1038  }
1039  } else {
1040  // Enumerate entries
1041  TSections::const_iterator sit = m_Sections.find(section);
1042  if (sit != m_Sections.end()) {
1043  ITERATE (TEntries, it, sit->second.entries) {
1044  if (IsNameSection(it->first, flags)
1045  && ((flags & fCountCleared) != 0
1046  || !it->second.value.empty() )) {
1047  entries.push_back(it->first);
1048  }
1049  }
1050  }
1051  }
1052 }
1053 
1054 
1056 {
1057  m_RegistryComment.erase();
1058  m_Sections.clear();
1059 }
1060 
1061 bool CMemoryRegistry::x_Set(const string& section, const string& name,
1062  const string& value, TFlags flags,
1063  const string& comment)
1064 {
1065  _TRACE(this << ": [" << section << ']' << name << " = " << value);
1066 #if 0 // historic behavior; could inappropriately expose entries in lower layers
1067  if (value.empty()) {
1068  return x_Unset(section, name, flags);
1069  } else
1070 #endif
1071  {
1072  TSections::iterator sit = m_Sections.find(section);
1073  if (sit == m_Sections.end()) {
1074  sit = m_Sections.insert(make_pair(section, SSection(m_Flags)))
1075  .first;
1076  sit->second.cleared = false;
1077  }
1078  SEntry& entry = sit->second.entries[name];
1079 #if 0
1080  if (entry.value == value) {
1081  if (entry.comment != comment) {
1082  return MaybeSet(entry.comment, comment, flags);
1083  }
1084  return false; // not actually modified
1085  }
1086 #endif
1087  if ( !value.empty() ) {
1088  sit->second.cleared = false;
1089  } else if ( !entry.value.empty() ) {
1090  _ASSERT( !sit->second.cleared );
1091  bool cleared = true;
1092  ITERATE (TEntries, eit, sit->second.entries) {
1093  if (&eit->second != &entry && !eit->second.value.empty() ) {
1094  cleared = false;
1095  break;
1096  }
1097  }
1098  sit->second.cleared = cleared;
1099  }
1100  if (MaybeSet(entry.value, value, flags)) {
1101  MaybeSet(entry.comment, comment, flags);
1102  return true;
1103  }
1104  return false;
1105  }
1106 }
1107 
1108 
1109 bool CMemoryRegistry::x_Unset(const string& section, const string& name,
1110  TFlags flags)
1111 {
1112  _TRACE(this << ": [" << section << ']' << name << " to be unset");
1113  TSections::iterator sit = m_Sections.find(section);
1114  if (sit == m_Sections.end()) {
1115  return false;
1116  }
1117  TEntries& entries = sit->second.entries;
1118  TEntries::iterator eit = entries.find(name);
1119  if (eit == entries.end()) {
1120  return false;
1121  } else {
1122  entries.erase(eit);
1123  if (entries.empty() && sit->second.comment.empty()
1124  && (flags & fCountCleared) == 0) {
1125  m_Sections.erase(sit);
1126  }
1127  return true;
1128  }
1129 }
1130 
1131 
1132 bool CMemoryRegistry::x_SetComment(const string& comment,
1133  const string& section, const string& name,
1134  TFlags flags)
1135 {
1136  if (comment.empty() && (flags & fNoOverride)) {
1137  return false;
1138  }
1139  if (section.empty()) {
1140  return MaybeSet(m_RegistryComment, comment, flags);
1141  }
1142  TSections::iterator sit = m_Sections.find(section);
1143  if (sit == m_Sections.end()) {
1144  if (comment.empty() && (flags & fCountCleared) == 0) {
1145  return false;
1146  } else {
1147  sit = m_Sections.insert(make_pair(section, SSection(m_Flags)))
1148  .first;
1149  sit->second.cleared = false;
1150  }
1151  }
1152  TEntries& entries = sit->second.entries;
1153  string& inner_comment = sit->second.in_section_comment;
1154  string& outer_comment = sit->second.comment;
1155  if (name.empty()) {
1156  if (comment.empty() && entries.empty() && inner_comment.empty()
1157  && (flags & fCountCleared) == 0) {
1158  m_Sections.erase(sit);
1159  return true;
1160  } else {
1161  return MaybeSet(outer_comment, comment, flags);
1162  }
1163  }
1164  if (name == sm_InSectionCommentName) {
1165  if (comment.empty() && entries.empty() && outer_comment.empty()
1166  && (flags & fCountCleared) == 0) {
1167  m_Sections.erase(sit);
1168  return true;
1169  } else {
1170  return MaybeSet(inner_comment, comment, flags);
1171  }
1172  }
1173  TEntries::iterator eit = entries.find(name);
1174  if (eit == entries.end()) {
1175  return false;
1176  } else {
1177  return MaybeSet(outer_comment, comment, flags);
1178  }
1179 }
1180 
1181 
1182 //////////////////////////////////////////////////////////////////////
1183 //
1184 // CCompoundRegistry
1185 
1187  const string& name)
1188 {
1189  // Needed for some operations that touch (only) metadata...
1190  IRegistry& nc_reg = const_cast<IRegistry&>(reg);
1191  // XXX - Check whether reg is a duplicate, at least in debug mode?
1193  (prio, CRef<IRegistry>(&nc_reg)));
1194  if (name.size()) {
1195  CRef<IRegistry>& preg = m_NameMap[name];
1196  if (preg) {
1198  "CCompoundRegistry::Add: name " + name
1199  + " already in use", 0);
1200  } else {
1201  preg.Reset(&nc_reg);
1202  }
1203  }
1204 }
1205 
1206 
1208 {
1210  if (it->second == &reg) {
1211  m_NameMap.erase(it);
1212  break; // subregistries should be unique
1213  }
1214  }
1216  if (it->second == &reg) {
1217  m_PriorityMap.erase(it);
1218  return; // subregistries should be unique
1219  }
1220  }
1221  // already returned if found...
1223  "CCompoundRegistry::Remove:"
1224  " reg is not a (direct) subregistry of this.", 0);
1225 }
1226 
1227 
1229 {
1231  return it == m_NameMap.end() ? CConstRef<IRegistry>() : it->second;
1232 }
1233 
1234 
1236  const string& entry,
1237  TFlags flags) const
1238 {
1239  TFlags has_entry_flags = (flags | fCountCleared) & ~fJustCore;
1241  if (it->second->HasEntry(section, entry, has_entry_flags)) {
1242  return it->second;
1243  }
1244  }
1245  return null;
1246 }
1247 
1248 
1250 {
1252  if ((flags & fJustCore) && (it->first < m_CoreCutoff)) {
1253  break;
1254  }
1255  if ( !it->second->Empty(flags & ~fJustCore) ) {
1256  return false;
1257  }
1258  }
1259  return true;
1260 }
1261 
1262 
1264 {
1266  if ((flags & fJustCore) && (it->first < m_CoreCutoff)) {
1267  break;
1268  }
1269  if ( it->second->Modified(flags & ~fJustCore) ) {
1270  return true;
1271  }
1272  }
1273  return false;
1274 }
1275 
1276 
1278 {
1279  _ASSERT( !modified );
1280  for (TPriorityMap::reverse_iterator it = m_PriorityMap.rbegin();
1281  it != m_PriorityMap.rend(); ++it) {
1282  if ((flags & fJustCore) && (it->first < m_CoreCutoff)) {
1283  break;
1284  }
1285  it->second->SetModifiedFlag(modified, flags & ~fJustCore);
1286  }
1287 }
1288 
1289 
1290 const string& CCompoundRegistry::x_Get(const string& section,
1291  const string& name,
1292  TFlags flags) const
1293 {
1294  CConstRef<IRegistry> reg = FindByContents(section, name,
1295  flags & ~fJustCore);
1296  return reg ? reg->Get(section, name, flags & ~fJustCore) : kEmptyStr;
1297 }
1298 
1299 
1300 bool CCompoundRegistry::x_HasEntry(const string& section, const string& name,
1301  TFlags flags) const
1302 {
1303  return FindByContents(section, name, flags).NotEmpty();
1304 }
1305 
1306 
1307 const string& CCompoundRegistry::x_GetComment(const string& section,
1308  const string& name, TFlags flags)
1309  const
1310 {
1311  if ( m_PriorityMap.empty() ) {
1312  return kEmptyStr;
1313  }
1314 
1316  if (section.empty()) {
1317  reg = m_PriorityMap.rbegin()->second;
1318  } else {
1319  reg = FindByContents(section, name, flags & ~fJustCore);
1320  }
1321  return reg ? reg->GetComment(section, name, flags & ~fJustCore)
1322  : kEmptyStr;
1323 }
1324 
1325 
1326 void CCompoundRegistry::x_Enumerate(const string& section,
1327  list<string>& entries, TFlags flags) const
1328 {
1329  set<string> accum;
1331  if ((flags & fJustCore) && (it->first < m_CoreCutoff)) {
1332  break;
1333  }
1334 
1335  list<string> tmp;
1336 
1337  if (flags & fInSectionComments) {
1338  it->second->EnumerateInSectionComments(section, &tmp,
1339  flags & ~fJustCore);
1340  } else {
1341  it->second->EnumerateEntries(section, &tmp, flags & ~fJustCore);
1342  }
1343  ITERATE (list<string>, it2, tmp) {
1344  accum.insert(*it2);
1345  }
1346  }
1347  ITERATE (set<string>, it, accum) {
1348  entries.push_back(*it);
1349  }
1350 }
1351 
1352 
1354 {
1356  ((*it->second).*action)();
1357  }
1358 }
1359 
1360 
1361 //////////////////////////////////////////////////////////////////////
1362 //
1363 // CTwoLayerRegistry
1364 
1366  : m_Transient(CRegRef(new CMemoryRegistry(flags))),
1367  m_Persistent(CRegRef(persistent ? persistent
1368  : new CMemoryRegistry(flags)))
1369 {
1370 }
1371 
1372 
1374 {
1375  // mask out fTPFlags whe
1376  if (flags & fTransient && !m_Transient->Empty(flags | fTPFlags) ) {
1377  return false;
1378  } else if (flags & fPersistent
1379  && !m_Persistent->Empty(flags | fTPFlags) ) {
1380  return false;
1381  } else {
1382  return true;
1383  }
1384 }
1385 
1386 
1388 {
1390  return true;
1391  } else if (flags & fPersistent
1393  return true;
1394  } else {
1395  return false;
1396  }
1397 }
1398 
1399 
1401 {
1402  if (flags & fTransient) {
1403  m_Transient->SetModifiedFlag(modified, flags | fTPFlags);
1404  }
1405  if (flags & fPersistent) {
1407  }
1408 }
1409 
1410 
1411 const string& CTwoLayerRegistry::x_Get(const string& section,
1412  const string& name, TFlags flags) const
1413 {
1414  if (flags & fTransient) {
1415  const string& result = m_Transient->Get(section, name,
1416  flags & ~fTPFlags);
1417  if ( !result.empty() || !(flags & fPersistent) ) {
1418  return result;
1419  }
1420  }
1421  return m_Persistent->Get(section, name, flags & ~fTPFlags);
1422 }
1423 
1424 
1425 bool CTwoLayerRegistry::x_HasEntry(const string& section, const string& name,
1426  TFlags flags) const
1427 {
1428  return (((flags & fTransient)
1429  && m_Transient->HasEntry(section, name, flags & ~fTPFlags)) ||
1430  ((flags & fPersistent)
1431  && m_Persistent->HasEntry(section, name, flags & ~fTPFlags)));
1432 }
1433 
1434 
1435 const string& CTwoLayerRegistry::x_GetComment(const string& section,
1436  const string& name,
1437  TFlags flags) const
1438 {
1439  if (flags & fTransient) {
1440  const string& result = m_Transient->GetComment(section, name,
1441  flags & ~fTPFlags);
1442  if ( !result.empty() || !(flags & fPersistent) ) {
1443  return result;
1444  }
1445  }
1446  return m_Persistent->GetComment(section, name, flags & ~fTPFlags);
1447 }
1448 
1449 
1450 void CTwoLayerRegistry::x_Enumerate(const string& section,
1451  list<string>& entries, TFlags flags) const
1452 {
1453  switch (flags & fTPFlags) {
1454  case fTransient:
1455  if (flags & fInSectionComments) {
1457  flags | fTPFlags);
1458  } else {
1459  m_Transient->EnumerateEntries(section, &entries,
1460  flags | fTPFlags);
1461  }
1462  break;
1463  case fPersistent:
1464  if (flags & fInSectionComments) {
1466  flags | fTPFlags);
1467  } else {
1469  flags | fTPFlags);
1470  }
1471  break;
1472  case fTPFlags:
1473  {
1474  list<string> tl, pl;
1475  if (flags & fInSectionComments) {
1476  m_Transient ->EnumerateInSectionComments(section, &tl,
1477  flags | fTPFlags);
1479  flags | fTPFlags);
1480  } else {
1481  m_Transient ->EnumerateEntries(section, &tl, flags | fTPFlags);
1482  m_Persistent->EnumerateEntries(section, &pl, flags | fTPFlags);
1483  }
1484  set_union(pl.begin(), pl.end(), tl.begin(), tl.end(),
1485  back_inserter(entries), PNocase());
1486  break;
1487  }
1488  default:
1489  _TROUBLE;
1490  }
1491 }
1492 
1493 
1495 {
1496  ((*m_Transient).*action)();
1497  ((*m_Persistent).*action)();
1498 }
1499 
1500 
1502 {
1503  if (flags & fTransient) {
1505  }
1506  if (flags & fPersistent) {
1508  }
1509 }
1510 
1511 
1512 bool CTwoLayerRegistry::x_Set(const string& section, const string& name,
1513  const string& value, TFlags flags,
1514  const string& comment)
1515 {
1516  if (flags & fPersistent) {
1517  return m_Persistent->Set(section, name, value, flags & ~fTPFlags,
1518  comment);
1519  } else {
1520  return m_Transient->Set(section, name, value, flags & ~fTPFlags,
1521  comment);
1522  }
1523 }
1524 
1525 
1526 bool CTwoLayerRegistry::x_Unset(const string& section, const string& name,
1527  TFlags flags)
1528 {
1529  bool result = false;
1530  if ((flags & fTPFlags) != fTransient) {
1531  result |= m_Persistent->Unset(section, name, flags & ~fTPFlags);
1532  }
1533  if ((flags & fTPFlags) != fPersistent) {
1534  result |= m_Transient->Unset(section, name, flags & ~fTPFlags);
1535  }
1536  return result;
1537 }
1538 
1539 
1540 bool CTwoLayerRegistry::x_SetComment(const string& comment,
1541  const string& section, const string& name,
1542  TFlags flags)
1543 {
1544  if (flags & fTransient) {
1545  return m_Transient->SetComment(comment, section, name,
1546  flags & ~fTPFlags);
1547  } else {
1548  return m_Persistent->SetComment(comment, section, name,
1549  flags & ~fTPFlags);
1550  }
1551 }
1552 
1553 
1554 
1555 //////////////////////////////////////////////////////////////////////
1556 //
1557 // CNcbiRegistry -- compound R/W registry with extra policy and
1558 // compatibility features. (See below for CCompoundRWRegistry,
1559 // which has been factored out.)
1560 
1561 const char* CNcbiRegistry::sm_EnvRegName = ".env";
1562 const char* CNcbiRegistry::sm_FileRegName = ".file";
1563 const char* CNcbiRegistry::sm_OverrideRegName = ".overrides";
1564 const char* CNcbiRegistry::sm_SysRegName = ".ncbirc";
1565 
1566 inline
1568 {
1570  TFlags cf = m_Flags & fCaseFlags;
1571  if (app) {
1573  eNoOwnership, cf));
1574  } else {
1576  }
1578 
1581 
1584 
1585  const TXChar* xoverride_path = NcbiSys_getenv(_TX("NCBI_CONFIG_OVERRIDES"));
1586  if (xoverride_path && *xoverride_path) {
1587  string override_path = _T_STDSTRING(xoverride_path);
1589  CMetaRegistry::SEntry entry
1591  0, cf, m_OverrideRegistry.GetPointer());
1592  if (entry.registry) {
1593  if (entry.registry != m_OverrideRegistry) {
1594  ERR_POST_X(5, Warning << "Resetting m_OverrideRegistry");
1596  }
1598  } else {
1600  << "NCBI_CONFIG_OVERRIDES names nonexistent file "
1601  << override_path);
1603  }
1604  }
1605 }
1606 
1607 
1609  : m_RuntimeOverrideCount(0), m_Flags(flags)
1610 {
1611  x_Init();
1612 }
1613 
1614 
1616  const string& path)
1617  : m_RuntimeOverrideCount(0), m_Flags(flags)
1618 {
1619  x_CheckFlags("CNcbiRegistry::CNcbiRegistry", flags,
1622  x_Init();
1624  LoadBaseRegistries(flags, 0, path);
1626 }
1627 
1628 
1630 {
1631 }
1632 
1633 
1635 {
1636  if (flags & fWithNcbirc) {
1637  flags &= ~fWithNcbirc;
1638  } else {
1639  return false;
1640  }
1641 
1642  if (getenv("NCBI_DONT_USE_NCBIRC")) {
1643  return false;
1644  }
1645 
1646  if (HasEntry("NCBI", "DONT_USE_NCBIRC")) {
1647  return false;
1648  }
1649 
1650  try {
1651  CMetaRegistry::SEntry entry
1654  if (entry.registry && entry.registry != m_SysRegistry) {
1655  ERR_POST_X(5, Warning << "Resetting m_SysRegistry");
1656  m_SysRegistry.Reset(entry.registry);
1657  }
1658  if (!entry.actual_name.empty()) return true;
1659  } catch (CRegistryException& e) {
1660  ERR_POST_X(6, Critical << "CNcbiRegistry: "
1661  "Syntax error in system-wide configuration file: "
1662  << e.what());
1663  return false;
1664  }
1665 
1666  if ( !m_SysRegistry->Empty() ) {
1667  return true;
1668  }
1669 
1670  return false;
1671 }
1672 
1673 
1674 void CNcbiRegistry::x_Clear(TFlags flags) // XXX - should this do more?
1675 {
1678 }
1679 
1680 
1682  const string& path)
1683 {
1684  // Normally, all settings should go to the main portion. However,
1685  // loading an initial configuration file should instead go to the
1686  // file portion so that environment settings can take priority.
1688  if (main_reg->Empty() && m_FileRegistry->Empty()) {
1690  LoadBaseRegistries(flags, 0, path);
1692  return NULL;
1693  } else if ((flags & fNoOverride) == 0) { // ensure proper layering
1696  crwreg->Read(is, flags);
1697  // Allow contents to override anything previously Set() directly.
1698  IRWRegistry& nc_main_reg
1699  = dynamic_cast<IRWRegistry&>(const_cast<IRegistry&>(*main_reg));
1700  if ((flags & fTransient) == 0) {
1701  flags |= fPersistent;
1702  }
1703  list<string> sections;
1704  crwreg->EnumerateSections(&sections, flags | fCountCleared);
1705  ITERATE (list<string>, sit, sections) {
1706  list<string> entries;
1707  crwreg->EnumerateEntries(*sit, &entries, flags | fCountCleared);
1708  ITERATE (list<string>, eit, entries) {
1709  // In principle, it should be possible to clear the setting
1710  // in nc_main_reg rather than duplicating it; however,
1711  // letting the entry in crwreg be visible would require
1712  // having CCompoundRegistry::FindByContents no longer force
1713  // fCountCleared, which breaks other corner cases (as shown
1714  // by test_sub_reg). :-/
1715  if (nc_main_reg.HasEntry(*sit, *eit, flags | fCountCleared)) {
1716  nc_main_reg.Set(*sit, *eit, crwreg->Get(*sit, *eit), flags);
1717  }
1718  }
1719  }
1723  return crwreg.GetPointer();
1724  } else {
1725  // This will only affect the main registry, but still needs to
1726  // go through CCompoundRWRegistry::x_Set.
1727  return CCompoundRWRegistry::x_Read(is, flags, path);
1728  }
1729 }
1730 
1731 
1732 const string& CNcbiRegistry::x_GetComment(const string& section,
1733  const string& name,
1734  TFlags flags) const
1735 {
1736  if (section.empty()) {
1737  return m_FileRegistry->GetComment(section, name, flags);
1738  }
1739 
1740  return CCompoundRWRegistry::x_GetComment(section, name, flags);
1741 }
1742 
1743 
1744 //////////////////////////////////////////////////////////////////////
1745 //
1746 // CCompoundRWRegistry -- general-purpose setup
1747 
1748 const char* CCompoundRWRegistry::sm_MainRegName = ".main";
1749 const char* CCompoundRWRegistry::sm_BaseRegNamePrefix = ".base:";
1750 
1751 
1753  : m_MainRegistry(new CTwoLayerRegistry),
1754  m_AllRegistries(new CCompoundRegistry),
1755  m_Flags(flags)
1756 {
1758  sm_MainRegName);
1759 }
1760 
1761 
1763 {
1764 }
1765 
1766 
1768 {
1769  return m_AllRegistries->GetCoreCutoff();
1770 }
1771 
1772 
1774 {
1776 }
1777 
1778 
1780  const string& name)
1781 {
1782  if (name.size() > 1 && name[0] == '.') {
1784  "The sub-registry name " + name + " is reserved.", 0);
1785  }
1786  if (prio > ePriority_MaxUser) {
1787  ERR_POST_X(7, Warning
1788  << "Reserved priority value automatically downgraded.");
1789  prio = ePriority_MaxUser;
1790  }
1791  x_Add(reg, prio, name);
1792 }
1793 
1794 
1796 {
1797  if (&reg == m_MainRegistry.GetPointer()) {
1799  "The primary portion of the registry may not be removed.",
1800  0);
1801  } else {
1802  m_AllRegistries->Remove(reg);
1803  }
1804 }
1805 
1806 
1808 {
1809  return m_AllRegistries->FindByName(name);
1810 }
1811 
1812 
1814  const string& entry,
1815  TFlags flags) const
1816 {
1817  return m_AllRegistries->FindByContents(section, entry, flags);
1818 }
1819 
1820 
1822  const string& path)
1823 {
1824  if (flags & fJustCore) {
1825  return false;
1826  }
1827 
1828  list<string> names;
1829  {{
1830  string s = m_MainRegistry->Get("NCBI", ".Inherits");
1831 
1833  s += ',';
1834  s += it->second->Get("NCBI", ".Inherits");
1835  }
1836 
1837  {
1838  if (dynamic_cast<CNcbiRegistry*>(this) != NULL) {
1839  _TRACE("LoadBaseRegistries(" << this
1840  << "): trying file registry");
1841  s += ',';
1843  ->Get("NCBI", ".Inherits");
1844  }
1845  }
1846  NStr::Split(s, ", ", names,
1850  if (names.empty()) return false;
1851  _TRACE("LoadBaseRegistries(" << this << "): using " << s);
1852  }}
1853 
1854  typedef pair<string, CRef<IRWRegistry> > TNewBase;
1855  typedef vector<TNewBase> TNewBases;
1856  TNewBases bases;
1857  SIZE_TYPE initial_num_bases = m_BaseRegNames.size();
1858 
1859  ITERATE (list<string>, it, names) {
1860  if (m_BaseRegNames.find(*it) != m_BaseRegNames.end()) {
1861  continue;
1862  }
1865  // First try adding .ini unless it's already present; when a
1866  // file with the unsuffixed name also exists, it is likely an
1867  // executable that would be inappropriate to try to parse.
1868  CMetaRegistry::SEntry entry2;
1869  if (NStr::EndsWith(*it, ".ini")) {
1870  entry2.registry = NULL;
1871  } else {
1873  metareg_flags, flags,
1874  reg2.GetPointer(), path);
1875  }
1876  if (entry2.registry == NULL) {
1878  metareg_flags, flags,
1879  reg2.GetPointer(), path);
1880  }
1881  if (entry2.registry) {
1882  m_BaseRegNames.insert(*it);
1883  bases.push_back(TNewBase(*it, entry2.registry));
1884  } else {
1885  ERR_POST(Critical << "Base registry " << *it
1886  << " absent or unreadable");
1887  }
1888  }
1889 
1890  for (SIZE_TYPE i = 0; i < bases.size(); ++i) {
1891  x_Add(*bases[i].second,
1892  TPriority(ePriority_MaxUser - initial_num_bases - i),
1893  sm_BaseRegNamePrefix + bases[i].first);
1894  }
1895 
1896  return !bases.empty();
1897 }
1898 
1899 
1901 {
1902  return m_AllRegistries->Empty(flags);
1903 }
1904 
1905 
1907 {
1908  return m_AllRegistries->Modified(flags);
1909 }
1910 
1911 
1913 {
1914  if (modified) {
1915  m_MainRegistry->SetModifiedFlag(modified, flags);
1916  } else {
1917  // CCompoundRegistry only permits clearing...
1919  }
1920 }
1921 
1922 
1923 const string& CCompoundRWRegistry::x_Get(const string& section,
1924  const string& name,
1925  TFlags flags) const
1926 {
1928  = m_ClearedEntries.find(s_FlatKey(section, name));
1929  if (it != m_ClearedEntries.end()) {
1930  flags &= ~it->second;
1931  if ( !(flags & ~fJustCore) ) {
1932  return kEmptyStr;
1933  }
1934  }
1935  return m_AllRegistries->Get(section, name, flags);
1936 }
1937 
1938 
1939 bool CCompoundRWRegistry::x_HasEntry(const string& section, const string& name,
1940  TFlags flags) const
1941 {
1943  = m_ClearedEntries.find(s_FlatKey(section, name));
1944  if (it != m_ClearedEntries.end()) {
1945  if ((flags & fCountCleared) && (flags & it->second)) {
1946  return true;
1947  }
1948  flags &= ~it->second;
1949  if ( !(flags & ~fJustCore) ) {
1950  return false;
1951  }
1952  }
1953  return m_AllRegistries->HasEntry(section, name, flags);
1954 }
1955 
1956 
1957 const string& CCompoundRWRegistry::x_GetComment(const string& section,
1958  const string& name,
1959  TFlags flags) const
1960 {
1961  const string* result;
1962  if (section.empty() || name.empty()) {
1963  result = &(m_MainRegistry->GetComment(section, name, flags));
1964  if (result->empty()) {
1965  auto reg = FindByName(".file");
1966  if (reg != NULL)
1967  result = &(reg->GetComment(section, name, flags));
1968  }
1969  return *result;
1970  }
1971 
1972  return m_AllRegistries->GetComment(section, name, flags);
1973 }
1974 
1975 
1976 void CCompoundRWRegistry::x_Enumerate(const string& section,
1977  list<string>& entries,
1978  TFlags flags) const
1979 {
1980  typedef set<string, PNocase> SetNoCase;
1981  SetNoCase accum;
1984  if ((flags & fJustCore) && (it->first < GetCoreCutoff())) {
1985  break;
1986  }
1987 
1988  list<string> tmp;
1989 
1990  if (flags & fInSectionComments) {
1991  it->second->EnumerateInSectionComments(section, &tmp,
1992  flags & ~fJustCore);
1993  } else {
1994  it->second->EnumerateEntries(section, &tmp, flags & ~fJustCore);
1995  }
1996 
1997  ITERATE (list<string>, it2, tmp) {
1998  // avoid reporting cleared entries
2001  : m_ClearedEntries.find(s_FlatKey(section, *it2));
2002  if (ceci == m_ClearedEntries.end()
2003  || (flags & ~fJustCore & ~ceci->second)) {
2004  accum.insert(*it2);
2005  }
2006  }
2007  }
2008  ITERATE(SetNoCase, it, accum) {
2009  entries.push_back(*it);
2010  }
2011 }
2012 
2013 
2015 {
2016  ((*m_AllRegistries).*action)();
2017 }
2018 
2019 
2020 void CCompoundRWRegistry::x_Clear(TFlags flags) // XXX - should this do more?
2021 {
2023 
2026  }
2028 }
2029 
2030 
2031 bool CCompoundRWRegistry::x_Set(const string& section, const string& name,
2032  const string& value, TFlags flags,
2033  const string& comment)
2034 {
2035  TFlags flags2 = (flags & fPersistent) ? flags : (flags | fTransient);
2036  flags2 &= fLayerFlags;
2037  _TRACE('[' << section << ']' << name << " = " << value);
2038  if ((flags & fNoOverride) && HasEntry(section, name, flags)) {
2039  return false;
2040  }
2041  if (value.empty()) {
2042  bool was_empty = Get(section, name, flags).empty();
2043  m_MainRegistry->Set(section, name, value, flags, comment);
2044  m_ClearedEntries[s_FlatKey(section, name)] |= flags2;
2045  return !was_empty;
2046  } else {
2048  = m_ClearedEntries.find(s_FlatKey(section, name));
2049  if (it != m_ClearedEntries.end()) {
2050  if ((it->second &= ~flags2) == 0) {
2051  m_ClearedEntries.erase(it);
2052  }
2053  }
2054  }
2055  return m_MainRegistry->Set(section, name, value, flags, comment);
2056 }
2057 
2058 
2059 bool CCompoundRWRegistry::x_Unset(const string& section, const string& name,
2060  TFlags flags)
2061 {
2062  bool result = false;
2065  IRWRegistry& subreg = dynamic_cast<IRWRegistry&>(*it->second);
2066  result |= subreg.Unset(section, name, flags);
2067  }
2068  return result;
2069 }
2070 
2071 
2072 bool CCompoundRWRegistry::x_SetComment(const string& comment,
2073  const string& section,
2074  const string& name, TFlags flags)
2075 {
2076  return m_MainRegistry->SetComment(comment, section, name, flags);
2077 }
2078 
2079 
2081  const string& path)
2082 {
2083  TFlags lbr_flags = flags;
2084  if ((flags & fNoOverride) == 0 && !Empty(fPersistent) ) {
2085  lbr_flags |= fOverride;
2086  } else {
2087  lbr_flags &= ~fOverride;
2088  }
2089  IRWRegistry::x_Read(in, flags, path);
2090  LoadBaseRegistries(lbr_flags, 0, path);
2091  return NULL;
2092 }
2093 
2094 
2096  const string& name)
2097 {
2098  m_AllRegistries->Add(reg, prio, name);
2099 }
2100 
2101 
2102 //////////////////////////////////////////////////////////////////////
2103 //
2104 // CRegistryException -- error reporting
2105 
2107 {
2108  switch (GetErrCode()) {
2109  case eSection: return "eSection";
2110  case eEntry: return "eEntry";
2111  case eValue: return "eValue";
2112  case eUnencrypted: return "eUnencrypted";
2113  case eDecryptionFailed: return "eDecryptionFailed";
2114  case eErr: return "eErr";
2115  default: return CException::GetErrCodeString();
2116  }
2117 }
2118 
2119 
CCompoundRegistry –.
Definition: ncbireg.hpp:654
CConstRef –.
Definition: ncbiobj.hpp:1266
CEnvironmentRegistry –.
Definition: env_reg.hpp:87
CMemoryRegistry –.
Definition: ncbireg.hpp:584
static SEntry Load(const string &name, ENameStyle style=eName_AsIs, TFlags flags=0, TRegFlags reg_flags=0, IRWRegistry *reg=0, const string &path=kEmptyStr)
Load the configuration file "name".
Definition: metareg.cpp:139
@ eName_RcOrIni
C Toolkit style; mostly useful with name = "ncbi".
Definition: metareg.hpp:66
@ eName_AsIs
Take the specified filename as is.
Definition: metareg.hpp:61
@ eName_Ini
Add .ini, dropping existing extensions as needed.
Definition: metareg.hpp:62
static CNcbiApplication * Instance(void)
Singleton method.
Definition: ncbiapp.cpp:264
static bool IsEncrypted(const string &data)
Check if the string contains valid encrypted data.
static string Decrypt(const string &encrypted_string)
Decrypt a string using the matching key found in the NCBI keys files.
CNcbiRegistry –.
Definition: ncbireg.hpp:913
CRegistryException –.
Definition: ncbireg.hpp:1005
CRegistry{Read,Write}Guard –.
Definition: ncbireg.hpp:1036
CStringException –.
Definition: ncbistr.hpp:4500
CTwoLayerRegistry –.
Definition: ncbireg.hpp:746
IRWRegistry –.
Definition: ncbireg.hpp:407
IRegistry –.
Definition: ncbireg.hpp:73
void erase(iterator pos)
Definition: map.hpp:167
const_iterator end() const
Definition: map.hpp:152
iterator_bool insert(const value_type &val)
Definition: map.hpp:165
bool empty() const
Definition: map.hpp:149
void clear()
Definition: map.hpp:169
const_iterator find(const key_type &key) const
Definition: map.hpp:153
void erase(iterator pos)
Definition: map.hpp:307
iterator insert(const value_type &val)
Definition: map.hpp:305
bool empty() const
Definition: map.hpp:289
iterator_bool insert(const value_type &val)
Definition: set.hpp:149
void clear()
Definition: set.hpp:153
size_type size() const
Definition: set.hpp:132
const_iterator find(const key_type &key) const
Definition: set.hpp:137
const_iterator end() const
Definition: set.hpp:136
static uch flags
Classes to support using environment variables as a backend for the registry framework.
static const struct name_t names[]
static DLIST_TYPE *DLIST_NAME() first(DLIST_LIST_TYPE *list)
Definition: dlist.tmpl.h:46
static const char * str(char *buf, int n)
Definition: stats.c:84
static char tmp[3200]
Definition: utf8.c:42
CNcbiEnvironment & SetEnvironment(void)
Get a non-const copy of the application's cached environment.
#define ITERATE(Type, Var, Cont)
ITERATE macro to sequence through container elements.
Definition: ncbimisc.hpp:815
#define NON_CONST_ITERATE(Type, Var, Cont)
Non constant version of ITERATE macro.
Definition: ncbimisc.hpp:822
#define REVERSE_ITERATE(Type, Var, Cont)
ITERATE macro to reverse sequence through container elements.
Definition: ncbimisc.hpp:827
@ eNoOwnership
No ownership is assumed.
Definition: ncbi_types.h:135
#define NULL
Definition: ncbistd.hpp:225
#define _TRACE(message)
Definition: ncbidbg.hpp:122
#define _DEBUG_ARG(arg)
Definition: ncbidbg.hpp:134
#define ERR_POST_ONCE(message)
Error posting only once during program execution.
Definition: ncbidiag.hpp:602
#define ERR_POST_X(err_subcode, message)
Error posting with default error code and given error subcode.
Definition: ncbidiag.hpp:550
#define ERR_POST(message)
Error posting with file, line number information but without error codes.
Definition: ncbidiag.hpp:186
void Critical(CExceptionArgs_Base &args)
Definition: ncbiexpt.hpp:1203
#define NCBI_RETHROW_SAME(prev_exception, message)
Generic macro to re-throw the same exception.
Definition: ncbiexpt.hpp:749
void Warning(CExceptionArgs_Base &args)
Definition: ncbiexpt.hpp:1191
#define NCBI_THROW2(exception_class, err_code, message, extra)
Throw exception with extra parameter.
Definition: ncbiexpt.hpp:1754
#define NCBI_RETHROW2(prev_exception, exception_class, err_code, message, extra)
Re-throw exception with extra parameter.
Definition: ncbiexpt.hpp:1761
virtual const char * GetErrCodeString(void) const
Get error code interpreted as text.
Definition: ncbiexpt.cpp:444
bool Empty(void) const THROWS_NONE
Check if CConstRef is empty – not pointing to any object which means having a null value.
Definition: ncbiobj.hpp:1385
TObjectType * GetPointer(void) THROWS_NONE
Get pointer,.
Definition: ncbiobj.hpp:998
void Reset(void)
Reset reference object.
Definition: ncbiobj.hpp:773
void Remove(const IRegistry &reg)
Remove sub-registry "reg".
Definition: ncbireg.cpp:1207
int TFlags
Binary OR of "EFlags".
Definition: ncbireg.hpp:107
CConstRef< IRegistry > FindByName(const string &name) const
Return a pointer to the sub-registry with the given name, or NULL if not found.
Definition: ncbireg.cpp:1228
const string & x_Get(const string &section, const string &name, TFlags flags) const
Definition: ncbireg.cpp:954
void x_Enumerate(const string &section, list< string > &entries, TFlags flags) const
Definition: ncbireg.cpp:1976
virtual void x_ChildLockAction(FLockAction)
Definition: ncbireg.hpp:389
int TPriority
Not restricted to ePriority_*.
Definition: ncbireg.hpp:813
CConstRef< IRegistry > FindByName(const string &name) const
Return a pointer to the sub-registry with the given name, or NULL if not found.
Definition: ncbireg.cpp:1807
static const char * sm_InSectionCommentName
Entry name for an in-section comment.
Definition: ncbireg.hpp:357
bool x_HasEntry(const string &section, const string &name, TFlags flags) const
Definition: ncbireg.cpp:1939
virtual bool GetBool(const string &section, const string &name, bool default_value, TFlags flags=0, EErrAction err_action=eThrow) const
Get boolean value of specified parameter name.
Definition: ncbireg.cpp:391
const string & x_GetComment(const string &section, const string &name, TFlags flags) const
Definition: ncbireg.cpp:1957
set< string > m_BaseRegNames
Definition: ncbireg.hpp:894
static void x_CheckFlags(const string &func, TFlags &flags, TFlags allowed)
Definition: ncbireg.cpp:558
static const char * sm_SysRegName
Definition: ncbireg.hpp:966
CRef< CTwoLayerRegistry > m_MainRegistry
Definition: ncbireg.hpp:892
virtual bool x_Set(const string &section, const string &name, const string &value, TFlags flags, const string &comment)=0
bool x_HasEntry(const string &section, const string &name, TFlags flags) const
Definition: ncbireg.cpp:966
CRWLock m_Lock
Definition: ncbireg.hpp:392
const string & x_GetComment(const string &section, const string &name, TFlags flags) const
Definition: ncbireg.cpp:995
virtual void x_Enumerate(const string &section, list< string > &entries, TFlags flags) const =0
virtual const string & x_Get(const string &section, const string &name, TFlags flags) const =0
bool x_Set(const string &section, const string &name, const string &value, TFlags flags, const string &comment)
Definition: ncbireg.cpp:2031
void x_Clear(TFlags flags)
Called locked, like the virtual methods inherited from IRegistry.
Definition: ncbireg.cpp:1501
bool x_HasEntry(const string &section, const string &name, TFlags flags) const
Definition: ncbireg.cpp:1300
bool x_Unset(const string &section, const string &name, TFlags flags)
Definition: ncbireg.cpp:1109
static bool MaybeSet(string &target, const string &value, TFlags flags)
Definition: ncbireg.cpp:925
void x_ChildLockAction(FLockAction action)
Definition: ncbireg.cpp:2014
bool x_Set(const string &section, const string &name, const string &value, TFlags flags, const string &comment)
Definition: ncbireg.cpp:1061
TFlags m_Flags
Definition: ncbireg.hpp:639
TClearedEntries m_ClearedEntries
Definition: ncbireg.hpp:891
virtual void x_SetModifiedFlag(bool, TFlags)
Definition: ncbireg.hpp:376
TFlags m_Flags
Definition: ncbireg.hpp:989
TSections m_Sections
Definition: ncbireg.hpp:638
virtual bool x_SetComment(const string &comment, const string &section, const string &name, TFlags flags)=0
virtual void EnumerateSections(list< string > *sections, TFlags flags=fAllLayers) const
Enumerate section names.
Definition: ncbireg.cpp:497
virtual void x_Clear(TFlags flags)=0
Called locked, like the virtual methods inherited from IRegistry.
void ReadLock(void)
Support for locking.
Definition: ncbireg.cpp:537
IRWRegistry * x_Read(CNcbiIstream &is, TFlags flags, const string &path)
Most implementations should not override this, but CNcbiRegistry must, to handle some special cases p...
Definition: ncbireg.cpp:2080
bool x_SetComment(const string &comment, const string &section, const string &name, TFlags flags)
Definition: ncbireg.cpp:1132
void x_SetModifiedFlag(bool modified, TFlags flags)
Definition: ncbireg.cpp:1400
virtual bool x_Empty(TFlags flags) const =0
Implementations of the fundamental operations above, to be run with the lock already acquired and som...
CConstRef< IRegistry > FindByContents(const string &section, const string &entry=kEmptyStr, TFlags flags=0) const
Return a pointer to the highest-priority sub-registry with a section named SECTION containing (if ENT...
Definition: ncbireg.cpp:1235
virtual const string & Get(const string &section, const string &name, TFlags flags=0) const
Get the parameter value.
Definition: ncbireg.cpp:262
TNameMap m_NameMap
excludes anonymous sub-registries
Definition: ncbireg.hpp:727
void x_Clear(TFlags flags)
Called locked, like the virtual methods inherited from IRegistry.
Definition: ncbireg.cpp:1674
void x_Enumerate(const string &section, list< string > &entries, TFlags flags) const
Definition: ncbireg.cpp:1326
void x_Enumerate(const string &section, list< string > &entries, TFlags flags) const
Definition: ncbireg.cpp:1450
CCompoundRWRegistry(TFlags m_Flags=0)
Constructor.
Definition: ncbireg.cpp:1752
bool x_Empty(TFlags flags) const
Implementations of the fundamental operations above, to be run with the lock already acquired and som...
Definition: ncbireg.cpp:1900
TPriority m_CoreCutoff
Definition: ncbireg.hpp:728
const string & x_Get(const string &section, const string &name, TFlags flags) const
Definition: ncbireg.cpp:1923
CRef< IRWRegistry > m_OverrideRegistry
Definition: ncbireg.hpp:986
virtual int GetInt(const string &section, const string &name, int default_value, TFlags flags=0, EErrAction err_action=eThrow) const
Get integer value of specified parameter name.
Definition: ncbireg.cpp:362
CTwoLayerRegistry(IRWRegistry *persistent=0, TFlags flags=0)
Constructor.
Definition: ncbireg.cpp:1365
virtual bool x_Modified(TFlags) const
Definition: ncbireg.hpp:375
bool x_HasEntry(const string &section, const string &name, TFlags flags) const
Definition: ncbireg.cpp:1425
static const char * sm_MainRegName
Predefined subregistry's name.
Definition: ncbireg.hpp:856
virtual IRWRegistry * x_Read(CNcbiIstream &is, TFlags flags, const string &path)
Most implementations should not override this, but CNcbiRegistry must, to handle some special cases p...
Definition: ncbireg.cpp:630
bool x_Empty(TFlags flags) const
Implementations of the fundamental operations above, to be run with the lock already acquired and som...
Definition: ncbireg.cpp:947
virtual const string & x_GetComment(const string &section, const string &name, TFlags flags) const =0
virtual bool x_HasEntry(const string &section, const string &name, TFlags flags) const =0
bool SetComment(const string &comment, const string &section=kEmptyStr, const string &name=kEmptyStr, TFlags flags=0)
Set comment "comment" for the registry entry "section:name".
Definition: ncbireg.cpp:895
virtual double GetDouble(const string &section, const string &name, double default_value, TFlags flags=0, EErrAction err_action=eThrow) const
Get double value of specified parameter name.
Definition: ncbireg.cpp:420
bool x_Modified(TFlags flags) const
Definition: ncbireg.cpp:1387
static TFlags AssessImpact(TFlags flags, EOperation op)
Indicate which portions of the registry the given operation would affect.
Definition: ncbireg.cpp:574
TPriority GetCoreCutoff(void) const
Subregistries whose priority is less than the core cutoff (ePriority_Default by default) will be igno...
Definition: ncbireg.hpp:687
CRegRef m_Transient
Definition: ncbireg.hpp:781
const string & x_GetComment(const string &section, const string &name, TFlags flags) const
Definition: ncbireg.cpp:1732
const string & x_GetComment(const string &section, const string &name, TFlags flags) const
Definition: ncbireg.cpp:1307
void x_Clear(TFlags flags)
Called locked, like the virtual methods inherited from IRegistry.
Definition: ncbireg.cpp:1055
EErrAction
What to do if parameter value is present but cannot be converted into the requested type.
Definition: ncbireg.hpp:200
CRef< CTwoLayerRegistry > m_FileRegistry
Definition: ncbireg.hpp:985
virtual void EnumerateInSectionComments(const string &section, list< string > *comments, TFlags flags=fAllLayers) const
Enumerate in-section comments.
Definition: ncbireg.cpp:474
virtual bool HasEntry(const string &section, const string &name=kEmptyStr, TFlags flags=0) const
Definition: ncbireg.cpp:290
bool Empty(TFlags flags=fAllLayers) const
Verify if Registry is empty.
Definition: ncbireg.cpp:162
static const char * sm_EnvRegName
Predefined subregistries' names.
Definition: ncbireg.hpp:963
bool x_Unset(const string &section, const string &name, TFlags flags)
Definition: ncbireg.cpp:1526
bool IncludeNcbircIfAllowed(TFlags flags=fWithNcbirc)
Attempt to load a systemwide configuration file (.ncbirc on Unix, ncbi.ini on Windows) as a low-prior...
Definition: ncbireg.cpp:1634
virtual void EnumerateEntries(const string &section, list< string > *entries, TFlags flags=fAllLayers) const
Enumerate parameter names for a specified section.
Definition: ncbireg.cpp:514
void x_Init(void)
Definition: ncbireg.cpp:1567
CRef< CEnvironmentRegistry > m_EnvRegistry
Definition: ncbireg.hpp:984
bool Modified(TFlags flags=fPersistent) const
Verify if persistent values have been modified.
Definition: ncbireg.cpp:173
void x_ChildLockAction(FLockAction action)
Definition: ncbireg.cpp:1353
void x_ChildLockAction(FLockAction action)
Definition: ncbireg.cpp:1494
void x_Clear(TFlags flags)
Called locked, like the virtual methods inherited from IRegistry.
Definition: ncbireg.cpp:2020
static const char * sm_FileRegName
Definition: ncbireg.hpp:964
CRegRef m_Persistent
Definition: ncbireg.hpp:782
bool x_SetComment(const string &comment, const string &section, const string &name, TFlags flags)
Definition: ncbireg.cpp:2072
IRWRegistry * Read(CNcbiIstream &is, TFlags flags=0, const string &path=kEmptyStr)
Read and parse the stream "is", and merge its content with current Registry entries.
Definition: ncbireg.cpp:605
void x_Enumerate(const string &section, list< string > &entries, TFlags flags) const
Definition: ncbireg.cpp:1016
void x_SetModifiedFlag(bool modified, TFlags flags)
Definition: ncbireg.cpp:1277
static bool IsNameEntry(const string &str, TFlags flags)
Definition: ncbireg.cpp:84
void Add(const IRegistry &reg, TPriority prio=ePriority_Default, const string &name=kEmptyStr)
Non-empty names must be unique within each compound registry, but there is no limit to the number of ...
Definition: ncbireg.cpp:1779
bool x_Empty(TFlags flags) const
Implementations of the fundamental operations above, to be run with the lock already acquired and som...
Definition: ncbireg.cpp:1373
virtual const string & GetComment(const string &section=kEmptyStr, const string &name=kEmptyStr, TFlags flags=0) const
Get comment of the registry entry "section:name".
Definition: ncbireg.cpp:450
void WriteLock(void)
Definition: ncbireg.cpp:544
virtual bool x_Unset(const string &section, const string &name, TFlags flags)=0
void Add(const IRegistry &reg, TPriority prio=ePriority_Default, const string &name=kEmptyStr)
Non-empty names must be unique within each compound registry, but there is no limit to the number of ...
Definition: ncbireg.cpp:1186
bool x_Set(const string &section, const string &name, const string &value, TFlags flags, const string &comment)
Definition: ncbireg.cpp:1512
static bool IsNameSection(const string &str, TFlags flags)
Check if "str" consists of alphanumeric and '_' only Treat the case of set fSectionlessEntries separa...
Definition: ncbireg.cpp:68
CConstRef< IRegistry > FindByContents(const string &section, const string &entry=kEmptyStr, TFlags flags=0) const
Return a pointer to the highest-priority sub-registry with a section named SECTION containing (if ENT...
Definition: ncbireg.cpp:1813
string GetEncryptedString(const string &section, const string &name, TFlags flags=0, const string &password=kEmptyStr) const
Get a value that was (potentially) stored encrypted.
Definition: ncbireg.cpp:329
unsigned int m_RuntimeOverrideCount
Definition: ncbireg.hpp:988
void SetCoreCutoff(TPriority prio)
Definition: ncbireg.cpp:1773
virtual const char * GetErrCodeString(void) const override
Translate from the error code value to its string representation.
Definition: ncbireg.cpp:2106
CRef< IRWRegistry > m_SysRegistry
Definition: ncbireg.hpp:987
virtual string GetString(const string &section, const string &name, const string &default_value, TFlags flags=0) const
Get the parameter string value.
Definition: ncbireg.cpp:321
bool x_Unset(const string &section, const string &name, TFlags flags)
Definition: ncbireg.cpp:2059
const string & x_Get(const string &section, const string &name, TFlags flags) const
Definition: ncbireg.cpp:1411
bool x_Modified(TFlags flags) const
True iff any sub-registry is modified.
Definition: ncbireg.cpp:1263
static const char * sm_OverrideRegName
Definition: ncbireg.hpp:965
bool LoadBaseRegistries(TFlags flags=0, int metareg_flags=0, const string &path=kEmptyStr)
Load any base registries listed in [NCBI].Inherits; returns true if able to load at least one,...
Definition: ncbireg.cpp:1821
int TPriority
Not restricted to ePriority_*.
Definition: ncbireg.hpp:671
bool x_SetComment(const string &comment, const string &section, const string &name, TFlags flags)
Definition: ncbireg.cpp:1540
~CCompoundRWRegistry()
Destructor.
Definition: ncbireg.cpp:1762
CRef< CCompoundRegistry > m_AllRegistries
Definition: ncbireg.hpp:893
void x_SetModifiedFlag(bool modified, TFlags flags)
Definition: ncbireg.cpp:1912
bool Write(CNcbiOstream &os, TFlags flags=0) const
Write the registry content to output stream.
Definition: ncbireg.cpp:196
void Remove(const IRegistry &reg)
Remove sub-registry "reg".
Definition: ncbireg.cpp:1795
bool x_Empty(TFlags flags) const
True iff all sub-registries are empty.
Definition: ncbireg.cpp:1249
CNcbiRegistry(TFlags flags=0)
Constructor.
Definition: ncbireg.cpp:1608
TPriority GetCoreCutoff(void) const
Subregistries whose priority is less than the core cutoff (ePriority_Reserved by default) will be ign...
Definition: ncbireg.cpp:1767
TPriorityMap m_PriorityMap
Definition: ncbireg.hpp:726
const string & x_Get(const string &section, const string &name, TFlags flags) const
Definition: ncbireg.cpp:1290
bool Unset(const string &section, const string &name, TFlags flags=0)
Fully unset the configuration parameter value, so that HasEntry returns false.
Definition: ncbireg.cpp:867
IRWRegistry * x_Read(CNcbiIstream &is, TFlags flags, const string &path)
Most implementations should not override this, but CNcbiRegistry must, to handle some special cases p...
Definition: ncbireg.cpp:1681
string m_RegistryComment
Definition: ncbireg.hpp:637
const string & x_GetComment(const string &section, const string &name, TFlags flags) const
Definition: ncbireg.cpp:1435
void x_Add(const IRegistry &reg, TPriority prio=ePriority_Default, const string &name=kEmptyStr)
Add an internal high-priority subregistry.
Definition: ncbireg.cpp:2095
void SetCoreCutoff(TPriority prio)
Definition: ncbireg.hpp:688
EOperation
Categories of modifying operations.
Definition: ncbireg.hpp:410
static const char * sm_BaseRegNamePrefix
Prefix for any base registries' names.
Definition: ncbireg.hpp:858
void Clear(TFlags flags=fAllLayers)
Reset the registry content.
Definition: ncbireg.cpp:590
void Unlock(void)
Definition: ncbireg.cpp:551
bool Set(const string &section, const string &name, const string &value, TFlags flags=0, const string &comment=kEmptyStr)
Set the configuration parameter value.
Definition: ncbireg.cpp:826
void SetModifiedFlag(bool modified, TFlags flags=fPersistent)
Indicate whether any relevant values are out of sync with some external resource (typically a configu...
Definition: ncbireg.cpp:184
bool x_Modified(TFlags flags) const
Definition: ncbireg.cpp:1906
@ fLayerFlags
Definition: ncbireg.hpp:366
@ fCaseFlags
Definition: ncbireg.hpp:105
@ fOverride
Existing value can be overriden.
Definition: ncbireg.hpp:85
@ fInternalCheckedAndLocked
Definition: ncbireg.hpp:102
@ fCountCleared
Let explicitly cleared entries stand.
Definition: ncbireg.hpp:94
@ fTruncate
Leading, trailing blanks can be truncated.
Definition: ncbireg.hpp:87
@ fPersistent
Persistent – saved when file is written.
Definition: ncbireg.hpp:84
@ fSectionlessEntries
Allow empty section names (for test_res framework)
Definition: ncbireg.hpp:97
@ fIgnoreErrors
Continue Read()ing after parse errors.
Definition: ncbireg.hpp:91
@ fWithNcbirc
Include .ncbirc (used only by CNcbiReg.)
Definition: ncbireg.hpp:93
@ fInternalSpaces
Allow internal whitespace in names.
Definition: ncbireg.hpp:92
@ fSections
Indicates that we want sections from x_Enumerate.
Definition: ncbireg.hpp:98
@ fNoOverride
Cannot change existing value.
Definition: ncbireg.hpp:86
@ fJustCore
Ignore auxiliary subregistries.
Definition: ncbireg.hpp:89
@ fPlaintextAllowed
Definition: ncbireg.hpp:99
@ fTransient
Transient – not saved by default.
Definition: ncbireg.hpp:83
@ fInSectionComments
Indicates that we want in-section comments from x_Enumerate.
Definition: ncbireg.hpp:100
@ fNotJustCore
Include auxiliary subregistries.
Definition: ncbireg.hpp:90
@ eReturn
Return default value.
Definition: ncbireg.hpp:203
@ eThrow
Throw an exception if an error occurs.
Definition: ncbireg.hpp:201
@ eErrPost
Log the error message and return default value.
Definition: ncbireg.hpp:202
@ ePriority_RuntimeOverrides
Definition: ncbireg.hpp:981
@ ePriority_Overrides
Definition: ncbireg.hpp:979
@ ePriority_Environment
Definition: ncbireg.hpp:980
@ eValue
General value format error.
Definition: ncbireg.hpp:1011
@ eErr
Other error.
Definition: ncbireg.hpp:1014
@ eUnencrypted
Value should have been encrypted, but wasn't.
Definition: ncbireg.hpp:1012
@ eSection
Section name format error.
Definition: ncbireg.hpp:1009
@ eDecryptionFailed
Value looked encrypted, but decryption failed.
Definition: ncbireg.hpp:1013
@ eEntry
Entry name format error.
Definition: ncbireg.hpp:1010
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:103
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
std::string CStringUTF8
Definition: ncbistl.hpp:254
CNcbiIstream & NcbiGetlineEOL(CNcbiIstream &is, string &str, string::size_type *count=NULL)
Read from "is" to "str" the next line (taking into account platform specifics of End-of-Line)
EEncodingForm
Helper functions to read plain-text data streams.
Definition: ncbistre.hpp:994
string Printable(char c)
Convert one single character to a "printable" form.
Definition: ncbistre.cpp:505
EEncodingForm GetTextEncodingForm(CNcbiIstream &input, EBOMDiscard discard_bom)
Detect if the stream has BOM.
Definition: ncbistre.cpp:782
IO_PREFIX::ostream CNcbiOstream
Portable alias for ostream.
Definition: ncbistre.hpp:149
const char * Endl(void)
Platform-specific EndOfLine.
Definition: ncbistre.cpp:184
IO_PREFIX::istream CNcbiIstream
Portable alias for istream.
Definition: ncbistre.hpp:146
EEncodingForm ReadIntoUtf8(CNcbiIstream &input, CStringUTF8 *result, EEncodingForm encoding_form=eEncodingForm_Unknown, EReadUnknownNoBOM what_if_no_bom=eNoBOM_GuessEncoding)
Read all input data from stream and try convert it into UTF8 string.
Definition: ncbistre.cpp:650
@ eEncodingForm_Utf16Foreign
Stream has UTF16 BOM. Byte order is nonnative for this OS.
Definition: ncbistre.hpp:1006
@ eEncodingForm_Utf16Native
Stream has UTF16 BOM. Byte order is native for this OS.
Definition: ncbistre.hpp:1004
@ eBOM_Discard
Discard the read BOM bytes.
Definition: ncbistre.hpp:1057
static bool StringToBool(const CTempString str)
Convert string to bool.
Definition: ncbistr.cpp:2812
NCBI_NS_STD::string::size_type SIZE_TYPE
Definition: ncbistr.hpp:132
static string PrintableString(const CTempString str, TPrintableMode mode=fNewLine_Quote|fNonAscii_Passthru)
Get a printable version of the specified string.
Definition: ncbistr.cpp:3944
#define kEmptyStr
Definition: ncbistr.hpp:123
static int StringToInt(const CTempString str, TStringToNumFlags flags=0, int base=10)
Convert string to int.
Definition: ncbistr.cpp:630
static list< string > & Split(const CTempString str, const CTempString delim, list< string > &arr, TSplitFlags flags=0, vector< SIZE_TYPE > *token_pos=NULL)
Split a string using specified delimiters.
Definition: ncbistr.cpp:3452
static bool EndsWith(const CTempString str, const CTempString end, ECase use_case=eCase)
Check if a string ends with a specified suffix value.
Definition: ncbistr.hpp:5424
char TXChar
Definition: ncbistr.hpp:172
static double StringToDouble(const CTempStringEx str, TStringToNumFlags flags=0)
Convert string to double.
Definition: ncbistr.cpp:1381
#define NPOS
Definition: ncbistr.hpp:133
static void TruncateSpacesInPlace(string &str, ETrunc where=eTrunc_Both)
Truncate whitespace in a string (in-place)
Definition: ncbistr.cpp:3192
PNocase_Generic< string > PNocase
Definition: ncbistr.hpp:4902
#define _T_STDSTRING(x)
Definition: ncbistr.hpp:180
static string ParseEscapes(const CTempString str, EEscSeqRange mode=eEscSeqRange_Standard, char user_char='?')
Parse C-style escape sequences in the specified string.
Definition: ncbistr.cpp:4784
static string UIntToString(unsigned int value, TNumToStringFlags flags=0, int base=10)
Convert UInt to string.
Definition: ncbistr.hpp:5103
#define _TX(x)
Definition: ncbistr.hpp:176
static bool SplitInTwo(const CTempString str, const CTempString delim, string &str1, string &str2, TSplitFlags flags=0)
Split a string into two pieces using the specified delimiters.
Definition: ncbistr.cpp:3545
static bool EqualNocase(const CTempString s1, SIZE_TYPE pos, SIZE_TYPE n, const char *s2)
Case-insensitive equality of a substring with another string.
Definition: ncbistr.hpp:5347
TErrCode GetErrCode(void) const
Get error code.
Definition: ncbistr.hpp:4449
static string TruncateSpaces(const string &str, ETrunc where=eTrunc_Both)
Truncate whitespace in a string.
Definition: ncbistr.cpp:3177
@ fDecimalPosixOrLocal
StringToDouble*(): For decimal point, try both C and current locale.
Definition: ncbistr.hpp:301
@ fSplit_Truncate
Definition: ncbistr.hpp:2503
@ fSplit_MergeDelimiters
Merge adjacent delimiters.
Definition: ncbistr.hpp:2500
@ fSplit_CanSingleQuote
Allow '...' quoting.
Definition: ncbistr.hpp:2506
void ReadLock(void)
Read lock.
Definition: ncbimtx.cpp:863
void WriteLock(void)
Write lock.
Definition: ncbimtx.cpp:1201
void Unlock(void)
Release the RW-lock.
Definition: ncbimtx.cpp:1558
Definition of all error codes used in corelib (xncbi.lib).
int i
int len
static void hex(unsigned char c)
Definition: mdb_dump.c:56
CMetaRegistry: Singleton class for loading CRegistry data from files; keeps track of what it loaded f...
const GenericPointer< typename T::ValueType > T2 value
Definition: pointer.h:1227
int strcmp(const char *str1, const char *str2)
Definition: odbc_utils.hpp:160
int isspace(Uchar c)
Definition: ncbictype.hpp:69
int isalnum(Uchar c)
Definition: ncbictype.hpp:62
Multi-threading – mutexes; rw-locks; semaphore.
string s_FlatKey(const string &section, const string &name)
Definition: ncbireg.cpp:150
static bool s_WriteComment(CNcbiOstream &os, const string &comment)
Definition: ncbireg.cpp:121
CRegistryReadGuard TReadGuard
Definition: ncbireg.cpp:55
static const string s_ConvertComment(const string &comment, bool is_file_comment=false)
Definition: ncbireg.cpp:91
CRegistryWriteGuard TWriteGuard
Definition: ncbireg.cpp:56
bool s_Backslashed(const string &s, SIZE_TYPE pos)
Definition: ncbireg.cpp:141
bool s_IsNameSectionSymbol(char ch, IRegistry::TFlags flags)
Definition: ncbireg.cpp:60
Process information in the NCBI Registry, including working with configuration files.
std::istream & in(std::istream &in_, double &x_)
Defines NCBI C++ secure resources API.
static SLJIT_INLINE sljit_ins msg(sljit_gpr r, sljit_s32 d, sljit_gpr x, sljit_gpr b)
#define NcbiSys_getenv
Definition: ncbisys.hpp:90
CRef< IRWRegistry > registry
Definition: metareg.hpp:78
string actual_name
Either an absolute path or empty.
Definition: metareg.hpp:75
#define _TROUBLE
#define _ASSERT
else result
Definition: token2.c:20
static wxAcceleratorEntry entries[3]
Modified on Fri Sep 20 14:57:43 2024 by modify_doxy.py rev. 669887