summaryrefslogtreecommitdiffstats
path: root/source/core/slang-io.cpp
diff options
context:
space:
mode:
authorEllie Hermaszewska <ellieh@nvidia.com>2024-10-29 14:49:26 +0800
committerGitHub <noreply@github.com>2024-10-29 14:49:26 +0800
commitf65d756bff8d4c5cbc15bd0322a2ae8e6b896a21 (patch)
treeea1d61342cd29368e19135000ec2948813096205 /source/core/slang-io.cpp
parenta729c15e9dce9f5116a38afc66329ab2ca4cea54 (diff)
format
* format * Minor test fixes * enable checking cpp format in ci
Diffstat (limited to 'source/core/slang-io.cpp')
-rw-r--r--source/core/slang-io.cpp2085
1 files changed, 1055 insertions, 1030 deletions
diff --git a/source/core/slang-io.cpp b/source/core/slang-io.cpp
index edd21639b..25c4c9389 100644
--- a/source/core/slang-io.cpp
+++ b/source/core/slang-io.cpp
@@ -1,15 +1,14 @@
#define _CRT_SECURE_NO_WARNINGS 1
#include "slang-io.h"
-#include "slang-exception.h"
+#include "slang-char-util.h"
#include "slang-com-helper.h"
-
+#include "slang-exception.h"
#include "slang-string-util.h"
-#include "slang-char-util.h"
#ifndef __STDC__
-# define __STDC__ 1
+#define __STDC__ 1
#endif
#include <sys/stat.h>
@@ -24,1366 +23,1392 @@
#endif
#if defined(__linux__) || defined(__CYGWIN__) || SLANG_APPLE_FAMILY || SLANG_WASM
-# include <fcntl.h>
-# include <unistd.h>
+#include <fcntl.h>
+#include <unistd.h>
// For Path::find
-# include <fnmatch.h>
-
-# include <dirent.h>
-# include <sys/stat.h>
-# include <sys/file.h>
-# include <ftw.h> // for nftw
+#include <dirent.h>
+#include <fnmatch.h>
+#include <ftw.h> // for nftw
+#include <sys/file.h>
+#include <sys/stat.h>
#endif
#if SLANG_APPLE_FAMILY
-# include <mach-o/dyld.h>
+#include <mach-o/dyld.h>
#endif
+#include <filesystem>
#include <limits.h> /* PATH_MAX */
#include <stdio.h>
#include <stdlib.h>
-#include <filesystem>
namespace Slang
{
- /* static */SlangResult File::remove(const String& fileName)
- {
+/* static */ SlangResult File::remove(const String& fileName)
+{
#ifdef _WIN32
- // https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-deletefilea
- if (DeleteFileA(fileName.getBuffer()))
- {
- return SLANG_OK;
- }
- return SLANG_FAIL;
+ // https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-deletefilea
+ if (DeleteFileA(fileName.getBuffer()))
+ {
+ return SLANG_OK;
+ }
+ return SLANG_FAIL;
#else
- // https://linux.die.net/man/3/remove
- if (::remove(fileName.getBuffer()) == 0)
- {
- return SLANG_OK;
- }
- return SLANG_FAIL;
-#endif
+ // https://linux.die.net/man/3/remove
+ if (::remove(fileName.getBuffer()) == 0)
+ {
+ return SLANG_OK;
}
+ return SLANG_FAIL;
+#endif
+}
#ifdef _WIN32
- /* static */SlangResult File::generateTemporary(const UnownedStringSlice& inPrefix, Slang::String& outFileName)
- {
- // https://docs.microsoft.com/en-us/windows/win32/fileio/creating-and-using-a-temporary-file
-
- String tempPath;
- {
- int count = MAX_PATH + 1;
- while (true)
- {
- char* chars = tempPath.prepareForAppend(count);
- // Gets the temp path env string (no guarantee it's a valid path).
- // https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettemppatha
- DWORD ret = ::GetTempPathA(count - 1, chars);
- if (ret == 0)
- {
- return SLANG_FAIL;
- }
- if (ret > DWORD(count - 1))
- {
- count = ret + 1;
- continue;
- }
- tempPath.appendInPlace(chars, count);
- break;
- }
- }
-
- if (!File::exists(tempPath))
- {
- return SLANG_FAIL;
- }
-
- const String prefix(inPrefix);
- String tempFileName;
+/* static */ SlangResult File::generateTemporary(
+ const UnownedStringSlice& inPrefix,
+ Slang::String& outFileName)
+{
+ // https://docs.microsoft.com/en-us/windows/win32/fileio/creating-and-using-a-temporary-file
+ String tempPath;
+ {
+ int count = MAX_PATH + 1;
+ while (true)
{
- int count = MAX_PATH + 1;
- char* chars = tempFileName.prepareForAppend(count);
-
- // https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettempfilenamea
- // Generates a temporary file name.
- // Will create a file with this name.
- DWORD ret = ::GetTempFileNameA(tempPath.getBuffer(), prefix.getBuffer(), 0, chars);
-
+ char* chars = tempPath.prepareForAppend(count);
+ // Gets the temp path env string (no guarantee it's a valid path).
+ // https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettemppatha
+ DWORD ret = ::GetTempPathA(count - 1, chars);
if (ret == 0)
{
return SLANG_FAIL;
}
- tempFileName.appendInPlace(chars, ::strlen(chars));
+ if (ret > DWORD(count - 1))
+ {
+ count = ret + 1;
+ continue;
+ }
+ tempPath.appendInPlace(chars, count);
+ break;
}
+ }
- SLANG_ASSERT(File::exists(tempFileName));
-
- outFileName = tempFileName;
- return SLANG_OK;
+ if (!File::exists(tempPath))
+ {
+ return SLANG_FAIL;
}
-#else
- /* static */SlangResult File::generateTemporary(const UnownedStringSlice& inPrefix, Slang::String& outFileName)
+
+ const String prefix(inPrefix);
+ String tempFileName;
+
{
- StringBuilder builder;
- builder << "/tmp/" << inPrefix << "-XXXXXX";
+ int count = MAX_PATH + 1;
+ char* chars = tempFileName.prepareForAppend(count);
- List<char> buffer;
- auto copySize = builder.getLength();
- buffer.setCount(copySize + 1);
- // Satisfy GCC
- SLANG_ASSUME(copySize < PTRDIFF_MAX && copySize > 0);
- ::memcpy(buffer.getBuffer(), builder.getBuffer(), copySize);
- buffer[copySize] = 0;
+ // https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettempfilenamea
+ // Generates a temporary file name.
+ // Will create a file with this name.
+ DWORD ret = ::GetTempFileNameA(tempPath.getBuffer(), prefix.getBuffer(), 0, chars);
- int handle = mkstemp(buffer.getBuffer());
- if (handle == -1)
+ if (ret == 0)
{
return SLANG_FAIL;
}
+ tempFileName.appendInPlace(chars, ::strlen(chars));
+ }
- // Close the handle..
- close(handle);
-
- outFileName = buffer.getBuffer();
- SLANG_ASSERT(File::exists(outFileName));
+ SLANG_ASSERT(File::exists(tempFileName));
- return SLANG_OK;
+ outFileName = tempFileName;
+ return SLANG_OK;
+}
+#else
+/* static */ SlangResult File::generateTemporary(
+ const UnownedStringSlice& inPrefix,
+ Slang::String& outFileName)
+{
+ StringBuilder builder;
+ builder << "/tmp/" << inPrefix << "-XXXXXX";
+
+ List<char> buffer;
+ auto copySize = builder.getLength();
+ buffer.setCount(copySize + 1);
+ // Satisfy GCC
+ SLANG_ASSUME(copySize < PTRDIFF_MAX && copySize > 0);
+ ::memcpy(buffer.getBuffer(), builder.getBuffer(), copySize);
+ buffer[copySize] = 0;
+
+ int handle = mkstemp(buffer.getBuffer());
+ if (handle == -1)
+ {
+ return SLANG_FAIL;
}
+
+ // Close the handle..
+ close(handle);
+
+ outFileName = buffer.getBuffer();
+ SLANG_ASSERT(File::exists(outFileName));
+
+ return SLANG_OK;
+}
#endif
- /* static */SlangResult File::makeExecutable(const String& fileName)
- {
+/* static */ SlangResult File::makeExecutable(const String& fileName)
+{
#ifdef _WIN32
- SLANG_UNUSED(fileName);
- // As long as file extension is executable, it can be executed
- return SLANG_OK;
+ SLANG_UNUSED(fileName);
+ // As long as file extension is executable, it can be executed
+ return SLANG_OK;
#else
- struct stat st;
- if(::stat(fileName.getBuffer(), &st) != 0)
- {
- return SLANG_FAIL;
- }
- if(st.st_mode & S_IXUSR)
- {
- return SLANG_OK;
- }
- // It would probably be slightly neater to set all executable bits
- // aside from those in umask..
- if(::chmod(fileName.getBuffer(), st.st_mode & 07777 | S_IXUSR) != 0)
- {
- return SLANG_FAIL;
- }
+ struct stat st;
+ if (::stat(fileName.getBuffer(), &st) != 0)
+ {
+ return SLANG_FAIL;
+ }
+ if (st.st_mode & S_IXUSR)
+ {
return SLANG_OK;
-#endif
}
+ // It would probably be slightly neater to set all executable bits
+ // aside from those in umask..
+ if (::chmod(fileName.getBuffer(), st.st_mode & 07777 | S_IXUSR) != 0)
+ {
+ return SLANG_FAIL;
+ }
+ return SLANG_OK;
+#endif
+}
- bool File::exists(const String& fileName)
- {
+bool File::exists(const String& fileName)
+{
#ifdef _WIN32
- struct _stat32 statVar;
- return ::_wstat32(((String)fileName).toWString(), &statVar) != -1;
+ struct _stat32 statVar;
+ return ::_wstat32(((String)fileName).toWString(), &statVar) != -1;
#else
- struct stat statVar;
- return ::stat(fileName.getBuffer(), &statVar) == 0;
+ struct stat statVar;
+ return ::stat(fileName.getBuffer(), &statVar) == 0;
#endif
- }
-
- String Path::replaceExt(const String& path, const char* newExt)
- {
- StringBuilder sb(path.getLength() + 10);
- Index dotPos = findExtIndex(path);
+}
- if (dotPos < 0)
- dotPos = path.getLength();
- sb.append(path.getBuffer(), dotPos);
- sb.append('.');
- sb.append(newExt);
- return sb.produceString();
- }
+String Path::replaceExt(const String& path, const char* newExt)
+{
+ StringBuilder sb(path.getLength() + 10);
+ Index dotPos = findExtIndex(path);
+
+ if (dotPos < 0)
+ dotPos = path.getLength();
+ sb.append(path.getBuffer(), dotPos);
+ sb.append('.');
+ sb.append(newExt);
+ return sb.produceString();
+}
- /* static */ Index Path::findLastSeparatorIndex(UnownedStringSlice const& path)
+/* static */ Index Path::findLastSeparatorIndex(UnownedStringSlice const& path)
+{
+ const char* chars = path.begin();
+ for (Index i = path.getLength() - 1; i >= 0; --i)
{
- const char* chars = path.begin();
- for (Index i = path.getLength() - 1; i >= 0; --i)
+ const char c = chars[i];
+ if (c == '/' || c == '\\')
{
- const char c = chars[i];
- if (c == '/' || c == '\\')
- {
- return i;
- }
+ return i;
}
- return -1;
}
+ return -1;
+}
- /* static */Index Path::findExtIndex(UnownedStringSlice const& path)
- {
- const Index sepIndex = findLastSeparatorIndex(path);
+/* static */ Index Path::findExtIndex(UnownedStringSlice const& path)
+{
+ const Index sepIndex = findLastSeparatorIndex(path);
- const Index dotIndex = path.lastIndexOf('.');
- if (sepIndex >= 0)
- {
- // Index has to be in the last part of the path
- return (dotIndex > sepIndex) ? dotIndex : -1;
- }
- else
- {
- return dotIndex;
- }
+ const Index dotIndex = path.lastIndexOf('.');
+ if (sepIndex >= 0)
+ {
+ // Index has to be in the last part of the path
+ return (dotIndex > sepIndex) ? dotIndex : -1;
}
-
- String Path::getFileName(const String& path)
+ else
{
- Index pos = findLastSeparatorIndex(path);
- if (pos >= 0)
- {
- pos = pos + 1;
- return path.subString(pos, path.getLength() - pos);
- }
- else
- {
- return path;
- }
+ return dotIndex;
}
+}
- /* static */String Path::getFileNameWithoutExt(const String& path)
+String Path::getFileName(const String& path)
+{
+ Index pos = findLastSeparatorIndex(path);
+ if (pos >= 0)
{
- Index sepIndex = findLastSeparatorIndex(path);
- sepIndex = (sepIndex < 0) ? 0 : (sepIndex + 1);
- Index dotIndex = findExtIndex(path);
- dotIndex = (dotIndex < 0) ? path.getLength() : dotIndex;
-
- return path.subString(sepIndex, dotIndex - sepIndex);
+ pos = pos + 1;
+ return path.subString(pos, path.getLength() - pos);
}
-
- /* static*/ String Path::getPathWithoutExt(const String& path)
+ else
{
- Index dotPos = findExtIndex(path);
- if (dotPos >= 0)
- return path.subString(0, dotPos);
- else
- return path;
+ return path;
}
+}
+
+/* static */ String Path::getFileNameWithoutExt(const String& path)
+{
+ Index sepIndex = findLastSeparatorIndex(path);
+ sepIndex = (sepIndex < 0) ? 0 : (sepIndex + 1);
+ Index dotIndex = findExtIndex(path);
+ dotIndex = (dotIndex < 0) ? path.getLength() : dotIndex;
+
+ return path.subString(sepIndex, dotIndex - sepIndex);
+}
- UnownedStringSlice Path::getPathExt(const UnownedStringSlice& path)
+/* static*/ String Path::getPathWithoutExt(const String& path)
+{
+ Index dotPos = findExtIndex(path);
+ if (dotPos >= 0)
+ return path.subString(0, dotPos);
+ else
+ return path;
+}
+
+UnownedStringSlice Path::getPathExt(const UnownedStringSlice& path)
+{
+ const Index dotPos = findExtIndex(path);
+ if (dotPos >= 0)
{
- const Index dotPos = findExtIndex(path);
- if (dotPos >= 0)
- {
- return path.subString(dotPos + 1, path.getLength() - dotPos - 1);
- }
- else
- {
- // Note that the caller can identify if path has no extension or just a .
- // as if it's a dot a zero length slice is returned in path
- // If it's not then a default slice is returned (which doesn't point into path).
- //
- // Granted this is a little obscure and perhaps should be improved.
- return UnownedStringSlice();
- }
+ return path.subString(dotPos + 1, path.getLength() - dotPos - 1);
}
-
- String Path::getParentDirectory(const String& path)
+ else
{
- Index pos = findLastSeparatorIndex(path);
- if (pos >= 0)
- return path.subString(0, pos);
- else
- return "";
+ // Note that the caller can identify if path has no extension or just a .
+ // as if it's a dot a zero length slice is returned in path
+ // If it's not then a default slice is returned (which doesn't point into path).
+ //
+ // Granted this is a little obscure and perhaps should be improved.
+ return UnownedStringSlice();
}
+}
- /* static */void Path::append(StringBuilder& ioBuilder, const UnownedStringSlice& path)
+String Path::getParentDirectory(const String& path)
+{
+ Index pos = findLastSeparatorIndex(path);
+ if (pos >= 0)
+ return path.subString(0, pos);
+ else
+ return "";
+}
+
+/* static */ void Path::append(StringBuilder& ioBuilder, const UnownedStringSlice& path)
+{
+ if (ioBuilder.getLength() == 0)
{
- if (ioBuilder.getLength() == 0)
- {
- ioBuilder.append(path);
- return;
- }
- if (path.getLength() > 0)
+ ioBuilder.append(path);
+ return;
+ }
+ if (path.getLength() > 0)
+ {
+ // If ioBuilder doesn't end in a delimiter, add one
+ if (!isDelimiter(ioBuilder[ioBuilder.getLength() - 1]))
{
- // If ioBuilder doesn't end in a delimiter, add one
- if (!isDelimiter(ioBuilder[ioBuilder.getLength() - 1]))
+ // Determine the preferred delimiter to use based on existing path.
+ char preferedDelimiter = kOSCanonicalPathDelimiter;
+ if (kOSAlternativePathDelimiter != preferedDelimiter)
{
- // Determine the preferred delimiter to use based on existing path.
- char preferedDelimiter = kOSCanonicalPathDelimiter;
- if (kOSAlternativePathDelimiter != preferedDelimiter)
+ // If we found the existing path uses the alternative delimiter, we will
+ // use that instead of the canonical one.
+ constexpr Index kMaxDelimiterSearchRange = 32;
+ for (Index i = 0; i < Math::Min(kMaxDelimiterSearchRange, ioBuilder.getLength());
+ i++)
{
- // If we found the existing path uses the alternative delimiter, we will
- // use that instead of the canonical one.
- constexpr Index kMaxDelimiterSearchRange = 32;
- for (Index i = 0; i < Math::Min(kMaxDelimiterSearchRange, ioBuilder.getLength()); i++)
+ if (ioBuilder[i] == kOSAlternativePathDelimiter)
{
- if (ioBuilder[i] == kOSAlternativePathDelimiter)
- {
- preferedDelimiter = kOSAlternativePathDelimiter;
- break;
- }
+ preferedDelimiter = kOSAlternativePathDelimiter;
+ break;
}
}
- ioBuilder.append(preferedDelimiter);
}
- // Check that path doesn't start with a path delimiter
- SLANG_ASSERT(!isDelimiter(path[0]));
- // Append the path
- ioBuilder.append(path);
+ ioBuilder.append(preferedDelimiter);
}
+ // Check that path doesn't start with a path delimiter
+ SLANG_ASSERT(!isDelimiter(path[0]));
+ // Append the path
+ ioBuilder.append(path);
}
+}
- /* static */void Path::combineIntoBuilder(const UnownedStringSlice& path1, const UnownedStringSlice& path2, StringBuilder& outBuilder)
+/* static */ void Path::combineIntoBuilder(
+ const UnownedStringSlice& path1,
+ const UnownedStringSlice& path2,
+ StringBuilder& outBuilder)
+{
+ outBuilder.clear();
+ outBuilder.append(path1);
+ append(outBuilder, path2);
+}
+
+String Path::combine(const String& path1, const String& path2)
+{
+ if (path1.getLength() == 0)
{
- outBuilder.clear();
- outBuilder.append(path1);
- append(outBuilder, path2);
+ return path2;
}
- String Path::combine(const String& path1, const String& path2)
+ StringBuilder sb;
+ combineIntoBuilder(path1.getUnownedSlice(), path2.getUnownedSlice(), sb);
+ return sb.produceString();
+}
+String Path::combine(const String& path1, const String& path2, const String& path3)
+{
+ StringBuilder sb;
+ sb.append(path1);
+ append(sb, path2.getUnownedSlice());
+ append(sb, path3.getUnownedSlice());
+ return sb.produceString();
+}
+
+/* static */ bool Path::isDriveSpecification(const UnownedStringSlice& element)
+{
+ switch (element.getLength())
{
- if (path1.getLength() == 0)
+ case 0:
{
- return path2;
+ // We'll just assume it is
+ return true;
}
-
- StringBuilder sb;
- combineIntoBuilder(path1.getUnownedSlice(), path2.getUnownedSlice(), sb);
- return sb.produceString();
- }
- String Path::combine(const String& path1, const String& path2, const String& path3)
- {
- StringBuilder sb;
- sb.append(path1);
- append(sb, path2.getUnownedSlice());
- append(sb, path3.getUnownedSlice());
- return sb.produceString();
- }
-
- /* static */ bool Path::isDriveSpecification(const UnownedStringSlice& element)
- {
- switch (element.getLength())
+ case 2:
{
- case 0:
- {
- // We'll just assume it is
- return true;
- }
- case 2:
- {
- // Look for a windows like drive spec
- const char firstChar = element[0];
- return element[1] == ':' && ((firstChar >= 'a' && firstChar <= 'z') || (firstChar >= 'A' && firstChar <= 'Z'));
- }
- default: return false;
+ // Look for a windows like drive spec
+ const char firstChar = element[0];
+ return element[1] == ':' && ((firstChar >= 'a' && firstChar <= 'z') ||
+ (firstChar >= 'A' && firstChar <= 'Z'));
}
+ default: return false;
}
+}
- UnownedStringSlice Path::getFirstElement(const UnownedStringSlice& in)
- {
- const char* end = in.end();
- const char* cur = in.begin();
- // Find delimiter or the end
- while (cur < end && !Path::isDelimiter(*cur)) ++cur;
- return UnownedStringSlice(in.begin(), cur);
- }
+UnownedStringSlice Path::getFirstElement(const UnownedStringSlice& in)
+{
+ const char* end = in.end();
+ const char* cur = in.begin();
+ // Find delimiter or the end
+ while (cur < end && !Path::isDelimiter(*cur))
+ ++cur;
+ return UnownedStringSlice(in.begin(), cur);
+}
- /* static */bool Path::isAbsolute(const UnownedStringSlice& path)
+/* static */ bool Path::isAbsolute(const UnownedStringSlice& path)
+{
+ if (path.getLength() > 0 && isDelimiter(path[0]))
{
- if (path.getLength() > 0 && isDelimiter(path[0]))
- {
- return true;
- }
+ return true;
+ }
#if SLANG_WINDOWS_FAMILY
- // Check for the \\ network drive style
- if (path.getLength() >= 2 && path[0] == '\\' && path[1] == '\\')
- {
- return true;
- }
-
- // Check for drive
- if (isDriveSpecification(getFirstElement(path)))
- {
- return true;
- }
-#endif
-
- return false;
+ // Check for the \\ network drive style
+ if (path.getLength() >= 2 && path[0] == '\\' && path[1] == '\\')
+ {
+ return true;
}
- /* static */void Path::split(const UnownedStringSlice& path, List<UnownedStringSlice>& splitOut)
+ // Check for drive
+ if (isDriveSpecification(getFirstElement(path)))
{
- splitOut.clear();
+ return true;
+ }
+#endif
- const char* start = path.begin();
- const char* end = path.end();
+ return false;
+}
- while (start < end)
- {
- const char* cur = start;
- // Find the split
- while (cur < end && !isDelimiter(*cur)) cur++;
+/* static */ void Path::split(const UnownedStringSlice& path, List<UnownedStringSlice>& splitOut)
+{
+ splitOut.clear();
- splitOut.add(UnownedStringSlice(start, cur));
+ const char* start = path.begin();
+ const char* end = path.end();
- // Next
- start = cur + 1;
- }
+ while (start < end)
+ {
+ const char* cur = start;
+ // Find the split
+ while (cur < end && !isDelimiter(*cur))
+ cur++;
- // Okay if the end is empty. And we aren't with a spec like // or c:/ , then drop the final slash
- if (splitOut.getCount() > 1 && splitOut.getLast().getLength() == 0)
- {
- if (splitOut.getCount() == 2 && isDriveSpecification(splitOut[0]))
- {
- return;
- }
- // Remove the last
- splitOut.removeLast();
- }
+ splitOut.add(UnownedStringSlice(start, cur));
+
+ // Next
+ start = cur + 1;
}
- /* static */bool Path::hasRelativeElement(const UnownedStringSlice& path)
+ // Okay if the end is empty. And we aren't with a spec like // or c:/ , then drop the final
+ // slash
+ if (splitOut.getCount() > 1 && splitOut.getLast().getLength() == 0)
{
- List<UnownedStringSlice> splitPath;
- split(path, splitPath);
-
- for (const auto& cur : splitPath)
+ if (splitOut.getCount() == 2 && isDriveSpecification(splitOut[0]))
{
- if (cur == "." || cur == "..")
- {
- return true;
- }
+ return;
}
- return false;
+ // Remove the last
+ splitOut.removeLast();
}
+}
- /* static */SlangResult Path::simplify(const UnownedStringSlice& path, SimplifyStyle style, StringBuilder& outPath)
+/* static */ bool Path::hasRelativeElement(const UnownedStringSlice& path)
+{
+ List<UnownedStringSlice> splitPath;
+ split(path, splitPath);
+
+ for (const auto& cur : splitPath)
{
- if (path.getLength() == 0)
+ if (cur == "." || cur == "..")
{
- return SLANG_FAIL;
+ return true;
}
+ }
+ return false;
+}
- List<UnownedStringSlice> splitPath;
- split(UnownedStringSlice(path), splitPath);
+/* static */ SlangResult Path::simplify(
+ const UnownedStringSlice& path,
+ SimplifyStyle style,
+ StringBuilder& outPath)
+{
+ if (path.getLength() == 0)
+ {
+ return SLANG_FAIL;
+ }
- simplify(splitPath);
+ List<UnownedStringSlice> splitPath;
+ split(UnownedStringSlice(path), splitPath);
- const auto simplifyIntegral = SimplifyIntegral(style);
+ simplify(splitPath);
- // If it has a relative part then it's not absolute
- if ((simplifyIntegral & SimplifyFlag::AbsoluteOnly) &&
- splitPath.indexOf(UnownedStringSlice::fromLiteral("..")) >= 0)
- {
- return SLANG_E_NOT_FOUND;
- }
+ const auto simplifyIntegral = SimplifyIntegral(style);
- // We allow splitPath.getCount() == 0, because
- // the original path could have been '.' or './.'
- //
- // Special handling this case is in Path::join
+ // If it has a relative part then it's not absolute
+ if ((simplifyIntegral & SimplifyFlag::AbsoluteOnly) &&
+ splitPath.indexOf(UnownedStringSlice::fromLiteral("..")) >= 0)
+ {
+ return SLANG_E_NOT_FOUND;
+ }
- // If we want the path produced such that is *not* output with a root (ie SimplifyFlag::NoRoot)
- // we detect if we a rooted path (ie in effect starting with "/") and so splitPath[0] == ""
- // and remove that part from when doing the join.
- if ((simplifyIntegral & SimplifyFlag::NoRoot) &&
- (splitPath.getCount() && splitPath[0].getLength() == 0))
- {
- // If we allow without a root, we remove from the join
- Path::join(splitPath.getBuffer() + 1, splitPath.getCount() - 1, outPath);
- }
- else
- {
- Path::join(splitPath.getBuffer(), splitPath.getCount(), outPath);
- }
+ // We allow splitPath.getCount() == 0, because
+ // the original path could have been '.' or './.'
+ //
+ // Special handling this case is in Path::join
- return SLANG_OK;
+ // If we want the path produced such that is *not* output with a root (ie SimplifyFlag::NoRoot)
+ // we detect if we a rooted path (ie in effect starting with "/") and so splitPath[0] == ""
+ // and remove that part from when doing the join.
+ if ((simplifyIntegral & SimplifyFlag::NoRoot) &&
+ (splitPath.getCount() && splitPath[0].getLength() == 0))
+ {
+ // If we allow without a root, we remove from the join
+ Path::join(splitPath.getBuffer() + 1, splitPath.getCount() - 1, outPath);
}
-
- /* static */void Path::simplify(List<UnownedStringSlice>& ioSplit)
+ else
{
- // Strictly speaking we could do something about case on platforms like window, but here we won't worry about that
- for (Index i = 0; i < ioSplit.getCount(); i++)
- {
- const UnownedStringSlice& cur = ioSplit[i];
- if (cur == "." && ioSplit.getCount() > 1)
- {
- // Just remove it
- ioSplit.removeAt(i);
- i--;
- }
- else if (cur == ".." && i > 0)
- {
- // Can we remove this and the one before ?
- UnownedStringSlice& before = ioSplit[i - 1];
- if (before == ".." || (i == 1 && isDriveSpecification(before)))
- {
- // Can't do it, but we allow relative, so just leave for now
- continue;
- }
- ioSplit.removeRange(i - 1, 2);
- i -= 2;
- }
- }
+ Path::join(splitPath.getBuffer(), splitPath.getCount(), outPath);
}
- /* static */void Path::join(const UnownedStringSlice* slices, Index count, StringBuilder& out)
- {
- out.clear();
+ return SLANG_OK;
+}
- if (count == 0)
- {
- out << ".";
- }
- else if (count == 1 && slices[0].getLength() == 0)
+/* static */ void Path::simplify(List<UnownedStringSlice>& ioSplit)
+{
+ // Strictly speaking we could do something about case on platforms like window, but here we
+ // won't worry about that
+ for (Index i = 0; i < ioSplit.getCount(); i++)
+ {
+ const UnownedStringSlice& cur = ioSplit[i];
+ if (cur == "." && ioSplit.getCount() > 1)
{
- // It's the root
- out << kPathDelimiter;
+ // Just remove it
+ ioSplit.removeAt(i);
+ i--;
}
- else
+ else if (cur == ".." && i > 0)
{
- StringUtil::join(slices, count, kPathDelimiter, out);
+ // Can we remove this and the one before ?
+ UnownedStringSlice& before = ioSplit[i - 1];
+ if (before == ".." || (i == 1 && isDriveSpecification(before)))
+ {
+ // Can't do it, but we allow relative, so just leave for now
+ continue;
+ }
+ ioSplit.removeRange(i - 1, 2);
+ i -= 2;
}
}
+}
+/* static */ void Path::join(const UnownedStringSlice* slices, Index count, StringBuilder& out)
+{
+ out.clear();
- /* static */String Path::simplify(const UnownedStringSlice& path)
+ if (count == 0)
{
- List<UnownedStringSlice> splitPath;
- split(path, splitPath);
- simplify(splitPath);
-
- // Reconstruct the string
- StringBuilder builder;
- join(splitPath.getBuffer(), splitPath.getCount(), builder);
- return builder.toString();
+ out << ".";
}
-
- bool Path::createDirectory(const String& path)
+ else if (count == 1 && slices[0].getLength() == 0)
+ {
+ // It's the root
+ out << kPathDelimiter;
+ }
+ else
{
+ StringUtil::join(slices, count, kPathDelimiter, out);
+ }
+}
+
+
+/* static */ String Path::simplify(const UnownedStringSlice& path)
+{
+ List<UnownedStringSlice> splitPath;
+ split(path, splitPath);
+ simplify(splitPath);
+
+ // Reconstruct the string
+ StringBuilder builder;
+ join(splitPath.getBuffer(), splitPath.getCount(), builder);
+ return builder.toString();
+}
+
+bool Path::createDirectory(const String& path)
+{
#if defined(_WIN32)
- return _wmkdir(path.toWString()) == 0;
+ return _wmkdir(path.toWString()) == 0;
#else
- return mkdir(path.getBuffer(), 0777) == 0;
+ return mkdir(path.getBuffer(), 0777) == 0;
#endif
- }
+}
- bool Path::createDirectoryRecursive(const String& path)
+bool Path::createDirectoryRecursive(const String& path)
+{
+ String finalPath = Path::simplify(path);
+ if (finalPath.getLength() == 0)
{
- String finalPath = Path::simplify(path);
- if (finalPath.getLength() == 0)
- {
- return false;
- }
-
- List<String> pathList;
-
- // Check whether the parent directories exist, and add to the pathList if they are
- // not, we will create all the directories from back of the list.
- String parentDir = finalPath;
- for(;;)
- {
- if (parentDir.getLength() == 0 || File::exists(parentDir))
- {
- break;
- }
- else
- {
- pathList.add(parentDir);
- parentDir = Path::getParentDirectory(parentDir);
- }
- }
+ return false;
+ }
- // If there are no directories to create, then we are done
- if (pathList.getCount() == 0)
- {
- return true;
- }
+ List<String> pathList;
- // Traverse from back of the list, because that is most outer directory.
- Int i = 0;
- for (i = pathList.getCount() - 1; i >= 0; i--)
+ // Check whether the parent directories exist, and add to the pathList if they are
+ // not, we will create all the directories from back of the list.
+ String parentDir = finalPath;
+ for (;;)
+ {
+ if (parentDir.getLength() == 0 || File::exists(parentDir))
{
- if (!createDirectory(pathList[i]))
- {
- break;
- }
+ break;
}
-
- // Something wrong when creating parent directories
- if (i > 0)
+ else
{
- // Remove the directories if we've created
- if (i != pathList.getCount() - 1)
- remove(pathList[i]);
-
- return false;
+ pathList.add(parentDir);
+ parentDir = Path::getParentDirectory(parentDir);
}
+ }
+ // If there are no directories to create, then we are done
+ if (pathList.getCount() == 0)
+ {
return true;
}
- /* static */SlangResult Path::getPathType(const String& path, SlangPathType* pathTypeOut)
+ // Traverse from back of the list, because that is most outer directory.
+ Int i = 0;
+ for (i = pathList.getCount() - 1; i >= 0; i--)
{
-#ifdef _WIN32
- // https://msdn.microsoft.com/en-us/library/14h5k7ff.aspx
- struct _stat32 statVar;
- if (::_wstat32(String(path).toWString(), &statVar) == 0)
+ if (!createDirectory(pathList[i]))
{
- if (statVar.st_mode & _S_IFDIR)
- {
- *pathTypeOut = SLANG_PATH_TYPE_DIRECTORY;
- return SLANG_OK;
- }
- else if (statVar.st_mode & _S_IFREG)
- {
- *pathTypeOut = SLANG_PATH_TYPE_FILE;
- return SLANG_OK;
- }
- return SLANG_FAIL;
+ break;
}
+ }
- return SLANG_E_NOT_FOUND;
-#else
- struct stat statVar;
- if (::stat(path.getBuffer(), &statVar) == 0)
- {
- if (S_ISDIR(statVar.st_mode))
- {
- *pathTypeOut = SLANG_PATH_TYPE_DIRECTORY;
- return SLANG_OK;
- }
- if (S_ISREG(statVar.st_mode))
- {
- *pathTypeOut = SLANG_PATH_TYPE_FILE;
- return SLANG_OK;
- }
- return SLANG_FAIL;
- }
+ // Something wrong when creating parent directories
+ if (i > 0)
+ {
+ // Remove the directories if we've created
+ if (i != pathList.getCount() - 1)
+ remove(pathList[i]);
- return SLANG_E_NOT_FOUND;
-#endif
+ return false;
}
+ return true;
+}
- /* static */SlangResult Path::getCanonical(const String& path, String& canonicalPathOut)
+/* static */ SlangResult Path::getPathType(const String& path, SlangPathType* pathTypeOut)
+{
+#ifdef _WIN32
+ // https://msdn.microsoft.com/en-us/library/14h5k7ff.aspx
+ struct _stat32 statVar;
+ if (::_wstat32(String(path).toWString(), &statVar) == 0)
{
-#if defined(_WIN32)
- // https://msdn.microsoft.com/en-us/library/506720ff.aspx
- wchar_t* absPath = ::_wfullpath(nullptr, path.toWString(), 0);
- if (!absPath)
+ if (statVar.st_mode & _S_IFDIR)
{
- return SLANG_FAIL;
+ *pathTypeOut = SLANG_PATH_TYPE_DIRECTORY;
+ return SLANG_OK;
}
-
- canonicalPathOut = String::fromWString(absPath);
- ::free(absPath);
- return SLANG_OK;
-#else
-# if 1
-
- // http://man7.org/linux/man-pages/man3/realpath.3.html
- char* canonicalPath = ::realpath(path.begin(), nullptr);
- if (canonicalPath)
+ else if (statVar.st_mode & _S_IFREG)
{
- canonicalPathOut = canonicalPath;
- ::free(canonicalPath);
+ *pathTypeOut = SLANG_PATH_TYPE_FILE;
return SLANG_OK;
}
return SLANG_FAIL;
-# else
- // This is a mechanism to get an approximation of canonical path if we don't have 'realpath'
- // We only can get if the file exists. This checks that the ../. etc are really valid
- SlangPathType pathType;
- SLANG_RETURN_ON_FAIL(getPathType(path, &pathType));
- if (isAbsolute(path))
+ }
+
+ return SLANG_E_NOT_FOUND;
+#else
+ struct stat statVar;
+ if (::stat(path.getBuffer(), &statVar) == 0)
+ {
+ if (S_ISDIR(statVar.st_mode))
{
- // If it's absolute, we can just simplify as is
- canonicalPathOut = Path::simplify(path);
+ *pathTypeOut = SLANG_PATH_TYPE_DIRECTORY;
return SLANG_OK;
}
- else
+ if (S_ISREG(statVar.st_mode))
{
- char buffer[PATH_MAX];
- // https://linux.die.net/man/3/getcwd
- const char* getCwdPath = getcwd(buffer, SLANG_COUNT_OF(buffer));
- if (!getCwdPath)
- {
- return SLANG_FAIL;
- }
-
- // Okay combine the paths
- String combinedPaths = Path::combine(String(getCwdPath), path);
- // Simplify
- canonicalPathOut = Path::simplify(combinedPaths);
+ *pathTypeOut = SLANG_PATH_TYPE_FILE;
return SLANG_OK;
}
-# endif
-#endif
+ return SLANG_FAIL;
}
- String Path::getCurrentPath()
+ return SLANG_E_NOT_FOUND;
+#endif
+}
+
+
+/* static */ SlangResult Path::getCanonical(const String& path, String& canonicalPathOut)
+{
+#if defined(_WIN32)
+ // https://msdn.microsoft.com/en-us/library/506720ff.aspx
+ wchar_t* absPath = ::_wfullpath(nullptr, path.toWString(), 0);
+ if (!absPath)
{
- Slang::String path;
- getCanonical(".", path);
- return path;
+ return SLANG_FAIL;
}
- String Path::getRelativePath(String base, String path)
+ canonicalPathOut = String::fromWString(absPath);
+ ::free(absPath);
+ return SLANG_OK;
+#else
+#if 1
+
+ // http://man7.org/linux/man-pages/man3/realpath.3.html
+ char* canonicalPath = ::realpath(path.begin(), nullptr);
+ if (canonicalPath)
{
- std::filesystem::path p1(base.getBuffer());
- std::filesystem::path p2(path.getBuffer());
- std::error_code ec;
- auto result = std::filesystem::relative(p2, p1, ec);
- if (ec)
- return path;
- return String(UnownedStringSlice(result.generic_u8string().c_str()));
+ canonicalPathOut = canonicalPath;
+ ::free(canonicalPath);
+ return SLANG_OK;
}
-
- SlangResult Path::remove(const String& path)
+ return SLANG_FAIL;
+#else
+ // This is a mechanism to get an approximation of canonical path if we don't have 'realpath'
+ // We only can get if the file exists. This checks that the ../. etc are really valid
+ SlangPathType pathType;
+ SLANG_RETURN_ON_FAIL(getPathType(path, &pathType));
+ if (isAbsolute(path))
+ {
+ // If it's absolute, we can just simplify as is
+ canonicalPathOut = Path::simplify(path);
+ return SLANG_OK;
+ }
+ else
{
+ char buffer[PATH_MAX];
+ // https://linux.die.net/man/3/getcwd
+ const char* getCwdPath = getcwd(buffer, SLANG_COUNT_OF(buffer));
+ if (!getCwdPath)
+ {
+ return SLANG_FAIL;
+ }
+
+ // Okay combine the paths
+ String combinedPaths = Path::combine(String(getCwdPath), path);
+ // Simplify
+ canonicalPathOut = Path::simplify(combinedPaths);
+ return SLANG_OK;
+ }
+#endif
+#endif
+}
+
+String Path::getCurrentPath()
+{
+ Slang::String path;
+ getCanonical(".", path);
+ return path;
+}
+
+String Path::getRelativePath(String base, String path)
+{
+ std::filesystem::path p1(base.getBuffer());
+ std::filesystem::path p2(path.getBuffer());
+ std::error_code ec;
+ auto result = std::filesystem::relative(p2, p1, ec);
+ if (ec)
+ return path;
+ return String(UnownedStringSlice(result.generic_u8string().c_str()));
+}
+
+SlangResult Path::remove(const String& path)
+{
#ifdef _WIN32
- // Need to determine if its a file or directory
+ // Need to determine if its a file or directory
- SlangPathType pathType;
- SLANG_RETURN_ON_FAIL(getPathType(path, &pathType));
+ SlangPathType pathType;
+ SLANG_RETURN_ON_FAIL(getPathType(path, &pathType));
- switch (pathType)
+ switch (pathType)
+ {
+ case SLANG_PATH_TYPE_FILE:
{
- case SLANG_PATH_TYPE_FILE:
+ // https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-deletefilea
+ if (DeleteFileA(path.getBuffer()))
{
- // https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-deletefilea
- if (DeleteFileA(path.getBuffer()))
- {
- return SLANG_OK;
- }
- break;
+ return SLANG_OK;
}
- case SLANG_PATH_TYPE_DIRECTORY:
+ break;
+ }
+ case SLANG_PATH_TYPE_DIRECTORY:
+ {
+ // https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-removedirectorya
+ if (RemoveDirectoryA(path.getBuffer()))
{
- // https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-removedirectorya
- if (RemoveDirectoryA(path.getBuffer()))
- {
- return SLANG_OK;
- }
- break;
+ return SLANG_OK;
}
- default: break;
+ break;
}
+ default: break;
+ }
- return SLANG_FAIL;
+ return SLANG_FAIL;
#else
- // https://linux.die.net/man/3/remove
- if (::remove(path.getBuffer()) == 0)
- {
- return SLANG_OK;
- }
- return SLANG_FAIL;
-#endif
+ // https://linux.die.net/man/3/remove
+ if (::remove(path.getBuffer()) == 0)
+ {
+ return SLANG_OK;
}
+ return SLANG_FAIL;
+#endif
+}
- /* static */SlangResult Path::removeNonEmpty(const String& path)
+/* static */ SlangResult Path::removeNonEmpty(const String& path)
+{
+ if (File::exists(path) == false)
{
- if (File::exists(path) == false)
- {
- return SLANG_OK;
- }
+ return SLANG_OK;
+ }
- StringBuilder msgBuilder;
- // Path::remove() doesn't support remove a non-empty directory, so we need to implement
- // a simple function to remove the directory recursively.
+ StringBuilder msgBuilder;
+ // Path::remove() doesn't support remove a non-empty directory, so we need to implement
+ // a simple function to remove the directory recursively.
#ifdef _WIN32
- // https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shfileoperationa
- // Note: the fromPath requires a double-null-terminated string.
- String newPath = path;
- newPath.append('\0');
- SHFILEOPSTRUCTA file_op = {
- NULL,
- FO_DELETE,
- newPath.begin(),
- nullptr,
- FOF_NOCONFIRMATION |
- FOF_NOERRORUI |
- FOF_SILENT,
- false,
- 0,
- nullptr };
- int ret = SHFileOperationA(&file_op);
- if (ret)
- {
- return SLANG_FAIL;
- }
+ // https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shfileoperationa
+ // Note: the fromPath requires a double-null-terminated string.
+ String newPath = path;
+ newPath.append('\0');
+ SHFILEOPSTRUCTA file_op = {
+ NULL,
+ FO_DELETE,
+ newPath.begin(),
+ nullptr,
+ FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_SILENT,
+ false,
+ 0,
+ nullptr};
+ int ret = SHFileOperationA(&file_op);
+ if (ret)
+ {
+ return SLANG_FAIL;
+ }
#else
- auto unlink_cb = [](const char* fpath, const struct stat* sb, int typeflag, struct FTW* ftwbuf) -> int
- {
- SLANG_UNUSED(sb)
- SLANG_UNUSED(typeflag)
- SLANG_UNUSED(ftwbuf)
- int rv = ::remove(fpath);
- if (rv)
- {
- perror(fpath);
- }
- return rv;
- };
- // https://linux.die.net/man/3/nftw
- int ret = ::nftw(path.begin(), unlink_cb, 64, FTW_DEPTH | FTW_PHYS);
- if (ret)
- {
- return SLANG_FAIL;
- }
+ auto unlink_cb =
+ [](const char* fpath, const struct stat* sb, int typeflag, struct FTW* ftwbuf) -> int
+ {
+ SLANG_UNUSED(sb)
+ SLANG_UNUSED(typeflag)
+ SLANG_UNUSED(ftwbuf)
+ int rv = ::remove(fpath);
+ if (rv)
+ {
+ perror(fpath);
+ }
+ return rv;
+ };
+ // https://linux.die.net/man/3/nftw
+ int ret = ::nftw(path.begin(), unlink_cb, 64, FTW_DEPTH | FTW_PHYS);
+ if (ret)
+ {
+ return SLANG_FAIL;
+ }
#endif
- return SLANG_OK;
- }
+ return SLANG_OK;
+}
#if defined(_WIN32)
- /* static */SlangResult Path::find(const String& directoryPath, const char* pattern, Visitor* visitor)
- {
- pattern = pattern ? pattern : "*";
- String searchPath = Path::combine(directoryPath, pattern);
+/* static */ SlangResult Path::find(
+ const String& directoryPath,
+ const char* pattern,
+ Visitor* visitor)
+{
+ pattern = pattern ? pattern : "*";
+ String searchPath = Path::combine(directoryPath, pattern);
- WIN32_FIND_DATAW fileData;
+ WIN32_FIND_DATAW fileData;
- HANDLE findHandle = FindFirstFileW(searchPath.toWString(), &fileData);
- if (findHandle == INVALID_HANDLE_VALUE)
- {
- return SLANG_E_NOT_FOUND;
- }
+ HANDLE findHandle = FindFirstFileW(searchPath.toWString(), &fileData);
+ if (findHandle == INVALID_HANDLE_VALUE)
+ {
+ return SLANG_E_NOT_FOUND;
+ }
- do
+ do
+ {
+ if (!((wcscmp(fileData.cFileName, L".") == 0) || (wcscmp(fileData.cFileName, L"..") == 0)))
{
- if (!((wcscmp(fileData.cFileName, L".") == 0) ||
- (wcscmp(fileData.cFileName, L"..") == 0)))
- {
- const Type type = (fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? Type::Directory : Type::File;
+ const Type type = (fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ ? Type::Directory
+ : Type::File;
- String filename = String::fromWString(fileData.cFileName);
- visitor->accept(type, filename.getUnownedSlice());
- }
+ String filename = String::fromWString(fileData.cFileName);
+ visitor->accept(type, filename.getUnownedSlice());
}
- while (FindNextFileW(findHandle, &fileData) != 0);
+ } while (FindNextFileW(findHandle, &fileData) != 0);
- ::FindClose(findHandle);
- return SLANG_OK;
- }
+ ::FindClose(findHandle);
+ return SLANG_OK;
+}
#else
- /* static */SlangResult Path::find(const String& directoryPath, const char* pattern, Visitor* visitor)
+/* static */ SlangResult Path::find(
+ const String& directoryPath,
+ const char* pattern,
+ Visitor* visitor)
+{
+ DIR* directory = opendir(directoryPath.getBuffer());
+
+ if (!directory)
{
- DIR* directory = opendir(directoryPath.getBuffer());
+ return SLANG_E_NOT_FOUND;
+ }
- if (!directory)
+ StringBuilder builder;
+ for (;;)
+ {
+ dirent* entry = readdir(directory);
+ if (entry == nullptr)
{
- return SLANG_E_NOT_FOUND;
+ break;
}
- StringBuilder builder;
- for (;;)
+ if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
{
- dirent* entry = readdir(directory);
- if (entry == nullptr)
- {
- break;
- }
-
- if (strcmp(entry->d_name, ".") == 0 ||
- strcmp(entry->d_name, "..") == 0)
- {
- continue;
- }
+ continue;
+ }
- // If there is a pattern, check if it matches, and if it doesn't ignore it
- if (pattern && fnmatch(pattern, entry->d_name, 0) != 0)
- {
- continue;
- }
+ // If there is a pattern, check if it matches, and if it doesn't ignore it
+ if (pattern && fnmatch(pattern, entry->d_name, 0) != 0)
+ {
+ continue;
+ }
- const UnownedStringSlice filename(entry->d_name);
+ const UnownedStringSlice filename(entry->d_name);
- // Produce the full path, to do stat
- Path::combineIntoBuilder(directoryPath.getUnownedSlice(), filename, builder);
+ // Produce the full path, to do stat
+ Path::combineIntoBuilder(directoryPath.getUnownedSlice(), filename, builder);
- // fprintf(stderr, "stat(%s)\n", path.getBuffer());
- struct stat fileInfo;
- if (stat(builder.getBuffer(), &fileInfo) != 0)
- {
- continue;
- }
-
- Type type = Type::Unknown;
- if (S_ISDIR(fileInfo.st_mode))
- {
- type = Type::Directory;
- }
- else if (S_ISREG(fileInfo.st_mode))
- {
- type = Type::File;
- }
+ // fprintf(stderr, "stat(%s)\n", path.getBuffer());
+ struct stat fileInfo;
+ if (stat(builder.getBuffer(), &fileInfo) != 0)
+ {
+ continue;
+ }
- visitor->accept(type, filename);
+ Type type = Type::Unknown;
+ if (S_ISDIR(fileInfo.st_mode))
+ {
+ type = Type::Directory;
+ }
+ else if (S_ISREG(fileInfo.st_mode))
+ {
+ type = Type::File;
}
- closedir(directory);
- return SLANG_OK;
+ visitor->accept(type, filename);
}
+
+ closedir(directory);
+ return SLANG_OK;
+}
#endif
- bool Path::equals(String path1, String path2)
- {
- Path::getCanonical(path1, path1);
- Path::getCanonical(path2, path2);
+bool Path::equals(String path1, String path2)
+{
+ Path::getCanonical(path1, path1);
+ Path::getCanonical(path2, path2);
#if SLANG_WINDOWS_FAMILY
- return path1.getUnownedSlice().caseInsensitiveEquals(path2.getUnownedSlice());
+ return path1.getUnownedSlice().caseInsensitiveEquals(path2.getUnownedSlice());
#else
- return path1 == path2;
+ return path1 == path2;
#endif
- }
+}
- /// Gets the path to the executable that was invoked that led to the current threads execution
- /// If run from a shared library/dll will be the path of the executable that loaded said library
- /// @param outPath Pointer to buffer to hold the path.
- /// @param ioPathSize Size of the buffer to hold the path (including zero terminator).
- /// @return SLANG_OK on success, SLANG_E_BUFFER_TOO_SMALL if buffer is too small. If ioPathSize is changed it will be the required size
- static SlangResult _calcExectuablePath(char* outPath, size_t* ioSize)
- {
- SLANG_ASSERT(ioSize);
- const size_t bufferSize = *ioSize;
- SLANG_ASSERT(bufferSize > 0);
+/// Gets the path to the executable that was invoked that led to the current threads execution
+/// If run from a shared library/dll will be the path of the executable that loaded said library
+/// @param outPath Pointer to buffer to hold the path.
+/// @param ioPathSize Size of the buffer to hold the path (including zero terminator).
+/// @return SLANG_OK on success, SLANG_E_BUFFER_TOO_SMALL if buffer is too small. If ioPathSize is
+/// changed it will be the required size
+static SlangResult _calcExectuablePath(char* outPath, size_t* ioSize)
+{
+ SLANG_ASSERT(ioSize);
+ const size_t bufferSize = *ioSize;
+ SLANG_ASSERT(bufferSize > 0);
#if SLANG_WINDOWS_FAMILY
- // https://docs.microsoft.com/en-us/windows/desktop/api/libloaderapi/nf-libloaderapi-getmodulefilenamea
+ // https://docs.microsoft.com/en-us/windows/desktop/api/libloaderapi/nf-libloaderapi-getmodulefilenamea
- DWORD res = ::GetModuleFileNameA(::GetModuleHandle(nullptr), outPath, DWORD(bufferSize));
- // If it fits it's the size not including terminator. So must be less than bufferSize
- if (res < bufferSize)
- {
- return SLANG_OK;
- }
- return SLANG_E_BUFFER_TOO_SMALL;
+ DWORD res = ::GetModuleFileNameA(::GetModuleHandle(nullptr), outPath, DWORD(bufferSize));
+ // If it fits it's the size not including terminator. So must be less than bufferSize
+ if (res < bufferSize)
+ {
+ return SLANG_OK;
+ }
+ return SLANG_E_BUFFER_TOO_SMALL;
#elif SLANG_LINUX_FAMILY
-# if defined(__linux__) || defined(__CYGWIN__)
- // https://linux.die.net/man/2/readlink
- // Mark last byte with 0, so can check overrun
- ssize_t resSize = ::readlink("/proc/self/exe", outPath, bufferSize);
- if (resSize < 0)
- {
- return SLANG_FAIL;
- }
- if (size_t(resSize) >= bufferSize)
- {
- return SLANG_E_BUFFER_TOO_SMALL;
- }
- // Zero terminate
- outPath[resSize - 1] = 0;
- return SLANG_OK;
-# else
- String text = Slang::File::readAllText("/proc/self/maps");
- Index startIndex = text.indexOf('/');
- if (startIndex == Index(-1))
- {
- return SLANG_FAIL;
- }
- Index endIndex = text.indexOf("\n", startIndex);
- endIndex = (endIndex == Index(-1)) ? text.getLength() : endIndex;
+#if defined(__linux__) || defined(__CYGWIN__)
+ // https://linux.die.net/man/2/readlink
+ // Mark last byte with 0, so can check overrun
+ ssize_t resSize = ::readlink("/proc/self/exe", outPath, bufferSize);
+ if (resSize < 0)
+ {
+ return SLANG_FAIL;
+ }
+ if (size_t(resSize) >= bufferSize)
+ {
+ return SLANG_E_BUFFER_TOO_SMALL;
+ }
+ // Zero terminate
+ outPath[resSize - 1] = 0;
+ return SLANG_OK;
+#else
+ String text = Slang::File::readAllText("/proc/self/maps");
+ Index startIndex = text.indexOf('/');
+ if (startIndex == Index(-1))
+ {
+ return SLANG_FAIL;
+ }
+ Index endIndex = text.indexOf("\n", startIndex);
+ endIndex = (endIndex == Index(-1)) ? text.getLength() : endIndex;
- auto path = text.subString(startIndex, endIndex - startIndex);
+ auto path = text.subString(startIndex, endIndex - startIndex);
- if (path.getLength() < bufferSize)
- {
- ::memcpy(outPath, path.begin(), path.getLength());
- outPath[path.getLength()] = 0;
- return SLANG_OK;
- }
+ if (path.getLength() < bufferSize)
+ {
+ ::memcpy(outPath, path.begin(), path.getLength());
+ outPath[path.getLength()] = 0;
+ return SLANG_OK;
+ }
- *ioSize = path.getLength() + 1;
- return SLANG_E_BUFFER_TOO_SMALL;
-# endif
+ *ioSize = path.getLength() + 1;
+ return SLANG_E_BUFFER_TOO_SMALL;
+#endif
#elif SLANG_APPLE_FAMILY
- // https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/dyld.3.html
- uint32_t size = uint32_t(*ioSize);
- switch (_NSGetExecutablePath(outPath, &size))
+ // https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/dyld.3.html
+ uint32_t size = uint32_t(*ioSize);
+ switch (_NSGetExecutablePath(outPath, &size))
+ {
+ case 0: return SLANG_OK;
+ case -1:
{
- case 0: return SLANG_OK;
- case -1:
- {
- *ioSize = size;
- return SLANG_E_BUFFER_TOO_SMALL;
- }
- default: break;
+ *ioSize = size;
+ return SLANG_E_BUFFER_TOO_SMALL;
}
- return SLANG_FAIL;
+ default: break;
+ }
+ return SLANG_FAIL;
#else
- SLANG_UNUSED(outPath);
- return SLANG_E_NOT_IMPLEMENTED;
+ SLANG_UNUSED(outPath);
+ return SLANG_E_NOT_IMPLEMENTED;
#endif
- }
+}
- static String _getExecutablePath()
+static String _getExecutablePath()
+{
+ List<char> buffer;
+ // Guess an initial buffer size
+ buffer.setCount(1024);
+
+ while (true)
{
- List<char> buffer;
- // Guess an initial buffer size
- buffer.setCount(1024);
+ const size_t size = size_t(buffer.getCount());
+ size_t bufferSize = size;
+ SlangResult res = _calcExectuablePath(buffer.getBuffer(), &bufferSize);
- while (true)
+ if (SLANG_SUCCEEDED(res))
{
- const size_t size = size_t(buffer.getCount());
- size_t bufferSize = size;
- SlangResult res = _calcExectuablePath(buffer.getBuffer(), &bufferSize);
-
- if (SLANG_SUCCEEDED(res))
- {
- return String(buffer.getBuffer());
- }
-
- if (res != SLANG_E_BUFFER_TOO_SMALL)
- {
- // Couldn't determine the executable string
- return String();
- }
-
- // If bufferSize changed it should be the exact fit size, else we just make the buffer bigger by a guess (50% bigger)
- bufferSize = (bufferSize > size) ? bufferSize : (bufferSize + bufferSize / 2);
- buffer.setCount(Index(bufferSize));
+ return String(buffer.getBuffer());
}
- }
-
- /* static */String Path::getExecutablePath()
- {
- // TODO(JS): It would be better if we lazily evaluated this, and then returned the same string on subsequent calls, because it has to do
- // a fair amount of work depending on target.
- // This was how previous code worked, with a static variable. Unfortunately this led to a memory leak being reported - because reporting
- // is done before a global variable is released.
- // It would be good to have a mechanism that allows 'core' library source free memory in some controlled manner.
- return _getExecutablePath();
- }
-
- SlangResult File::readAllText(const Slang::String& fileName, String& outText)
- {
- RefPtr<FileStream> stream(new FileStream);
- SLANG_RETURN_ON_FAIL(stream->init(fileName, FileMode::Open, FileAccess::Read, FileShare::ReadWrite));
- StreamReader reader;
- SLANG_RETURN_ON_FAIL(reader.init(stream));
- SLANG_RETURN_ON_FAIL(reader.readToEnd(outText));
+ if (res != SLANG_E_BUFFER_TOO_SMALL)
+ {
+ // Couldn't determine the executable string
+ return String();
+ }
- return SLANG_OK;
+ // If bufferSize changed it should be the exact fit size, else we just make the buffer
+ // bigger by a guess (50% bigger)
+ bufferSize = (bufferSize > size) ? bufferSize : (bufferSize + bufferSize / 2);
+ buffer.setCount(Index(bufferSize));
}
+}
- SlangResult File::readAllBytes(const Slang::String& path, Slang::List<unsigned char>& out)
- {
- FileStream stream;
- SLANG_RETURN_ON_FAIL(stream.init(path, FileMode::Open, FileAccess::Read, FileShare::ReadWrite));
+/* static */ String Path::getExecutablePath()
+{
+ // TODO(JS): It would be better if we lazily evaluated this, and then returned the same string
+ // on subsequent calls, because it has to do a fair amount of work depending on target. This was
+ // how previous code worked, with a static variable. Unfortunately this led to a memory leak
+ // being reported - because reporting is done before a global variable is released. It would be
+ // good to have a mechanism that allows 'core' library source free memory in some controlled
+ // manner.
+ return _getExecutablePath();
+}
- const Int64 start = stream.getPosition();
- stream.seek(SeekOrigin::End, 0);
- const Int64 end = stream.getPosition();
- stream.seek(SeekOrigin::Start, start);
+SlangResult File::readAllText(const Slang::String& fileName, String& outText)
+{
+ RefPtr<FileStream> stream(new FileStream);
+ SLANG_RETURN_ON_FAIL(
+ stream->init(fileName, FileMode::Open, FileAccess::Read, FileShare::ReadWrite));
- const Int64 positionSizeInBytes = end - start;
+ StreamReader reader;
+ SLANG_RETURN_ON_FAIL(reader.init(stream));
+ SLANG_RETURN_ON_FAIL(reader.readToEnd(outText));
- if (UInt64(positionSizeInBytes) > UInt64(kMaxIndex))
- {
- // It's too large to fit in memory.
- return SLANG_FAIL;
- }
+ return SLANG_OK;
+}
- const Index sizeInBytes = Index(positionSizeInBytes);
+SlangResult File::readAllBytes(const Slang::String& path, Slang::List<unsigned char>& out)
+{
+ FileStream stream;
+ SLANG_RETURN_ON_FAIL(stream.init(path, FileMode::Open, FileAccess::Read, FileShare::ReadWrite));
- out.setCount(sizeInBytes);
+ const Int64 start = stream.getPosition();
+ stream.seek(SeekOrigin::End, 0);
+ const Int64 end = stream.getPosition();
+ stream.seek(SeekOrigin::Start, start);
- size_t readSizeInBytes;
- SLANG_RETURN_ON_FAIL(stream.read(out.getBuffer(), sizeInBytes, readSizeInBytes));
+ const Int64 positionSizeInBytes = end - start;
- // If not all read just return an error
- return (size_t(sizeInBytes) == readSizeInBytes) ? SLANG_OK : SLANG_FAIL;
+ if (UInt64(positionSizeInBytes) > UInt64(kMaxIndex))
+ {
+ // It's too large to fit in memory.
+ return SLANG_FAIL;
}
- SlangResult File::readAllBytes(const String& path, ScopedAllocation& out)
- {
- FileStream stream;
- SLANG_RETURN_ON_FAIL(stream.init(path, FileMode::Open, FileAccess::Read, FileShare::ReadWrite));
+ const Index sizeInBytes = Index(positionSizeInBytes);
- const Int64 start = stream.getPosition();
- stream.seek(SeekOrigin::End, 0);
- const Int64 end = stream.getPosition();
- stream.seek(SeekOrigin::Start, start);
+ out.setCount(sizeInBytes);
- const Int64 positionSizeInBytes = end - start;
+ size_t readSizeInBytes;
+ SLANG_RETURN_ON_FAIL(stream.read(out.getBuffer(), sizeInBytes, readSizeInBytes));
- if (UInt64(positionSizeInBytes) > UInt64(~size_t(0)))
- {
- // It's too large to fit in memory.
- return SLANG_FAIL;
- }
+ // If not all read just return an error
+ return (size_t(sizeInBytes) == readSizeInBytes) ? SLANG_OK : SLANG_FAIL;
+}
- const size_t sizeInBytes = size_t(positionSizeInBytes);
+SlangResult File::readAllBytes(const String& path, ScopedAllocation& out)
+{
+ FileStream stream;
+ SLANG_RETURN_ON_FAIL(stream.init(path, FileMode::Open, FileAccess::Read, FileShare::ReadWrite));
- void* data = out.allocateTerminated(sizeInBytes);
- if (!data)
- {
- return SLANG_E_OUT_OF_MEMORY;
- }
+ const Int64 start = stream.getPosition();
+ stream.seek(SeekOrigin::End, 0);
+ const Int64 end = stream.getPosition();
+ stream.seek(SeekOrigin::Start, start);
- size_t readSizeInBytes;
- SLANG_RETURN_ON_FAIL(stream.read(data, sizeInBytes, readSizeInBytes));
+ const Int64 positionSizeInBytes = end - start;
- // If not all read just return an error
- return (sizeInBytes == readSizeInBytes) ? SLANG_OK : SLANG_FAIL;
+ if (UInt64(positionSizeInBytes) > UInt64(~size_t(0)))
+ {
+ // It's too large to fit in memory.
+ return SLANG_FAIL;
}
- SlangResult File::writeAllBytes(const String& path, const void* data, size_t size)
+ const size_t sizeInBytes = size_t(positionSizeInBytes);
+
+ void* data = out.allocateTerminated(sizeInBytes);
+ if (!data)
{
- FileStream stream;
- SLANG_RETURN_ON_FAIL(stream.init(path, FileMode::Create, FileAccess::Write, FileShare::ReadWrite));
- SLANG_RETURN_ON_FAIL(stream.write(data, size));
- return SLANG_OK;
+ return SLANG_E_OUT_OF_MEMORY;
}
- SlangResult File::writeAllText(const Slang::String& fileName, const Slang::String& text)
- {
- RefPtr<FileStream> stream = new FileStream;
- SLANG_RETURN_ON_FAIL(stream->init(fileName, FileMode::Create));
+ size_t readSizeInBytes;
+ SLANG_RETURN_ON_FAIL(stream.read(data, sizeInBytes, readSizeInBytes));
- StreamWriter writer;
- SLANG_RETURN_ON_FAIL(writer.init(stream));
- SLANG_RETURN_ON_FAIL(writer.write(text));
+ // If not all read just return an error
+ return (sizeInBytes == readSizeInBytes) ? SLANG_OK : SLANG_FAIL;
+}
- return SLANG_OK;
- }
+SlangResult File::writeAllBytes(const String& path, const void* data, size_t size)
+{
+ FileStream stream;
+ SLANG_RETURN_ON_FAIL(
+ stream.init(path, FileMode::Create, FileAccess::Write, FileShare::ReadWrite));
+ SLANG_RETURN_ON_FAIL(stream.write(data, size));
+ return SLANG_OK;
+}
+
+SlangResult File::writeAllText(const Slang::String& fileName, const Slang::String& text)
+{
+ RefPtr<FileStream> stream = new FileStream;
+ SLANG_RETURN_ON_FAIL(stream->init(fileName, FileMode::Create));
- SlangResult File::writeAllTextIfChanged(const String& fileName, UnownedStringSlice text)
+ StreamWriter writer;
+ SLANG_RETURN_ON_FAIL(writer.init(stream));
+ SLANG_RETURN_ON_FAIL(writer.write(text));
+
+ return SLANG_OK;
+}
+
+SlangResult File::writeAllTextIfChanged(const String& fileName, UnownedStringSlice text)
+{
+ String existingContent;
+ auto result = File::readAllText(fileName, existingContent);
+ if (SLANG_FAILED(result) || existingContent != text)
{
- String existingContent;
- auto result = File::readAllText(fileName, existingContent);
- if (SLANG_FAILED(result) || existingContent != text)
- {
- return File::writeNativeText(fileName, text.begin(), text.getLength());
- }
- return SLANG_OK;
+ return File::writeNativeText(fileName, text.begin(), text.getLength());
}
+ return SLANG_OK;
+}
- /* static */SlangResult File::writeNativeText(const String& path, const void* data, size_t size)
+/* static */ SlangResult File::writeNativeText(const String& path, const void* data, size_t size)
+{
+ FILE* file = fopen(path.getBuffer(), "w");
+ if (!file)
{
- FILE* file = fopen(path.getBuffer(), "w");
- if (!file)
- {
- return SLANG_FAIL;
- }
+ return SLANG_FAIL;
+ }
- const auto count = fwrite(data, size, 1, file);
- fclose(file);
+ const auto count = fwrite(data, size, 1, file);
+ fclose(file);
- return (count == 1) ? SLANG_OK : SLANG_FAIL;
- }
+ return (count == 1) ? SLANG_OK : SLANG_FAIL;
+}
- String URI::getPath() const
- {
- Index startIndex = uri.indexOf("://");
- if (startIndex == -1)
- return String();
- startIndex += 3;
- Index endIndex = uri.indexOf('?');
- if (endIndex == -1)
- endIndex = uri.getLength();
- StringBuilder sb;
+String URI::getPath() const
+{
+ Index startIndex = uri.indexOf("://");
+ if (startIndex == -1)
+ return String();
+ startIndex += 3;
+ Index endIndex = uri.indexOf('?');
+ if (endIndex == -1)
+ endIndex = uri.getLength();
+ StringBuilder sb;
#if SLANG_WINDOWS_FAMILY
- if (uri[startIndex] == '/')
- startIndex++;
+ if (uri[startIndex] == '/')
+ startIndex++;
#endif
- for (Index i = startIndex; i < endIndex;)
+ for (Index i = startIndex; i < endIndex;)
+ {
+ auto ch = uri[i];
+ if (ch == '%')
{
- auto ch = uri[i];
- if (ch == '%')
- {
- Int charVal = CharUtil::getHexDigitValue(uri[i + 1]) * 16 +
- CharUtil::getHexDigitValue(uri[i + 2]);
- sb.appendChar((char)charVal);
- i += 3;
- }
- else
- {
- sb.appendChar(uri[i]);
- i++;
- }
+ Int charVal = CharUtil::getHexDigitValue(uri[i + 1]) * 16 +
+ CharUtil::getHexDigitValue(uri[i + 2]);
+ sb.appendChar((char)charVal);
+ i += 3;
+ }
+ else
+ {
+ sb.appendChar(uri[i]);
+ i++;
}
- return sb.produceString();
}
+ return sb.produceString();
+}
- StringSlice URI::getProtocol() const
- {
- Index separatorIndex = uri.indexOf("://");
- if (separatorIndex != -1)
- return uri.subString(0, separatorIndex);
- return StringSlice();
- }
+StringSlice URI::getProtocol() const
+{
+ Index separatorIndex = uri.indexOf("://");
+ if (separatorIndex != -1)
+ return uri.subString(0, separatorIndex);
+ return StringSlice();
+}
- bool URI::isSafeURIChar(char ch)
- {
- return (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') ||
- ch == '-' || ch == '_' || ch == '/' || ch == '.';
- }
+bool URI::isSafeURIChar(char ch)
+{
+ return (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') ||
+ ch == '-' || ch == '_' || ch == '/' || ch == '.';
+}
- URI URI::fromLocalFilePath(UnownedStringSlice path)
- {
- URI uri;
- StringBuilder sb;
- sb << "file://";
+URI URI::fromLocalFilePath(UnownedStringSlice path)
+{
+ URI uri;
+ StringBuilder sb;
+ sb << "file://";
#if SLANG_WINDOWS_FAMILY
- sb << "/";
+ sb << "/";
#endif
- for (auto ch : path)
+ for (auto ch : path)
+ {
+ if (isSafeURIChar(ch))
{
- if (isSafeURIChar(ch))
- {
- sb.appendChar(ch);
- }
- else if (ch == '\\')
- {
- sb.appendChar('/');
- }
- else
- {
- char buffer[32];
- int length = intToAscii(buffer, (int)ch, 16);
- sb << "%" << UnownedStringSlice(buffer, length);
- }
+ sb.appendChar(ch);
+ }
+ else if (ch == '\\')
+ {
+ sb.appendChar('/');
+ }
+ else
+ {
+ char buffer[32];
+ int length = intToAscii(buffer, (int)ch, 16);
+ sb << "%" << UnownedStringSlice(buffer, length);
}
- return URI::fromString(sb.getUnownedSlice());
}
+ return URI::fromString(sb.getUnownedSlice());
+}
- URI URI::fromString(UnownedStringSlice uriString)
- {
- URI uri;
- uri.uri = uriString;
- return uri;
- }
+URI URI::fromString(UnownedStringSlice uriString)
+{
+ URI uri;
+ uri.uri = uriString;
+ return uri;
+}
- SlangResult LockFile::open(const String& fileName)
- {
+SlangResult LockFile::open(const String& fileName)
+{
#if SLANG_WINDOWS_FAMILY
- m_fileHandle = ::CreateFileW(
- fileName.toWString(),
- GENERIC_READ | GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
- NULL,
- CREATE_ALWAYS,
- FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
- NULL
- );
- m_isOpen = m_fileHandle != INVALID_HANDLE_VALUE;
+ m_fileHandle = ::CreateFileW(
+ fileName.toWString(),
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
+ NULL);
+ m_isOpen = m_fileHandle != INVALID_HANDLE_VALUE;
#else
- m_fileHandle = ::open(fileName.getBuffer(), O_RDWR | O_CREAT, 0600);
- m_isOpen = m_fileHandle != -1;
+ m_fileHandle = ::open(fileName.getBuffer(), O_RDWR | O_CREAT, 0600);
+ m_isOpen = m_fileHandle != -1;
#endif
- return m_isOpen ? SLANG_OK : SLANG_E_CANNOT_OPEN;
- }
+ return m_isOpen ? SLANG_OK : SLANG_E_CANNOT_OPEN;
+}
- void LockFile::close()
- {
- if (!m_isOpen)
- return;
+void LockFile::close()
+{
+ if (!m_isOpen)
+ return;
#if SLANG_WINDOWS_FAMILY
- ::CloseHandle(m_fileHandle);
+ ::CloseHandle(m_fileHandle);
#else
- ::close(m_fileHandle);
+ ::close(m_fileHandle);
#endif
- m_isOpen = false;
- }
+ m_isOpen = false;
+}
- SlangResult LockFile::tryLock(LockType lockType)
- {
- if (!m_isOpen)
- return SLANG_E_CANNOT_OPEN;
+SlangResult LockFile::tryLock(LockType lockType)
+{
+ if (!m_isOpen)
+ return SLANG_E_CANNOT_OPEN;
- SlangResult result = SLANG_OK;
+ SlangResult result = SLANG_OK;
#if SLANG_WINDOWS_FAMILY
- OVERLAPPED overlapped = {0};
- DWORD flags = lockType == LockType::Shared ? LOCKFILE_FAIL_IMMEDIATELY : (LOCKFILE_EXCLUSIVE_LOCK | LOCKFILE_FAIL_IMMEDIATELY);
- if (::LockFileEx(m_fileHandle, flags, DWORD(0), ~DWORD(0), ~DWORD(0), &overlapped) == 0)
- {
- result = SLANG_E_TIME_OUT;
- }
+ OVERLAPPED overlapped = {0};
+ DWORD flags = lockType == LockType::Shared
+ ? LOCKFILE_FAIL_IMMEDIATELY
+ : (LOCKFILE_EXCLUSIVE_LOCK | LOCKFILE_FAIL_IMMEDIATELY);
+ if (::LockFileEx(m_fileHandle, flags, DWORD(0), ~DWORD(0), ~DWORD(0), &overlapped) == 0)
+ {
+ result = SLANG_E_TIME_OUT;
+ }
#else
- int operation = lockType == LockType::Shared ? (LOCK_SH | LOCK_NB) : (LOCK_EX | LOCK_NB);
- if (::flock(m_fileHandle, operation) != 0)
- {
- result = SLANG_E_TIME_OUT;
- }
-#endif
- return result;
+ int operation = lockType == LockType::Shared ? (LOCK_SH | LOCK_NB) : (LOCK_EX | LOCK_NB);
+ if (::flock(m_fileHandle, operation) != 0)
+ {
+ result = SLANG_E_TIME_OUT;
}
+#endif
+ return result;
+}
- SlangResult LockFile::lock(LockType lockType)
- {
- if (!m_isOpen)
- return SLANG_E_CANNOT_OPEN;
+SlangResult LockFile::lock(LockType lockType)
+{
+ if (!m_isOpen)
+ return SLANG_E_CANNOT_OPEN;
- SlangResult result = SLANG_OK;
+ SlangResult result = SLANG_OK;
#if SLANG_WINDOWS_FAMILY
- OVERLAPPED overlapped = {0};
- overlapped.hEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
- DWORD flags = lockType == LockType::Shared ? 0 : LOCKFILE_EXCLUSIVE_LOCK;
- if (::LockFileEx(m_fileHandle, flags, DWORD(0), ~DWORD(0), ~DWORD(0), &overlapped) == 0)
+ OVERLAPPED overlapped = {0};
+ overlapped.hEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
+ DWORD flags = lockType == LockType::Shared ? 0 : LOCKFILE_EXCLUSIVE_LOCK;
+ if (::LockFileEx(m_fileHandle, flags, DWORD(0), ~DWORD(0), ~DWORD(0), &overlapped) == 0)
+ {
+ auto err = ::GetLastError();
+ if (err == ERROR_IO_PENDING)
{
- auto err = ::GetLastError();
- if (err == ERROR_IO_PENDING)
- {
- DWORD bytes;
- if (::GetOverlappedResult(m_fileHandle, &overlapped, &bytes, TRUE) == 0)
- {
- result = SLANG_E_INTERNAL_FAIL;
- }
- }
- else
+ DWORD bytes;
+ if (::GetOverlappedResult(m_fileHandle, &overlapped, &bytes, TRUE) == 0)
{
result = SLANG_E_INTERNAL_FAIL;
}
}
- ::CloseHandle(overlapped.hEvent);
-#else
- int operation = lockType == LockType::Shared ? LOCK_SH : LOCK_EX;
- if (::flock(m_fileHandle, operation) != 0)
+ else
{
result = SLANG_E_INTERNAL_FAIL;
}
+ }
+ ::CloseHandle(overlapped.hEvent);
+#else
+ int operation = lockType == LockType::Shared ? LOCK_SH : LOCK_EX;
+ if (::flock(m_fileHandle, operation) != 0)
+ {
+ result = SLANG_E_INTERNAL_FAIL;
+ }
#endif
- return result;
+ return result;
}
- SlangResult LockFile::unlock()
- {
- if (!m_isOpen)
- return SLANG_E_CANNOT_OPEN;
+SlangResult LockFile::unlock()
+{
+ if (!m_isOpen)
+ return SLANG_E_CANNOT_OPEN;
#if SLANG_WINDOWS_FAMILY
- OVERLAPPED overlapped = {0};
- if (::UnlockFileEx(m_fileHandle, DWORD(0), ~DWORD(0), ~DWORD(0), &overlapped) == 0)
- {
- return SLANG_E_INTERNAL_FAIL;
- }
+ OVERLAPPED overlapped = {0};
+ if (::UnlockFileEx(m_fileHandle, DWORD(0), ~DWORD(0), ~DWORD(0), &overlapped) == 0)
+ {
+ return SLANG_E_INTERNAL_FAIL;
+ }
#else
- if (::flock(m_fileHandle, LOCK_UN) != 0)
- {
- return SLANG_E_INTERNAL_FAIL;
- }
+ if (::flock(m_fileHandle, LOCK_UN) != 0)
+ {
+ return SLANG_E_INTERNAL_FAIL;
+ }
#endif
- return SLANG_OK;
+ return SLANG_OK;
}
- LockFile::LockFile()
- : m_isOpen(false)
- {}
+LockFile::LockFile()
+ : m_isOpen(false)
+{
+}
- LockFile::~LockFile()
- {
- close();
- }
+LockFile::~LockFile()
+{
+ close();
}
+} // namespace Slang