CppCommon  1.0.4.1
C++ Common Library
environment.cpp
Go to the documentation of this file.
1 
9 #include "system/environment.h"
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>
21 extern 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>
29 extern 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 
39 namespace 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 
415 std::string Environment::EndLine()
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 
436 std::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 
473 std::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 
493 void 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 
504 void 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:33
static std::string ToUTF8(std::wstring_view wstr)
Convert system wide-string to UTF-8 encoded string.
Definition: encoding.cpp:19
static bool IsBigEndian()
Is big-endian system?
static bool Is64BitProcess()
Is 64-bit running process?
Definition: environment.cpp:70
static std::string UnixEndLine()
Get Unix text end line separator.
static bool Is64BitOS()
Is 64-bit OS?
Definition: environment.cpp:46
static bool Is32BitProcess()
Is 32-bit running process?
Definition: environment.cpp:65
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?
Definition: environment.cpp:94
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?
Definition: environment.cpp:89
static std::string OSVersion()
Get OS version string.
static bool Is32BitOS()
Is 32-bit OS?
Definition: environment.cpp:41
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.
Definition: token_bucket.h:15
auto resource(T handle, TCleaner cleaner)
Resource smart cleaner pattern.
Definition: resource.h:43
Resource smart cleaner pattern definition.