1
0
mirror of https://github.com/VCMP-SqMod/SqMod.git synced 2024-11-08 08:47:17 +01:00
SqMod/source/Library/SysPath.cpp
Sandu Liviu Catalin b818a162ee Initial implementation of the standard math library.
Implemented utilities to convert between fundamental types.
Implemented helper functions to retrieve numeric values from the stack at all costs.
Implemented various delegates on the long integer types to mimic the standard types.
Moved most of the stack utilities in a separate source.
Various other fixes and improvements.
2016-04-14 03:08:06 +03:00

1730 lines
50 KiB
C++

// ------------------------------------------------------------------------------------------------
#include "Library/SysPath.hpp"
#include "Library/SysEnv.hpp"
#include "Base/Stack.hpp"
// ------------------------------------------------------------------------------------------------
#include <cctype>
// ------------------------------------------------------------------------------------------------
#include <utility>
// ------------------------------------------------------------------------------------------------
#ifdef SQMOD_OS_WINDOWS
#include <windows.h>
#else
#include <linux/limits.h>
#include <unistd.h>
#endif
// ------------------------------------------------------------------------------------------------
namespace SqMod {
// ------------------------------------------------------------------------------------------------
#ifdef SQMOD_OS_WINDOWS
// Maximum path size in characters
#define SQMOD_MAX_PATH (sizeof(TCHAR) * MAX_PATH)
// Character to be used when working with path
typedef TCHAR PChar;
#else
// Maximum path size in characters
#define SQMOD_MAX_PATH (PATH_MAX)
// Character to be used when working with path
typedef CharT PChar;
#endif // SQMOD_OS_WINDOWS
// ------------------------------------------------------------------------------------------------
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
{
return BufferToStrObj(ToBuffer());
}
// ------------------------------------------------------------------------------------------------
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:
STHROWF("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
{
STHROWF("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:
STHROWF("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:
STHROWF("Unknown system path style");
}
}
else
{
STHROWF("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:
STHROWF("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
{
return BufferToStrObj(ToBuffer(static_cast< Style >(style)));
}
// ------------------------------------------------------------------------------------------------
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("Build"), &SysPath::ToStr)
.Func(_SC("ToStr"), &SysPath::ToStr)
.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