jaulib v1.4.1
Jau Support Library (C++, Java, ..)
Loading...
Searching...
No Matches
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 <algorithm>
27#include <cstdint>
28#include <cstdio>
29#include <cstdlib>
30#include <cstring>
31#include <memory>
32#include <string>
33#include <vector>
34
35#include <jau/debug.hpp>
36#include <jau/environment.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(), '.', '_'); // NOLINT(modernize-use-ranges)
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 const std::string value = getProperty(name);
111 if ( 0 == value.length() ) {
112 COND_PRINT(local_debug, "env::getInt32Property %s: null -> %" PRId32 " (default)", name.c_str(), default_value);
113 return default_value;
114 } else {
115 int32_t res = default_value;
116 char* endptr = nullptr;
117 const long int res0 = strtol(value.c_str(), &endptr, 10);
118 if ( *endptr == '\0' ) {
119 // string value completely valid
120 if ( INT32_MIN <= res0 && res0 <= INT32_MAX ) {
121 // matching int32_t value range
122 const int32_t res1 = (int32_t)res0;
123 if ( min_allowed <= res1 && res1 <= max_allowed ) {
124 // matching user value range
125 res = res1;
126 COND_PRINT(local_debug, "env::getInt32Property %s (default %" PRId32 "): %" PRId32 "/%s",
127 name.c_str(), default_value, res, value.c_str());
128 } else {
129 // invalid user value range
130 ERR_PRINT("env::getInt32Property %s: %" PRId32 "/%s (invalid user range [% " PRId32 "..%" PRId32 "]) -> %" PRId32 " (default)",
131 name.c_str(), res1, value.c_str(), min_allowed, max_allowed, res);
132 }
133 } else {
134 // invalid int32_t range
135 ERR_PRINT("env::getInt32Property %s: %" PRIu64 "/%s (invalid int32_t range) -> %" PRId32 " (default)",
136 name.c_str(), (uint64_t)res0, value.c_str(), res);
137 }
138 } else {
139 // string value not fully valid
140 ERR_PRINT("env::getInt32Property %s: %s (invalid string) -> %" PRId32 " (default)",
141 name.c_str(), value.c_str(), res);
142 }
143 return res;
144 }
145}
146
147uint32_t environment::getUint32Property(const std::string& name, const uint32_t default_value,
148 const uint32_t min_allowed, const uint32_t max_allowed) noexcept {
149 const std::string value = getProperty(name);
150 if ( 0 == value.length() ) {
151 COND_PRINT(local_debug, "env::getUint32Property %s: null -> %" PRIu32 " (default)", name.c_str(), default_value);
152 return default_value;
153 } else {
154 uint32_t res = default_value;
155 char* endptr = nullptr;
156 unsigned long int res0 = strtoul(value.c_str(), &endptr, 10);
157 if ( *endptr == '\0' ) {
158 // string value completely valid
159 if ( res0 <= UINT32_MAX ) {
160 // matching uint32_t value range
161 const uint32_t res1 = (uint32_t)res0;
162 if ( min_allowed <= res1 && res1 <= max_allowed ) {
163 // matching user value range
164 res = res1;
165 COND_PRINT(local_debug, "env::getUint32Property %s (default %" PRIu32 "): %" PRIu32 "/%s",
166 name.c_str(), default_value, res, value.c_str());
167 } else {
168 // invalid user value range
169 ERR_PRINT("env::getUint32Property %s: %" PRIu32 "/%s (invalid user range [% " PRIu32 "..%" PRIu32 "]) -> %" PRIu32 " (default)",
170 name.c_str(), res1, value.c_str(), min_allowed, max_allowed, res);
171 }
172 } else {
173 // invalid uint32_t range
174 ERR_PRINT("env::getUint32Property %s: %" PRIu64 "/%s (invalid uint32_t range) -> %" PRIu32 " (default)",
175 name.c_str(), (uint64_t)res0, value.c_str(), res);
176 }
177 } else {
178 // string value not fully valid
179 ERR_PRINT("env::getUint32Property %s: %s (invalid string) -> %" PRIu32 " (default)",
180 name.c_str(), value.c_str(), res);
181 }
182 return res;
183 }
184}
185
186fraction_i64 environment::getFractionProperty(const std::string& name, const fraction_i64& default_value,
187 const fraction_i64& min_allowed, const fraction_i64& max_allowed) noexcept {
188 const std::string value = getProperty(name);
189 if ( 0 == value.length() ) {
190 COND_PRINT(local_debug, "env::getFractionProperty %s: null -> %s (default)", name.c_str(), default_value.toString().c_str());
191 return default_value;
192 } else {
193 auto [result, consumed, complete] = to_fraction_i64(value, min_allowed, max_allowed);
194 if ( !complete ) {
195 ERR_PRINT("env::getFractionProperty %s: value %s not valid or in range[%s .. %s] -> %s (default)",
196 name.c_str(), value.c_str(), min_allowed.toString().c_str(), max_allowed.toString().c_str(), default_value.toString().c_str());
197 }
198 return result;
199 }
200}
201
202void environment::envSet(const std::string& prefix_domain, std::string basepair) noexcept {
203 trimInPlace(basepair);
204 if ( basepair.length() > 0 ) {
205 size_t pos = 0, start = 0;
206 if ( (pos = basepair.find('=', start)) != std::string::npos ) {
207 const size_t elem_len = pos - start; // excluding '='
208 std::string name = prefix_domain + "." + basepair.substr(start, elem_len);
209 std::string value = basepair.substr(pos + 1, std::string::npos);
212 if ( name.length() > 0 ) {
213 if ( value.length() > 0 ) {
214 COND_PRINT(local_debug, "env::setProperty %s -> %s (explode)", name.c_str(), value.c_str());
215 ::setenv(name.c_str(), value.c_str(), 1 /* overwrite */);
216 } else {
217 COND_PRINT(local_debug, "env::setProperty %s -> true (explode default-1)", name.c_str());
218 ::setenv(name.c_str(), "true", 1 /* overwrite */);
219 }
220 }
221 } else {
222 const std::string name = prefix_domain + "." + basepair;
223 COND_PRINT(local_debug, "env::setProperty %s -> true (explode default-0)", name.c_str());
224 ::setenv(name.c_str(), "true", 1 /* overwrite */);
225 }
226 }
227}
228
229void environment::envExplodeProperties(const std::string& prefix_domain, const std::string& list) noexcept {
230 size_t pos = 0, start = 0;
231 while ( (pos = list.find(',', start)) != std::string::npos ) {
232 const size_t elem_len = pos - start; // excluding ','
233 envSet(prefix_domain, list.substr(start, elem_len));
234 start = pos + 1; // skip ','
235 }
236 const size_t elem_len = list.length() - start; // last one
237 if ( elem_len > 0 ) {
238 envSet(prefix_domain, list.substr(start, elem_len));
239 }
240 COND_PRINT(local_debug, "env::setProperty %s -> true (explode default)", prefix_domain.c_str());
241 ::setenv(prefix_domain.c_str(), "true", 1 /* overwrite */);
242}
243
244bool environment::getExplodingPropertiesImpl(const std::string& root_prefix_domain, const std::string& prefix_domain) noexcept {
245 std::string value = environment::getProperty(prefix_domain, s_false);
246 if ( s_false == value ) {
247 return false;
248 }
249 if ( s_true == value ) {
250 return true;
251 }
252 if ( root_prefix_domain.length() > 0 && root_prefix_domain + ".debug" == prefix_domain ) {
253 local_debug = true;
254 }
255 envExplodeProperties(prefix_domain, value);
256 return true;
257}
258
259environment::environment(const std::string& root_prefix_domain_) noexcept
260: root_prefix_domain(root_prefix_domain_),
261 debug(getExplodingPropertiesImpl(root_prefix_domain_, root_prefix_domain_ + ".debug")),
262 debug_jni(getBooleanProperty(root_prefix_domain_ + ".debug.jni", false)),
263 verbose(getExplodingPropertiesImpl(root_prefix_domain_, root_prefix_domain_ + ".verbose") || environment::debug) {
264}
static std::string getProperty(const std::string &name) noexcept
Returns the value of the environment's variable 'name'.
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...
static const fraction_timespec startupTimeMonotonic
Module startup time t0 in monotonic time using high precision and range of fraction_timespec.
static const uint64_t startupTimeMilliseconds
Module startup time t0 in monotonic time in milliseconds.
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.
static bool is_terminating() noexcept
Returns true if program is terminating as detected via atexit() callback or set_terminating() has bee...
#define ERR_PRINT(...)
Use for unconditional error messages, prefix '[elapsed_time] Error @ FILE:LINE FUNC: '.
Definition debug.hpp:122
#define COND_PRINT(C,...)
Use for conditional plain messages, prefix '[elapsed_time] '.
Definition debug.hpp:162
static const std::string s_false("false")
static const std::string s_true("true")
static jau::sc_atomic_bool is_terminating_
static bool atexit_cockie
static void at_exit_func() noexcept
static int install_atexit() noexcept
ordered_atomic< bool, std::memory_order_seq_cst > sc_atomic_bool
SC atomic integral scalar boolean.
constexpr bool value(const Bool rhs) noexcept
constexpr std::string_view name(const Bool v) noexcept
@ verbose
Enable verbosity mode, potentially used by a path_visitor implementation like remove().
fraction_timespec getMonotonicTime() noexcept
Returns current monotonic time since Unix Epoch 00:00:00 UTC on 1970-01-01.
FracI64SizeBoolTuple to_fraction_i64(const std::string &value, const fraction_i64 &min_allowed, const fraction_i64 &max_allowed) noexcept
Returns the fraction_i64 of the given string in format <num>/<denom>, which may contain whitespace.
fraction< int64_t > fraction_i64
fraction using int64_t as integral type
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.
Timespec structure using int64_t for its components in analogy to struct timespec_t on 64-bit platfor...