mirror of
https://github.com/VCMP-SqMod/SqMod.git
synced 2025-02-22 04:37:13 +01:00
Implemented utilities to convert between fundamental types. Implemented helper functions to retrieve numeric values from the stack at all costs. Implemented various delegates on the long integer types to mimic the standard types. Moved most of the stack utilities in a separate source. Various other fixes and improvements.
1210 lines
39 KiB
C++
1210 lines
39 KiB
C++
// ------------------------------------------------------------------------------------------------
|
|
#include "Library/SysEnv.hpp"
|
|
#include "Base/Stack.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
|