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

Go to the SVN repository for this file.

1 /* $Id: env_reg.cpp 99116 2023-02-15 17:27:47Z vasilche $
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: Aaron Ucko
27  *
28  * File Description:
29  * Classes to support using environment variables as a backend for
30  * the registry framework.
31  *
32  */
33 
34 #include <ncbi_pch.hpp>
35 #include <corelib/env_reg.hpp>
36 #include <corelib/ncbienv.hpp>
37 #include <corelib/error_codes.hpp>
38 #include <set>
39 
40 
41 #define NCBI_USE_ERRCODE_X Corelib_Env
42 
43 
45 
46 
47 //#define UPPER_CASE_ONLY
48 
49 
51  : m_Env(new CNcbiEnvironment, eTakeOwnership),
52  m_Modified(false), m_Flags(flags)
53 {
55 }
56 
57 
59  EOwnership own, TFlags flags)
60  : m_Env(&env, own), m_Modified(false), m_Flags(flags)
61 {
63 }
64 
65 
67 {
68 }
69 
70 
72  TPriority prio)
73 {
75  (prio, CConstRef<IEnvRegMapper>(&mapper)));
76 }
77 
78 
80 {
82  if (it->second == &mapper) {
83  m_PriorityMap.erase(it);
84  return; // mappers should be unique
85  }
86  }
87  // already returned if found...
89  "CEnvironmentRegistry::RemoveMapper:"
90  " unknown mapper (already removed?)", 0);
91 }
92 
94 {
95  // return (flags & fTransient) ? m_PriorityMap.empty() : true;
96  list<string> l;
97  string section, name;
99  m_Env->Enumerate(l, mapper->second->GetPrefix());
100  ITERATE (list<string>, it, l) {
101  if (mapper->second->EnvToReg(*it, section, name)) {
102  return false;
103  }
104  }
105  }
106  return true;
107 }
108 
109 
111 {
112  return (flags & fTransient) ? m_Modified : false;
113 }
114 
115 
117 {
118  if (flags & fTransient) {
119  m_Modified = modified;
120  }
121 }
122 
123 
124 const string& CEnvironmentRegistry::x_Get(const string& section,
125  const string& name,
126  TFlags flags) const
127 {
128  bool found;
129  return x_Get(section, name, flags, found);
130 }
131 
132 
133 const string& CEnvironmentRegistry::x_Get(const string& section,
134  const string& name,
135  TFlags flags,
136  bool& found) const
137 {
138  if ((flags & fTPFlags) == fPersistent) {
139  return kEmptyStr;
140  }
142  string var_name = it->second->RegToEnv(section, name);
143  const string* resultp = &m_Env->Get(var_name, &found);
144  if ((m_Flags & fCaseFlags) == 0 && !found) {
145  // try capitalizing the name
146  resultp = &m_Env->Get(NStr::ToUpper(var_name), &found);
147  }
148  if (found) {
149  return *resultp;
150  }
151  }
152  return kEmptyStr;
153 }
154 
155 
156 bool CEnvironmentRegistry::x_HasEntry(const string& section,
157  const string& name,
158  TFlags flags) const
159 {
160  bool found = false;
161  x_Get(section, name, flags, found);
162  return found;
163 }
164 
165 
166 const string& CEnvironmentRegistry::x_GetComment(const string&, const string&,
167  TFlags) const
168 {
169  return kEmptyStr;
170 }
171 
172 
173 void CEnvironmentRegistry::x_Enumerate(const string& section,
174  list<string>& entries,
175  TFlags flags) const
176 {
177  // Environment does not provide comments, so if we came for in-section
178  // comments, we can just return doing nothing
179  if (flags & fInSectionComments) {
180  return;
181  }
182  if ( !(flags & fTransient) ) {
183  return;
184  }
185 
186  NStr::ECase use_case = (flags & fSectionCase) == 0 ? NStr::eNocase : NStr::eCase;
187  typedef set<string, PNocase_Conditional> TEntrySet;
188 
189  list<string> l;
190  TEntrySet entry_set(use_case);
191  string parsed_section, parsed_name;
192 
193  ITERATE (TPriorityMap, mapper, m_PriorityMap) {
194  m_Env->Enumerate(l, mapper->second->GetPrefix());
195  ITERATE (list<string>, it, l) {
196  if (mapper->second->EnvToReg(*it, parsed_section, parsed_name)) {
197  if (section.empty()) {
198  entry_set.insert(parsed_section);
199  } else if (NStr::Equal(section, parsed_section, use_case)) {
200  entry_set.insert(parsed_name);
201  }
202  }
203  }
204  }
205  ITERATE (TEntrySet, it, entry_set) {
206  entries.push_back(*it);
207  }
208 }
209 
210 
212 {
213 }
214 
215 
217 {
218  if (flags & fTransient) {
219  // m_Mappers.clear();
220  }
221 }
222 
223 
224 bool CEnvironmentRegistry::x_Set(const string& section, const string& name,
225  const string& value, TFlags flags,
226  const string& /*comment*/)
227 {
229  const_cast<const TPriorityMap&>(m_PriorityMap)) {
230  string var_name = it->second->RegToEnv(section, name);
231  if ( !var_name.empty() ) {
232  string cap_name = var_name;
233  NStr::ToUpper(cap_name);
234  string old_value = m_Env->Get(var_name);
235  if ((m_Flags & fCaseFlags) == 0 && old_value.empty()) {
236  old_value = m_Env->Get(cap_name);
237  }
238  if (MaybeSet(old_value, value, flags)) {
239  m_Env->Set(var_name, value);
240  // m_Env->Set(cap_name, value);
241  return true;
242  }
243  return false;
244  }
245  }
246 
247  ERR_POST_X(1, Warning << "CEnvironmentRegistry::x_Set: "
248  "no mapping defined for [" << section << ']' << name);
249  return false;
250 }
251 
252 
253 bool CEnvironmentRegistry::x_Unset(const string& section, const string& name,
254  TFlags /*flags*/)
255 {
256  bool result = false;
258  string var_name = it->second->RegToEnv(section, name);
259  bool found;
260  if (var_name.empty()) {
261  continue;
262  }
263  m_Env->Get(var_name, &found);
264  if (found) {
265  result = true;
266  m_Env->Unset(var_name);
267  }
268  if ((m_Flags & fCaseFlags) == 0) {
269  string cap_name = var_name;
270  NStr::ToUpper(cap_name);
271  m_Env->Get(cap_name, &found);
272  if (found) {
273  result = true;
274  m_Env->Unset(cap_name);
275  }
276  }
277  }
278  return result;
279 }
280 
281 bool CEnvironmentRegistry::x_SetComment(const string&, const string&,
282  const string&, TFlags)
283 {
285  << "CEnvironmentRegistry::x_SetComment: unsupported operation");
286  return false;
287 }
288 
289 
291  const string& prefix,
292  const string& suffix)
293  : m_Section(section), m_Prefix(prefix), m_Suffix(suffix)
294 {
295 }
296 
297 
298 string CSimpleEnvRegMapper::RegToEnv(const string& section, const string& name)
299  const
300 {
301  return (section == m_Section ? (m_Prefix + name + m_Suffix) : kEmptyStr);
302 }
303 
304 
305 bool CSimpleEnvRegMapper::EnvToReg(const string& env, string& section,
306  string& name) const
307 {
308  SIZE_TYPE plen = m_Prefix.length();
309  SIZE_TYPE tlen = plen + m_Suffix.length();
310  if (env.size() > tlen && NStr::StartsWith(env, m_Prefix, NStr::eNocase)
312  section = m_Section;
313  name = env.substr(plen, env.length() - tlen);
314  return true;
315  }
316  return false;
317 }
318 
319 
321 {
322  return m_Prefix;
323 }
324 
325 
326 const char* CNcbiEnvRegMapper::sm_Prefix = "NCBI_CONFIG_";
327 
328 
329 string CNcbiEnvRegMapper::RegToEnv(const string& section, const string& name)
330  const
331 {
332  string result(sm_Prefix);
333  if (NStr::StartsWith(name, ".")) {
334  result += name.substr(1) + "__" + section;
335  } else {
336  result += "_" + section + "__" + name;
337  }
338 #ifdef UPPER_CASE_ONLY
340 #endif
341  if (result.find_first_of(".-/ ") != NPOS) {
342  NStr::ReplaceInPlace(result, ".", "_DOT_");
343  NStr::ReplaceInPlace(result, "-", "_HYPHEN_");
344  NStr::ReplaceInPlace(result, "/", "_SLASH_");
345  NStr::ReplaceInPlace(result, " ", "_SPACE_");
346  }
347  return result;
348 }
349 
350 
351 inline
352 static char s_IdentifySubstitution(const CTempString& s) {
353  switch (s[0]) {
354  case 'D':
355  if (s.size() == 3 && s == "DOT") {
356  return '.';
357  }
358  break;
359  case 'H':
360  if (s.size() == 6 && s == "HYPHEN") {
361  return '-';
362  }
363  break;
364  case 'S':
365  if (s.size() == 5) {
366  if (s == "SLASH") {
367  return '/';
368  } else if (s == "SPACE") {
369  return ' ';
370  }
371  }
372  break;
373  default:
374  break;
375  }
376  return '\0';
377 }
378 
379 
380 bool CNcbiEnvRegMapper::EnvToReg(const string& env_in, string& section,
381  string& name) const
382 {
383  static const SIZE_TYPE kPfxLen = strlen(sm_Prefix);
384  if (env_in.size() <= kPfxLen || !NStr::StartsWith(env_in, sm_Prefix) ) {
385  return false;
386  }
387 #ifdef UPPER_CASE_ONLY
388  for ( auto c : env_in ) {
389  if ( islower(c) ) {
390  return false;
391  }
392  }
393 #endif
394  vector<CTempString> v;
395  NStr::Split(env_in, "_", v);
396  string env;
397  env.reserve(env_in.size());
398  for (const auto& it : v) {
399  SIZE_TYPE l = env.size();
400  char c = '\0';
401  if (&it != &v.back() && !env.empty() && env[l - 1] == '_'
402  && !it.empty()) {
403  c = s_IdentifySubstitution(it);
404  }
405  if (c == '\0') {
406  env += it;
407  if (&it != &v.back()) {
408  env += '_';
409  }
410  } else {
411  env[l - 1] = c;
412  }
413  }
414  // Make an offset until the first symbol that could be section name
415  // (alphanumeric character)
416  SIZE_TYPE section_start_pos = kPfxLen;
417  for ( ; section_start_pos < env.size(); section_start_pos++) {
418  if (isalnum(env[section_start_pos])) break;
419  }
420  SIZE_TYPE uu_pos = env.find("__", section_start_pos + 1);
421  if (uu_pos == NPOS || uu_pos == env.size() - 2) {
422  return false;
423  }
424  /* Parse section and entry names from the variable */
425  if (env[kPfxLen] == '_') { // regular entry
426  section = env.substr(kPfxLen + 1, uu_pos - kPfxLen - 1);
427  name = env.substr(uu_pos + 2);
428  } else {
429  name = env.substr(kPfxLen - 1, uu_pos - kPfxLen + 1);
430  _ASSERT(name[0] == '_');
431  name[0] = '.';
432  section = env.substr(uu_pos + 2);
433  }
435  ERR_POST(Info << "Invalid registry section name in environment "
436  "variable " << env);
437  }
439  ERR_POST(Info << "Invalid registry entry name in environment "
440  "variable " << env);
441  }
442  return true;
443 }
444 
445 
447 {
448  return sm_Prefix;
449 }
450 
451 
#define false
Definition: bool.h:36
CNcbiEnvRegMapper –.
Definition: env_reg.hpp:182
CNcbiEnvironment –.
Definition: ncbienv.hpp:104
CRegistryException –.
Definition: ncbireg.hpp:1005
CTempString implements a light-weight string on top of a storage buffer whose lifetime management is ...
Definition: tempstr.hpp:65
IEnvRegMapper –.
Definition: env_reg.hpp:57
void erase(iterator pos)
Definition: map.hpp:307
iterator insert(const value_type &val)
Definition: map.hpp:305
char value[7]
Definition: config.c:431
static uch flags
static char s_IdentifySubstitution(const CTempString &s)
Definition: env_reg.cpp:352
Classes to support using environment variables as a backend for the registry framework.
#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
@ eTakeOwnership
An object can take ownership of another.
Definition: ncbi_types.h:136
#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 Set(const string &name, const string &value)
Set an environment variable by name.
Definition: ncbienv.cpp:147
const string & Get(const string &name, bool *found=NULL) const
Get environment value by name.
Definition: ncbienv.cpp:109
void Unset(const string &name)
Delete an environment variable by name.
Definition: ncbienv.cpp:176
void Enumerate(list< string > &names, const string &prefix=kEmptyStr) const
Find all variable names starting with an optional prefix.
Definition: ncbienv.cpp:133
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
void Info(CExceptionArgs_Base &args)
Definition: ncbiexpt.hpp:1185
CSimpleEnvRegMapper(const string &section, const string &prefix, const string &suffix=kEmptyStr)
Definition: env_reg.cpp:290
int TFlags
Binary OR of "EFlags".
Definition: ncbireg.hpp:107
bool x_Unset(const string &section, const string &name, TFlags flags)
Definition: env_reg.cpp:253
string RegToEnv(const string &section, const string &name) const
Returns empty strings for unsupported (section, name) pairs.
Definition: env_reg.cpp:298
void RemoveMapper(const IEnvRegMapper &mapper)
Definition: env_reg.cpp:79
AutoPtr< CNcbiEnvironment > m_Env
Definition: env_reg.hpp:138
~CEnvironmentRegistry()
Destructor.
Definition: env_reg.cpp:66
void x_Clear(TFlags flags)
Called locked, like the virtual methods inherited from IRegistry.
Definition: env_reg.cpp:216
string GetPrefix(void) const
Can be overriden to speed enumeration.
Definition: env_reg.cpp:320
const string & x_Get(const string &section, const string &name, TFlags flags) const
Definition: env_reg.cpp:124
static bool MaybeSet(string &target, const string &value, TFlags flags)
Definition: ncbireg.cpp:925
bool EnvToReg(const string &env, string &section, string &name) const
The return value indicates whether the environment variable was appropriately formatted.
Definition: env_reg.cpp:380
bool x_HasEntry(const string &section, const string &name, TFlags flags) const
Definition: env_reg.cpp:156
const string & x_GetComment(const string &section, const string &name, TFlags flags) const
Definition: env_reg.cpp:166
bool x_Empty(TFlags flags) const
Implementations of the fundamental operations above, to be run with the lock already acquired and som...
Definition: env_reg.cpp:93
TPriorityMap m_PriorityMap
Definition: env_reg.hpp:139
int TPriority
Not restricted to ePriority_*.
Definition: env_reg.hpp:102
string GetPrefix(void) const
Can be overriden to speed enumeration.
Definition: env_reg.cpp:446
void x_ChildLockAction(FLockAction action)
Definition: env_reg.cpp:211
bool x_Set(const string &section, const string &name, const string &value, TFlags flags, const string &comment)
Definition: env_reg.cpp:224
void x_SetModifiedFlag(bool modified, TFlags flags)
Definition: env_reg.cpp:116
bool x_Modified(TFlags flags) const
Definition: env_reg.cpp:110
string RegToEnv(const string &section, const string &name) const
Returns empty strings for unsupported (section, name) pairs.
Definition: env_reg.cpp:329
void x_Enumerate(const string &section, list< string > &entries, TFlags flags) const
Definition: env_reg.cpp:173
bool m_Modified
only tracks mods made through this.
Definition: env_reg.hpp:140
static bool IsNameEntry(const string &str, TFlags flags)
Definition: ncbireg.cpp:84
void AddMapper(const IEnvRegMapper &mapper, TPriority prio=ePriority_Default)
Definition: env_reg.cpp:71
bool x_SetComment(const string &comment, const string &section, const string &name, TFlags flags)
Definition: env_reg.cpp:281
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
static const char * sm_Prefix
Definition: env_reg.hpp:189
bool EnvToReg(const string &env, string &section, string &name) const
The return value indicates whether the environment variable was appropriately formatted.
Definition: env_reg.cpp:305
CEnvironmentRegistry(TFlags flags=0)
Constructors.
Definition: env_reg.cpp:50
@ fCaseFlags
Definition: ncbireg.hpp:105
@ fPersistent
Persistent – saved when file is written.
Definition: ncbireg.hpp:84
@ fInternalSpaces
Allow internal whitespace in names.
Definition: ncbireg.hpp:92
@ fSectionCase
Create with case-sensitive section names.
Definition: ncbireg.hpp:95
@ 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
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:103
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
NCBI_NS_STD::string::size_type SIZE_TYPE
Definition: ncbistr.hpp:132
#define kEmptyStr
Definition: ncbistr.hpp:123
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:3457
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:5429
#define NPOS
Definition: ncbistr.hpp:133
static bool StartsWith(const CTempString str, const CTempString start, ECase use_case=eCase)
Check if a string starts with a specified prefix value.
Definition: ncbistr.hpp:5411
ECase
Which type of string comparison.
Definition: ncbistr.hpp:1204
static bool Equal(const CTempString s1, SIZE_TYPE pos, SIZE_TYPE n, const char *s2, ECase use_case=eCase)
Test for equality of a substring with another string.
Definition: ncbistr.hpp:5383
static string & ReplaceInPlace(string &src, const string &search, const string &replace, SIZE_TYPE start_pos=0, SIZE_TYPE max_replace=0, SIZE_TYPE *num_replace=0)
Replace occurrences of a substring within a string.
Definition: ncbistr.cpp:3401
static string & ToUpper(string &str)
Convert string to upper case – string& version.
Definition: ncbistr.cpp:424
size_type size(void) const
Return the length of the represented array.
Definition: tempstr.hpp:327
@ eNocase
Case insensitive compare.
Definition: ncbistr.hpp:1206
@ eCase
Case sensitive compare.
Definition: ncbistr.hpp:1205
enum ENcbiOwnership EOwnership
Ownership relations between objects.
Definition of all error codes used in corelib (xncbi.lib).
int isalnum(Uchar c)
Definition: ncbictype.hpp:62
int islower(Uchar c)
Definition: ncbictype.hpp:66
Defines unified interface to application:
static const char * suffix[]
Definition: pcregrep.c:408
static const char * prefix[]
Definition: pcregrep.c:405
#define _ASSERT
else result
Definition: token2.c:20
static HENV env
Definition: transaction2.c:38
static wxAcceleratorEntry entries[3]
Modified on Sat Dec 09 04:45:35 2023 by modify_doxy.py rev. 669887