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

Go to the SVN repository for this file.

1 /* $Id: ncbienv.cpp 100515 2023-08-08 18:50:35Z ivanov $
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, Eugene Vasilchenko
27  *
28  * File Description:
29  * Unified interface to application:
30  * environment -- CNcbiEnvironment
31  * cmd.-line args -- CNcbiArguments
32  *
33  */
34 
35 #include <ncbi_pch.hpp>
36 #include <corelib/ncbienv.hpp>
37 #include <corelib/ncbifile.hpp>
39 #include <corelib/error_codes.hpp>
40 #include <common/ncbi_sanitizers.h>
41 #include <algorithm>
42 #include <stdarg.h>
43 #include "ncbisys.hpp"
44 
45 #ifdef NCBI_OS_LINUX
46 # include <unistd.h>
47 #endif
48 
49 #ifdef NCBI_OS_MSWIN
50 # include <stdlib.h>
51 #elif defined (NCBI_OS_DARWIN)
52 # include <crt_externs.h>
53 # define environ (*_NSGetEnviron())
54 #else
55 extern char** environ;
56 #endif
57 
58 
59 #define NCBI_USE_ERRCODE_X Corelib_Env
60 
61 
63 
64 
65 ///////////////////////////////////////////////////////
66 // CNcbiEnvironment::
67 
68 
70 {
71  Reset(environ);
72 }
73 
74 
75 CNcbiEnvironment::CNcbiEnvironment(const char* const* envp)
76 {
77  Reset(envp);
78 }
79 
80 
82 {
83  return;
84 }
85 
86 
87 void CNcbiEnvironment::Reset(const char* const* envp)
88 {
89  // load new environment values from "envp"
90  if ( !envp )
91  return;
92 
94  // delete old environment values
95  m_Cache.clear();
96 
97  for ( ; *envp; envp++) {
98  const char* s = *envp;
99  const char* eq = strchr(s, '=');
100  if ( !eq ) {
101  ERR_POST_X(3, "CNcbiEnvironment: bad string '" << s << "'");
102  continue;
103  }
104  m_Cache[string(s, (size_t)(eq - s))] = SEnvValue(eq + 1, kEmptyXCStr);
105  }
106 }
107 
108 
109 const string& CNcbiEnvironment::Get(const string& name, bool* found) const
110 {
113  bool fake_found;
114  if (found == NULL) {
115  found = &fake_found;
116  }
117  if ( i != m_Cache.end() ) {
118  if (i->second.ptr == NULL && i->second.value.empty()) {
119  *found = false;
120  return kEmptyStr;
121  } else {
122  *found = true;
123  return i->second.value;
124  }
125  }
126  string loaded_value = Load(name, *found);
127  m_Cache[name] = SEnvValue(loaded_value, *found ? kEmptyXCStr : NULL);
128  const string& s = m_Cache[name].value;
129  return s.empty() ? kEmptyStr : s;
130 }
131 
132 
133 void CNcbiEnvironment::Enumerate(list<string>& names, const string& prefix)
134  const
135 {
136  names.clear();
138  for (TCache::const_iterator it = m_Cache.lower_bound(prefix);
139  it != m_Cache.end() && NStr::StartsWith(it->first, prefix); ++it) {
140  if ( !it->second.value.empty() || it->second.ptr == kEmptyXCStr) {
141  // ignore entries the app cleared out
142  names.push_back(it->first);
143  }
144  }
145 }
146 
147 void CNcbiEnvironment::Set(const string& name, const string& value)
148 {
149 
150  TXChar* str = nullptr;
151  {{
152  // Deliberate leak
154  str = NcbiSys_strdup(_T_XCSTRING(name + "=" + value));
155  }}
156  if ( !str ) {
157  throw bad_alloc();
158  }
159 
160  if (NcbiSys_putenv(str) != 0) {
161  free(str);
163  "failed to set environment variable " + name);
164  }
165 
168  if ( i != m_Cache.end() ) {
169  if (i->second.ptr != NULL && i->second.ptr != kEmptyXCStr) {
170  free(const_cast<TXChar*>(i->second.ptr));
171  }
172  }
173  m_Cache[name] = SEnvValue(value, str);
174 }
175 
176 void CNcbiEnvironment::Unset(const string& name)
177 {
178 #ifdef NCBI_OS_MSWIN
179  Set(name, kEmptyStr);
180 #elif defined(NCBI_OS_IRIX)
181  {{
182  char* p = getenv(name.c_str());
183  if (p) {
184  _ASSERT(p[-1] == '=');
185  _ASSERT( !memcmp(p - name.size() - 1, name.data(), name.size()) );
186  p[-1] = '\0';
187  }
188  }}
189 #else
190  unsetenv(name.c_str());
191 #endif
192 
194  TCache::iterator i = m_Cache.find(name);
195  if ( i != m_Cache.end() ) {
196  if (i->second.ptr != NULL && i->second.ptr != kEmptyXCStr) {
197  free(const_cast<TXChar*>(i->second.ptr));
198  }
199  m_Cache.erase(i);
200  }
201 }
202 
203 string CNcbiEnvironment::Load(const string& name, bool& found) const
204 {
205  const TXChar* s = NcbiSys_getenv(_T_XCSTRING(name));
206  if (s == NULL) {
207  found = false;
208  return NcbiEmptyString;
209  } else {
210  found = true;
211  return _T_STDSTRING(s);
212  }
213 }
214 
215 
216 
217 
218 ///////////////////////////////////////////////////////
219 // CAutoEnvironmentVariable::
220 
221 
223  const CTempString& value,
225  : m_Env(env, eNoOwnership), m_VariableName(var_name)
226 {
227  if ( !env ) {
229  if (app) {
231  } else {
233  }
234  }
236  if ( value.empty() ) {
238  } else {
240  }
241 }
242 
244 {
245  if (m_WasSet) {
247  } else {
249  }
250 }
251 
252 
253 
254 
255 ///////////////////////////////////////////////////////
256 // CEnvironmentCleaner::
257 
258 
260 {
261  if (s != NULL) {
262  Clean(s);
263  va_list ap;
264  va_start(ap, s);
265  for (;;) {
266  const char* p = va_arg(ap, const char*);
267  if (p == NULL) {
268  break;
269  }
270  Clean(p);
271  }
272  va_end(ap);
273  }
274 }
275 
276 void CEnvironmentCleaner::Clean(const string& name)
277 {
279  if (app) {
280  app->SetEnvironment().Unset(name);
281  } else {
282 #ifdef NCBI_OS_MSWIN
283  ::SetEnvironmentVariable(_T_XCSTRING(name), NULL);
284 #elif defined(NCBI_OS_IRIX)
285  char* p = getenv(name.c_str());
286  if (p) {
287  _ASSERT(p[-1] == '=');
288  _ASSERT( !memcmp(p - name.size() - 1, name.data(), name.size()) );
289  p[-1] = '\0';
290  }
291 #else
292  unsetenv(name.c_str());
293 #endif
294  }
295 }
296 
297 
298 
299 
300 ///////////////////////////////////////////////////////
301 // CNcbiArguments::
302 
303 
304 CNcbiArguments::CNcbiArguments(int argc, const char* const* argv,
305  const string& program_name,
306  const string& real_name)
307 {
308  Reset(argc, argv, program_name, real_name);
309 }
310 
311 
313 {
314  return;
315 }
316 
317 
319  : m_ProgramName(args.m_ProgramName),
320  m_Args(args.m_Args),
321  m_ResolvedName(args.m_ResolvedName)
322 {
323  return;
324 }
325 
326 
328 {
329  if (&args == this)
330  return *this;
331 
333  m_Args.clear();
334  copy(args.m_Args.begin(), args.m_Args.end(), back_inserter(m_Args));
335  return *this;
336 }
337 
338 
339 void CNcbiArguments::Reset(int argc, const char* const* argv,
340  const string& program_name, const string& real_name)
341 {
342  // check args
343  if (argc < 0) {
344  NCBI_THROW(CArgumentsException,eNegativeArgc,
345  "Negative number of command-line arguments");
346  }
347 
348  if ((argc == 0) != (argv == 0)) {
349  if (argv == 0) {
351  "Command-line arguments are absent");
352  }
353  ERR_POST_X(4, Info <<
354  "CNcbiArguments(): zero \"argc\", non-zero \"argv\"");
355  }
356 
357  // clear old args, store new ones
358  m_Args.clear();
359  for (int i = 0; i < argc; i++) {
360  if ( !argv[i] ) {
361  ERR_POST_X(5, Warning <<
362  "CNcbiArguments() -- NULL cmd.-line arg #" << i);
363  continue;
364  }
365  m_Args.push_back(argv[i]);
366  }
367 
368  // set application name
369  SetProgramName(program_name, real_name);
370 }
371 
372 
373 const string& CNcbiArguments::GetProgramName(EFollowLinks follow_links) const
374 {
375  if (follow_links) {
377  if ( !m_ResolvedName.size() ) {
378 #ifdef NCBI_OS_LINUX
379  string proc_link = "/proc/" + NStr::IntToString(getpid()) + "/exe";
380  m_ResolvedName = CDirEntry::NormalizePath(proc_link, follow_links);
381 #else
383 #endif
384  }
385  return m_ResolvedName;
386  } else if ( !m_ProgramName.empty() ) {
387  return m_ProgramName;
388  } else if ( m_Args.size() ) {
389  return m_Args[0];
390  } else {
391  static CSafeStatic<string> kDefProgramName;
392  kDefProgramName->assign("ncbi");
393  return kDefProgramName.Get();
394  }
395 }
396 
397 
399 {
400  const string& name = GetProgramName(follow_links);
401  SIZE_TYPE base_pos = name.find_last_of("/\\:");
402  if (base_pos == NPOS)
403  return name;
404  return name.substr(base_pos + 1);
405 }
406 
407 
409 {
410  const string& name = GetProgramName(follow_links);
411  SIZE_TYPE base_pos = name.find_last_of("/\\:");
412  if (base_pos == NPOS)
413  return NcbiEmptyString;
414  return name.substr(0, base_pos + 1);
415 }
416 
417 
418 void CNcbiArguments::SetProgramName(const string& program_name,
419  const string& real_name)
420 {
421  m_ProgramName = program_name;
423  m_ResolvedName = real_name;
424 }
425 
426 
427 void CNcbiArguments::Add(const string& arg)
428 {
429  m_Args.push_back(arg);
430 }
431 
433 {
434  while (n-- > 0) {
435  if (m_Args.size() > 1) {
436  m_Args.erase( ++m_Args.begin());
437  }
438  }
439 }
440 
442 {
443  switch (GetErrCode()) {
444  case eNegativeArgc: return "eNegativeArgc";
445  case eNoArgs: return "eNoArgs";
446  default: return CException::GetErrCodeString();
447  }
448 }
449 
450 
CArgumentsException –.
Definition: ncbienv.hpp:76
CNcbiArguments –.
Definition: ncbienv.hpp:236
CNcbiEnvironment –.
Definition: ncbienv.hpp:110
T & Get(void)
Create the variable if not created yet, return the reference.
CTempString implements a light-weight string on top of a storage buffer whose lifetime management is ...
Definition: tempstr.hpp:65
void erase(iterator pos)
Definition: map.hpp:167
const_iterator end() const
Definition: map.hpp:152
const_iterator lower_bound(const key_type &key) const
Definition: map.hpp:154
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
static const struct name_t names[]
static const char * str(char *buf, int n)
Definition: stats.c:84
static HENV env
Definition: transaction2.c:38
#define unsetenv(n)
Definition: replacements.h:187
void reset(element_type *p=0, EOwnership ownership=eTakeOwnership)
Reset will delete the old pointer (if owned), set content to the new value, and assume the ownership ...
Definition: ncbimisc.hpp:480
CNcbiEnvironment & SetEnvironment(void)
Get a non-const copy of the application's cached environment.
static CNcbiApplicationGuard InstanceGuard(void)
Singleton method.
Definition: ncbiapp.cpp:133
EFollowLinks
Whether to follow symbolic links (also known as shortcuts or aliases)
Definition: ncbimisc.hpp:143
@ eIgnoreLinks
Do not follow symbolic links.
Definition: ncbimisc.hpp:144
@ eTakeOwnership
An object can take ownership of another.
Definition: ncbi_types.h:136
@ eNoOwnership
No ownership is assumed.
Definition: ncbi_types.h:135
string
Definition: cgiapp.hpp:690
#define NULL
Definition: ncbistd.hpp:225
#define ERR_POST_X(err_subcode, message)
Error posting with default error code and given error subcode.
Definition: ncbidiag.hpp:550
virtual const char * GetErrCodeString(void) const override
Translate from the error code value to its string representation.
Definition: ncbienv.cpp:441
void Shift(int n=1)
Delete arguments from 1 to n.
Definition: ncbienv.cpp:432
string m_PrevValue
Previous value of the environment variable manipulated.
Definition: ncbienv.hpp:199
deque< string > m_Args
Queue of arguments.
Definition: ncbienv.hpp:296
string m_ProgramName
Program name if different from the default m_Args[0].
Definition: ncbienv.hpp:294
void Reset(int argc, const char *const *argv, const string &program_name=kEmptyStr, const string &real_name=kEmptyStr)
Reset arguments.
Definition: ncbienv.cpp:339
CAutoEnvironmentVariable(const CTempString &var_name, const CTempString &value="1", CNcbiEnvironment *env=NULL)
Initializes the environment variable passed as an argument to the corresponding value ("1" by default...
Definition: ncbienv.cpp:222
virtual string Load(const string &name, bool &found) const
Load value of specified environment variable.
Definition: ncbienv.cpp:203
string GetProgramDirname(EFollowLinks follow_links=eIgnoreLinks) const
Get program directory name.
Definition: ncbienv.cpp:408
CEnvironmentCleaner(const char *s=NULL,...)
Immediately clean some settings, to be passed in as a NULL-terminated sequence of C strings.
Definition: ncbienv.cpp:259
void Set(const string &name, const string &value)
Set an environment variable by name.
Definition: ncbienv.cpp:147
CNcbiArguments & operator=(const CNcbiArguments &args)
Assignment operator.
Definition: ncbienv.cpp:327
CFastMutex m_CacheMutex
Definition: ncbienv.hpp:164
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
CFastMutex m_ResolvedNameMutex
Definition: ncbienv.hpp:299
void SetProgramName(const string &program_name, const string &real_name=kEmptyStr)
Set program name.
Definition: ncbienv.cpp:418
bool m_WasSet
Was the variable originally set at all?
Definition: ncbienv.hpp:201
void Add(const string &arg)
Add a new argument.
Definition: ncbienv.cpp:427
string GetProgramBasename(EFollowLinks follow_links=eIgnoreLinks) const
Get program base name.
Definition: ncbienv.cpp:398
void Reset(const char *const *envp=0)
Reset environment.
Definition: ncbienv.cpp:87
CNcbiEnvironment(void)
Constructor.
Definition: ncbienv.cpp:69
virtual ~CNcbiEnvironment(void)
Destructor.
Definition: ncbienv.cpp:81
string m_ResolvedName
Definition: ncbienv.hpp:298
void Clean(const string &name)
Clean the specified setting.
Definition: ncbienv.cpp:276
void Enumerate(list< string > &names, const string &prefix=kEmptyStr) const
Find all variable names starting with an optional prefix.
Definition: ncbienv.cpp:133
~CAutoEnvironmentVariable()
Destructor which restores the modifications made in the environment by this class.
Definition: ncbienv.cpp:243
virtual ~CNcbiArguments(void)
Destructor.
Definition: ncbienv.cpp:312
CNcbiArguments(int argc, const char *const *argv, const string &program_name=kEmptyStr, const string &real_name=kEmptyStr)
Constructor.
Definition: ncbienv.cpp:304
string m_VariableName
Name of the environment variable manipulated.
Definition: ncbienv.hpp:197
AutoPtr< CNcbiEnvironment > m_Env
Affected CNcbiEnvironment instance.
Definition: ncbienv.hpp:195
const string & GetProgramName(EFollowLinks follow_links=eIgnoreLinks) const
Get program name.
Definition: ncbienv.cpp:373
@ eNegativeArgc
Negative argc value.
Definition: ncbienv.hpp:80
@ eNoArgs
No arguments.
Definition: ncbienv.hpp:81
#define NCBI_THROW(exception_class, err_code, message)
Generic macro to throw an exception, given the exception class, error code and message string.
Definition: ncbiexpt.hpp:704
void Warning(CExceptionArgs_Base &args)
Definition: ncbiexpt.hpp:1191
TErrCode GetErrCode(void) const
Definition: ncbiexpt.hpp:1493
virtual const char * GetErrCodeString(void) const
Get error code interpreted as text.
Definition: ncbiexpt.cpp:444
void Info(CExceptionArgs_Base &args)
Definition: ncbiexpt.hpp:1185
static string NormalizePath(const string &path, EFollowLinks follow_links=eIgnoreLinks)
Normalize a path.
Definition: ncbifile.cpp:820
#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
char TXChar
Definition: ncbistr.hpp:172
#define NPOS
Definition: ncbistr.hpp:133
static string IntToString(int value, TNumToStringFlags flags=0, int base=10)
Convert int to string.
Definition: ncbistr.hpp:5078
#define kEmptyXCStr
Definition: ncbistr.hpp:187
#define _T_STDSTRING(x)
Definition: ncbistr.hpp:180
#define _T_XCSTRING(x)
Definition: ncbistr.hpp:181
#define NcbiEmptyString
Definition: ncbistr.hpp:122
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:5406
Definition of all error codes used in corelib (xncbi.lib).
int i
yy_size_t n
const GenericPointer< typename T::ValueType > T2 value
Definition: pointer.h:1227
Static variables safety - create on demand, destroy on application termination.
Common macro to detect used sanitizers and suppress memory leaks if run under LeakSanitizer.
#define NCBI_LSAN_DISABLE_GUARD
Defines unified interface to application:
Defines classes: CDirEntry, CFile, CDir, CSymLink, CMemoryFile, CFileUtil, CFileLock,...
bool eq(T x_, T y_, T round_)
Definition: njn_approx.hpp:79
void copy(Njn::Matrix< S > *matrix_, const Njn::Matrix< T > &matrix0_)
Definition: njn_matrix.hpp:613
#define NcbiSys_getenv
Definition: ncbisys.hpp:90
#define NcbiSys_putenv
Definition: ncbisys.hpp:93
#define NcbiSys_strdup
Definition: ncbisys.hpp:104
Cached environment <name,value> pair.
Definition: ncbienv.hpp:152
#define _ASSERT
void free(voidpf ptr)
Modified on Fri Sep 20 14:58:16 2024 by modify_doxy.py rev. 669887