jaulib v1.3.0
Jau Support Library (C++, Java, ..)
environment.cpp
Go to the documentation of this file.
1/*
2 * Author: Sven Gothel <sgothel@jausoft.com>
3 * Copyright (c) 2020 Gothel Software e.K.
4 * Copyright (c) 2020 ZAFENA AB
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be
15 * included in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25
26#include <cstring>
27#include <string>
28#include <algorithm>
29#include <memory>
30#include <cstdint>
31#include <vector>
32#include <cstdio>
33#include <cstdlib>
34
35#include <jau/environment.hpp>
36#include <jau/debug.hpp>
37
38using namespace jau;
39
41
42static void at_exit_func() noexcept {
43 is_terminating_ = true;
44}
45static int install_atexit() noexcept {
46 return atexit(at_exit_func);
47}
48static bool atexit_cockie = 0 == install_atexit();
49bool root_environment::is_terminating() noexcept { (void)atexit_cockie; return is_terminating_.load(); }
51
54
55bool environment::local_debug = false;
56
57static const std::string s_true("true");
58static const std::string s_false("false");
59
60std::string environment::getProperty(const std::string & name) noexcept {
61 const char * value = ::getenv(name.c_str());
62 if( nullptr != value ) {
63 COND_PRINT(local_debug, "env::getProperty0 '%s': '%s'", name.c_str(), value);
64 return std::string( value );
65 }
66 if( std::string::npos != name.find('.', 0) ) {
67 // Retry with '.' -> '_' to please unix shell
68 std::string alt_name(name);
69 std::replace( alt_name.begin(), alt_name.end(), '.', '_');
70 value = ::getenv(alt_name.c_str());
71 if( nullptr != value ) {
72 COND_PRINT(local_debug, "env::getProperty0 '%s' -> '%s': '%s'", name.c_str(), alt_name.c_str(), value);
73 return std::string( value );
74 }
75 COND_PRINT(local_debug, "env::getProperty0 '%s' -> '%s': NOT FOUND", name.c_str(), alt_name.c_str());
76 } else {
77 COND_PRINT(local_debug, "env::getProperty0 '%s': NOT FOUND", name.c_str());
78 }
79 // not found: empty string
80 return std::string();
81}
82
83std::string environment::getProperty(const std::string & name, const std::string & default_value) noexcept {
84 std::string value = getProperty(name);
85 if( 0 == value.length() ) {
86 COND_PRINT(local_debug, "env::getProperty1 %s: null -> %s (default)", name.c_str(), default_value.c_str());
87 return default_value;
88 } else {
89 COND_PRINT(local_debug, "env::getProperty1 %s (default %s): %s", name.c_str(), default_value.c_str(), value.c_str());
90 return value;
91 }
92}
93
94bool environment::getBooleanProperty(const std::string & name, const bool default_value) noexcept {
95 const std::string value = getProperty(name);
96 if( 0 == value.length() ) {
97 COND_PRINT(local_debug, "env::getBooleanProperty %s: null -> %d (default)", name.c_str(), default_value);
98 return default_value;
99 } else {
100 const bool res = "true" == value;
101 COND_PRINT(local_debug, "env::getBooleanProperty %s (default %d): %d/%s", name.c_str(), default_value, res, value.c_str());
102 return res;
103 }
104}
105
106#include <climits>
107
108int32_t environment::getInt32Property(const std::string & name, const int32_t default_value,
109 const int32_t min_allowed, const int32_t max_allowed) noexcept
110{
111 const std::string value = getProperty(name);
112 if( 0 == value.length() ) {
113 COND_PRINT(local_debug, "env::getInt32Property %s: null -> %" PRId32 " (default)", name.c_str(), default_value);
114 return default_value;
115 } else {
116 int32_t res = default_value;
117 char *endptr = nullptr;
118 const long int res0 = strtol(value.c_str(), &endptr, 10);
119 if( *endptr == '\0' ) {
120 // string value completely valid
121 if( INT32_MIN <= res0 && res0 <= INT32_MAX ) {
122 // matching int32_t value range
123 const int32_t res1 = (int32_t)res0;
124 if( min_allowed <= res1 && res1 <= max_allowed ) {
125 // matching user value range
126 res = res1;
127 COND_PRINT(local_debug, "env::getInt32Property %s (default %" PRId32 "): %" PRId32 "/%s",
128 name.c_str(), default_value, res, value.c_str());
129 } else {
130 // invalid user value range
131 ERR_PRINT("env::getInt32Property %s: %" PRId32 "/%s (invalid user range [% " PRId32 "..%" PRId32 "]) -> %" PRId32 " (default)",
132 name.c_str(), res1, value.c_str(), min_allowed, max_allowed, res);
133 }
134 } else {
135 // invalid int32_t range
136 ERR_PRINT("env::getInt32Property %s: %" PRIu64 "/%s (invalid int32_t range) -> %" PRId32 " (default)",
137 name.c_str(), (uint64_t)res0, value.c_str(), res);
138 }
139 } else {
140 // string value not fully valid
141 ERR_PRINT("env::getInt32Property %s: %s (invalid string) -> %" PRId32 " (default)",
142 name.c_str(), value.c_str(), res);
143 }
144 return res;
145 }
146}
147
148uint32_t environment::getUint32Property(const std::string & name, const uint32_t default_value,
149 const uint32_t min_allowed, const uint32_t max_allowed) noexcept
150{
151 const std::string value = getProperty(name);
152 if( 0 == value.length() ) {
153 COND_PRINT(local_debug, "env::getUint32Property %s: null -> %" PRIu32 " (default)", name.c_str(), default_value);
154 return default_value;
155 } else {
156 uint32_t res = default_value;
157 char *endptr = nullptr;
158 unsigned long int res0 = strtoul(value.c_str(), &endptr, 10);
159 if( *endptr == '\0' ) {
160 // string value completely valid
161 if( res0 <= UINT32_MAX ) {
162 // matching uint32_t value range
163 const uint32_t res1 = (uint32_t)res0;
164 if( min_allowed <= res1 && res1 <= max_allowed ) {
165 // matching user value range
166 res = res1;
167 COND_PRINT(local_debug, "env::getUint32Property %s (default %" PRIu32 "): %" PRIu32 "/%s",
168 name.c_str(), default_value, res, value.c_str());
169 } else {
170 // invalid user value range
171 ERR_PRINT("env::getUint32Property %s: %" PRIu32 "/%s (invalid user range [% " PRIu32 "..%" PRIu32 "]) -> %" PRIu32 " (default)",
172 name.c_str(), res1, value.c_str(), min_allowed, max_allowed, res);
173 }
174 } else {
175 // invalid uint32_t range
176 ERR_PRINT("env::getUint32Property %s: %" PRIu64 "/%s (invalid uint32_t range) -> %" PRIu32 " (default)",
177 name.c_str(), (uint64_t)res0, value.c_str(), res);
178 }
179 } else {
180 // string value not fully valid
181 ERR_PRINT("env::getUint32Property %s: %s (invalid string) -> %" PRIu32 " (default)",
182 name.c_str(), value.c_str(), res);
183 }
184 return res;
185 }
186}
187
188fraction_i64 environment::getFractionProperty(const std::string & name, const fraction_i64& default_value,
189 const fraction_i64& min_allowed, const fraction_i64& max_allowed) noexcept {
190 const std::string value = getProperty(name);
191 if( 0 == value.length() ) {
192 COND_PRINT(local_debug, "env::getFractionProperty %s: null -> %s (default)", name.c_str(), default_value.to_string().c_str());
193 return default_value;
194 } else {
195 fraction_i64 result = default_value;
196 if( !to_fraction_i64(result, value, min_allowed, max_allowed) ) {
197 ERR_PRINT("env::getFractionProperty %s: value %s not valid or in range[%s .. %s] -> %s (default)",
198 name.c_str(), value.c_str(), min_allowed.to_string().c_str(), max_allowed.to_string().c_str(), default_value.to_string().c_str());
199 }
200 return result;
201 }
202}
203
204void environment::envSet(const std::string& prefix_domain, std::string basepair) noexcept {
205 trimInPlace(basepair);
206 if( basepair.length() > 0 ) {
207 size_t pos = 0, start = 0;
208 if( (pos = basepair.find('=', start)) != std::string::npos ) {
209 const size_t elem_len = pos-start; // excluding '='
210 std::string name = prefix_domain+"."+basepair.substr(start, elem_len);
211 std::string value = basepair.substr(pos+1, std::string::npos);
212 trimInPlace(name);
213 trimInPlace(value);
214 if( name.length() > 0 ) {
215 if( value.length() > 0 ) {
216 COND_PRINT(local_debug, "env::setProperty %s -> %s (explode)", name.c_str(), value.c_str());
217 ::setenv(name.c_str(), value.c_str(), 1 /* overwrite */);
218 } else {
219 COND_PRINT(local_debug, "env::setProperty %s -> true (explode default-1)", name.c_str());
220 ::setenv(name.c_str(), "true", 1 /* overwrite */);
221 }
222 }
223 } else {
224 const std::string name = prefix_domain+"."+basepair;
225 COND_PRINT(local_debug, "env::setProperty %s -> true (explode default-0)", name.c_str());
226 ::setenv(name.c_str(), "true", 1 /* overwrite */);
227 }
228 }
229}
230
231void environment::envExplodeProperties(const std::string& prefix_domain, const std::string& list) noexcept {
232 size_t pos = 0, start = 0;
233 while( (pos = list.find(',', start)) != std::string::npos ) {
234 const size_t elem_len = pos-start; // excluding ','
235 envSet(prefix_domain, list.substr(start, elem_len));
236 start = pos+1; // skip ','
237 }
238 const size_t elem_len = list.length()-start; // last one
239 if( elem_len > 0 ) {
240 envSet(prefix_domain, list.substr(start, elem_len));
241 }
242 COND_PRINT(local_debug, "env::setProperty %s -> true (explode default)", prefix_domain.c_str());
243 ::setenv(prefix_domain.c_str(), "true", 1 /* overwrite */);
244}
245
246bool environment::getExplodingPropertiesImpl(const std::string& root_prefix_domain, const std::string & prefix_domain) noexcept {
247 std::string value = environment::getProperty(prefix_domain, s_false);
248 if( s_false == value ) {
249 return false;
250 }
251 if( s_true == value ) {
252 return true;
253 }
254 if( root_prefix_domain.length() > 0 && root_prefix_domain+".debug" == prefix_domain ) {
255 local_debug = true;
256 }
257 envExplodeProperties(prefix_domain, value);
258 return true;
259}
260
261environment::environment(const std::string & root_prefix_domain_) noexcept
262: root_prefix_domain(root_prefix_domain_),
263 debug( getExplodingPropertiesImpl(root_prefix_domain_, root_prefix_domain_+".debug") ),
264 debug_jni( getBooleanProperty(root_prefix_domain_+".debug.jni", false) ),
265 verbose( getExplodingPropertiesImpl(root_prefix_domain_, root_prefix_domain_+".verbose") || environment::debug )
266{
267}
static std::string getProperty(const std::string &name) noexcept
Returns the value of the environment's variable 'name'.
Definition: environment.cpp:60
const bool debug
Debug logging enabled or disabled.
static int32_t getInt32Property(const std::string &name, const int32_t default_value, const int32_t min_allowed=INT32_MIN, const int32_t max_allowed=INT32_MAX) noexcept
Returns the int32_t value of the environment's variable 'name', or the 'default_value' if the environ...
static fraction_i64 getFractionProperty(const std::string &name, const fraction_i64 &default_value, const fraction_i64 &min_allowed, const fraction_i64 &max_allowed) noexcept
Returns the fraction_i64 value of the environment's variable 'name' in format <num>/<denom>,...
static bool getBooleanProperty(const std::string &name, const bool default_value) noexcept
Returns the boolean value of the environment's variable 'name', or the 'default_value' if the environ...
Definition: environment.cpp:94
static const fraction_timespec startupTimeMonotonic
Module startup time t0 in monotonic time using high precision and range of fraction_timespec.
Definition: environment.hpp:91
static const uint64_t startupTimeMilliseconds
Module startup time t0 in monotonic time in milliseconds.
Definition: environment.hpp:96
static uint32_t getUint32Property(const std::string &name, const uint32_t default_value, const uint32_t min_allowed=0, const uint32_t max_allowed=UINT32_MAX) noexcept
Returns the uint32_t value of the environment's variable 'name', or the 'default_value' if the enviro...
static void set_terminating() noexcept
Optional path to signal early termination, i.e.
Definition: environment.cpp:50
#define ERR_PRINT(...)
Use for unconditional error messages, prefix '[elapsed_time] Error @ FILE:LINE FUNC: '.
Definition: debug.hpp:109
#define COND_PRINT(C,...)
Use for conditional plain messages, prefix '[elapsed_time] '.
Definition: debug.hpp:151
static const std::string s_false("false")
static const std::string s_true("true")
static jau::sc_atomic_bool is_terminating_
Definition: environment.cpp:40
static bool atexit_cockie
Definition: environment.cpp:48
static void at_exit_func() noexcept
Definition: environment.cpp:42
static int install_atexit() noexcept
Definition: environment.cpp:45
@ verbose
Enable verbosity mode, potentially used by a path_visitor implementation like remove().
bool to_fraction_i64(fraction_i64 &result, const std::string &value, const fraction_i64 &min_allowed, const fraction_i64 &max_allowed) noexcept
Stores the fraction_i64 value of the given string value in format <num>/<denom>, which may contain wh...
fraction_timespec getMonotonicTime() noexcept
Returns current monotonic time since Unix Epoch 00:00:00 UTC on 1970-01-01.
Definition: basic_types.cpp:52
void trimInPlace(std::string &s) noexcept
trim in place
__pack(...): Produces MSVC, clang and gcc compatible lead-in and -out macros.
Definition: backtrace.hpp:32
uint64_t getCurrentMilliseconds() noexcept
Returns current monotonic time in milliseconds.
Definition: basic_types.cpp:64
Timespec structure using int64_t for its components in analogy to struct timespec_t on 64-bit platfor...
CXX_ALWAYS_INLINE _Tp load() const noexcept