CppCommon 1.0.5.0
C++ Common Library
Loading...
Searching...
No Matches
environment.cpp
Go to the documentation of this file.
1
10
11#include "string/encoding.h"
12#include "utility/resource.h"
13
14#if defined(__GNUC__)
15#pragma GCC diagnostic push
16#pragma GCC diagnostic ignored "-Wdeprecated-declarations" // GCC: warning: 'wstring_convert' is deprecated
17#endif
18
19#include <codecvt>
20#include <cstring>
21#include <locale>
22#include <sstream>
23
24#if defined(__APPLE__)
25#include <sys/sysctl.h>
26extern char **environ;
27#elif defined(unix) || defined(__unix) || defined(__unix__)
28#include <sys/stat.h>
29#include <sys/utsname.h>
30#include <stdlib.h>
31#include <cstring>
32#include <fstream>
33#include <regex>
34extern char **environ;
35#endif
36#if defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
37#include <windows.h>
38#include <winternl.h>
39#define STATUS_SUCCESS 0x00000000
40#include <map>
41#include <vector>
42#endif
43
44namespace CppCommon {
45
47{
48 return !Is64BitOS();
49}
50
52{
53#if defined(__APPLE__)
54 return true;
55#elif defined(linux) || defined(__linux) || defined(__linux__)
56 struct stat buffer;
57 return (stat("/lib64/ld-linux-x86-64.so.2", &buffer) == 0);
58#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
59#if defined(_WIN64)
60 return true;
61#elif defined(_WIN32) || defined(__CYGWIN__)
62 BOOL bWow64Process = FALSE;
63 return IsWow64Process(GetCurrentProcess(), &bWow64Process) && bWow64Process;
64#endif
65#else
66 #error Unsupported platform
67#endif
68}
69
71{
72 return !Is64BitProcess();
73}
74
76{
77#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
78#if defined(__x86_64__) || defined(__amd64__) || defined(__aarch64__) || defined(__ia64__) || defined(__ppc64__)
79 return true;
80#else
81 return false;
82#endif
83#elif defined(_WIN32) || defined(_WIN64)
84#if defined(_WIN64)
85 return true;
86#elif defined(_WIN32)
87 return false;
88#endif
89#else
90 #error Unsupported platform
91#endif
92}
93
95{
96 return !IsRelease();
97}
98
100{
101#if defined(NDEBUG)
102 return true;
103#else
104 return false;
105#endif
106}
107
109{
110 char16_t test = 0x0102;
111 return ((char*)&test)[0] == 0x01;
112}
113
115{
116 char16_t test = 0x0102;
117 return ((char*)&test)[0] == 0x02;
118}
119
121{
122#if defined(__APPLE__)
123 char result[1024];
124 size_t size = sizeof(result);
125 if (sysctlbyname("kern.osrelease", result, &size, nullptr, 0) == 0)
126 return result;
127
128 return "<apple>";
129#elif defined(__CYGWIN__)
130 struct utsname name;
131 if (uname(&name) == 0)
132 {
133 std::string result(name.sysname);
134 result.append(" ");
135 result.append(name.release);
136 result.append(" ");
137 result.append(name.version);
138 return result;
139 }
140
141 return "<cygwin>";
142#elif defined(linux) || defined(__linux) || defined(__linux__)
143 static std::regex pattern("DISTRIB_DESCRIPTION=\"(.*)\"");
144
145 std::string line;
146 std::ifstream stream("/etc/lsb-release");
147 while (getline(stream, line))
148 {
149 std::smatch matches;
150 if (std::regex_match(line, matches, pattern))
151 return matches[1];
152 }
153
154 return "<linux>";
155#elif defined(_WIN32) || defined(_WIN64)
156 static NTSTATUS(__stdcall *RtlGetVersion)(OUT PRTL_OSVERSIONINFOEXW lpVersionInformation) = (NTSTATUS(__stdcall*)(PRTL_OSVERSIONINFOEXW))GetProcAddress(GetModuleHandle("ntdll.dll"), "RtlGetVersion");
157 static void(__stdcall *GetNativeSystemInfo)(OUT LPSYSTEM_INFO lpSystemInfo) = (void(__stdcall*)(LPSYSTEM_INFO))GetProcAddress(GetModuleHandle("kernel32.dll"), "GetNativeSystemInfo");
158 static BOOL(__stdcall *GetProductInfo)(IN DWORD dwOSMajorVersion, IN DWORD dwOSMinorVersion, IN DWORD dwSpMajorVersion, IN DWORD dwSpMinorVersion, OUT PDWORD pdwReturnedProductType) = (BOOL(__stdcall*)(DWORD, DWORD, DWORD, DWORD, PDWORD))GetProcAddress(GetModuleHandle("kernel32.dll"), "GetProductInfo");
159
160 OSVERSIONINFOEXW osvi;
161 ZeroMemory(&osvi, sizeof(OSVERSIONINFOEXW));
162 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW);
163
164 if (RtlGetVersion != nullptr)
165 {
166 NTSTATUS ntRtlGetVersionStatus = RtlGetVersion(&osvi);
167 if (ntRtlGetVersionStatus != STATUS_SUCCESS)
168 return "<windows>";
169 }
170 else
171 {
172#if defined(_MSC_VER)
173#pragma warning(push)
174#pragma warning(disable: 4996) // C4996: 'function': was declared deprecated
175#endif
176 BOOL bOsVersionInfoEx = GetVersionExW((OSVERSIONINFOW*)&osvi);
177 if (bOsVersionInfoEx == 0)
178 return "<windows>";
179#if defined(_MSC_VER)
180#pragma warning(pop)
181#endif
182 }
183
184 SYSTEM_INFO si;
185 ZeroMemory(&si, sizeof(SYSTEM_INFO));
186
187 if (GetNativeSystemInfo != nullptr)
188 GetNativeSystemInfo(&si);
189 else
190 GetSystemInfo(&si);
191
192 if ((osvi.dwPlatformId != VER_PLATFORM_WIN32_NT) || (osvi.dwMajorVersion <= 4))
193 {
194 return "<windows>";
195 }
196
197 std::stringstream os;
198
199 // Windows version
200 os << "Microsoft ";
201 if (osvi.dwMajorVersion >= 6)
202 {
203 if (osvi.dwMajorVersion == 10)
204 {
205 if (osvi.dwMinorVersion == 0)
206 {
207 if (osvi.wProductType == VER_NT_WORKSTATION)
208 {
209 if (osvi.dwBuildNumber >= 22000)
210 os << "Windows 11 ";
211 else
212 os << "Windows 10 ";
213 }
214 else
215 {
216 if (osvi.dwBuildNumber >= 20348)
217 os << "Windows Server 2022 ";
218 else if (osvi.dwBuildNumber >= 17763)
219 os << "Windows Server 2019 ";
220 else
221 os << "Windows Server 2016 ";
222 }
223 }
224 }
225 else if (osvi.dwMajorVersion == 6)
226 {
227 if (osvi.dwMinorVersion == 3)
228 {
229 if (osvi.wProductType == VER_NT_WORKSTATION)
230 os << "Windows 8.1 ";
231 else
232 os << "Windows Server 2012 R2 ";
233 }
234 else if (osvi.dwMinorVersion == 2)
235 {
236 if (osvi.wProductType == VER_NT_WORKSTATION)
237 os << "Windows 8 ";
238 else
239 os << "Windows Server 2012 ";
240 }
241 else if (osvi.dwMinorVersion == 1)
242 {
243 if (osvi.wProductType == VER_NT_WORKSTATION)
244 os << "Windows 7 ";
245 else
246 os << "Windows Server 2008 R2 ";
247 }
248 else if (osvi.dwMinorVersion == 0)
249 {
250 if (osvi.wProductType == VER_NT_WORKSTATION)
251 os << "Windows Vista ";
252 else
253 os << "Windows Server 2008 ";
254 }
255 }
256
257 DWORD dwType;
258 if ((GetProductInfo != nullptr) && GetProductInfo(osvi.dwMajorVersion, osvi.dwMinorVersion, 0, 0, &dwType))
259 {
260 switch (dwType)
261 {
262 case PRODUCT_ULTIMATE:
263 os << "Ultimate Edition";
264 break;
265 case PRODUCT_PROFESSIONAL:
266 os << "Professional";
267 break;
268 case PRODUCT_HOME_PREMIUM:
269 os << "Home Premium Edition";
270 break;
271 case PRODUCT_HOME_BASIC:
272 os << "Home Basic Edition";
273 break;
274 case PRODUCT_ENTERPRISE:
275 os << "Enterprise Edition";
276 break;
277 case PRODUCT_BUSINESS:
278 os << "Business Edition";
279 break;
280 case PRODUCT_STARTER:
281 os << "Starter Edition";
282 break;
283 case PRODUCT_CLUSTER_SERVER:
284 os << "Cluster Server Edition";
285 break;
286 case PRODUCT_DATACENTER_SERVER:
287 os << "Datacenter Edition";
288 break;
289 case PRODUCT_DATACENTER_SERVER_CORE:
290 os << "Datacenter Edition (core installation)";
291 break;
292 case PRODUCT_ENTERPRISE_SERVER:
293 os << "Enterprise Edition";
294 break;
295 case PRODUCT_ENTERPRISE_SERVER_CORE:
296 os << "Enterprise Edition (core installation)";
297 break;
298 case PRODUCT_ENTERPRISE_SERVER_IA64:
299 os << "Enterprise Edition for Itanium-based Systems";
300 break;
301 case PRODUCT_SMALLBUSINESS_SERVER:
302 os << "Small Business Server";
303 break;
304 case PRODUCT_SMALLBUSINESS_SERVER_PREMIUM:
305 os << "Small Business Server Premium Edition";
306 break;
307 case PRODUCT_STANDARD_SERVER:
308 os << "Standard Edition";
309 break;
310 case PRODUCT_STANDARD_SERVER_CORE:
311 os << "Standard Edition (core installation)";
312 break;
313 case PRODUCT_WEB_SERVER:
314 os << "Web Server Edition";
315 break;
316 }
317 }
318 }
319 else if ((osvi.dwMajorVersion == 5) && (osvi.dwMinorVersion == 2))
320 {
321 if (GetSystemMetrics(SM_SERVERR2))
322 os << "Windows Server 2003 R2, ";
323 else if (osvi.wSuiteMask & VER_SUITE_STORAGE_SERVER)
324 os << "Windows Storage Server 2003";
325 else if (osvi.wSuiteMask & VER_SUITE_WH_SERVER)
326 os << "Windows Home Server";
327 else if ((osvi.wProductType == VER_NT_WORKSTATION) && (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64))
328 os << "Windows XP Professional x64 Edition";
329 else
330 os << "Windows Server 2003, ";
331 if (osvi.wProductType != VER_NT_WORKSTATION)
332 {
333 if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64)
334 {
335 if (osvi.wSuiteMask & VER_SUITE_DATACENTER)
336 os << "Datacenter Edition for Itanium-based Systems";
337 else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE)
338 os << "Enterprise Edition for Itanium-based Systems";
339 }
340 else if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
341 {
342 if (osvi.wSuiteMask & VER_SUITE_DATACENTER)
343 os << "Datacenter x64 Edition";
344 else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE)
345 os << "Enterprise x64 Edition";
346 else
347 os << "Standard x64 Edition";
348 }
349 else
350 {
351 if (osvi.wSuiteMask & VER_SUITE_COMPUTE_SERVER)
352 os << "Compute Cluster Edition";
353 else if (osvi.wSuiteMask & VER_SUITE_DATACENTER)
354 os << "Datacenter Edition";
355 else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE)
356 os << "Enterprise Edition";
357 else if (osvi.wSuiteMask & VER_SUITE_BLADE)
358 os << "Web Edition";
359 else
360 os << "Standard Edition";
361 }
362 }
363 }
364 else if ((osvi.dwMajorVersion == 5) && (osvi.dwMinorVersion == 1))
365 {
366 os << "Windows XP ";
367 if (osvi.wSuiteMask & VER_SUITE_PERSONAL)
368 os << "Home Edition";
369 else
370 os << "Professional";
371 }
372 else if ((osvi.dwMajorVersion == 5) && (osvi.dwMinorVersion == 0))
373 {
374 os << "Windows 2000 ";
375 if (osvi.wProductType == VER_NT_WORKSTATION)
376 os << "Professional";
377 else
378 {
379 if (osvi.wSuiteMask & VER_SUITE_DATACENTER)
380 os << "Datacenter Server";
381 else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE)
382 os << "Advanced Server";
383 else
384 os << "Server";
385 }
386 }
387
388 // Windows Service Pack version
389 std::wstring sp_version(osvi.szCSDVersion);
390 std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> convert;
391 if (std::wcslen(osvi.szCSDVersion) > 0)
392 os << " " << convert.to_bytes(sp_version.data(), sp_version.data() + sp_version.size());
393
394 // Windows build
395 os << " (build " << osvi.dwBuildNumber << ")";
396
397 // Windows architecture
398 if (osvi.dwMajorVersion >= 6)
399 {
400 if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL)
401 os << ", 32-bit";
402 else if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
403 os << ", 64-bit";
404 else if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64)
405 os << ", Intel Itanium";
406 else if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_ARM)
407 os << ", ARM";
408#if !defined(__MINGW32__) && !defined(__MINGW64__)
409 else if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_ARM64)
410 os << ", ARM64";
411#endif
412 }
413
414 return os.str();
415#else
416 #error Unsupported platform
417#endif
418}
419
421{
422#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
423 return "\n";
424#elif defined(_WIN32) || defined(_WIN64)
425 return "\r\n";
426#else
427 #error Unsupported platform
428#endif
429}
430
432{
433 return "\n";
434}
435
437{
438 return "\r\n";
439}
440
441std::map<std::string, std::string> Environment::envars()
442{
443 std::map<std::string, std::string> result;
444#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
445 for (char** envars = environ; *envars; ++envars)
446 {
447 char* envar = *envars;
448 int offset = (envar[0] == '=') ? 1 : 0;
449 char* separator = std::strchr(envar + offset, '=');
450 std::string key(envar, separator - envar);
451
452 char* pvalue = separator + 1;
453 std::string value(pvalue);
454
455 result[key] = value;
456 }
457#elif defined(_WIN32) || defined(_WIN64)
458 // Smart resource cleaner pattern
459 auto envars = resource(GetEnvironmentStringsW(), [](wchar_t* penv) { FreeEnvironmentStringsW(penv); });
460
461 for (const wchar_t* envar = envars.get(); *envar != L'\0'; )
462 {
463 int offset = (envar[0] == '=') ? 1 : 0;
464 const wchar_t* separator = std::wcschr(envar + offset, L'=');
465 std::wstring key(envar, separator - envar);
466
467 const wchar_t* pvalue = separator + 1;
468 std::wstring value(pvalue);
469
470 result[Encoding::ToUTF8(key)] = Encoding::ToUTF8(value);
471
472 envar = pvalue + value.size() + 1;
473 }
474#endif
475 return result;
476}
477
478std::string Environment::GetEnvar(const std::string name)
479{
480#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
481 char* envar = getenv(name.c_str());
482 return (envar != nullptr) ? std::string(envar) : std::string();
483#elif defined(_WIN32) || defined(_WIN64)
484 std::wstring wname = Encoding::FromUTF8(name);
485 std::vector<wchar_t> buffer(MAX_PATH);
486
487 DWORD size = GetEnvironmentVariableW(wname.c_str(), buffer.data(), (DWORD)buffer.size());
488 if (size > buffer.size())
489 {
490 buffer.resize(size);
491 size = GetEnvironmentVariableW(wname.c_str(), buffer.data(), (DWORD)buffer.size());
492 }
493
494 return (size > 0) ? Encoding::ToUTF8(std::wstring(buffer.data(), size)) : std::string();
495#endif
496}
497
498void Environment::SetEnvar(const std::string name, const std::string value)
499{
500#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
501 if (setenv(name.c_str(), value.c_str(), 1) != 0)
502 throwex SystemException("Cannot set environment variable - " + name);
503#elif defined(_WIN32) || defined(_WIN64)
504 if (!SetEnvironmentVariableW(Encoding::FromUTF8(name).c_str(), Encoding::FromUTF8(value).c_str()))
505 throwex SystemException("Cannot set environment variable - " + name);
506#endif
507}
508
509void Environment::ClearEnvar(const std::string name)
510{
511#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
512 if (unsetenv(name.c_str()) != 0)
513 throwex SystemException("Cannot clear environment variable - " + name);
514#elif defined(_WIN32) || defined(_WIN64)
515 if (!SetEnvironmentVariableW(Encoding::FromUTF8(name).c_str(), nullptr))
516 throwex SystemException("Cannot clear environment variable - " + name);
517#endif
518}
519
520} // namespace CppCommon
521
522#if defined(__GNUC__)
523#pragma GCC diagnostic pop
524#endif
static std::wstring FromUTF8(std::string_view str)
Convert UTF-8 encoded string to system wide-string.
Definition encoding.cpp:43
static std::string ToUTF8(std::wstring_view wstr)
Convert system wide-string to UTF-8 encoded string.
Definition encoding.cpp:29
static bool IsBigEndian()
Is big-endian system?
static bool Is64BitProcess()
Is 64-bit running process?
static std::string UnixEndLine()
Get Unix text end line separator.
static bool Is64BitOS()
Is 64-bit OS?
static bool Is32BitProcess()
Is 32-bit running process?
static void SetEnvar(const std::string name, const std::string value)
Set environment variable value by the given name.
static bool IsRelease()
Is compiled in release mode?
static void ClearEnvar(const std::string name)
Clear environment variable by the given name.
static std::map< std::string, std::string > envars()
Get all environment variables.
static bool IsDebug()
Is compiled in debug mode?
static std::string OSVersion()
Get OS version string.
static bool Is32BitOS()
Is 32-bit OS?
static bool IsLittleEndian()
Is little-endian system?
static std::string EndLine()
Get text end line separator.
static std::string WindowsEndLine()
Get Windows text end line separator.
static std::string GetEnvar(const std::string name)
Get environment variable value by the given name.
System exception.
Definition exceptions.h:107
Encoding utilities definition.
Environment management definition.
#define throwex
Throw extended exception macro.
Definition exceptions.h:23
C++ Common project definitions.
auto resource(T handle, TCleaner cleaner)
Resource smart cleaner pattern.
Definition resource.h:43
Resource smart cleaner pattern definition.