From 4cac7d2d30c70f4877e5e5d9a71f50834c7cc05a Mon Sep 17 00:00:00 2001 From: Sandu Liviu Catalin Date: Fri, 11 Mar 2016 04:14:28 +0200 Subject: [PATCH] Updated the buffer class to include an optional numeric value to be used as an edit cursor or to mark the used buffer size. Basic implementation of the system path class and several fuctions to retrieve information about the running system. --- cbp/Module.cbp | 4 +- source/Base/Buffer.cpp | 137 ++- source/Base/Buffer.hpp | 448 ++++++++-- source/Library/Crypt.cpp | 12 +- source/Library/SysEnv.cpp | 1218 +++++++++++++++++++++++++ source/Library/SysEnv.hpp | 316 +++++++ source/Library/SysPath.cpp | 1739 ++++++++++++++++++++++++++++++++++++ source/Library/SysPath.hpp | 729 +++++++++++++++ source/Library/System.cpp | 0 source/Library/System.hpp | 0 source/Register.cpp | 4 + 11 files changed, 4503 insertions(+), 104 deletions(-) create mode 100644 source/Library/SysEnv.cpp create mode 100644 source/Library/SysEnv.hpp delete mode 100644 source/Library/System.cpp delete mode 100644 source/Library/System.hpp diff --git a/cbp/Module.cbp b/cbp/Module.cbp index c3865803..afb62105 100644 --- a/cbp/Module.cbp +++ b/cbp/Module.cbp @@ -459,10 +459,10 @@ + + - - diff --git a/source/Base/Buffer.cpp b/source/Base/Buffer.cpp index 2698a74d..a68e57b4 100644 --- a/source/Base/Buffer.cpp +++ b/source/Base/Buffer.cpp @@ -1,5 +1,5 @@ // ------------------------------------------------------------------------------------------------ -#include "Buffer.hpp" +#include "Base/Buffer.hpp" // ------------------------------------------------------------------------------------------------ #include @@ -40,7 +40,9 @@ void ThrowMemExcept(const char * msg, ...) int ret = vsnprintf(buffer, sizeof(buffer), msg, args); // Check for formatting errors if (ret < 0) + { throw std::runtime_error("Unknown memory error"); + } // Throw the actual exception throw std::runtime_error(buffer); } @@ -54,7 +56,9 @@ static Buffer::Pointer AllocMem(Buffer::SzType size) Buffer::Pointer ptr = reinterpret_cast< Buffer::Pointer >(malloc(size)); // Validate the allocated memory if (!ptr) + { ThrowMemExcept("Unable to allocate (%u) bytes of memory", size); + } // Return the allocated memory return ptr; } @@ -100,7 +104,9 @@ private: * Base constructor. */ Node(Node * next) - : mCap(0), mPtr(nullptr), mNext(next) + : mCap(0) + , mPtr(nullptr) + , mNext(next) { /* ... */ } @@ -130,7 +136,9 @@ private: { // Free the memory (if any) if (node->mPtr) + { free(node->mPtr); + } // Save the next node next = node->mNext; // Release the node instance @@ -149,7 +157,9 @@ private: { // Free the memory (if any) if (node->mPtr) + { free(node->mPtr); + } // Save the next node next = node->mNext; // Release the node instance @@ -173,10 +183,14 @@ private: { // Was there a previous node? if (prev) + { prev->mNext = node->mNext; + } // Probably this was the head else + { m_Head = node->mNext; + } // Assign the memory ptr = node->mPtr; // Assign the size @@ -208,7 +222,9 @@ private: void Drop(Pointer & ptr, SzType & size) { if (!ptr) + { ThrowMemExcept("Cannot store invalid memory buffer"); + } // Request a node instance Node * node = Pull(); // Assign the specified memory @@ -232,7 +248,9 @@ private: s_Nodes = new Node(s_Nodes); // Validate the head node if (!s_Nodes) + { ThrowMemExcept("Unable to allocate memory nodes"); + } } } @@ -243,7 +261,9 @@ private: { // Are there any nodes available? if (!s_Nodes) + { Make(); // Make some! + } // Grab the head node Node * node = s_Nodes; // Promote the next node as the head @@ -259,7 +279,9 @@ private: { // See if the node is even valid if (!node) + { ThrowMemExcept("Attempting to push invalid node"); + } // Demote the current head node node->mNext = s_Nodes; // Promote as the head node @@ -324,7 +346,9 @@ MemRef MemRef::s_Mem; void MemRef::Grab() { if (m_Ptr) + { ++(*m_Ref); + } } // ------------------------------------------------------------------------------------------------ @@ -354,7 +378,8 @@ const MemRef & MemRef::Get() // ------------------------------------------------------------------------------------------------ Buffer::Buffer(const Buffer & o) : m_Ptr(nullptr) - , m_Cap(0) + , m_Cap(o.m_Cap) + , m_Cur(o.m_Cur) , m_Mem(o.m_Mem) { if (m_Cap) @@ -369,7 +394,9 @@ Buffer::~Buffer() { // Do we have a buffer? if (m_Ptr) + { Release(); // Release it! + } } // ------------------------------------------------------------------------------------------------ @@ -379,30 +406,51 @@ Buffer & Buffer::operator = (const Buffer & o) { // Can we work in the current buffer? if (m_Cap && o.m_Cap <= m_Cap) + { // It's safe to copy the data - memcpy(m_Ptr, o.m_Ptr, m_Cap); + memcpy(m_Ptr, o.m_Ptr, o.m_Cap); + } // Do we even have data to copy? else if (!o.m_Cap) { // Do we have a buffer? if (m_Ptr) + { Release(); // Release it! + } } else { // Do we have a buffer? if (m_Ptr) + { Release(); // Release it! + } // Request a larger buffer Request(o.m_Cap); // Now it's safe to copy the data memcpy(m_Ptr, o.m_Ptr, o.m_Cap); } + // Also copy the edit cursor + m_Cur = o.m_Cur; } return *this; } +// ------------------------------------------------------------------------------------------------ +void Buffer::Grow(SzType n) +{ + // Backup the current memory + Buffer bkp(m_Ptr, m_Cap, m_Cur, m_Mem); + // Acquire a bigger buffer + Request(bkp.m_Cap + n); + // Copy the data from the old buffer + memcpy(m_Ptr, bkp.m_Ptr, bkp.m_Cap); + // Copy the previous edit cursor + m_Cur = bkp.m_Cur; +} + // ------------------------------------------------------------------------------------------------ void Buffer::Request(SzType n) { @@ -417,11 +465,17 @@ void Buffer::Request(SzType n) } // Find out in which category does this buffer reside else if (n <= 1024) + { m_Mem->m_Small.Grab(m_Ptr, n); + } else if (n <= 4096) + { m_Mem->m_Medium.Grab(m_Ptr, n); + } else + { m_Mem->m_Large.Grab(m_Ptr, n); + } // If no errors occurred then we can set the size m_Cap = n; } @@ -432,32 +486,41 @@ void Buffer::Release() // TODO: Implement a limit on how much memory can actually be pooled. // Is there a memory manager available? if (!m_Mem) + { free(m_Ptr); // Deallocate the memory directly + } // Find out to which category does this buffer belong else if (m_Cap <= 1024) + { m_Mem->m_Small.Drop(m_Ptr, m_Cap); + } else if (m_Cap <= 4096) + { m_Mem->m_Medium.Drop(m_Ptr, m_Cap); + } else + { m_Mem->m_Large.Drop(m_Ptr, m_Cap); + } // Explicitly reset the buffer m_Ptr = nullptr; m_Cap = 0; + m_Cur = 0; } // ------------------------------------------------------------------------------------------------ Buffer::SzType Buffer::Write(SzType pos, ConstPtr data, SzType size) { - // Make sure the position is not out of bounds - if (pos > m_Cap || !data || !size) + // Do we have what to write? + if (!data || !size) + { return 0; + } // See if the buffer size must be adjusted else if ((pos + size) >= m_Cap) { - // Allocate a larger memory chunk and backup old data - Buffer bkp(Adjust< Value >(NextPow2(pos + size))); - // Copy data back from the old buffer - memcpy(m_Ptr, bkp.m_Ptr, bkp.m_Cap); + // Acquire a larger buffer + Grow((pos + size) - m_Cap + 32); } // Copy the data into the internal buffer memcpy(m_Ptr + pos, data, size); @@ -472,7 +535,7 @@ Buffer::SzType Buffer::WriteF(SzType pos, const char * fmt, ...) va_list args; va_start(args, fmt); // Call the function that takes the variable argument list - SzType ret = WriteF(pos, fmt, args); + const SzType ret = WriteF(pos, fmt, args); // Finalize the variable argument list va_end(args); // Return the result @@ -482,9 +545,12 @@ Buffer::SzType Buffer::WriteF(SzType pos, const char * fmt, ...) // ------------------------------------------------------------------------------------------------ Buffer::SzType Buffer::WriteF(SzType pos, const char * fmt, va_list args) { - // Make sure the position is not out of bounds - if (pos > m_Cap) - return 0; + // Is the specified position within range? + if (pos >= m_Cap) + { + // Acquire a larger buffer + Grow(pos - m_Cap + 32); + } // Backup the variable argument list va_list args_cpy; va_copy(args_cpy, args); @@ -494,18 +560,53 @@ Buffer::SzType Buffer::WriteF(SzType pos, const char * fmt, va_list args) // Do we need a bigger buffer? if ((pos + ret) >= m_Cap) { - // Allocate a larger memory chunk and backup old data - Buffer bkp(Adjust< Value >(NextPow2(pos + ret))); - // Copy data back from the old buffer - memcpy(m_Ptr, bkp.m_Ptr, bkp.m_Cap); + // Acquire a larger buffer + Grow((pos + ret) - m_Cap + 32); // Retry writing the requested information ret = vsnprintf(m_Ptr + pos, m_Cap, fmt, args_cpy); } // Return the value 0 if data could not be written if (ret < 0) + { return 0; + } // Return the number of written characters return static_cast< SzType >(ret); } +// ------------------------------------------------------------------------------------------------ +Buffer::SzType Buffer::WriteS(SzType pos, ConstPtr str) +{ + // Is there any string to write? + if (str && *str != '\0') + { + // Forward this to the regular write function + return Write(pos, str, strlen(str)); + } + // Nothing to write + return 0; +} + +// ------------------------------------------------------------------------------------------------ +void Buffer::AppendF(const char * fmt, ...) +{ + // Initialize the variable argument list + va_list args; + va_start(args, fmt); + // Forward this to the regular write function + m_Cur += WriteF(m_Cur, fmt, args); + // Finalize the variable argument list + va_end(args); +} + +// ------------------------------------------------------------------------------------------------ +void Buffer::AppendS(const char * str) +{ + // Is there any string to write? + if (str) + { + m_Cur += Write(m_Cur, str, strlen(str)); + } +} + } // Namespace:: SqMod diff --git a/source/Base/Buffer.hpp b/source/Base/Buffer.hpp index f719f93e..8b319838 100644 --- a/source/Base/Buffer.hpp +++ b/source/Base/Buffer.hpp @@ -52,7 +52,8 @@ public: * Default constructor (null). */ MemRef() - : m_Ptr(s_Mem.m_Ptr), m_Ref(s_Mem.m_Ref) + : m_Ptr(s_Mem.m_Ptr) + , m_Ref(s_Mem.m_Ref) { Grab(); } @@ -61,7 +62,8 @@ public: * Copy constructor. */ MemRef(const MemRef & o) - : m_Ptr(o.m_Ptr), m_Ref(o.m_Ref) + : m_Ptr(o.m_Ptr) + , m_Ref(o.m_Ref) { Grab(); @@ -189,13 +191,15 @@ private: /* -------------------------------------------------------------------------------------------- * Construct and take ownership of the specified buffer. */ - Buffer(Pointer & ptr, SzType & cap, const MemRef & mem) + Buffer(Pointer & ptr, SzType & cap, SzType & cur, const MemRef & mem) : m_Ptr(ptr) , m_Cap(cap) + , m_Cur(cur) , m_Mem(mem) { ptr = nullptr; cap = 0; + cur = 0; } public: @@ -206,6 +210,7 @@ public: Buffer() : m_Ptr(nullptr) , m_Cap(0) + , m_Cur(0) , m_Mem(MemRef::Get()) { /* ... */ @@ -217,6 +222,7 @@ public: Buffer(SzType n) : m_Ptr(nullptr) , m_Cap(0) + , m_Cur(0) , m_Mem(MemRef::Get()) { Request(n < 8 ? 8 : n); @@ -231,7 +237,10 @@ public: * Move constructor. */ Buffer(Buffer && o) - : m_Ptr(o.m_Ptr), m_Cap(o.m_Cap), m_Mem(o.m_Mem) + : m_Ptr(o.m_Ptr) + , m_Cap(o.m_Cap) + , m_Cur(o.m_Cur) + , m_Mem(o.m_Mem) { o.m_Ptr = nullptr; } @@ -254,9 +263,12 @@ public: if (m_Ptr != o.m_Ptr) { if (m_Ptr) + { Release(); + } m_Ptr = o.m_Ptr; m_Cap = o.m_Cap; + m_Cur = o.m_Cur; m_Mem = o.m_Mem; o.m_Ptr = nullptr; } @@ -319,72 +331,6 @@ public: return m_Ptr; } - /* -------------------------------------------------------------------------------------------- - * Retrieve the internal buffer casted as a different type. - */ - template < typename T = Value> T * Get() - { - return reinterpret_cast< T * >(m_Ptr); - } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the internal buffer casted as a different type. - */ - template < typename T = Value> const T * Get() const - { - return reinterpret_cast< const T * >(m_Ptr); - } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the a certain element. - */ - template < typename T = Value> T & At(SzType n) - { - assert(n < m_Cap); - return reinterpret_cast< T * >(m_Ptr)[n]; - } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the a certain element. - */ - template < typename T = Value> const T & At(SzType n) const - { - assert(n < m_Cap); - return reinterpret_cast< const T * >(m_Ptr)[n]; - } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the internal buffer casted as a different type. - */ - template < typename T = Value> T * Begin() - { - return reinterpret_cast< T * >(m_Ptr); - } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the internal buffer casted as a different type. - */ - template < typename T = Value> const T * Begin() const - { - return reinterpret_cast< const T * >(m_Ptr); - } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the internal buffer casted as a different type. - */ - template < typename T = Value> T * End() - { - return reinterpret_cast< T * >(m_Ptr) + (m_Cap / sizeof(T)); - } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the internal buffer casted as a different type. - */ - template < typename T = Value> const T * End() const - { - return reinterpret_cast< const T * >(m_Ptr) + (m_Cap / sizeof(T)); - } - /* -------------------------------------------------------------------------------------------- * Retrieve the internal buffer. */ @@ -401,20 +347,273 @@ public: return m_Ptr; } + /* -------------------------------------------------------------------------------------------- + * Retrieve the internal buffer casted as a different type. + */ + template < typename T = Value > T * Get() + { + return reinterpret_cast< T * >(m_Ptr); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the internal buffer casted as a different type. + */ + template < typename T = Value > const T * Get() const + { + return reinterpret_cast< const T * >(m_Ptr); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the a certain element. + */ + template < typename T = Value > T & At(SzType n) + { + assert(n < m_Cap); + return reinterpret_cast< T * >(m_Ptr)[n]; + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the a certain element. + */ + template < typename T = Value > const T & At(SzType n) const + { + assert(n < m_Cap); + return reinterpret_cast< const T * >(m_Ptr)[n]; + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the internal buffer casted as a different type. + */ + template < typename T = Value > T * Begin() + { + return reinterpret_cast< T * >(m_Ptr); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the internal buffer casted as a different type. + */ + template < typename T = Value > const T * Begin() const + { + return reinterpret_cast< const T * >(m_Ptr); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the internal buffer casted as a different type. + */ + template < typename T = Value > T * End() + { + return reinterpret_cast< T * >(m_Ptr) + (m_Cap / sizeof(T)); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the internal buffer casted as a different type. + */ + template < typename T = Value > const T * End() const + { + return reinterpret_cast< const T * >(m_Ptr) + (m_Cap / sizeof(T)); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the element at the front of the buffer. + */ + template < typename T = Value > T & Front() + { + assert(m_Cap >= sizeof(T)); + return reinterpret_cast< T * >(m_Ptr)[0]; + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the element at the front of the buffer. + */ + template < typename T = Value > const T & Front() const + { + assert(m_Cap >= sizeof(T)); + return reinterpret_cast< const T * >(m_Ptr)[0]; + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the element after the first element in the buffer. + */ + template < typename T = Value > T & Next() + { + assert(m_Cap >= (sizeof(T) * 2)); + return reinterpret_cast< T * >(m_Ptr)[1]; + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the element after the first element in the buffer. + */ + template < typename T = Value > const T & Next() const + { + assert(m_Cap >= (sizeof(T) * 2)); + return reinterpret_cast< const T * >(m_Ptr)[1]; + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the element at the back of the buffer. + */ + template < typename T = Value > T & Back() + { + assert(m_Cap >= sizeof(T)); + return reinterpret_cast< T * >(m_Ptr)[m_Cap-1]; + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the element at the back of the buffer. + */ + template < typename T = Value > const T & Back() const + { + assert(m_Cap >= sizeof(T)); + return reinterpret_cast< const T * >(m_Ptr)[m_Cap-1]; + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the element before the last element in the buffer. + */ + template < typename T = Value > T & Prev() + { + assert(m_Cap >= (sizeof(T) * 2)); + return reinterpret_cast< T * >(m_Ptr)[m_Cap-2]; + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the element before the last element in the buffer. + */ + template < typename T = Value > const T & Prev() const + { + assert(m_Cap >= (sizeof(T) * 2)); + return reinterpret_cast< const T * >(m_Ptr)[m_Cap-2]; + } + + /* -------------------------------------------------------------------------------------------- + * Reposition the edit cursor to the specified number of elements ahead. + */ + template < typename T = Value > void Advance(SzType n) + { + // Do we need to scale the buffer? + if ((m_Cur + (n * sizeof(T))) >= m_Cap) + { + Grow(m_Cur + (n * sizeof(T))); + } + // Advance to the specified position + m_Cur += (n * sizeof(T)); + } + + /* -------------------------------------------------------------------------------------------- + * Reposition the edit cursor to the specified number of elements behind. + */ + template < typename T = Value > void Retreat(SzType n) + { + // Can we move that much backward? + if ((n * sizeof(T)) <= m_Cur) + { + m_Cur -= (n * sizeof(T)); + } + // Just got to the beginning + else + { + m_Cur = 0; + } + } + + /* -------------------------------------------------------------------------------------------- + * Reposition the edit cursor to a fixed position within the buffer. + */ + template < typename T = Value > void Move(SzType n) + { + // Do we need to scale the buffer? + if ((n * sizeof(T)) >= m_Cap) + { + Grow(n * sizeof(T)); + } + // Move to the specified position + m_Cur = (n * sizeof(T)); + } + + /* -------------------------------------------------------------------------------------------- + * Reposition the edit cursor to a fixed position within the buffer. + */ + template < typename T = Value > void Push(T v) + { + // Do we need to scale the buffer? + if ((m_Cur + sizeof(T)) >= m_Cap) + { + Grow(m_Cap + sizeof(T)); + } + // Assign the specified value + reinterpret_cast< T * >(m_Ptr)[m_Cur] = v; + // Move to the next element + m_Cur += sizeof(T); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the element at the cursor position. + */ + template < typename T = Value > T & Cursor() + { + assert((m_Cur / sizeof(T)) < (m_Cap / sizeof(T))); + return reinterpret_cast< T * >(m_Ptr)[m_Cur]; + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the element at the cursor position. + */ + template < typename T = Value > const T & Cursor() const + { + assert((m_Cur / sizeof(T)) < (m_Cap / sizeof(T))); + return reinterpret_cast< const T * >(m_Ptr)[m_Cur]; + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the element before the cursor position. + */ + template < typename T = Value > T & Before() + { + assert(m_Cur >= sizeof(T)); + return reinterpret_cast< T * >(m_Ptr)[m_Cur-1]; + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the element before the cursor position. + */ + template < typename T = Value > const T & Before() const + { + assert(m_Cur >= sizeof(T)); + return reinterpret_cast< const T * >(m_Ptr)[m_Cur-1]; + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the element after the cursor position. + */ + template < typename T = Value > T & After() + { + assert((m_Cur + sizeof(T)) <= (m_Cap - sizeof(T))); + return reinterpret_cast< T * >(m_Ptr)[m_Cur+1]; + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the element after the cursor position. + */ + template < typename T = Value > const T & After() const + { + assert((m_Cur + sizeof(T)) <= (m_Cap - sizeof(T))); + return reinterpret_cast< const T * >(m_Ptr)[m_Cur+1]; + } + /* -------------------------------------------------------------------------------------------- * Retrieve maximum elements it can hold for a certain type. */ - template < typename T = Value> static SzType Max() + template < typename T = Value > static SzType Max() { - return (0xFFFFFFFF / sizeof(T)); + return static_cast< SzType >(0xFFFFFFFF / sizeof(T)); } /* -------------------------------------------------------------------------------------------- * Retrieve the current buffer capacity in element count. */ - template < typename T = Value> SzType Size() const + template < typename T = Value > SzType Size() const { - return (m_Cap / sizeof(T)); + return static_cast< SzType >(m_Cap / sizeof(T)); } /* -------------------------------------------------------------------------------------------- @@ -425,25 +624,52 @@ public: return m_Cap; } + /* -------------------------------------------------------------------------------------------- + * Retrieve the current position of the cursor in the buffer. + */ + template < typename T = Value > SzType Position() const + { + return static_cast< SzType >(m_Cur / sizeof(T)); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the amount of unused buffer after the edit cursor. + */ + template < typename T = Value > SzType Remaining() const + { + return static_cast< SzType >((m_Cap - m_Cur) / sizeof(T)); + } + + /* -------------------------------------------------------------------------------------------- + * Grow the size of the internal buffer by the specified amount of bytes. + */ + void Grow(SzType n); + /* -------------------------------------------------------------------------------------------- * Makes sure there is enough capacity to hold the specified element count. */ - template < typename T = Value> Buffer Adjust(SzType n) + template < typename T = Value > Buffer Adjust(SzType n) { // Do we meet the minimum size? if (n < 8) + { n = 8; // Adjust to minimum size + } // See if the requested capacity doesn't exceed the limit if (n > Max< T >()) + { ThrowMemExcept("Requested buffer of (%u) elements exceeds the (%u) limit", n, Max< T >()); + } // Is there an existing buffer? else if (n && !m_Cap) + { Request(n * sizeof(T)); // Request the memory + } // Should the size be increased? else if (n > m_Cap) { // Backup the current memory - Buffer bkp(m_Ptr, m_Cap, m_Mem); + Buffer bkp(m_Ptr, m_Cap, m_Cur, m_Mem); // Request the memory Request(n * sizeof(T)); // Return the backup @@ -459,7 +685,9 @@ public: void Reset() { if (m_Ptr) + { Release(); + } } /* -------------------------------------------------------------------------------------------- @@ -476,10 +704,18 @@ public: } /* -------------------------------------------------------------------------------------------- - * Write a portion of a buffet to the internal buffer. + * Write a portion of a buffer to the internal buffer. */ SzType Write(SzType pos, ConstPtr data, SzType size); + /* -------------------------------------------------------------------------------------------- + * Write another buffer to the internal buffer. + */ + SzType Write(SzType pos, const Buffer & b) + { + return Write(pos, b.m_Ptr, b.m_Cur); + } + /* -------------------------------------------------------------------------------------------- * Write a formatted string to the internal buffer. */ @@ -490,6 +726,61 @@ public: */ SzType WriteF(SzType pos, const char * fmt, va_list args); + /* -------------------------------------------------------------------------------------------- + * Write a string to the internal buffer. + */ + SzType WriteS(SzType pos, const char * str); + + /* -------------------------------------------------------------------------------------------- + * Write a portion of a string to the internal buffer. + */ + SzType WriteS(SzType pos, const char * str, SzType size) + { + return Write(pos, str, size); + } + + /* -------------------------------------------------------------------------------------------- + * Append a portion of a buffer to the internal buffer. + */ + void Append(ConstPtr data, SzType size) + { + m_Cur += Write(m_Cur, data, size); + } + + /* -------------------------------------------------------------------------------------------- + * Append another buffer to the internal buffer. + */ + void Append(const Buffer & b) + { + m_Cur += Write(m_Cur, b.m_Ptr, b.m_Cur); + } + + /* -------------------------------------------------------------------------------------------- + * Append a formatted string to the internal buffer. + */ + void AppendF(const char * fmt, ...); + + /* -------------------------------------------------------------------------------------------- + * Append a formatted string to the internal buffer. + */ + void AppendF(const char * fmt, va_list args) + { + m_Cur += WriteF(m_Cur, fmt, args); + } + + /* -------------------------------------------------------------------------------------------- + * Append a string to the internal buffer. + */ + void AppendS(const char * str); + + /* -------------------------------------------------------------------------------------------- + * Append a portion of a string to the internal buffer. + */ + void AppendS(const char * str, SzType size) + { + m_Cur += Write(m_Cur, str, size); + } + protected: /* -------------------------------------------------------------------------------------------- @@ -507,9 +798,10 @@ private: // -------------------------------------------------------------------------------------------- Pointer m_Ptr; /* Pointer to the memory buffer. */ SzType m_Cap; /* The total size of the buffer. */ + SzType m_Cur; /* The buffer edit cursor. */ // -------------------------------------------------------------------------------------------- - MemRef m_Mem; + MemRef m_Mem; /* Reference to the associated memory manager. */ }; } // Namespace:: SqMod diff --git a/source/Library/Crypt.cpp b/source/Library/Crypt.cpp index 78942f41..8bdec5c1 100644 --- a/source/Library/Crypt.cpp +++ b/source/Library/Crypt.cpp @@ -209,12 +209,12 @@ void Register_Crypt(HSQUIRRELVM vm) RegisterWrapper< SHA256 >(hashns, _SC("SHA256")); RegisterWrapper< SHA3 >(hashns, _SC("SHA3")); - hashns.SquirrelFunc(_SC("GetCRC32"), &HashF< CRC32 >); - hashns.SquirrelFunc(_SC("GetKeccak"), &HashF< Keccak >); - hashns.SquirrelFunc(_SC("GetMD5"), &HashF< MD5 >); - hashns.SquirrelFunc(_SC("GetSHA1"), &HashF< SHA1 >); - hashns.SquirrelFunc(_SC("GetSHA256"), &HashF< SHA256 >); - hashns.SquirrelFunc(_SC("GetSHA3"), &HashF< SHA3 >); + hashns.SquirrelFunc(_SC("SqCRC32"), &HashF< CRC32 >); + hashns.SquirrelFunc(_SC("SqKeccak"), &HashF< Keccak >); + hashns.SquirrelFunc(_SC("SqMD5"), &HashF< MD5 >); + hashns.SquirrelFunc(_SC("SqSHA1"), &HashF< SHA1 >); + hashns.SquirrelFunc(_SC("SqSHA256"), &HashF< SHA256 >); + hashns.SquirrelFunc(_SC("SqSHA3"), &HashF< SHA3 >); RootTable(vm).Bind(_SC("SqHash"), hashns); diff --git a/source/Library/SysEnv.cpp b/source/Library/SysEnv.cpp new file mode 100644 index 00000000..95c15415 --- /dev/null +++ b/source/Library/SysEnv.cpp @@ -0,0 +1,1218 @@ +// ------------------------------------------------------------------------------------------------ +#include "Library/SysEnv.hpp" + +// ------------------------------------------------------------------------------------------------ +#include +#include +#include +#include + +// ------------------------------------------------------------------------------------------------ +#ifdef SQMOD_OS_WINDOWS + #include + #include +#else + #include + #include + #include +#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 + Buffer.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.WriteS("/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.WriteS("/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 Object BufferToObj(const Buffer & b) +{ + // Obtain the initial stack size + const StackGuard sg(DefaultVM::Get()); + // Push the string onto the stack + sq_pushstring(DefaultVM::Get(), b.Data(), b.Position()); + // Obtain the object from the stack and return it + return Var< Object >(DefaultVM::Get(), -1).value; +} + +// ------------------------------------------------------------------------------------------------ +static bool SqEnv_Has(CCStr name) +{ + return SysEnv::Has(name); +} + +// ------------------------------------------------------------------------------------------------ +static Object SqEnv_Get(CCStr name) +{ + return BufferToObj(SysEnv::Get(name, nullptr)); +} + +// ------------------------------------------------------------------------------------------------ +static Object SqEnv_GetOr(CCStr name, CCStr fallback) +{ + return BufferToObj(SysEnv::Get(name, fallback)); +} + +// ------------------------------------------------------------------------------------------------ +static void SqEnv_Set(CCStr name, CCStr value) +{ + SysEnv::Set(name, value); +} + +// ------------------------------------------------------------------------------------------------ +static Object SqEnv_ExpandVars(CCStr str) +{ + return BufferToObj(SysEnv::ExpandVars(str)); +} + +// ------------------------------------------------------------------------------------------------ +static Object SqEnv_ExpandPath(CCStr path) +{ + return BufferToObj(SysEnv::ExpandPath(path)); +} + +// ------------------------------------------------------------------------------------------------ +static Object SqEnv_WorkingDir() +{ + return BufferToObj(SysEnv::WorkingDir()); +} + +// ------------------------------------------------------------------------------------------------ +static Object SqEnv_HomeDir() +{ + return BufferToObj(SysEnv::HomeDir()); +} + +// ------------------------------------------------------------------------------------------------ +static Object SqEnv_ConfigHomeDir() +{ + return BufferToObj(SysEnv::ConfigHomeDir()); +} + +// ------------------------------------------------------------------------------------------------ +static Object SqEnv_DataHomeDir() +{ + return BufferToObj(SysEnv::DataHomeDir()); +} + +// ------------------------------------------------------------------------------------------------ +static Object SqEnv_TempHomeDir() +{ + return BufferToObj(SysEnv::TempHomeDir()); +} + +// ------------------------------------------------------------------------------------------------ +static Object SqEnv_CacheHomeDir() +{ + return BufferToObj(SysEnv::CacheHomeDir()); +} + +// ------------------------------------------------------------------------------------------------ +static Object SqEnv_TempDir() +{ + return BufferToObj(SysEnv::TempDir()); +} + +// ------------------------------------------------------------------------------------------------ +static Object SqEnv_ConfigDir() +{ + return BufferToObj(SysEnv::ConfigDir()); +} + +// ------------------------------------------------------------------------------------------------ +static Object SqEnv_SystemDir() +{ + return BufferToObj(SysEnv::SystemDir()); +} + +// ------------------------------------------------------------------------------------------------ +static Object SqEnv_NullDir() +{ + return BufferToObj(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 diff --git a/source/Library/SysEnv.hpp b/source/Library/SysEnv.hpp new file mode 100644 index 00000000..37edaf87 --- /dev/null +++ b/source/Library/SysEnv.hpp @@ -0,0 +1,316 @@ +#ifndef _LIBRARY_SYSENV_HPP_ +#define _LIBRARY_SYSENV_HPP_ + +// ------------------------------------------------------------------------------------------------ +#include "Base/Shared.hpp" +#include "Base/Buffer.hpp" + +// ------------------------------------------------------------------------------------------------ +namespace SqMod { + +/* ------------------------------------------------------------------------------------------------ + * This class provides access to environment variables and some general system information. +*/ +struct SysEnv +{ + /* -------------------------------------------------------------------------------------------- + * Default constructor. (disabled) + */ + SysEnv() = delete; + + /* -------------------------------------------------------------------------------------------- + * Copy constructor. (disabled) + */ + SysEnv(const SysEnv &) = delete; + + /* -------------------------------------------------------------------------------------------- + * Move constructor. (disabled) + */ + SysEnv(SysEnv &&) = delete; + + /* -------------------------------------------------------------------------------------------- + * Destructor. (disabled) + */ + ~SysEnv() = delete; + + /* -------------------------------------------------------------------------------------------- + * Copy assignment operator. (disabled) + */ + SysEnv & operator = (const SysEnv &) = delete; + + /* -------------------------------------------------------------------------------------------- + * Move assignment operator. (disabled) + */ + SysEnv & operator = (SysEnv &&) = delete; + +public: + + /* -------------------------------------------------------------------------------------------- + * Returns true if an environment variable with the given name is defined. + */ + static bool Has(CCStr name); + + /* -------------------------------------------------------------------------------------------- + * Returns true if an environment variable with the given name is defined. + */ + static bool Has(const String & name); + + /* -------------------------------------------------------------------------------------------- + * Returns the value of the environment variable with the given name. + * If the environment variable is undefined, returns fallback value instead. + */ + static void Get(Buffer & b, CCStr name, CCStr fallback); + + /* -------------------------------------------------------------------------------------------- + * Returns the value of the environment variable with the given name. + */ + static Buffer Get(CCStr name) + { + return Get(name, nullptr); + } + + /* -------------------------------------------------------------------------------------------- + * Returns the value of the environment variable with the given name. + */ + static Buffer Get(const String & name) + { + return Get(name.c_str(), nullptr); + } + + /* -------------------------------------------------------------------------------------------- + * Returns the value of the environment variable with the given name. + * If the environment variable is undefined, returns fallback value instead. + */ + static Buffer Get(CCStr name, CCStr fallback); + + /* -------------------------------------------------------------------------------------------- + * Returns the value of the environment variable with the given name. + * If the environment variable is undefined, returns fallback value instead. + */ + static Buffer Get(CCStr name, const String & fallback) + { + return Get(name, fallback.c_str()); + } + + /* -------------------------------------------------------------------------------------------- + * Returns the value of the environment variable with the given name. + * If the environment variable is undefined, returns fallback value instead. + */ + static Buffer Get(const String & name, CCStr fallback) + { + return Get(name.c_str(), fallback); + } + + /* -------------------------------------------------------------------------------------------- + * Returns the value of the environment variable with the given name. + * If the environment variable is undefined, returns fallback value instead. + */ + static Buffer Get(const String & name, const String & fallback) + { + return Get(name.c_str(), fallback.c_str()); + } + + /* -------------------------------------------------------------------------------------------- + * Sets the environment variable with the given name to the given value. + */ + static bool Set(CCStr name, CCStr value); + + /* -------------------------------------------------------------------------------------------- + * Sets the environment variable with the given name to the given value. + */ + static bool Set(const String & name, const String & value); + + /* -------------------------------------------------------------------------------------------- + * Returns the operating system name. + */ + static String OSName(); + + /* -------------------------------------------------------------------------------------------- + * Returns the operating system name in a more "user-friendly" way. This only affects Windows. + */ + static String OSDisplayName(); + + /* -------------------------------------------------------------------------------------------- + * Returns the operating system version. + */ + static String OSVersion(); + + /* -------------------------------------------------------------------------------------------- + * Returns the operating system architecture. + */ + static String OSArchitecture(); + + /* -------------------------------------------------------------------------------------------- + * Returns the node (or host) name. + */ + static String NodeName(); + + /* -------------------------------------------------------------------------------------------- + * Returns the number of processors installed in the system. If the number of processors + * cannot be determined, returns 1. + */ + static Uint32 ProcessorCount(); + +protected: + + /* -------------------------------------------------------------------------------------------- + * Make sure that the path in the specified buffer contains a trailing slash. + */ + static void TerminatePath(Buffer & b); + + /* -------------------------------------------------------------------------------------------- + * Expands all environment variables contained in the string. + */ + static void ExpandVars(Buffer & b, CCStr pos, CCStr end); + + /* -------------------------------------------------------------------------------------------- + * Expands all environment variables contained in the path. Uses the Unix variable style. + */ + static void ExpandPath(Buffer & b, CCStr pos, CCStr end); + +public: + + /* -------------------------------------------------------------------------------------------- + * Expands all environment variables contained in the string. + */ + static void ExpandVars(Buffer & b, CCStr str); + + /* -------------------------------------------------------------------------------------------- + * Expands all environment variables contained in the string. + */ + static void ExpandVars(Buffer & b, const String & str); + + /* -------------------------------------------------------------------------------------------- + * Expands all environment variables contained in the string. + */ + static Buffer ExpandVars(CCStr str); + + /* -------------------------------------------------------------------------------------------- + * Expands all environment variables contained in the string. + */ + static Buffer ExpandVars(const String & str); + + /* -------------------------------------------------------------------------------------------- + * Expands all environment variables contained in the path. Uses the Unix variable style. + */ + static void ExpandPath(Buffer & b, CCStr path); + + /* -------------------------------------------------------------------------------------------- + * Expands all environment variables contained in the path. Uses the Unix variable style. + */ + static void ExpandPath(Buffer & b, const String & path); + + /* -------------------------------------------------------------------------------------------- + * Expands all environment variables contained in the path. Uses the Unix variable style. + */ + static Buffer ExpandPath(CCStr path); + + /* -------------------------------------------------------------------------------------------- + * Expands all environment variables contained in the path. Uses the Unix variable style. + */ + static Buffer ExpandPath(const String & path); + + /* -------------------------------------------------------------------------------------------- + * Obtain the current working directory within the specified buffer. + */ + static void WorkingDir(Buffer & b); + + /* -------------------------------------------------------------------------------------------- + * Obtain the current working directory within a buffer and return it. + */ + static Buffer WorkingDir(); + + /* -------------------------------------------------------------------------------------------- + * Obtain the user's home directory within the specified buffer. + */ + static void HomeDir(Buffer & b); + + /* -------------------------------------------------------------------------------------------- + * Obtain the user's home directory within a buffer and return it. + */ + static Buffer HomeDir(); + + /* -------------------------------------------------------------------------------------------- + * Obtain the user's config directory within the specified buffer. + */ + static void ConfigHomeDir(Buffer & b); + + /* -------------------------------------------------------------------------------------------- + * Obtain the user's config directory within a buffer and return it. + */ + static Buffer ConfigHomeDir(); + + /* -------------------------------------------------------------------------------------------- + * Obtain the user's data directory within the specified buffer. + */ + static void DataHomeDir(Buffer & b); + + /* -------------------------------------------------------------------------------------------- + * Obtain the user's data directory within a buffer and return it. + */ + static Buffer DataHomeDir(); + + /* -------------------------------------------------------------------------------------------- + * Obtain the user's temporary directory within the specified buffer. + */ + static void TempHomeDir(Buffer & b); + + /* -------------------------------------------------------------------------------------------- + * Obtain the user's temporary directory within a buffer and return it. + */ + static Buffer TempHomeDir(); + + /* -------------------------------------------------------------------------------------------- + * Obtain the user's cache directory within the specified buffer. + */ + static void CacheHomeDir(Buffer & b); + + /* -------------------------------------------------------------------------------------------- + * Obtain the user's cache directory within a buffer and return it. + */ + static Buffer CacheHomeDir(); + + /* -------------------------------------------------------------------------------------------- + * Obtain the temporary directory within the specified buffer. + */ + static void TempDir(Buffer & b); + + /* -------------------------------------------------------------------------------------------- + * Obtain the temporary directory within a buffer and return it. + */ + static Buffer TempDir(); + + /* -------------------------------------------------------------------------------------------- + * Obtain the systemwide config directory within the specified buffer. + */ + static void ConfigDir(Buffer & b); + + /* -------------------------------------------------------------------------------------------- + * Obtain the systemwide config directory within a buffer and return it. + */ + static Buffer ConfigDir(); + + /* -------------------------------------------------------------------------------------------- + * Obtain the system directory within the specified buffer. + */ + static void SystemDir(Buffer & b); + + /* -------------------------------------------------------------------------------------------- + * Obtain the system directory within a buffer and return it. + */ + static Buffer SystemDir(); + + /* -------------------------------------------------------------------------------------------- + * Obtain the null directory within the specified buffer. + */ + static void NullDir(Buffer & b); + + /* -------------------------------------------------------------------------------------------- + * Obtain the null directory within a buffer and return it. + */ + static Buffer NullDir(); +}; + +} // Namespace:: SqMod + +#endif // _LIBRARY_SYSENV_HPP_ diff --git a/source/Library/SysPath.cpp b/source/Library/SysPath.cpp index e69de29b..03c477c4 100644 --- a/source/Library/SysPath.cpp +++ b/source/Library/SysPath.cpp @@ -0,0 +1,1739 @@ +// ------------------------------------------------------------------------------------------------ +#include "Library/SysPath.hpp" +#include "Library/SysEnv.hpp" + +// ------------------------------------------------------------------------------------------------ +#include + +// ------------------------------------------------------------------------------------------------ +#include + +// ------------------------------------------------------------------------------------------------ +#ifdef SQMOD_OS_WINDOWS + #include +#else + #include +#endif + +// ------------------------------------------------------------------------------------------------ +#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 + +// ------------------------------------------------------------------------------------------------ +namespace SqMod { + +// ------------------------------------------------------------------------------------------------ +SQInteger SysPath::Typename(HSQUIRRELVM vm) +{ + static SQChar name[] = _SC("SqSysPath"); + sq_pushstring(vm, name, sizeof(name)); + return 1; +} + +// ------------------------------------------------------------------------------------------------ +SysPath::SysPath() + : m_Dirs() + , m_Name() + , m_Drive(0) + , m_Absolute(false) +{ + /* ... */ +} + +// ------------------------------------------------------------------------------------------------ +SysPath::SysPath(bool absolute) + : m_Dirs() + , m_Name() + , m_Drive(0) + , m_Absolute(absolute) +{ + /* ... */ +} + +// ------------------------------------------------------------------------------------------------ +SysPath::SysPath(CSStr path) + : m_Dirs() + , m_Name() + , m_Drive(0) + , m_Absolute(false) +{ + Assign(path); +} + +// ------------------------------------------------------------------------------------------------ +SysPath::SysPath(CSStr path, Int32 style) + : m_Dirs() + , m_Name() + , m_Drive(0) + , m_Absolute(false) +{ + Assign(path, static_cast< Style >(style)); +} + +// ------------------------------------------------------------------------------------------------ +SysPath::SysPath(CSStr path, Style style) + : m_Dirs() + , m_Name() + , m_Drive(0) + , m_Absolute(false) +{ + Assign(path, style); +} + +// ------------------------------------------------------------------------------------------------ +SysPath::SysPath(const Buffer & path, Int32 size) + : m_Dirs() + , m_Name() + , m_Drive(0) + , m_Absolute(false) +{ + Assign(path, Style::Guess, size); +} + +// ------------------------------------------------------------------------------------------------ +SysPath::SysPath(const Buffer & path, Style style, Int32 size) + : m_Dirs() + , m_Name() + , m_Drive(0) + , m_Absolute(false) +{ + Assign(path, style, size); +} + +// ------------------------------------------------------------------------------------------------ +SysPath::SysPath(const String & path) + : m_Dirs() + , m_Name() + , m_Drive(0) + , m_Absolute(false) +{ + Assign(path, Style::Guess); +} + +// ------------------------------------------------------------------------------------------------ +SysPath::SysPath(const String & path, Style style) + : m_Dirs() + , m_Name() + , m_Drive(0) + , m_Absolute(false) +{ + Assign(path, style); +} + +// ------------------------------------------------------------------------------------------------ +SysPath::SysPath(const SysPath & parent, CSStr name) + : m_Dirs(parent.m_Dirs) + , m_Name(name ? name : "") + , m_Drive(parent.m_Drive) + , m_Absolute(parent.m_Absolute) +{ + /* ... */ +} + +// ------------------------------------------------------------------------------------------------ +SysPath::SysPath(const SysPath & parent, const String & name) + : m_Dirs(parent.m_Dirs) + , m_Name(name) + , m_Drive(parent.m_Drive) + , m_Absolute(parent.m_Absolute) +{ + /* ... */ +} + +// ------------------------------------------------------------------------------------------------ +SysPath::SysPath(const SysPath & parent, const SysPath & relative) + : m_Dirs(parent.m_Dirs) + , m_Name(parent.m_Name) + , m_Drive(parent.m_Drive) + , m_Absolute(parent.m_Absolute) +{ + // Resolve the specified path + Resolve(relative); +} + +// ------------------------------------------------------------------------------------------------ +SysPath::SysPath(const SysPath & o) + : m_Dirs(o.m_Dirs) + , m_Name(o.m_Name) + , m_Drive(o.m_Drive) + , m_Absolute(o.m_Absolute) +{ + /* ... */ +} + +// ------------------------------------------------------------------------------------------------ +SysPath::SysPath(SysPath && o) + : m_Dirs(std::move(o.m_Dirs)) + , m_Name(std::move(o.m_Name)) + , m_Drive(o.m_Drive) + , m_Absolute(o.m_Absolute) +{ + /* ... */ +} + +// ------------------------------------------------------------------------------------------------ +SysPath::~SysPath() +{ + /* ... */ +} + +// ------------------------------------------------------------------------------------------------ +SysPath & SysPath::operator = (const SysPath & o) +{ + // Prevent self assignment + if (this != &o) + { + m_Dirs = o.m_Dirs; + m_Name = o.m_Name; + m_Drive = o.m_Drive; + m_Absolute = o.m_Absolute; + } + + return *this; +} + +// ------------------------------------------------------------------------------------------------ +SysPath & SysPath::operator = (SysPath && o) +{ + // Prevent self assignment + if (this != &o) + { + m_Dirs = std::move(o.m_Dirs); + m_Name = std::move(o.m_Name); + m_Drive = o.m_Drive; + m_Absolute = o.m_Absolute; + } + + return *this; +} + +// ------------------------------------------------------------------------------------------------ +SysPath & SysPath::operator = (CSStr path) +{ + Assign(path); + return *this; +} + +// ------------------------------------------------------------------------------------------------ +SysPath & SysPath::operator = (const String & path) +{ + Assign(path); + return *this; +} + +// ------------------------------------------------------------------------------------------------ +bool SysPath::operator == (const SysPath & o) const +{ + return (m_Drive == o.m_Drive) && (m_Absolute == o.m_Absolute) + && (m_Name == o.m_Name) && (m_Dirs == o.m_Dirs); +} + +// ------------------------------------------------------------------------------------------------ +bool SysPath::operator != (const SysPath & o) const +{ + return !(*this == o); +} + +// ------------------------------------------------------------------------------------------------ +SysPath::operator bool () const +{ + return (m_Dirs.empty() && m_Name.empty() && (m_Drive == 0) && !m_Absolute); +} + +// ------------------------------------------------------------------------------------------------ +const String & SysPath::operator [] (Uint32 n) const +{ + // Is this within the bounds of the directory list? + if (n < m_Dirs.size()) + { + return m_Dirs[n]; + } + // Fall back to the file name + else + { + return m_Name; + } +} + +// ------------------------------------------------------------------------------------------------ +Int32 SysPath::Cmp(const SysPath & o) const +{ + if (*this == o) + return 0; + else if (ToBuffer().Position() > o.ToBuffer().Position()) + return 1; + else + return -1; +} + +// ------------------------------------------------------------------------------------------------ +Object SysPath::ToString() const +{ + // Transform the path components into a string + Buffer b(ToBuffer()); + // Obtain the initial stack size + const StackGuard sg(DefaultVM::Get()); + // Push the string onto the stack + sq_pushstring(DefaultVM::Get(), b.Data(), b.Position()); + // Obtain the object from the stack and return it + return Var< Object >(DefaultVM::Get(), -1).value; +} + +// ------------------------------------------------------------------------------------------------ +void SysPath::Swap(SysPath & path) +{ + m_Dirs.swap(path.m_Dirs); + m_Name.swap(path.m_Name); + std::swap(m_Drive, path.m_Drive); + std::swap(m_Absolute, path.m_Absolute); +} + +// ------------------------------------------------------------------------------------------------ +void SysPath::Clear() +{ + m_Dirs.clear(); + m_Name.clear(); + m_Drive = 0; + m_Absolute = false; +} + +// ------------------------------------------------------------------------------------------------ +SysPath & SysPath::Assign(CSStr path) +{ + // Is the specified path valid? + if (!path || *path == '\0') + { + // Just clear current path + Clear(); + } + else + { +#ifdef SQMOD_OS_WINDOWS + ParseWindows(path, path + strlen(path)); +#else + ParseUnix(path, path + strlen(path)); +#endif // SQMOD_OS_WINDOWS + } + // Allow chaining + return *this; +} + +// ------------------------------------------------------------------------------------------------ +SysPath & SysPath::Assign(CSStr path, Int32 style) +{ + return Assign(path, static_cast< Style >(style)); +} + +// ------------------------------------------------------------------------------------------------ +SysPath & SysPath::Assign(CSStr path, Style style) +{ + // Is the specified path valid? + if (!path || *path == '\0') + { + // Just clear current path + Clear(); + } + else + { + // Identify which style was requested + switch (style) + { + case Style::Unix: + ParseUnix(path, path + strlen(path)); + break; + case Style::Windows: + ParseWindows(path, path + strlen(path)); + break; + case Style::Native: +#ifdef SQMOD_OS_WINDOWS + ParseWindows(path, path + strlen(path)); +#else + ParseUnix(path, path + strlen(path)); +#endif // SQMOD_OS_WINDOWS + break; + case Style::Guess: + ParseGuess(path, path + strlen(path)); + break; + case Style::Dynamic: + ParseDynamic(path, path + strlen(path)); + break; + default: + SqThrowF("Unknown system path style"); + } + } + // Allow chaining + return *this; +} + +// ------------------------------------------------------------------------------------------------ +SysPath & SysPath::Assign(const Buffer & path, Int32 size) +{ + // Is the specified path valid? + if (!path) + { + // Just clear current path + Clear(); + } + else if (size < 0) + { +#ifdef SQMOD_OS_WINDOWS + ParseWindows(path.Data(), &path.Cursor()); +#else + ParseUnix(path.Data(), &path.Cursor()); +#endif // SQMOD_OS_WINDOWS + } + else if (static_cast< Uint32 >(size) < path.Capacity()) + { +#ifdef SQMOD_OS_WINDOWS + ParseWindows(path.Data(), path.Data() + size); +#else + ParseUnix(path.Data(), path.Data() + size); +#endif // SQMOD_OS_WINDOWS + } + else + { + SqThrowF("The specified path size is out of range: %u >= %u", size, path.Capacity()); + } + // Allow chaining + return *this; +} + +// ------------------------------------------------------------------------------------------------ +SysPath & SysPath::Assign(const Buffer & path, Style style, Int32 size) +{ + // Is the specified path valid? + if (!path) + { + // Just clear current path + Clear(); + } + else if (size < 0) + { + // Identify which style was requested + switch (style) + { + case Style::Unix: + ParseUnix(path.Data(), &path.Cursor()); + break; + case Style::Windows: + ParseWindows(path.Data(), &path.Cursor()); + break; + case Style::Native: +#ifdef SQMOD_OS_WINDOWS + ParseWindows(path.Data(), &path.Cursor()); +#else + ParseUnix(path.Data(), &path.Cursor()); +#endif // SQMOD_OS_WINDOWS + break; + case Style::Guess: + ParseGuess(path.Data(), &path.Cursor()); + break; + case Style::Dynamic: + ParseDynamic(path.Data(), &path.Cursor()); + break; + default: + SqThrowF("Unknown system path style"); + } + } + else if (static_cast< Uint32 >(size) < path.Capacity()) + { + // Identify which style was requested + switch (style) + { + case Style::Unix: + ParseUnix(path.Data(), path.Data() + size); + break; + case Style::Windows: + ParseWindows(path.Data(), path.Data() + size); + break; + case Style::Native: +#ifdef SQMOD_OS_WINDOWS + ParseWindows(path.Data(), path.Data() + size); +#else + ParseUnix(path.Data(), path.Data() + size); +#endif // SQMOD_OS_WINDOWS + break; + case Style::Guess: + ParseGuess(path.Data(), path.Data() + size); + break; + case Style::Dynamic: + ParseDynamic(path.Data(), path.Data() + size); + break; + default: + SqThrowF("Unknown system path style"); + } + } + else + { + SqThrowF("The specified path size is out of range: %u >= %u", size, path.Capacity()); + } + // Allow chaining + return *this; +} + +// ------------------------------------------------------------------------------------------------ +SysPath & SysPath::Assign(const String & path) +{ + // Is the specified path valid? + if (path.empty()) + { + // Just clear current path + Clear(); + } + else + { +#ifdef SQMOD_OS_WINDOWS + ParseWindows(path.data(), path.data() + path.size()); +#else + ParseUnix(path.data(), path.data() + path.size()); +#endif // SQMOD_OS_WINDOWS + } + // Allow chaining + return *this; +} + +// ------------------------------------------------------------------------------------------------ +SysPath & SysPath::Assign(const String & path, Style style) +{ + // Is the specified path valid? + if (path.empty()) + { + // Just clear current path + Clear(); + } + else + { + // Identify which style was requested + switch (style) + { + case Style::Unix: + ParseUnix(path.data(), path.data() + path.size()); + break; + case Style::Windows: + ParseWindows(path.data(), path.data() + path.size()); + break; + case Style::Native: +#ifdef SQMOD_OS_WINDOWS + ParseWindows(path.data(), path.data() + path.size()); +#else + ParseUnix(path.data(), path.data() + path.size()); +#endif // SQMOD_OS_WINDOWS + break; + case Style::Guess: + ParseGuess(path.data(), path.data() + path.size()); + break; + case Style::Dynamic: + ParseDynamic(path.data(), path.data() + path.size()); + break; + default: + SqThrowF("Unknown system path style"); + } + } + // Allow chaining + return *this; +} + +// ------------------------------------------------------------------------------------------------ +SysPath & SysPath::Assign(const SysPath & parent, CSStr name) +{ + // Copy the parent values + *this = parent; + // Set the specified file name + SetFilename(name); + // Allow chaining + return *this; +} + +// ------------------------------------------------------------------------------------------------ +SysPath & SysPath::Assign(const SysPath & parent, const String & name) +{ + // Copy the parent values + *this = parent; + // Set the specified file name + SetFilename(name); + // Allow chaining + return *this; +} + +// ------------------------------------------------------------------------------------------------ +SysPath & SysPath::Assign(const SysPath & parent, const SysPath & relative) +{ + // Copy the parent values + *this = parent; + // Resolve the specified path + Resolve(relative); + // Allow chaining + return *this; +} + +// ------------------------------------------------------------------------------------------------ +SysPath & SysPath::Assign(const SysPath & path) +{ + // Just use regular assignment + *this = path; + // Allow chaining + return *this; +} + +// ------------------------------------------------------------------------------------------------ +SysPath & SysPath::Assign(SysPath && path) +{ + // Just use regular assignment + *this = path; + // Allow chaining + return *this; +} + +// ------------------------------------------------------------------------------------------------ +SysPath & SysPath::AssignDir(CSStr path) +{ + // Assign the specified path + Assign(path); + // Force it to be a directory and allow chaining + return MakeDirectory(); +} + +// ------------------------------------------------------------------------------------------------ +SysPath & SysPath::AssignDir(CSStr path, Int32 style) +{ + // Assign the specified path + Assign(path, style); + // Force it to be a directory and allow chaining + return MakeDirectory(); +} + +// ------------------------------------------------------------------------------------------------ +SysPath & SysPath::AssignDir(CSStr path, Style style) +{ + // Assign the specified path + Assign(path, style); + // Force it to be a directory and allow chaining + return MakeDirectory(); +} + +// ------------------------------------------------------------------------------------------------ +SysPath & SysPath::AssignDir(const Buffer & path, Int32 size) +{ + // Assign the specified path + Assign(path, size); + // Force it to be a directory and allow chaining + return MakeDirectory(); +} + +// ------------------------------------------------------------------------------------------------ +SysPath & SysPath::AssignDir(const Buffer & path, Style style, Int32 size) +{ + // Assign the specified path + Assign(path, style, size); + // Force it to be a directory and allow chaining + return MakeDirectory(); +} + +// ------------------------------------------------------------------------------------------------ +SysPath & SysPath::AssignDir(const String & path) +{ + // Assign the specified path + Assign(path); + // Force it to be a directory and allow chaining + return MakeDirectory(); +} + +// ------------------------------------------------------------------------------------------------ +SysPath & SysPath::AssignDir(const String & path, Style style) +{ + // Assign the specified path + Assign(path, style); + // Force it to be a directory and allow chaining + return MakeDirectory(); +} + +// ------------------------------------------------------------------------------------------------ +Buffer SysPath::ToBuffer() const +{ +#ifdef SQMOD_OS_WINDOWS + return BuildWindows(); +#else + return BuildUnix(); +#endif // SQMOD_OS_WINDOWS +} + +// ------------------------------------------------------------------------------------------------ +Buffer SysPath::ToBuffer(Style style) const +{ + if (style == Style::Unix) + { + return BuildUnix(); + } + else if (style == Style::Windows) + { + return BuildWindows(); + } +#ifdef SQMOD_OS_WINDOWS + return BuildWindows(); +#else + return BuildUnix(); +#endif // SQMOD_OS_WINDOWS +} + +// ------------------------------------------------------------------------------------------------ +Object SysPath::ToStr(Int32 style) const +{ + // Transform the path components into a string + Buffer b(ToBuffer(static_cast< Style >(style))); + // Obtain the initial stack size + const StackGuard sg(DefaultVM::Get()); + // Push the string onto the stack + sq_pushstring(DefaultVM::Get(), b.Data(), b.Position()); + // Obtain the object from the stack and return it + return Var< Object >(DefaultVM::Get(), -1).value; +} + +// ------------------------------------------------------------------------------------------------ +void SysPath::FromString(CSStr path) +{ + Assign(path); +} + +// ------------------------------------------------------------------------------------------------ +SysPath & SysPath::MakeDirectory() +{ + // Do we even have a name? + if (!m_Name.empty()) + { + // Make it a directory + m_Dirs.push_back(std::move(m_Name)); + } + // Allow chaining + return *this; +} + +// ------------------------------------------------------------------------------------------------ +SysPath & SysPath::MakeFile() +{ + // Do we have some directories and no existing file? + if (!m_Dirs.empty() && m_Name.empty()) + { + // Use the last directory as a file + m_Name = std::move(m_Dirs.back()); + // Remove it from the directory list + m_Dirs.pop_back(); + } + // Allow chaining + return *this; +} + +// ------------------------------------------------------------------------------------------------ +SysPath & SysPath::MakeParent() +{ + // Do we have a name? + if (m_Name.empty()) + { + // Do we have any existing directories? + if (m_Dirs.empty()) + { + // Make sure this path isn't absolute + if (!m_Absolute) + { + // Reference the parent directory + m_Dirs.emplace_back(".."); + } + } + else + { + // Are we already referencing a parent? + if (m_Dirs.back().compare("..") == 0) + { + // Then reference the parent of that parent + m_Dirs.emplace_back(".."); + } + // Just pop the last directory + else + { + m_Dirs.pop_back(); + } + } + } + // Just clear the name + else + { + m_Name.clear(); + } + // Allow chaining + return *this; +} + +// ------------------------------------------------------------------------------------------------ +SysPath & SysPath::MakeAbsolute() +{ + // Is this path already absolute? + if (!m_Absolute) + { + MakeAbsolute(Working()); + } + // Allow chaining + return *this; +} + +// ------------------------------------------------------------------------------------------------ +SysPath & SysPath::MakeAbsolute(const SysPath & base) +{ + // Is this path already absolute? + if (!m_Absolute) + { + MakeAbsolute(base); + } + // Allow chaining + return *this; +} + +// ------------------------------------------------------------------------------------------------ +SysPath & SysPath::MakeAbsolute(SysPath && base) +{ + // Is this path already absolute? + if (!m_Absolute) + { + // Reserve the space upfront + base.m_Dirs.reserve(base.m_Dirs.size() + m_Dirs.size()); + // Move our directories at the back + for (auto & dir : m_Dirs) + { + base.m_Dirs.push_back(std::move(dir)); + } + // Take ownership of base directories + m_Dirs.swap(base.m_Dirs); + // Copy the drive letter + m_Drive = base.m_Drive; + // Make absolute only if base is + m_Absolute = base.m_Absolute; + } + // Allow chaining + return *this; +} + +// ------------------------------------------------------------------------------------------------ +SysPath & SysPath::Append(const SysPath & path) +{ + // Make sure this is a directory + MakeDirectory(); + // Only attempt to append if not empty + if (!path.Empty()) + { + // Append the directories from the specified path + m_Dirs.insert(m_Dirs.end(), path.m_Dirs.begin(), path.m_Dirs.end()); + // Copy the file name if any + m_Name = path.m_Name; + } + // Allow chaining + return *this; +} + +// ------------------------------------------------------------------------------------------------ +SysPath & SysPath::Append(SysPath && path) +{ + // Make sure this is a directory + MakeDirectory(); + // Only attempt to append if not empty + if (!path.Empty()) + { + // Request the necessary directory list size upfront + m_Dirs.reserve(m_Dirs.size() + path.m_Dirs.size()); + // Move all directories at the back of our list + for (auto & dir : path.m_Dirs) + { + m_Dirs.push_back(std::move(dir)); + } + // Move the file name if any + m_Name = std::move(path.m_Name); + } + // Allow chaining + return *this; +} + +// ------------------------------------------------------------------------------------------------ +SysPath & SysPath::Append(CSStr path) +{ + return Append(SysPath(path)); +} + +// ------------------------------------------------------------------------------------------------ +SysPath & SysPath::Append(CSStr path, Int32 style) +{ + return Append(SysPath(path, style)); +} + +// ------------------------------------------------------------------------------------------------ +SysPath & SysPath::Append(CSStr path, Style style) +{ + return Append(SysPath(path, style)); +} + +// ------------------------------------------------------------------------------------------------ +SysPath & SysPath::Append(const Buffer & path, Int32 size) +{ + return Append(SysPath(path, size)); +} + +// ------------------------------------------------------------------------------------------------ +SysPath & SysPath::Append(const Buffer & path, Style style, Int32 size) +{ + return Append(SysPath(path, style, size)); +} + +// ------------------------------------------------------------------------------------------------ +SysPath & SysPath::Append(const String & path) +{ + return Append(SysPath(path)); +} + +// ------------------------------------------------------------------------------------------------ +SysPath & SysPath::Append(const String & path, Style style) +{ + return Append(SysPath(path, style)); +} + +// ------------------------------------------------------------------------------------------------ +const String & SysPath::Directory(Uint32 n) const +{ + // Is this within the bounds of the directory list? + if (n < m_Dirs.size()) + { + return m_Dirs[n]; + } + // Fall back to the file name + else + { + return m_Name; + } +} + +// ------------------------------------------------------------------------------------------------ +SysPath & SysPath::Push(CSStr dir) +{ + // Is the specified directory valid? + if (dir && *dir != 0) + { + Push(String(dir)); + } + // Allow chaining + return *this; +} + +// ------------------------------------------------------------------------------------------------ +SysPath & SysPath::Push(const String & dir) +{ + // Is the specified directory valid? + if (!dir.empty() && dir.compare(".") != 0) + { + Push(String(dir)); + } + // Allow chaining + return *this; +} + +// ------------------------------------------------------------------------------------------------ +SysPath & SysPath::Push(String && dir) +{ + // Is the specified directory valid? + if (!dir.empty() && dir.compare(".") != 0) + { + // Does it refer to a parent directory? + if (dir.compare("..") == 0) + { + // Is out last directory already a reference to a parent? + if (!m_Dirs.empty() && m_Dirs.back().compare("..") != 0) + { + m_Dirs.pop_back(); + } + // Move it at the back of our list + else if (!m_Absolute) + { + m_Dirs.push_back(dir); + } + } + // Move it at the back of our list + else + { + m_Dirs.push_back(dir); + } + } + // Allow chaining + return *this; +} + +// ------------------------------------------------------------------------------------------------ +SysPath & SysPath::PopBack() +{ + // Do we even have any directories? + if (!m_Dirs.empty()) + { + // Erase the last one + m_Dirs.pop_back(); + } + // Allow chaining + return *this; +} + +// ------------------------------------------------------------------------------------------------ +SysPath & SysPath::PopFront() +{ + // Do we even have any directories? + if (!m_Dirs.empty()) + { + // Erase the first one + m_Dirs.erase(m_Dirs.begin()); + } + // Allow chaining + return *this; +} + +// ------------------------------------------------------------------------------------------------ +SysPath & SysPath::SetFilename(CSStr name) +{ + // Is the file name even valid? + if (name) + { + m_Name.assign(name); + } + // Allow chaining + return *this; +} + +// ------------------------------------------------------------------------------------------------ +SysPath & SysPath::SetFilename(const String & name) +{ + // Is the file name even valid? + m_Name.assign(name); + // Allow chaining + return *this; +} + +// ------------------------------------------------------------------------------------------------ +SysPath & SysPath::SetFilename(String && name) +{ + // Is the file name even valid? + m_Name.assign(name); + // Allow chaining + return *this; +} + +// ------------------------------------------------------------------------------------------------ +SysPath & SysPath::SetBasename(CSStr name) +{ + // Is the file name even valid? + if (name) + { + // Extract the current extension + String ext = GetExtension(); + // Assign the new base name + m_Name.assign(name); + // Was there an extension before? + if (!ext.empty()) + { + // Add the extension separator + m_Name.push_back('.'); + // Add the original extension + m_Name.append(ext); + } + } + // Allow chaining + return *this; +} + +// ------------------------------------------------------------------------------------------------ +SysPath & SysPath::SetBasename(const String & name) +{ + // Extract the current extension + String ext = GetExtension(); + // Assign the new base name + m_Name.assign(name); + // Was there an extension before? + if (!ext.empty()) + { + // Add the extension separator + m_Name.push_back('.'); + // Add the original extension + m_Name.append(ext); + } + // Allow chaining + return *this; +} + +// ------------------------------------------------------------------------------------------------ +SysPath & SysPath::SetBasename(String && name) +{ + // Extract the current extension + String ext = GetExtension(); + // Assign the new base name + m_Name.assign(name); + // Was there an extension before? + if (!ext.empty()) + { + // Add the extension separator + m_Name.push_back('.'); + // Add the original extension + m_Name.append(ext); + } + // Allow chaining + return *this; +} + +// ------------------------------------------------------------------------------------------------ +String SysPath::GetBasename() const +{ + // Attempt to find the last dot in the file name + const String::size_type pos = m_Name.rfind('.'); + // Was there an extension separator? + if (pos != String::npos) + { + // Return everything before the separator + return m_Name.substr(0, pos); + } + // Return the whole name + return m_Name; +} + +// ------------------------------------------------------------------------------------------------ +SysPath & SysPath::SetExtension(CSStr ext) +{ + // Attempt to find the last dot in the file name + const String::size_type pos = m_Name.rfind('.'); + // Was there an extension separator? + if (pos != String::npos) + { + // Erase the current extension + m_Name.resize(pos); + } + // Is there an extension to append? + if (ext && *ext != 0) + { + m_Name.push_back('.'); + m_Name.append(ext); + } + // Allow chaining + return *this; +} + +// ------------------------------------------------------------------------------------------------ +SysPath & SysPath::SetExtension(const String & ext) +{ + // Attempt to find the last dot in the file name + const String::size_type pos = m_Name.rfind('.'); + // Was there an extension separator? + if (pos != String::npos) + { + // Erase the current extension + m_Name.resize(pos); + } + // Is there an extension to append? + if (!ext.empty()) + { + m_Name.push_back('.'); + m_Name.append(ext); + } + // Allow chaining + return *this; +} + +// ------------------------------------------------------------------------------------------------ +String SysPath::GetExtension() const +{ + // Attempt to find the last dot in the file name + const String::size_type pos = m_Name.rfind('.'); + // Was there an extension separator? + if (pos != String::npos) + { + // Return everything after the separator + return m_Name.substr(pos + 1); + } + // Default to an empty string + return String(); +} + +// ------------------------------------------------------------------------------------------------ +CSStr SysPath::GetExtensionC() const +{ + // Attempt to find the last dot in the file name + const String::size_type pos = m_Name.rfind('.'); + // Was there an extension separator? + if (pos != String::npos) + { + // Because indexing starts from 0, the separator is skipped + return &m_Name[pos+1]; + } + // Default to an empty string + return ""; +} + +// ------------------------------------------------------------------------------------------------ +SysPath SysPath::Parent() const +{ + // Make a copy + SysPath p(*this); + // Force the copy to be parent + p.MakeParent(); + // Return ownership of copy + return std::move(p); +} + +// ------------------------------------------------------------------------------------------------ +SysPath & SysPath::Resolve(const SysPath & path) +{ + // Is the specified path absolute? + if (path.m_Absolute) + { + // Copy it's values + Assign(path); + } + else + { + // Append its directories + for (const auto & dir : path.m_Dirs) + { + Push(dir); + } + // Copy its file name + m_Name = path.m_Name; + } + // Allow chaining + return *this; +} + +// ------------------------------------------------------------------------------------------------ +void SysPath::ParseUnix(CSStr pos, CSStr end) +{ + // Clear previous path information + Clear(); + // Is there even a path to parse? + if (pos == end) + { + return; + } + // If the path starts with a forward slash then the path is absolute + else if (*pos == '/') + { + // This is now an absolute path + m_Absolute = true; + // Skip this directory separator + ++pos; + } + // 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 or no other character + if (pos == end || *(++pos) == '/') + { + // Obtain the home path + SysPath up(Home()); + // Take ownership, don't copy + m_Dirs.swap(up.m_Dirs); + // This is now an absolute path + m_Absolute = true; + } + // Go back to the previous character and use it literally + else + { + --pos; + } + } + // Make another iterator to slice directory names in one go + CSStr itr = pos; + // Extract the remaining directories from the specified path + while (itr != end) + { + // Have we encountered a directory separator? + if (*itr == '/') + { + // Slice the name from the path if valid + if (itr != pos) + { + m_Dirs.emplace_back(pos, itr); + } + // Move the iterator to the current position + pos = ++itr; + } + else + { + ++itr; + } + } + // Grab the last name if any + if (pos != end) + { + m_Name.assign(pos, end); + } +} + +// ------------------------------------------------------------------------------------------------ +void SysPath::ParseWindows(CSStr pos, CSStr end) +{ + // Clear previous path information + Clear(); + // Is there even a path to parse? + if (pos == end) + { + return; + } + // If the path starts with a forward slash then the path is absolute + else if (*pos == '\\') + { + // This is now an absolute path + m_Absolute = true; + // Skip this directory separator + ++pos; + } + // 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 or no other character + if (pos == end || *(++pos) == '\\') + { + // Obtain the home path + SysPath up(Home()); + // Take ownership, don't copy + m_Dirs.swap(up.m_Dirs); + // Also copy the drive letter + m_Drive = up.m_Drive; + // This is now an absolute path + m_Absolute = true; + } + // Go back to the previous character and use it literally + else + { + --pos; + } + } + // Is it possible to have a drive letter? + else if ((end - pos) > 2 && pos[1] == ':' && pos[2] == '\\' && isalpha(*pos) != 0) + { + // Grab the drive letter + m_Drive = *pos; + // Skip the drive path and colon + pos += 2; + } + // Is it possible to have just the drive letter? + else if ((end - pos) == 2 && pos[1] == ':' && isalpha(*pos) != 0) + { + // Grab the drive letter + m_Drive = *pos; + // Nothing left to parse + return; + } + // Make another iterator to slice directory names in one go + CSStr itr = pos; + // Extract the remaining directories from the specified path + while (itr != end) + { + // Have we encountered a directory separator? + if (*itr == '\\') + { + // Slice the name from the path if valid + if (itr != pos) + { + m_Dirs.emplace_back(pos, itr); + } + // Move the iterator to the current position + pos = ++itr; + } + else + { + ++itr; + } + } + // Grab the last name if any + if (pos != end) + { + m_Name.assign(pos, end); + } +} + +// ------------------------------------------------------------------------------------------------ +void SysPath::ParseDynamic(CSStr pos, CSStr end) +{ + // Clear previous path information + Clear(); + // Is there even a path to parse? + if (pos == end) + { + return; + } + // If the path starts with a slash then the path is absolute + else if (*pos == '\\' || *pos == '/') + { + // This is now an absolute path + m_Absolute = true; + // Skip this directory separator + ++pos; + } + // If the path starts with the tilde character then the home directory was requested + else if (*pos == '~') + { + // Skip the tilde character + ++pos; + // The tilde character must be followed by a slash or no other character to be expanded + if (pos == end || *pos == '/' || *pos == '\\') + { + // Obtain the home path + SysPath up(Home()); + // Take ownership, don't copy + m_Dirs.swap(up.m_Dirs); +#ifdef SQMOD_OS_WINDOWS + // Also copy the drive letter + m_Drive = up.m_Drive; +#endif // SQMOD_OS_WINDOWS + // This is now an absolute path + m_Absolute = true; + } + // Go back to the previous character and use it literally + else + { + --pos; + } + } +#ifdef SQMOD_OS_WINDOWS + // Is it possible to have a drive letter? + else if ((end - pos) > 2 && pos[1] == ':' && (pos[2] == '\\' || pos[2] == '/') && isalpha(*pos) != 0) + { + // Grab the drive letter + m_Drive = *pos; + // Skip the drive path and colon + pos += 2; + } + // Is it possible to have just the drive letter? + else if ((end - pos) == 2 && pos[1] == ':' && isalpha(*pos) != 0) + { + // Grab the drive letter + m_Drive = *pos; + // Nothing left to parse + return; + } +#endif // SQMOD_OS_WINDOWS + // Make another iterator to slice directory names in one go + CSStr itr = pos; + // Extract the remaining directories from the specified path + while (itr != end) + { + // Have we encountered a directory separator? + if (*itr == '/' || *itr == '\\') + { + // Slice the name from the path if valid + if (itr != pos) + { + m_Dirs.emplace_back(pos, itr); + } + // Move the iterator to the current position + pos = ++itr; + } + else + { + ++itr; + } + } + // Grab the last name if any + if (pos != end) + { + m_Name.assign(pos, end); + } +} + +// ------------------------------------------------------------------------------------------------ +void SysPath::ParseGuess(CSStr pos, CSStr end) +{ + // Scan for forward slash + const bool has_fwslash = (strchr(pos, '/') != NULL); + const bool has_bwslash = (strchr(pos, '\\') != NULL); + // Does it contain both forward and backward slashes? + if (has_fwslash && has_bwslash) + { + ParseDynamic(pos, end); + } + // Does it contain the forward slash? + else if (has_fwslash) + { + ParseUnix(pos, end); + } + // Does it contain the backward slash? + else if (has_bwslash) + { + ParseWindows(pos, end); + } + // Does it contain a drive letter? + else if ((end - pos) == 2 && pos[1] == ':' && isalpha(*pos) != 0) + { + ParseWindows(pos, end); + } + // Try to parse it as a dynamic path + else + { + ParseDynamic(pos, end); + } +} + +// ------------------------------------------------------------------------------------------------ +Buffer SysPath::BuildUnix() const +{ + // Obtain a buffer capable of storing a full path + Buffer b(SQMOD_MAX_PATH); + // Is this an absolute path? + if (m_Absolute) + { + // Start with a slash + b.Push('/'); + } + // Concatenate all directories + for (const auto & dir : m_Dirs) + { + // Append the name + b.AppendS(dir.c_str(), dir.size()); + // Separate from next + b.Push('/'); + } + // Is there a file name to add? + if (!m_Name.empty()) + { + b.AppendS(m_Name.c_str(), m_Name.size()); + } + // Make sure the string is null terminated + b.Cursor() = '\0'; + // Return ownership of buffer + return std::move(b); +} + +// ------------------------------------------------------------------------------------------------ +Buffer SysPath::BuildWindows() const +{ + // Obtain a buffer capable of storing a full path + Buffer b(SQMOD_MAX_PATH); + // Does it have a drive letter? + if (isalpha(m_Drive) != 0) + { + // Add the drive letter + b.Push(m_Drive); + // Add the colon + b.Push(':'); + // Add the slash + b.Push('\\'); + } + // Is this an absolute path? + else if (m_Absolute) + { + // Start with a slash + b.Push('\\'); + } + // Concatenate all directories + for (const auto & dir : m_Dirs) + { + // Append the name + b.AppendS(dir.c_str(), dir.size()); + // Separate from next + b.Push('\\'); + } + // Is there a file name to add? + if (!m_Name.empty()) + { + b.AppendS(m_Name.c_str(), m_Name.size()); + } + // Make sure the string is null terminated + b.Cursor() = '\0'; + // Return ownership of buffer + return std::move(b); +} + +// ------------------------------------------------------------------------------------------------ +SysPath SysPath::ForDirectory(CSStr path) +{ + return SysPath(path).MakeDirectory(); +} + +// ------------------------------------------------------------------------------------------------ +SysPath SysPath::ForDirectory(CSStr path, Int32 style) +{ + return SysPath(path, style).MakeDirectory(); +} + +// ------------------------------------------------------------------------------------------------ +SysPath SysPath::ForDirectory(CSStr path, Style style) +{ + return SysPath(path, style).MakeDirectory(); +} + +// ------------------------------------------------------------------------------------------------ +SysPath SysPath::ForDirectory(const String & path) +{ + return SysPath(path).MakeDirectory(); +} + +// ------------------------------------------------------------------------------------------------ +SysPath SysPath::ForDirectory(const String & path, Style style) +{ + return SysPath(path, style).MakeDirectory(); +} + +// ------------------------------------------------------------------------------------------------ +SysPath SysPath::Expand(CSStr path) +{ + return SysPath(SysEnv::ExpandPath(path)); +} + +// ------------------------------------------------------------------------------------------------ +SysPath SysPath::Home() +{ + return SysPath(SysEnv::HomeDir()); +} + +// ------------------------------------------------------------------------------------------------ +SysPath SysPath::ConfigHome() +{ + return SysPath(SysEnv::ConfigHomeDir()); +} + +// ------------------------------------------------------------------------------------------------ +SysPath SysPath::DataHome() +{ + return SysPath(SysEnv::DataHomeDir()); +} + +// ------------------------------------------------------------------------------------------------ +SysPath SysPath::TempHome() +{ + return SysPath(SysEnv::TempHomeDir()); +} + +// ------------------------------------------------------------------------------------------------ +SysPath SysPath::CacheHome() +{ + return SysPath(SysEnv::CacheHomeDir()); +} + +// ------------------------------------------------------------------------------------------------ +SysPath SysPath::Working() +{ + return SysPath(SysEnv::WorkingDir()); +} + +// ------------------------------------------------------------------------------------------------ +SysPath SysPath::Temp() +{ + return SysPath(SysEnv::TempDir()); +} + +// ------------------------------------------------------------------------------------------------ +SysPath SysPath::Config() +{ + return SysPath(SysEnv::ConfigDir()); +} + +// ------------------------------------------------------------------------------------------------ +SysPath SysPath::System() +{ + return SysPath(SysEnv::SystemDir()); +} + +// ------------------------------------------------------------------------------------------------ +SysPath SysPath::Null() +{ + return SysPath(SysEnv::NullDir()); +} + +// ------------------------------------------------------------------------------------------------ +SysPath SysPath::With(const SysPath & parent, CSStr name) +{ + return SysPath(parent, name); +} + +// ================================================================================================ +void Register_SysPath(HSQUIRRELVM vm) +{ + RootTable(vm).Bind("SqSysPath", Class< SysPath >(vm, "SqSysPath") + // Constructors + .Ctor() + .Ctor< CSStr >() + .Ctor< CSStr, Int32 >() + // Metamethods + .Func(_SC("_cmp"), &SysPath::Cmp) + .SquirrelFunc(_SC("_typename"), &SysPath::Typename) + .Func(_SC("_tostring"), &SysPath::ToString) + // Properties + .Prop(_SC("String"), &SysPath::ToString, &SysPath::FromString) + .Prop(_SC("Absolute"), &SysPath::IsAbsolute) + .Prop(_SC("Relative"), &SysPath::IsRelative) + .Prop(_SC("Directory"), &SysPath::IsDirectory) + .Prop(_SC("File"), &SysPath::IsFile) + .Prop(_SC("Empty"), &SysPath::Empty) + .Prop(_SC("Drive"), &SysPath::GetDrive, &SysPath::SetDrive) + .Prop(_SC("Depth"), &SysPath::Depth) + .Prop(_SC("Filename"), &SysPath::GetFilename, &SysPath::SqSetFilename) + .Prop(_SC("Basename"), &SysPath::GetBasename, &SysPath::SqSetBasename) + .Prop(_SC("Extension"), &SysPath::GetExtensionC, &SysPath::SqSetExtension) + .Prop(_SC("Parent"), &SysPath::Parent) + // Member Methods + .Func(_SC("Swap"), &SysPath::Swap) + .Func(_SC("Clear"), &SysPath::Clear) + .Func< SysPath & (SysPath::*)(const SysPath &) >(_SC("AssignPath"), &SysPath::Assign) + .Func< SysPath & (SysPath::*)(const SysPath &) >(_SC("AppendPath"), &SysPath::Append) + .Func(_SC("MakeDir"), &SysPath::MakeDirectory) + .Func(_SC("MakeDirectory"), &SysPath::MakeDirectory) + .Func(_SC("MakeFile"), &SysPath::MakeFile) + .Func(_SC("MakeParent"), &SysPath::MakeParent) + .Func(_SC("Dir"), &SysPath::Directory) + .Func(_SC("Directory"), &SysPath::Directory) + .Func< SysPath & (SysPath::*)(CSStr) >(_SC("Push"), &SysPath::Push) + .Func(_SC("PopBack"), &SysPath::PopBack) + .Func(_SC("PopFront"), &SysPath::PopFront) + .Func< SysPath & (SysPath::*)(CSStr) >(_SC("SetFilename"), &SysPath::SetFilename) + .Func(_SC("GetFilename"), &SysPath::GetFilename) + .Func< SysPath & (SysPath::*)(CSStr) >(_SC("SetBasename"), &SysPath::SetBasename) + .Func(_SC("GetBasename"), &SysPath::GetBasename) + .Func< SysPath & (SysPath::*)(CSStr) >(_SC("SetExtension"), &SysPath::SetExtension) + .Func(_SC("GetExtension"), &SysPath::GetExtension) + .Func(_SC("Resolve"), &SysPath::Resolve) + // Member Overloads + .Overload< SysPath & (SysPath::*)(CSStr) >(_SC("Assign"), &SysPath::Assign) + .Overload< SysPath & (SysPath::*)(CSStr, Int32) >(_SC("Assign"), &SysPath::Assign) + .Overload< SysPath & (SysPath::*)(CSStr) >(_SC("AssignDir"), &SysPath::AssignDir) + .Overload< SysPath & (SysPath::*)(CSStr, Int32) >(_SC("AssignDir"), &SysPath::AssignDir) + .Overload< SysPath & (SysPath::*)(CSStr) >(_SC("Append"), &SysPath::Append) + .Overload< SysPath & (SysPath::*)(CSStr, Int32) >(_SC("Append"), &SysPath::Append) + .Overload< SysPath & (SysPath::*)(void) >(_SC("MakeAbsolute"), &SysPath::MakeAbsolute) + .Overload< SysPath & (SysPath::*)(const SysPath &) >(_SC("MakeAbsolute"), &SysPath::MakeAbsolute) + // Static Functions + .StaticFunc(_SC("Separator"), &SysPath::Separator) + .StaticFunc(_SC("PathSeparator"), &SysPath::PathSeparator) + .StaticFunc< SysPath (*)(CSStr) >(_SC("Expand"), &SysPath::Expand) + .StaticFunc(_SC("Home"), &SysPath::Home) + .StaticFunc(_SC("ConfigHome"), &SysPath::ConfigHome) + .StaticFunc(_SC("DataHome"), &SysPath::DataHome) + .StaticFunc(_SC("TempHome"), &SysPath::TempHome) + .StaticFunc(_SC("CacheHome"), &SysPath::CacheHome) + .StaticFunc(_SC("Current"), &SysPath::Working) + .StaticFunc(_SC("Working"), &SysPath::Working) + .StaticFunc(_SC("Temp"), &SysPath::Temp) + .StaticFunc(_SC("Config"), &SysPath::Config) + .StaticFunc(_SC("System"), &SysPath::System) + .StaticFunc(_SC("Null"), &SysPath::Null) + .StaticFunc(_SC("With"), &SysPath::With) + // Static Overloads + .StaticOverload< SysPath (*)(CSStr) >(_SC("ForDir"), &SysPath::ForDirectory) + .StaticOverload< SysPath (*)(CSStr, Int32) >(_SC("ForDir"), &SysPath::ForDirectory) + .StaticOverload< SysPath (*)(CSStr) >(_SC("ForDirectory"), &SysPath::ForDirectory) + .StaticOverload< SysPath (*)(CSStr, Int32) >(_SC("ForDirectory"), &SysPath::ForDirectory) + ); + + ConstTable(vm).Enum(_SC("SqSysPathStyle"), Enumeration(vm) + .Const(_SC("Unix"), static_cast< Int32 >(SysPath::Style::Unix)) + .Const(_SC("Windows"), static_cast< Int32 >(SysPath::Style::Windows)) + .Const(_SC("Native"), static_cast< Int32 >(SysPath::Style::Native)) + .Const(_SC("Guess"), static_cast< Int32 >(SysPath::Style::Guess)) + .Const(_SC("Dynamic"), static_cast< Int32 >(SysPath::Style::Dynamic)) + ); +} + +} // Namespace:: SqMod diff --git a/source/Library/SysPath.hpp b/source/Library/SysPath.hpp index e69de29b..9b6fad5d 100644 --- a/source/Library/SysPath.hpp +++ b/source/Library/SysPath.hpp @@ -0,0 +1,729 @@ +#ifndef _LIBRARY_SYSPATH_HPP_ +#define _LIBRARY_SYSPATH_HPP_ + +// ------------------------------------------------------------------------------------------------ +#include "Base/Shared.hpp" + +// ------------------------------------------------------------------------------------------------ +#include + +// ------------------------------------------------------------------------------------------------ +namespace SqMod { + +/* ------------------------------------------------------------------------------------------------ + * This class represents filesystem paths in a platform-independent manner. +*/ +class SysPath +{ +public: + + // -------------------------------------------------------------------------------------------- + typedef std::vector< String > StrVec; // Directory list. + + /* -------------------------------------------------------------------------------------------- + * Styles of directories to expect when parsing or to export. + */ + enum struct Style + { + Unix = 0, + Windows, + Native, + Guess, + Dynamic + }; + + /* -------------------------------------------------------------------------------------------- + * Creates an empty relative path. + */ + SysPath(); + + /* -------------------------------------------------------------------------------------------- + * Creates an empty absolute or relative path. + */ + SysPath(bool absolute); + + /* -------------------------------------------------------------------------------------------- + * Creates a path in native format from a string. + */ + SysPath(CSStr path); + + /* -------------------------------------------------------------------------------------------- + * Creates a path from a string. + */ + SysPath(CSStr path, Int32 style); + + /* -------------------------------------------------------------------------------------------- + * Creates a path from a string. + */ + SysPath(CSStr path, Style style); + + /* -------------------------------------------------------------------------------------------- + * Creates a path in native format from a string. + */ + SysPath(const Buffer & path, Int32 size = -1); + + /* -------------------------------------------------------------------------------------------- + * Creates a path from a string. + */ + SysPath(const Buffer & path, Style style, Int32 size = -1); + + /* -------------------------------------------------------------------------------------------- + * Creates a path in native format from a string. + */ + SysPath(const String & path); + + /* -------------------------------------------------------------------------------------------- + * Creates a path from a string. + */ + SysPath(const String & path, Style style); + + /* -------------------------------------------------------------------------------------------- + * Creates a path from a parent path and a file name. The parent path is expected to reference + * a directory. + */ + SysPath(const SysPath & parent, CSStr name); + + /* -------------------------------------------------------------------------------------------- + * Creates a path from a parent path and a file name. The parent path is expected to reference + * a directory. + */ + SysPath(const SysPath & parent, const String & name); + + /* -------------------------------------------------------------------------------------------- + * Creates a path from a parent path and a relative path. The parent path is expected + * to reference a directory. The relative path is appended to the parent path. + */ + SysPath(const SysPath & parent, const SysPath & relative); + + /* -------------------------------------------------------------------------------------------- + * Copy constructor. + */ + SysPath(const SysPath & o); + + /* -------------------------------------------------------------------------------------------- + * Move constructor. + */ + SysPath(SysPath && o); + + /* -------------------------------------------------------------------------------------------- + * Destructor. + */ + ~SysPath(); + + /* -------------------------------------------------------------------------------------------- + * Copy assignment operator. + */ + SysPath & operator = (const SysPath & o); + + /* -------------------------------------------------------------------------------------------- + * Move assignment operator. + */ + SysPath & operator = (SysPath && o); + + /* -------------------------------------------------------------------------------------------- + * Assigns a string containing a path in native format. + */ + SysPath & operator = (CSStr path); + + /* -------------------------------------------------------------------------------------------- + * Assigns a string containing a path in native format. + */ + SysPath & operator = (const String & path); + + /* -------------------------------------------------------------------------------------------- + * Equality comparison. + */ + bool operator == (const SysPath & o) const; + + /* -------------------------------------------------------------------------------------------- + * Inequality comparison. + */ + bool operator != (const SysPath & o) const; + + /* -------------------------------------------------------------------------------------------- + * Implicit conversion to boolean operator. + */ + operator bool () const; + + /* -------------------------------------------------------------------------------------------- + * Returns the n'th directory in the directory list. If n == depth(), returns the file name. + */ + const String & operator [] (Uint32 n) const; + + /* -------------------------------------------------------------------------------------------- + * Used by the script engine to compare two instances of this type. + */ + Int32 Cmp(const SysPath & o) const; + + /* -------------------------------------------------------------------------------------------- + * Used by the script engine to convert an instance of this type to a string. + */ + Object ToString() const; + + /* -------------------------------------------------------------------------------------------- + * Used by the script engine to retrieve the name from instances of this type. + */ + static SQInteger Typename(HSQUIRRELVM vm); + + /* -------------------------------------------------------------------------------------------- + * Swaps the path with another one. + */ + void Swap(SysPath & path); + + /* -------------------------------------------------------------------------------------------- + * Clears all components. + */ + void Clear(); + + /* -------------------------------------------------------------------------------------------- + * Assigns a string containing a path in native format. + */ + SysPath & Assign(CSStr path); + + /* -------------------------------------------------------------------------------------------- + * Assigns a string containing a path. + */ + SysPath & Assign(CSStr path, Int32 style); + + /* -------------------------------------------------------------------------------------------- + * Assigns a string containing a path. + */ + SysPath & Assign(CSStr path, Style style); + + /* -------------------------------------------------------------------------------------------- + * Assigns a string containing a path in native format. + */ + SysPath & Assign(const Buffer & path, Int32 size = -1); + + /* -------------------------------------------------------------------------------------------- + * Assigns a string containing a path. + */ + SysPath & Assign(const Buffer & path, Style style, Int32 size = -1); + + /* -------------------------------------------------------------------------------------------- + * Assigns a string containing a path in native format. + */ + SysPath & Assign(const String & path); + + /* -------------------------------------------------------------------------------------------- + * Assigns a string containing a path. + */ + SysPath & Assign(const String & path, Style style); + + /* -------------------------------------------------------------------------------------------- + * Creates a path from a parent path and a file name. The parent path is expected to reference + * a directory. + */ + SysPath & Assign(const SysPath & parent, CSStr name); + + /* -------------------------------------------------------------------------------------------- + * Creates a path from a parent path and a file name. The parent path is expected to reference + * a directory. + */ + SysPath & Assign(const SysPath & parent, const String & name); + + /* -------------------------------------------------------------------------------------------- + * Creates a path from a parent path and a relative path. The parent path is expected + * to reference a directory. The relative path is appended to the parent path. + */ + SysPath & Assign(const SysPath & parent, const SysPath & relative); + + /* -------------------------------------------------------------------------------------------- + * Copy the components from another path. + */ + SysPath & Assign(const SysPath & path); + + /* -------------------------------------------------------------------------------------------- + * Move the components of another path into this instance. + */ + SysPath & Assign(SysPath && path); + + /* -------------------------------------------------------------------------------------------- + * The resulting path always refers to a directory and the filename part is empty. + */ + SysPath & AssignDir(CSStr path); + + /* -------------------------------------------------------------------------------------------- + * The resulting path always refers to a directory and the filename part is empty. + */ + SysPath & AssignDir(CSStr path, Int32 style); + + /* -------------------------------------------------------------------------------------------- + * The resulting path always refers to a directory and the filename part is empty. + */ + SysPath & AssignDir(CSStr path, Style style); + + /* -------------------------------------------------------------------------------------------- + * The resulting path always refers to a directory and the filename part is empty. + */ + SysPath & AssignDir(const Buffer & path, Int32 size = -1); + + /* -------------------------------------------------------------------------------------------- + * The resulting path always refers to a directory and the filename part is empty. + */ + SysPath & AssignDir(const Buffer & path, Style style, Int32 size = -1); + + /* -------------------------------------------------------------------------------------------- + * The resulting path always refers to a directory and the filename part is empty. + */ + SysPath & AssignDir(const String & path); + + /* -------------------------------------------------------------------------------------------- + * The resulting path always refers to a directory and the filename part is empty. + */ + SysPath & AssignDir(const String & path, Style style); + + /* -------------------------------------------------------------------------------------------- + * Returns a string containing the path in native format. + */ + Buffer ToBuffer() const; + + /* -------------------------------------------------------------------------------------------- + * Returns a string containing the path in the given format. + */ + Buffer ToBuffer(Style style) const; + + /* -------------------------------------------------------------------------------------------- + * Returns a string containing the path in the given format. + */ + Object ToStr(Int32 style) const; + + /* -------------------------------------------------------------------------------------------- + * Assigns a string containing a path. + */ + void FromString(CSStr path); + + /* -------------------------------------------------------------------------------------------- + * See whether the path is absolute. + */ + bool IsAbsolute() const + { + return m_Absolute; + } + + /* -------------------------------------------------------------------------------------------- + * See whether the path is relative. + */ + bool IsRelative() const + { + return !m_Absolute; + } + + /* -------------------------------------------------------------------------------------------- + * See whether the path references a directory. + */ + bool IsDirectory() const + { + return m_Name.empty(); + } + + /* -------------------------------------------------------------------------------------------- + * See whether the path references a file. + */ + bool IsFile() const + { + return !m_Name.empty(); + } + + /* -------------------------------------------------------------------------------------------- + * See whether the path Does not contain a drive, directories or file name. + */ + bool Empty() const + { + return (!m_Dirs.empty() || !m_Name.empty() || m_Drive != 0); + } + + /* -------------------------------------------------------------------------------------------- + * If the path contains a file name, the file name is appended to the directory list and cleared. + */ + SysPath & MakeDirectory(); + + /* -------------------------------------------------------------------------------------------- + * If the path contains no file name, the last directory becomes the file name. + */ + SysPath & MakeFile(); + + /* -------------------------------------------------------------------------------------------- + * Makes the path refer to its parent. + */ + SysPath & MakeParent(); + + /* -------------------------------------------------------------------------------------------- + * Makes the path absolute if it is relative. The current working directory is taken + * as base directory. + */ + SysPath & MakeAbsolute(); + + /* -------------------------------------------------------------------------------------------- + * Makes the path absolute if it is relative. The given path is taken as base. + */ + SysPath & MakeAbsolute(const SysPath & base); + + /* -------------------------------------------------------------------------------------------- + * Makes the path absolute if it is relative. The given path is taken as base. + */ + SysPath & MakeAbsolute(SysPath && base); + + /* -------------------------------------------------------------------------------------------- + * Appends the given path. + */ + SysPath & Append(const SysPath & path); + + /* -------------------------------------------------------------------------------------------- + * Appends the given path. + */ + SysPath & Append(SysPath && path); + + /* -------------------------------------------------------------------------------------------- + * Parse the given string and append the resulted path. + */ + SysPath & Append(CSStr path); + + /* -------------------------------------------------------------------------------------------- + * Parse the given string and append the resulted path. + */ + SysPath & Append(CSStr path, Int32 style); + + /* -------------------------------------------------------------------------------------------- + * Parse the given string and append the resulted path. + */ + SysPath & Append(CSStr path, Style style); + + /* -------------------------------------------------------------------------------------------- + * Parse the given string and append the resulted path. + */ + SysPath & Append(const Buffer & path, Int32 size = -1); + + /* -------------------------------------------------------------------------------------------- + * Parse the given string and append the resulted path. + */ + SysPath & Append(const Buffer & path, Style style, Int32 size = -1); + + /* -------------------------------------------------------------------------------------------- + * Parse the given string and append the resulted path. + */ + SysPath & Append(const String & path); + + /* -------------------------------------------------------------------------------------------- + * Parse the given string and append the resulted path. + */ + SysPath & Append(const String & path, Style style); + + /* -------------------------------------------------------------------------------------------- + * Returns the drive letter. + */ + CharT GetDrive() const + { + return m_Drive; + } + + /* -------------------------------------------------------------------------------------------- + * Modifies the drive letter. + */ + void SetDrive(CharT drive) + { + m_Drive = drive; + } + + /* -------------------------------------------------------------------------------------------- + * Returns the number of directories in the directory list. + */ + Uint32 Depth() const + { + return m_Dirs.size(); + } + + /* -------------------------------------------------------------------------------------------- + * Returns the n'th directory in the directory list. If n == depth(), returns the file name. + */ + const String & Directory(Uint32 n) const; + + /* -------------------------------------------------------------------------------------------- + * Adds a directory to the directory list. + */ + SysPath & Push(CSStr dir); + + /* -------------------------------------------------------------------------------------------- + * Adds a directory to the directory list. + */ + SysPath & Push(const String & dir); + + /* -------------------------------------------------------------------------------------------- + * Adds a directory to the directory list. + */ + SysPath & Push(String && dir); + + /* -------------------------------------------------------------------------------------------- + * Removes the last directory from the directory list. + */ + SysPath & PopBack(); + + /* -------------------------------------------------------------------------------------------- + * Removes the first directory from the directory list. + */ + SysPath & PopFront(); + + /* -------------------------------------------------------------------------------------------- + * Set the specified file name. + */ + SysPath & SetFilename(CSStr name); + + /* -------------------------------------------------------------------------------------------- + * Set the specified file name. + */ + SysPath & SetFilename(const String & name); + + /* -------------------------------------------------------------------------------------------- + * Set the specified file name. + */ + SysPath & SetFilename(String && name); + + /* -------------------------------------------------------------------------------------------- + * Retrieves the file name. + */ + const String & GetFilename() const + { + return m_Name; + } + + /* -------------------------------------------------------------------------------------------- + * Set the specified file name. + */ + void SqSetFilename(CSStr name) + { + SetFilename(name); + } + + /* -------------------------------------------------------------------------------------------- + * Sets the basename part of the file name and does not change the extension. + */ + SysPath & SetBasename(CSStr name); + + /* -------------------------------------------------------------------------------------------- + * Sets the basename part of the file name and does not change the extension. + */ + SysPath & SetBasename(const String & name); + + /* -------------------------------------------------------------------------------------------- + * Sets the basename part of the file name and does not change the extension. + */ + SysPath & SetBasename(String && name); + + /* -------------------------------------------------------------------------------------------- + * Returns the basename (the file name without extension) of the path. + */ + String GetBasename() const; + + /* -------------------------------------------------------------------------------------------- + * Sets the basename part of the file name and does not change the extension. + */ + void SqSetBasename(CSStr name) + { + SetBasename(name); + } + + /* -------------------------------------------------------------------------------------------- + * Sets the file name extension. + */ + SysPath & SetExtension(CSStr ext); + + /* -------------------------------------------------------------------------------------------- + * Sets the file name extension. + */ + SysPath & SetExtension(const String & ext); + + /* -------------------------------------------------------------------------------------------- + * Returns the file name extension. + */ + String GetExtension() const; + + /* -------------------------------------------------------------------------------------------- + * Sets the file name extension. + */ + void SqSetExtension(CSStr ext) + { + SetExtension(ext); + } + + /* -------------------------------------------------------------------------------------------- + * Returns a pointer to the internal name string where the extension starts. + */ + CSStr GetExtensionC() const; + + /* -------------------------------------------------------------------------------------------- + * Returns a path referring to the path's directory. + */ + SysPath Parent() const; + + /* -------------------------------------------------------------------------------------------- + * Resolves the given path against the current one. If the given path is absolute, it replaces + * the current one. Otherwise, the relative path is appended to the current path. + */ + SysPath & Resolve(const SysPath & path); + +protected: + + /* -------------------------------------------------------------------------------------------- + * Parse a path using the unix standards. + */ + void ParseUnix(CSStr pos, CSStr end); + + /* -------------------------------------------------------------------------------------------- + * Parse a path using the windows standards. + */ + void ParseWindows(CSStr pos, CSStr end); + + /* -------------------------------------------------------------------------------------------- + * Parse a path and expect combined windows and unix styles. + */ + void ParseDynamic(CSStr pos, CSStr end); + + /* -------------------------------------------------------------------------------------------- + * Parse a path and try to detect it's type automatically. + */ + void ParseGuess(CSStr pos, CSStr end); + + /* -------------------------------------------------------------------------------------------- + * Build a path string using the Unix conventions. + */ + Buffer BuildUnix() const; + + /* -------------------------------------------------------------------------------------------- + * Build a path string using the Windows conventions. + */ + Buffer BuildWindows() const; + +private: + + // -------------------------------------------------------------------------------------------- + StrVec m_Dirs; /* The list of directories that form the path. */ + String m_Name; /* The file name if one was specified. */ + CharT m_Drive; /* The drive letter if one was specified. */ + bool m_Absolute; /* Whether this path is an absolute path. */ + +public: + + /* -------------------------------------------------------------------------------------------- + * Returns the platform's path name separator, which separates the components (names) in a path. + */ + static CharT Separator() + { +#ifdef GMOD_OS_WINDOWS + return '\\'; +#else + return '/'; +#endif // GMOD_OS_WINDOWS + } + + /* -------------------------------------------------------------------------------------------- + * Returns the platform's path separator, which separates single paths in a list of paths. + */ + static CharT PathSeparator() + { +#ifdef GMOD_OS_WINDOWS + return ';'; +#else + return ':'; +#endif // GMOD_OS_WINDOWS + } + + /* -------------------------------------------------------------------------------------------- + * Creates a path referring to a directory. + */ + static SysPath ForDirectory(CSStr path); + + /* -------------------------------------------------------------------------------------------- + * Creates a path referring to a directory. + */ + static SysPath ForDirectory(CSStr path, Int32 style); + + /* -------------------------------------------------------------------------------------------- + * Creates a path referring to a directory. + */ + static SysPath ForDirectory(CSStr path, Style style); + + /* -------------------------------------------------------------------------------------------- + * Creates a path referring to a directory. + */ + static SysPath ForDirectory(const String & path); + + /* -------------------------------------------------------------------------------------------- + * Creates a path referring to a directory. + */ + static SysPath ForDirectory(const String & path, Style style); + + /* -------------------------------------------------------------------------------------------- + * Expands all environment variables contained in the path. On Unix, a tilde as first character + * in the path is replaced with the path to user's home directory. + */ + static SysPath Expand(CSStr path); + + /* -------------------------------------------------------------------------------------------- + * Expands all environment variables contained in the path. + */ + static SysPath Expand(const String & path) + { + return Expand(path.c_str()); + } + + /* -------------------------------------------------------------------------------------------- + * Returns the user's home directory. + */ + static SysPath Home(); + + /* -------------------------------------------------------------------------------------------- + * Returns the user's config directory. + */ + static SysPath ConfigHome(); + + /* -------------------------------------------------------------------------------------------- + * Returns the user's data directory. + */ + static SysPath DataHome(); + + /* -------------------------------------------------------------------------------------------- + * Returns the user's temp directory. + */ + static SysPath TempHome(); + + /* -------------------------------------------------------------------------------------------- + * Returns the user's temp directory. + */ + static SysPath CacheHome(); + + /* -------------------------------------------------------------------------------------------- + * Returns the current working directory. + */ + static SysPath Working(); + + /* -------------------------------------------------------------------------------------------- + * Returns the temporary directory. + */ + static SysPath Temp(); + + /* -------------------------------------------------------------------------------------------- + * Returns the systemwide config directory. + */ + static SysPath Config(); + + /* -------------------------------------------------------------------------------------------- + * Returns the system directory. + */ + static SysPath System(); + + /* -------------------------------------------------------------------------------------------- + * Returns the name of the null device. + */ + static SysPath Null(); + + /* -------------------------------------------------------------------------------------------- + * Creates a path from a parent path and a file name. The parent path is expected to reference + * a directory. + */ + static SysPath With(const SysPath & parent, CSStr name); + +}; + +} // Namespace:: SqMod + +#endif // _LIBRARY_SYSPATH_HPP_ diff --git a/source/Library/System.cpp b/source/Library/System.cpp deleted file mode 100644 index e69de29b..00000000 diff --git a/source/Library/System.hpp b/source/Library/System.hpp deleted file mode 100644 index e69de29b..00000000 diff --git a/source/Register.cpp b/source/Register.cpp index 74d48ae9..e82389cf 100644 --- a/source/Register.cpp +++ b/source/Register.cpp @@ -38,6 +38,8 @@ extern void Register_Crypt(HSQUIRRELVM vm); extern void Register_Numeric(HSQUIRRELVM vm); extern void Register_Random(HSQUIRRELVM vm); extern void Register_String(HSQUIRRELVM vm); +extern void Register_SysEnv(HSQUIRRELVM vm); +extern void Register_SysPath(HSQUIRRELVM vm); extern void Register_Time(HSQUIRRELVM vm); // ------------------------------------------------------------------------------------------------ @@ -80,6 +82,8 @@ bool RegisterAPI(HSQUIRRELVM vm) Register_Random(vm); Register_Numeric(vm); Register_String(vm); + Register_SysEnv(vm); + Register_SysPath(vm); Register_Time(vm); Register_Constants(vm);