mirror of
https://github.com/VCMP-SqMod/SqMod.git
synced 2024-11-14 03:37:16 +01:00
1209 lines
39 KiB
C++
1209 lines
39 KiB
C++
// ------------------------------------------------------------------------------------------------
|
|
#include "Library/System/Environment.hpp"
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
#include <cctype>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <utility>
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
#ifdef SQMOD_OS_WINDOWS
|
|
#include <windows.h>
|
|
#include <shlobj.h>
|
|
#else
|
|
#include <linux/limits.h>
|
|
#include <sys/utsname.h>
|
|
#include <unistd.h>
|
|
#include <pwd.h>
|
|
#endif
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
namespace SqMod {
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
#ifdef SQMOD_OS_WINDOWS
|
|
// Maximum path size in characters
|
|
#define SQMOD_MAX_PATH (sizeof(TCHAR) * MAX_PATH)
|
|
// Character to be used when working with path
|
|
typedef TCHAR PChar;
|
|
#else
|
|
// Maximum path size in characters
|
|
#define SQMOD_MAX_PATH (PATH_MAX)
|
|
// Character to be used when working with path
|
|
typedef CharT PChar;
|
|
#endif // SQMOD_OS_WINDOWS
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void SysEnv::Get(Buffer & b, CCStr name, CCStr fallback)
|
|
{
|
|
// Make sure the requested variable name is valid
|
|
if (name && *name != 0)
|
|
{
|
|
// Is there a buffer to work with?
|
|
if (!b)
|
|
{
|
|
// Acquire a moderately sized buffer
|
|
b = Buffer(128);
|
|
}
|
|
#ifdef SQMOD_OS_WINDOWS
|
|
// Retrieve the variable contents into the buffer that we have
|
|
DWORD len = GetEnvironmentVariableA(name, &b.Cursor(), b.Remaining());
|
|
// If the returned length is 0 then the variable doesn't exist
|
|
if (!len)
|
|
{
|
|
// Write the fall-back value into the buffer instead
|
|
len = b.WriteS(b.Position(), fallback);
|
|
}
|
|
// Did we have enough space left in the buffer?
|
|
else if (len > b.Remaining())
|
|
{
|
|
// Acquire a new buffer with a more appropriate capacity this time
|
|
b.Grow(len - b.Remaining() + 2);
|
|
// Attempt to retrieve the variable contents one more time
|
|
len = GetEnvironmentVariableA(name, &b.Cursor(), b.Remaining());
|
|
}
|
|
// Move the edit cursor to the end of the appended data
|
|
b.Advance(len);
|
|
#else
|
|
// Retrieve the pointer to the variable contents
|
|
CSStr val = getenv(name);
|
|
// If the returned pointer is null then the variable doesn't exist
|
|
if (!val)
|
|
{
|
|
// Write the fall-back value into the buffer instead
|
|
b.AppendS(fallback);
|
|
}
|
|
else
|
|
{
|
|
// Write the variable contents to the buffer
|
|
b.AppendS(val);
|
|
}
|
|
#endif
|
|
}
|
|
// Make sure that whatever string is in the buffer is null terminated
|
|
b.Cursor() = '\0';
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
bool SysEnv::Has(CCStr name)
|
|
{
|
|
#ifdef SQMOD_OS_WINDOWS
|
|
return (GetEnvironmentVariableA(name, nullptr, 0) > 0);
|
|
#else
|
|
return (getenv(name) != 0);
|
|
#endif
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
bool SysEnv::Has(const String & name)
|
|
{
|
|
#ifdef SQMOD_OS_WINDOWS
|
|
return (GetEnvironmentVariableA(name.c_str(), nullptr, 0) > 0);
|
|
#else
|
|
return (getenv(name.c_str()) != 0);
|
|
#endif
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Buffer SysEnv::Get(CCStr name, CCStr fallback)
|
|
{
|
|
// Allocate a moderately sized buffer
|
|
Buffer b(128);
|
|
// Forward the call to the shared function
|
|
Get(b, name, fallback);
|
|
// Return ownership of the buffer
|
|
return std::move(b);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
bool SysEnv::Set(CCStr name, CCStr value)
|
|
{
|
|
#ifdef SQMOD_OS_WINDOWS
|
|
// Set the specified environment variable and return the result
|
|
return (SetEnvironmentVariableA(name, value) != 0);
|
|
#else
|
|
// Allocated a moderately sized buffer
|
|
Buffer b(256);
|
|
// Generate the necessary set command
|
|
b.WriteF(0, "%s=%s", name, value);
|
|
// Set the resulted environment variable and return the result
|
|
return (putenv(b.Data()) == 0);
|
|
#endif
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
bool SysEnv::Set(const String & name, const String & value)
|
|
{
|
|
#ifdef SQMOD_OS_WINDOWS
|
|
// Set the specified environment variable and return the result
|
|
return (SetEnvironmentVariableA(name.c_str(), value.c_str()) != 0);
|
|
#else
|
|
// Obtain a temporary buffer capable of holding the set command
|
|
Buffer b(name.size() + value.size() + 2);
|
|
// Generate the necessary set command
|
|
b.WriteF(0, "%s=%s", name.c_str(), value.c_str());
|
|
// Set the resulted environment variable and return the result
|
|
return (putenv(b.Data()) == 0);
|
|
#endif
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
String SysEnv::OSName()
|
|
{
|
|
#ifdef SQMOD_OS_WINDOWS
|
|
// Prepare the structure in which the OS information is retrieved
|
|
OSVERSIONINFO vi;
|
|
// Specify the size of the structure
|
|
vi.dwOSVersionInfoSize = sizeof(vi);
|
|
// Attempt to populate the previously created structure with information
|
|
if (GetVersionEx(&vi) == 0)
|
|
{
|
|
return "Unknown Windows";
|
|
}
|
|
// Identify the platform from the obtained information
|
|
switch (vi.dwPlatformId)
|
|
{
|
|
case VER_PLATFORM_WIN32s:
|
|
return "Windows 3.x";
|
|
case VER_PLATFORM_WIN32_WINDOWS:
|
|
return vi.dwMinorVersion == 0 ? "Windows 95" : "Windows 98";
|
|
case VER_PLATFORM_WIN32_NT:
|
|
return "Windows NT";
|
|
default:
|
|
return "Windows [Unknown]";
|
|
}
|
|
#else
|
|
// Prepare the structure in which the OS information is retrieved
|
|
struct utsname uts;
|
|
// Attempt to populate the previously created structure with information
|
|
if (uname(&uts) < 0)
|
|
{
|
|
return String("Unknown Unix");
|
|
}
|
|
// Return the requested information
|
|
return uts.sysname;
|
|
#endif
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
String SysEnv::OSDisplayName()
|
|
{
|
|
#ifdef SQMOD_OS_WINDOWS
|
|
// Prepare the structure in which the OS information is retrieved
|
|
OSVERSIONINFO vi;
|
|
// Specify the size of the structure
|
|
vi.dwOSVersionInfoSize = sizeof(vi);
|
|
// Attempt to populate the previously created structure with information
|
|
if (GetVersionEx(&vi) == 0)
|
|
{
|
|
return "Unknown Windows";
|
|
}
|
|
// Identify the platform from the obtained information
|
|
switch(vi.dwMajorVersion)
|
|
{
|
|
case 6:
|
|
switch (vi.dwMinorVersion)
|
|
{
|
|
case 0: return "Windows Vista/Server 2008";
|
|
case 1: return "Windows 7/Server 2008 R2";
|
|
case 2: return "Windows 8/Server 2012";
|
|
default: return "Windows 6.x [Unknown]";
|
|
}
|
|
case 5:
|
|
switch (vi.dwMinorVersion)
|
|
{
|
|
case 0: return "Windows 2000";
|
|
case 1: return "Windows XP";
|
|
case 2: return "Windows Server 2003/Windows Server 2003 R2";
|
|
default: return "Windows 5.x [Unknown]";
|
|
}
|
|
case 4:
|
|
switch (vi.dwMinorVersion)
|
|
{
|
|
case 0: return "Windows 95/Windows NT 4.0";
|
|
case 10: return "Windows 98";
|
|
case 90: return "Windows ME";
|
|
default: return "Windows 4.x [Unknown]";
|
|
}
|
|
default: return "Windows [Unknown]";
|
|
}
|
|
#else
|
|
// Use the same same output from OSName
|
|
return OSName();
|
|
#endif
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
String SysEnv::OSVersion()
|
|
{
|
|
#ifdef SQMOD_OS_WINDOWS
|
|
// Prepare the structure in which the OS information is retrieved
|
|
OSVERSIONINFO vi;
|
|
// Specify the size of the structure
|
|
vi.dwOSVersionInfoSize = sizeof(vi);
|
|
// Attempt to populate the previously created structure with information
|
|
if (GetVersionEx(&vi) == 0)
|
|
{
|
|
String("Unknown");
|
|
}
|
|
// Obtain a temporary buffer capable of holding the version string
|
|
Buffer b(128);
|
|
// The amount of data written to the buffer
|
|
Uint32 sz = 0;
|
|
// Generate the version string with the received information
|
|
if (vi.szCSDVersion[0])
|
|
{
|
|
sz = b.WriteF(0, "%lu.%lu (Build %lu : %s)",
|
|
vi.dwMajorVersion, vi.dwMinorVersion, vi.dwBuildNumber, vi.szCSDVersion);
|
|
}
|
|
else
|
|
{
|
|
sz = b.WriteF(0, "%lu.%lu (Build %lu)", vi.dwMajorVersion, vi.dwMinorVersion, vi.dwBuildNumber);
|
|
}
|
|
// Return a string with the buffer contents and leave the buffer clean after itself
|
|
return String(b.Get< String::value_type >(), sz);
|
|
#else
|
|
// Prepare the structure in which the OS information is retrieved
|
|
struct utsname uts;
|
|
// Attempt to populate the previously created structure with information
|
|
if (uname(&uts) < 0)
|
|
{
|
|
return String("Unknown");
|
|
}
|
|
// Return the requested information
|
|
return uts.release;
|
|
#endif
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
String SysEnv::OSArchitecture()
|
|
{
|
|
#ifdef SQMOD_OS_WINDOWS
|
|
// Prepare the structure in which the system information is retrieved
|
|
SYSTEM_INFO si;
|
|
// Attempt to populate the previously created structure with information
|
|
GetSystemInfo(&si);
|
|
// Identify the architecture from the obtained information
|
|
switch (si.wProcessorArchitecture)
|
|
{
|
|
case PROCESSOR_ARCHITECTURE_INTEL: return "IA32";
|
|
case PROCESSOR_ARCHITECTURE_MIPS: return "MIPS";
|
|
case PROCESSOR_ARCHITECTURE_ALPHA: return "ALPHA";
|
|
case PROCESSOR_ARCHITECTURE_PPC: return "PPC";
|
|
case PROCESSOR_ARCHITECTURE_IA64: return "IA64";
|
|
#ifdef PROCESSOR_ARCHITECTURE_IA32_ON_WIN64
|
|
case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64: return "IA64/32";
|
|
#endif
|
|
#ifdef PROCESSOR_ARCHITECTURE_AMD64
|
|
case PROCESSOR_ARCHITECTURE_AMD64: return "AMD64";
|
|
#endif
|
|
default: return "Unknown";
|
|
}
|
|
#else
|
|
// Prepare the structure in which the OS information is retrieved
|
|
struct utsname uts;
|
|
// Attempt to populate the previously created structure with information
|
|
if (uname(&uts) < 0)
|
|
{
|
|
return String("Unknown");
|
|
}
|
|
// Return the requested information
|
|
return uts.machine;
|
|
#endif
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
String SysEnv::NodeName()
|
|
{
|
|
#ifdef SQMOD_OS_WINDOWS
|
|
// Obtain a temporary buffer capable of holding the node name string
|
|
Buffer b(MAX_COMPUTERNAME_LENGTH + 1);
|
|
// Used to tell the size of our buffer and the size of data written to it
|
|
DWORD size = b.Size< TCHAR >();
|
|
// Attempt to obtain the requested information
|
|
if (GetComputerNameA(b.Data(), &size) == 0)
|
|
{
|
|
return String();
|
|
}
|
|
// Return a string with the buffer contents and leave the buffer clean after itself
|
|
return String(b.Get< String::value_type >(), size);
|
|
#else
|
|
// Prepare the structure in which the OS information is retrieved
|
|
struct utsname uts;
|
|
// Attempt to populate the previously created structure with information
|
|
if (uname(&uts) < 0)
|
|
{
|
|
return String("Unknown");
|
|
}
|
|
// Return the requested information
|
|
return uts.nodename;
|
|
#endif
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Uint32 SysEnv::ProcessorCount()
|
|
{
|
|
#ifdef SQMOD_OS_WINDOWS
|
|
// Prepare the structure in which the system information is retrieved
|
|
SYSTEM_INFO si;
|
|
// Attempt to populate the previously created structure with information
|
|
GetSystemInfo(&si);
|
|
// Return the requested information
|
|
return si.dwNumberOfProcessors;
|
|
#elif defined(_SC_NPROCESSORS_ONLN)
|
|
// Attempt to obtain the number of processors available on the system
|
|
const Int32 count = sysconf(_SC_NPROCESSORS_ONLN);
|
|
// Validate the result and return the appropriate value
|
|
return (count < 0) ? 1 : static_cast< Uint32 >(count);
|
|
#else
|
|
// Obviously at least one processor should be available
|
|
return 1;
|
|
#endif
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void SysEnv::TerminatePath(Buffer & b)
|
|
{
|
|
// Is there any path to terminate?
|
|
if (!b)
|
|
{
|
|
return;
|
|
}
|
|
// Make sure that the path contains a trailing slash if necessary
|
|
else if (b.Cursor() == 0 && b.Before() != SQMOD_DIRSEP_CHAR)
|
|
{
|
|
b.Push(SQMOD_DIRSEP_CHAR);
|
|
}
|
|
// Make sure that whatever string is in the buffer, if any, is null terminated
|
|
b.Cursor() = '\0';
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void SysEnv::ExpandVars(Buffer & b, CCStr pos, CCStr end)
|
|
{
|
|
// Let's have a string to store the extracted variable name and value
|
|
String var;
|
|
// Extract the remaining directories from the specified path
|
|
while (pos != end)
|
|
{
|
|
// Should we start looking for a variable name?
|
|
if (*pos == '$')
|
|
{
|
|
// Clear previous name, if any
|
|
var.clear();
|
|
// Where the name of the variable starts and where it ends
|
|
CCStr start = ++pos, stop = pos;
|
|
// Is this variable name enclosed within curly braces?
|
|
if (*start == '{')
|
|
{
|
|
// Find the closing brace
|
|
stop = strchr(start, '}');
|
|
// Was there a closing brace?
|
|
if (!stop)
|
|
{
|
|
// Append the rest of the string to the buffer
|
|
b.AppendS(pos - 1, end - pos + 1);
|
|
// Stop parsing here
|
|
break;
|
|
}
|
|
// Is there anything between the brace?
|
|
else if ((stop - start) >= 1)
|
|
{
|
|
// Slice the variable name
|
|
var.assign(start + 1, stop - start - 1);
|
|
// Skip the ending brace
|
|
++stop;
|
|
}
|
|
}
|
|
// Is the dollar character followed by a character allowed in variable names?
|
|
else if (isalnum(*start) != 0 || *start == '_')
|
|
{
|
|
// Find the first character that isn't allowed in variable names
|
|
while (stop != end && (isalnum(*stop) != 0 || *stop == '_'))
|
|
{
|
|
++stop;
|
|
}
|
|
// Have we found anything?
|
|
if (start != stop)
|
|
{
|
|
// Slice the variable name
|
|
var.assign(start, stop - start);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Just add the character to the buffer as is
|
|
b.Push('$');
|
|
// Skip to the next character
|
|
continue;
|
|
}
|
|
// Update the position
|
|
pos = stop;
|
|
// Do we have a valid variable name and does it exist?
|
|
if (!var.empty() && Has(var))
|
|
{
|
|
// Append the variable contents to our buffer
|
|
Get(b, var.c_str(), nullptr);
|
|
}
|
|
}
|
|
// Just add the character to the buffer as is
|
|
else
|
|
{
|
|
b.Push(*(pos++));
|
|
}
|
|
}
|
|
// Make sure the string in the buffer is null terminated
|
|
b.Cursor() = '\0';
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void SysEnv::ExpandPath(Buffer & b, CCStr pos, CCStr end)
|
|
{
|
|
// Does the path even contain something to be expanded?
|
|
if (pos == end || *pos == '\0')
|
|
{
|
|
return; // Nothing to expand!
|
|
}
|
|
// If the path starts with the tilde character then the home directory was requested
|
|
else if (*pos == '~')
|
|
{
|
|
// To be expanded, the tilde character must be followed by a slash
|
|
if (*(++pos) == SQMOD_DIRSEP_CHAR)
|
|
{
|
|
// Let's expand this tilde to the home directory
|
|
HomeDir(b);
|
|
// Let's skip the slash as well
|
|
++pos;
|
|
}
|
|
// Go back to the previous character and use it literally
|
|
else
|
|
{
|
|
--pos;
|
|
}
|
|
}
|
|
// The remaining string can be expanded normally
|
|
ExpandVars(b, pos, end);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void SysEnv::ExpandVars(Buffer & b, CCStr str)
|
|
{
|
|
// Do we have anything to expand?
|
|
if (!str || *str == '\0')
|
|
{
|
|
// Make sure the string in the specified buffer, if any, is null terminated
|
|
if (b)
|
|
{
|
|
b.Cursor() = '\0';
|
|
}
|
|
// Nothing to expand!
|
|
return;
|
|
}
|
|
// Calculate the size of the specified string
|
|
const Uint32 len = strlen(str);
|
|
// Forward the call to the internal function
|
|
ExpandVars(b, str, str + len);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void SysEnv::ExpandVars(Buffer & b, const String & str)
|
|
{
|
|
// Do we have anything to expand?
|
|
if (str.empty())
|
|
{
|
|
// Make sure the string in the specified buffer, if any, is null terminated
|
|
if (b)
|
|
{
|
|
b.Cursor() = '\0';
|
|
}
|
|
// Nothing to expand!
|
|
return;
|
|
}
|
|
// Forward the call to the internal function
|
|
ExpandVars(b, str.c_str(), str.c_str() + str.size());
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Buffer SysEnv::ExpandVars(CCStr str)
|
|
{
|
|
// Do we have anything to expand?
|
|
if (!str || *str == '\0')
|
|
{
|
|
return Buffer(); // Nothing to expand!
|
|
}
|
|
// Calculate the size of the specified string
|
|
const Uint32 len = strlen(str);
|
|
// Allocate a moderately sized buffer
|
|
Buffer b(len + 128);
|
|
// Forward the call to the internal function
|
|
ExpandVars(b, str, str + len);
|
|
// Return ownership of the buffer
|
|
return std::move(b);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Buffer SysEnv::ExpandVars(const String & str)
|
|
{
|
|
// Do we have anything to expand?
|
|
if (str.empty())
|
|
{
|
|
return Buffer(); // Nothing to expand!
|
|
}
|
|
// Allocate a moderately sized buffer
|
|
Buffer b(str.size() + 128);
|
|
// Forward the call to the internal function
|
|
ExpandVars(b, str.c_str(), str.c_str() + str.size());
|
|
// Return ownership of the buffer
|
|
return std::move(b);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void SysEnv::ExpandPath(Buffer & b, CCStr path)
|
|
{
|
|
// Do we have anything to expand?
|
|
if (!path || *path == '\0')
|
|
{
|
|
// Make sure the string in the specified buffer, if any, is null terminated
|
|
if (b)
|
|
{
|
|
b.Cursor() = '\0';
|
|
}
|
|
// Nothing to expand!
|
|
return;
|
|
}
|
|
// Calculate the size of the specified string
|
|
const Uint32 len = strlen(path);
|
|
// Forward the call to the internal function
|
|
ExpandPath(b, path, path + len);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void SysEnv::ExpandPath(Buffer & b, const String & path)
|
|
{
|
|
// Do we have anything to expand?
|
|
if (path.empty())
|
|
{
|
|
// Make sure the string in the specified buffer, if any, is null terminated
|
|
if (b)
|
|
{
|
|
b.Cursor() = '\0';
|
|
}
|
|
// Nothing to expand!
|
|
return;
|
|
}
|
|
// Forward the call to the internal function
|
|
ExpandPath(b, path.c_str(), path.c_str() + path.size());
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Buffer SysEnv::ExpandPath(CCStr path)
|
|
{
|
|
// Do we have anything to expand?
|
|
if (!path || *path == '\0')
|
|
{
|
|
return Buffer(); // Nothing to expand!
|
|
}
|
|
// Calculate the size of the specified string
|
|
const Uint32 len = strlen(path);
|
|
// Allocate buffer capable of storing a full path
|
|
Buffer b(SQMOD_MAX_PATH);
|
|
// Forward the call to the internal function
|
|
ExpandPath(b, path, path + len);
|
|
// Return ownership of the buffer
|
|
return std::move(b);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Buffer SysEnv::ExpandPath(const String & path)
|
|
{
|
|
// Do we have anything to expand?
|
|
if (path.empty())
|
|
{
|
|
return Buffer(); // Nothing to expand!
|
|
}
|
|
// Allocate buffer capable of storing a full path
|
|
Buffer b(SQMOD_MAX_PATH);
|
|
// Forward the call to the internal function
|
|
ExpandPath(b, path.c_str(), path.c_str() + path.size());
|
|
// Return ownership of the buffer
|
|
return std::move(b);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void SysEnv::WorkingDir(Buffer & b)
|
|
{
|
|
#ifdef SQMOD_OS_WINDOWS
|
|
// Is there a buffer to work with?
|
|
if (!b)
|
|
{
|
|
// Allocate buffer capable of storing a full path
|
|
b = Buffer(SQMOD_MAX_PATH);
|
|
}
|
|
// Retrieve the current directory for the current process
|
|
DWORD len = GetCurrentDirectoryA(b.Remaining(), &b.Cursor());
|
|
// Did we have enough space left in the buffer?
|
|
if (len > b.Remaining())
|
|
{
|
|
// Acquire a new buffer with a more appropriate capacity this time
|
|
b.Grow(len - b.Remaining() + 2);
|
|
// Attempt to retrieve the working directory one more time
|
|
len = GetCurrentDirectoryA(b.Remaining(), &b.Cursor());
|
|
// ^ On failure the null terminator is included in the length
|
|
}
|
|
// Move the edit cursor to the end of the appended data
|
|
b.Advance(len);
|
|
#else
|
|
// Do we have enough space to store a full path?
|
|
if (b.Remaining() < SQMOD_MAX_PATH)
|
|
{
|
|
b.Grow(SQMOD_MAX_PATH - b.Remaining() + 2);
|
|
}
|
|
// Attempt to retrieve the current working directory and validate result
|
|
if (getcwd(&b.Cursor(), b.Remaining()))
|
|
{
|
|
// Move the edit cursor to the end of the appended data
|
|
b.Advance(strlen(&b.Cursor()));
|
|
}
|
|
#endif // SQMOD_OS_WINDOWS
|
|
// Make sure that the path is properly terminated
|
|
TerminatePath(b);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Buffer SysEnv::WorkingDir()
|
|
{
|
|
// Allocate buffer capable of storing a full path
|
|
Buffer b(SQMOD_MAX_PATH);
|
|
// Forward the call to the regular function
|
|
WorkingDir(b);
|
|
// Return ownership of the buffer
|
|
return std::move(b);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void SysEnv::HomeDir(Buffer & b)
|
|
{
|
|
#ifdef SQMOD_OS_WINDOWS
|
|
// Do we have enough space to store a full path?
|
|
if (b.Remaining() < SQMOD_MAX_PATH)
|
|
{
|
|
b.Grow(SQMOD_MAX_PATH - b.Remaining() + 2);
|
|
}
|
|
// Try the primary method of retrieving the home directory
|
|
if (SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_PROFILE, nullptr, 0, &b.Cursor())))
|
|
{
|
|
// Move the edit cursor to the end of the appended data
|
|
b.Advance(strlen(&b.Cursor()));
|
|
}
|
|
// Try the secondary method of retrieving the home directory
|
|
else if (Has("USERPROFILE"))
|
|
{
|
|
// Append the contents of the USERPROFILE environment variable
|
|
Get(b, "USERPROFILE", nullptr);
|
|
}
|
|
else if (Has("HOMEDRIVE") && Has("HOMEPATH"))
|
|
{
|
|
// Append the contents of the HOMEDRIVE environment variable
|
|
Get(b, "HOMEDRIVE", nullptr);
|
|
// Append the contents of the HOMEPATH environment variable
|
|
Get(b, "HOMEPATH", nullptr);
|
|
}
|
|
#else
|
|
// Try the primary method of retrieving the home directory
|
|
struct passwd * pwd = getpwuid(getuid());
|
|
// Validate the success of the previous operation
|
|
if (pwd)
|
|
{
|
|
// Append the path to our buffer
|
|
b.AppendS(pwd->pw_dir);
|
|
}
|
|
else
|
|
{
|
|
// Try the secondary method of retrieving the home directory
|
|
pwd = getpwuid(geteuid());
|
|
// Validate the success of the previous operation
|
|
if (pwd)
|
|
{
|
|
// Write the path to our buffer and store the size
|
|
b.AppendS(pwd->pw_dir);
|
|
}
|
|
// Fall back to the system environment variables
|
|
else if (Has("HOME"))
|
|
{
|
|
// Append the contents of the HOME environment variable
|
|
Get(b, "HOME", nullptr);
|
|
}
|
|
}
|
|
#endif // SQMOD_OS_WINDOWS
|
|
// Make sure that the path is properly terminated
|
|
TerminatePath(b);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Buffer SysEnv::HomeDir()
|
|
{
|
|
// Allocate buffer capable of storing a full path
|
|
Buffer b(SQMOD_MAX_PATH);
|
|
// Forward the call to the regular function
|
|
HomeDir(b);
|
|
// Return ownership of the buffer
|
|
return std::move(b);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void SysEnv::ConfigHomeDir(Buffer & b)
|
|
{
|
|
#ifdef SQMOD_OS_WINDOWS
|
|
// Is there a buffer to work with?
|
|
if (!b)
|
|
{
|
|
// Allocate buffer capable of storing a full path
|
|
b = Buffer(SQMOD_MAX_PATH);
|
|
}
|
|
// Does the APPDATA environment variable exist?
|
|
if (Has("APPDATA"))
|
|
{
|
|
// Obtain the contents of the APPDATA environment variable
|
|
Get(b, "APPDATA", nullptr);
|
|
}
|
|
else
|
|
{
|
|
// Default to the home directory
|
|
HomeDir(b);
|
|
}
|
|
#else
|
|
// Obtain the home directory path (should contain a trailing slash)
|
|
HomeDir(b);
|
|
// Use the home directory and append the ".config" sub folder
|
|
b.AppendS(".config");
|
|
#endif // SQMOD_OS_WINDOWS
|
|
// Make sure that the path is properly terminated
|
|
TerminatePath(b);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Buffer SysEnv::ConfigHomeDir()
|
|
{
|
|
// Allocate buffer capable of storing a full path
|
|
Buffer b(SQMOD_MAX_PATH);
|
|
// Forward the call to the regular function
|
|
ConfigHomeDir(b);
|
|
// Return ownership of the buffer
|
|
return std::move(b);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void SysEnv::DataHomeDir(Buffer & b)
|
|
{
|
|
#ifdef SQMOD_OS_WINDOWS
|
|
// Is there a buffer to work with?
|
|
if (!b)
|
|
{
|
|
// Allocate buffer capable of storing a full path
|
|
b = Buffer(SQMOD_MAX_PATH);
|
|
}
|
|
// Does the LOCALAPPDATA environment variable exist?
|
|
if (Has("LOCALAPPDATA"))
|
|
{
|
|
// Obtain the contents of the LOCALAPPDATA environment variable
|
|
return Get(b, "LOCALAPPDATA", nullptr);
|
|
}
|
|
// Default to the home config directory
|
|
return ConfigHomeDir(b);
|
|
#else
|
|
// Obtain the home directory path (should contain a trailing slash)
|
|
HomeDir(b);
|
|
// Use the home directory and append the ".local/share" sub folder
|
|
b.AppendS(".config/share");
|
|
#endif // SQMOD_OS_WINDOWS
|
|
// Make sure that the path is properly terminated
|
|
TerminatePath(b);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Buffer SysEnv::DataHomeDir()
|
|
{
|
|
// Allocate buffer capable of storing a full path
|
|
Buffer b(SQMOD_MAX_PATH);
|
|
// Forward the call to the regular function
|
|
DataHomeDir(b);
|
|
// Return ownership of the buffer
|
|
return std::move(b);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void SysEnv::TempHomeDir(Buffer & b)
|
|
{
|
|
#ifdef SQMOD_OS_WINDOWS
|
|
// Use the regular temp directory
|
|
TempDir(b);
|
|
#else
|
|
// Obtain the home directory path (should contain a trailing slash)
|
|
HomeDir(b);
|
|
// Use the home directory and append the ".local/tmp" folder
|
|
b.AppendS(".local/tmp");
|
|
// Make sure that the path is properly terminated
|
|
TerminatePath(b);
|
|
#endif // SQMOD_OS_WINDOWS
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Buffer SysEnv::TempHomeDir()
|
|
{
|
|
// Allocate buffer capable of storing a full path
|
|
Buffer b(SQMOD_MAX_PATH);
|
|
// Forward the call to the regular function
|
|
TempHomeDir(b);
|
|
// Return ownership of the buffer
|
|
return std::move(b);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void SysEnv::CacheHomeDir(Buffer & b)
|
|
{
|
|
#ifdef SQMOD_OS_WINDOWS
|
|
// Use the regular temp directory
|
|
TempDir(b);
|
|
#else
|
|
// Obtain the home directory path (should contain a trailing slash)
|
|
HomeDir(b);
|
|
// Use the home directory and append the ".cache" folder
|
|
b.AppendS(".cache");
|
|
// Make sure that the path is properly terminated
|
|
TerminatePath(b);
|
|
#endif // SQMOD_OS_WINDOWS
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Buffer SysEnv::CacheHomeDir()
|
|
{
|
|
// Allocate buffer capable of storing a full path
|
|
Buffer b(SQMOD_MAX_PATH);
|
|
// Forward the call to the regular function
|
|
CacheHomeDir(b);
|
|
// Return ownership of the buffer
|
|
return std::move(b);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void SysEnv::TempDir(Buffer & b)
|
|
{
|
|
#ifdef SQMOD_OS_WINDOWS
|
|
// Is there a buffer to work with?
|
|
if (!b)
|
|
{
|
|
// Allocate buffer capable of storing a full path
|
|
b = Buffer(SQMOD_MAX_PATH);
|
|
}
|
|
// Retrieve the path of the directory designated for temporary files
|
|
DWORD len = GetTempPathA(b.Remaining(), &b.Cursor());
|
|
// Did we failed to retrieve the path?
|
|
if (len == 0)
|
|
{
|
|
return; // Unable to retrieve the path!
|
|
}
|
|
// Did we have enough space left in the buffer?
|
|
else if (len > b.Remaining())
|
|
{
|
|
// Acquire a new buffer with a more appropriate capacity this time
|
|
b.Grow(len - b.Remaining() + 2);
|
|
// Attempt to retrieve the temporary directory one more time
|
|
len = GetTempPathA(b.Remaining(), &b.Cursor());
|
|
// ^ On failure the null terminator is included in the length
|
|
}
|
|
// Convert the acquired path to its long form
|
|
len = GetLongPathNameA(&b.Cursor(), &b.Cursor(), b.Remaining());
|
|
// Did we failed to convert the path?
|
|
if (len == 0)
|
|
{
|
|
return; // Unable to convert the path!
|
|
}
|
|
// Did we have enough space left in the buffer?
|
|
else if (len > b.Remaining())
|
|
{
|
|
// Acquire a new buffer with a more appropriate capacity this time
|
|
b.Grow(len - b.Remaining() + 2);
|
|
// Attempt to retrieve the temporary directory again because we reused the buffer
|
|
GetTempPathA(b.Remaining(), &b.Cursor());
|
|
// Attempt to convert the acquired path to its long form one more time
|
|
len = GetLongPathNameA(&b.Cursor(), &b.Cursor(), b.Remaining());
|
|
// ^ On failure the null terminator is included in the length
|
|
}
|
|
// Move the edit cursor to the end of the appended data
|
|
b.Advance(len);
|
|
#else
|
|
// Does the TMPDIR environment variable exist?
|
|
if (SysEnv::Has("TMPDIR"))
|
|
{
|
|
// Obtain the contents of the TMPDIR environment variable
|
|
Get(b, "TMPDIR", nullptr);
|
|
}
|
|
else
|
|
{
|
|
// Default to the "/tmp" directory
|
|
b.AppendS("/tmp/");
|
|
}
|
|
#endif // SQMOD_OS_WINDOWS
|
|
// Make sure that the path is properly terminated
|
|
TerminatePath(b);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Buffer SysEnv::TempDir()
|
|
{
|
|
// Allocate buffer capable of storing a full path
|
|
Buffer b(SQMOD_MAX_PATH);
|
|
// Forward the call to the regular function
|
|
TempDir(b);
|
|
// Return ownership of the buffer
|
|
return std::move(b);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void SysEnv::ConfigDir(Buffer & b)
|
|
{
|
|
#ifdef SQMOD_OS_WINDOWS
|
|
// Is there a buffer to work with?
|
|
if (!b)
|
|
{
|
|
// Allocate buffer capable of storing a full path
|
|
b = Buffer(SQMOD_MAX_PATH);
|
|
}
|
|
// Does the PROGRAMDATA environment variable exist?
|
|
if (Has("PROGRAMDATA"))
|
|
{
|
|
// Obtain the contents of the PROGRAMDATA environment variable
|
|
Get(b, "PROGRAMDATA", nullptr);
|
|
}
|
|
else
|
|
{
|
|
// Make sure that whatever string is in the buffer, if any, is null terminated
|
|
b.Cursor() = '\0';
|
|
// Unable to retrieve the path!
|
|
return;
|
|
}
|
|
#else
|
|
// Default to "/etc" directory
|
|
b.AppendS("/etc/");
|
|
#endif // SQMOD_OS_WINDOWS
|
|
// Make sure that the path is properly terminated
|
|
TerminatePath(b);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Buffer SysEnv::ConfigDir()
|
|
{
|
|
// Allocate buffer capable of storing a full path
|
|
Buffer b(SQMOD_MAX_PATH);
|
|
// Forward the call to the regular function
|
|
ConfigDir(b);
|
|
// Return ownership of the buffer
|
|
return std::move(b);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void SysEnv::SystemDir(Buffer & b)
|
|
{
|
|
#ifdef SQMOD_OS_WINDOWS
|
|
// Is there a buffer to work with?
|
|
if (!b)
|
|
{
|
|
// Allocate buffer capable of storing a full path
|
|
b = Buffer(SQMOD_MAX_PATH);
|
|
}
|
|
// Retrieve the path of the system directory
|
|
DWORD len = GetSystemDirectoryA(&b.Cursor(), b.Remaining());
|
|
// Did we failed to retrieve the path?
|
|
if (len == 0)
|
|
{
|
|
return; // Unable to retrieve the path!
|
|
}
|
|
// Did we have enough space left in the buffer?
|
|
else if (len > b.Remaining())
|
|
{
|
|
// Acquire a new buffer with a more appropriate capacity this time
|
|
b.Grow(len - b.Remaining() + 2);
|
|
// Attempt to retrieve the path of the system directory one more time
|
|
len = GetSystemDirectoryA(&b.Cursor(), b.Remaining());
|
|
// ^ On failure the null terminator is included in the length
|
|
}
|
|
// Move the edit cursor to the end of the appended data
|
|
b.Advance(len);
|
|
#else
|
|
// Use a dummy directory for now
|
|
b.AppendS("/sys/");
|
|
#endif // SQMOD_OS_WINDOWS
|
|
// Make sure that the path is properly terminated
|
|
TerminatePath(b);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Buffer SysEnv::SystemDir()
|
|
{
|
|
// Allocate buffer capable of storing a full path
|
|
Buffer b(SQMOD_MAX_PATH);
|
|
// Forward the call to the regular function
|
|
SystemDir(b);
|
|
// Return ownership of the buffer
|
|
return std::move(b);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void SysEnv::NullDir(Buffer & b)
|
|
{
|
|
#ifdef SQMOD_OS_WINDOWS
|
|
b.AppendS("NUL:");
|
|
#else
|
|
b.AppendS("/dev/null/");
|
|
#endif // SQMOD_OS_WINDOWS
|
|
// Make sure that whatever string is in the buffer, if any, is null terminated
|
|
b.Cursor() = '\0';
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Buffer SysEnv::NullDir()
|
|
{
|
|
// Allocate buffer capable of storing a full path
|
|
Buffer b(SQMOD_MAX_PATH);
|
|
// Append the null path
|
|
#ifdef SQMOD_OS_WINDOWS
|
|
b.AppendS("NUL:");
|
|
#else
|
|
b.AppendS("/dev/null/");
|
|
#endif // SQMOD_OS_WINDOWS
|
|
// Make sure that whatever string is in the buffer, if any, is null terminated
|
|
b.Cursor() = '\0';
|
|
// Return ownership of the buffer
|
|
return std::move(b);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
static bool SqEnv_Has(CCStr name)
|
|
{
|
|
return SysEnv::Has(name);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
static Object SqEnv_Get(CCStr name)
|
|
{
|
|
return BufferToStrObj(SysEnv::Get(name, nullptr));
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
static Object SqEnv_GetOr(CCStr name, CCStr fallback)
|
|
{
|
|
return BufferToStrObj(SysEnv::Get(name, fallback));
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
static void SqEnv_Set(CCStr name, CCStr value)
|
|
{
|
|
SysEnv::Set(name, value);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
static Object SqEnv_ExpandVars(CCStr str)
|
|
{
|
|
return BufferToStrObj(SysEnv::ExpandVars(str));
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
static Object SqEnv_ExpandPath(CCStr path)
|
|
{
|
|
return BufferToStrObj(SysEnv::ExpandPath(path));
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
static Object SqEnv_WorkingDir()
|
|
{
|
|
return BufferToStrObj(SysEnv::WorkingDir());
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
static Object SqEnv_HomeDir()
|
|
{
|
|
return BufferToStrObj(SysEnv::HomeDir());
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
static Object SqEnv_ConfigHomeDir()
|
|
{
|
|
return BufferToStrObj(SysEnv::ConfigHomeDir());
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
static Object SqEnv_DataHomeDir()
|
|
{
|
|
return BufferToStrObj(SysEnv::DataHomeDir());
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
static Object SqEnv_TempHomeDir()
|
|
{
|
|
return BufferToStrObj(SysEnv::TempHomeDir());
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
static Object SqEnv_CacheHomeDir()
|
|
{
|
|
return BufferToStrObj(SysEnv::CacheHomeDir());
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
static Object SqEnv_TempDir()
|
|
{
|
|
return BufferToStrObj(SysEnv::TempDir());
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
static Object SqEnv_ConfigDir()
|
|
{
|
|
return BufferToStrObj(SysEnv::ConfigDir());
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
static Object SqEnv_SystemDir()
|
|
{
|
|
return BufferToStrObj(SysEnv::SystemDir());
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
static Object SqEnv_NullDir()
|
|
{
|
|
return BufferToStrObj(SysEnv::NullDir());
|
|
}
|
|
|
|
// ================================================================================================
|
|
void Register_SysEnv(HSQUIRRELVM vm)
|
|
{
|
|
Table sens(vm);
|
|
|
|
sens.Func(_SC("Has"), &SqEnv_Has);
|
|
sens.Func(_SC("Get"), &SqEnv_Get);
|
|
sens.Func(_SC("GetOr"), &SqEnv_GetOr);
|
|
sens.Func(_SC("Set"), &SqEnv_Set);
|
|
sens.Func(_SC("OSName"), &SysEnv::OSName);
|
|
sens.Func(_SC("OSDisplayName"), &SysEnv::OSDisplayName);
|
|
sens.Func(_SC("OSVersion"), &SysEnv::OSVersion);
|
|
sens.Func(_SC("OSArchitecture"), &SysEnv::OSArchitecture);
|
|
sens.Func(_SC("NodeName"), &SysEnv::NodeName);
|
|
sens.Func(_SC("ProcessorCount"), &SysEnv::ProcessorCount);
|
|
sens.Func(_SC("ExpandVars"), &SqEnv_ExpandVars);
|
|
sens.Func(_SC("ExpandPath"), &SqEnv_ExpandPath);
|
|
sens.Func(_SC("WorkingDir"), &SqEnv_WorkingDir);
|
|
sens.Func(_SC("HomeDir"), &SqEnv_HomeDir);
|
|
sens.Func(_SC("ConfigHomeDir"), &SqEnv_ConfigHomeDir);
|
|
sens.Func(_SC("DataHomeDir"), &SqEnv_DataHomeDir);
|
|
sens.Func(_SC("TempHomeDir"), &SqEnv_TempHomeDir);
|
|
sens.Func(_SC("CacheHomeDir"), &SqEnv_CacheHomeDir);
|
|
sens.Func(_SC("TempDir"), &SqEnv_TempDir);
|
|
sens.Func(_SC("ConfigDir"), &SqEnv_ConfigDir);
|
|
sens.Func(_SC("SystemDir"), &SqEnv_SystemDir);
|
|
sens.Func(_SC("NullDir"), &SqEnv_NullDir);
|
|
|
|
RootTable(vm).Bind(_SC("SqSysEnv"), sens);
|
|
}
|
|
|
|
} // Namespace:: SqMod
|