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