summaryrefslogtreecommitdiffstats
path: root/source
diff options
context:
space:
mode:
authorjsmall-nvidia <jsmall@nvidia.com>2021-04-29 09:01:46 -0400
committerGitHub <noreply@github.com>2021-04-29 09:01:46 -0400
commit972bd3c4c24b06501c52127416afb763a066b8ad (patch)
treee3874d4952ac557d5c323bb1e43be4584c100afc /source
parent541d1cab81d895c406fc33cb476e37ce8a6a9702 (diff)
Support for escaped paths in tools (#1823)
* #include an absolute path didn't work - because paths were taken to always be relative. * Split out StringEscapeUtil. * Added StringEscapeUtil. * Fix typo in unix quoting type. * Small comment improvements. * Try to fix linux linking issue. * Fix typo. * Attempt to fix linux link issue. * Update VS proj even though nothing really changed. * Fix another typo issue. * Fix for windows issue. Fixed bug. * Make separate Utils for escaping. * Fix typo. * Split out into StringEscapeHandler. * Windows shell does handle removing quotes (so remove code to remove them). * Handle unescaping if not initiating using the shell. * Slight improvement around shell like decoding. * Simplify command extraction. * Add shared-library category type. * Fix bug in command extraction. * Typo in transcendental category. * Enable unit-test on in smoke test category. * Make parsing failing output as a failing test. * Fixes for transcendental tests. Disable tests that do not work. * Changed category parsing. * Removed the TestResult parameter from _gatherTestsForFile. Made testsList only output. * Remove testing if all tests were disabled. * Fix typo. * Disable path canonical test on linux because CI issue.
Diffstat (limited to 'source')
-rw-r--r--source/compiler-core/slang-nvrtc-compiler.cpp2
-rw-r--r--source/compiler-core/slang-source-loc.cpp6
-rw-r--r--source/core/slang-process-util.h17
-rw-r--r--source/core/slang-string-escape-util.cpp548
-rw-r--r--source/core/slang-string-escape-util.h77
-rw-r--r--source/core/slang-string-util.cpp75
-rw-r--r--source/core/slang-string-util.h4
-rw-r--r--source/core/unix/slang-unix-process-util.cpp41
-rw-r--r--source/core/windows/slang-win-process-util.cpp50
-rw-r--r--source/slang/slang-options.cpp2
-rw-r--r--source/slang/slang-preprocessor.cpp5
11 files changed, 663 insertions, 164 deletions
diff --git a/source/compiler-core/slang-nvrtc-compiler.cpp b/source/compiler-core/slang-nvrtc-compiler.cpp
index 7a8d5bcfd..79ece266b 100644
--- a/source/compiler-core/slang-nvrtc-compiler.cpp
+++ b/source/compiler-core/slang-nvrtc-compiler.cpp
@@ -824,7 +824,7 @@ SlangResult NVRTCDownstreamCompiler::compile(const CompileOptions& options, RefP
}
ScopeProgram scope(this, program);
- List<const char*> dstOptions;
+ List<const char*> dstOptions;
dstOptions.setCount(cmdLine.m_args.getCount());
for (Index i = 0; i < cmdLine.m_args.getCount(); ++i)
{
diff --git a/source/compiler-core/slang-source-loc.cpp b/source/compiler-core/slang-source-loc.cpp
index 4b589fbf3..29fc0465a 100644
--- a/source/compiler-core/slang-source-loc.cpp
+++ b/source/compiler-core/slang-source-loc.cpp
@@ -2,6 +2,7 @@
#include "slang-source-loc.h"
#include "../core/slang-string-util.h"
+#include "../core/slang-string-escape-util.h"
namespace Slang {
@@ -66,10 +67,7 @@ void PathInfo::appendDisplayName(StringBuilder& out) const
case Type::FromString:
case Type::FoundPath:
{
-
- out.appendChar('"');
- StringUtil::appendEscaped(foundPath.getUnownedSlice(), out);
- out.appendChar('"');
+ StringEscapeUtil::appendQuoted(StringEscapeUtil::getHandler(StringEscapeUtil::Style::Cpp), foundPath.getUnownedSlice(), out);
break;
}
default: break;
diff --git a/source/core/slang-process-util.h b/source/core/slang-process-util.h
index 5d8c358e8..d47a4793b 100644
--- a/source/core/slang-process-util.h
+++ b/source/core/slang-process-util.h
@@ -5,6 +5,8 @@
#include "slang-string.h"
#include "slang-list.h"
+#include "slang-string-escape-util.h"
+
namespace Slang {
struct CommandLine
@@ -80,6 +82,10 @@ struct ExecuteResult
struct ProcessUtil
{
+ /// The quoting style used for the command line on this target. Currently just uses Space,
+ /// but in future may take into account platform sec
+ static StringEscapeHandler* getEscapeHandler();
+
/// Get the suffix used on this platform
static UnownedStringSlice getExecutableSuffix();
@@ -89,9 +95,6 @@ struct ProcessUtil
/// Execute the command line
static SlangResult execute(const CommandLine& commandLine, ExecuteResult& outExecuteResult);
- /// Append text escaped for using on a command line
- static void appendCommandLineEscaped(const UnownedStringSlice& slice, StringBuilder& out);
-
static uint64_t getClockFrequency();
static uint64_t getClockTick();
@@ -116,6 +119,8 @@ SLANG_INLINE Index CommandLine::findArgIndex(const UnownedStringSlice& slice) co
// -----------------------------------------------------------------------
SLANG_INLINE void CommandLine::addPrefixPathArg(const char* prefix, const String& path, const char* pathPostfix)
{
+ auto escapeHandler = ProcessUtil::getEscapeHandler();
+
StringBuilder builder;
builder << prefix;
if (pathPostfix)
@@ -123,12 +128,12 @@ SLANG_INLINE void CommandLine::addPrefixPathArg(const char* prefix, const String
// Work out the path with the postfix
StringBuilder fullPath;
fullPath << path << pathPostfix;
- ProcessUtil::appendCommandLineEscaped(fullPath.getUnownedSlice(), builder);
+ StringEscapeUtil::appendMaybeQuoted(escapeHandler, fullPath.getUnownedSlice(), builder);
}
else
{
- ProcessUtil::appendCommandLineEscaped(path.getUnownedSlice(), builder);
- }
+ StringEscapeUtil::appendMaybeQuoted(escapeHandler, path.getUnownedSlice(), builder);
+ }
// This arg doesn't need subsequent escaping
addEscapedArg(builder);
diff --git a/source/core/slang-string-escape-util.cpp b/source/core/slang-string-escape-util.cpp
new file mode 100644
index 000000000..13fce6dc7
--- /dev/null
+++ b/source/core/slang-string-escape-util.cpp
@@ -0,0 +1,548 @@
+#include "slang-string-escape-util.h"
+
+#include "slang-char-util.h"
+#include "slang-text-io.h"
+
+#include "../../slang-com-helper.h"
+
+namespace Slang {
+
+// !!!!!!!!!!!!!!!!!!!!!!!!!! SpaceStringEscapeHandler !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+class SpaceStringEscapeHandler : public StringEscapeHandler
+{
+public:
+ typedef StringEscapeHandler Super;
+
+ virtual bool isQuotingNeeded(const UnownedStringSlice& slice) SLANG_OVERRIDE { return isEscapingNeeded(slice); }
+
+ virtual bool isEscapingNeeded(const UnownedStringSlice& slice) SLANG_OVERRIDE;
+ virtual SlangResult appendEscaped(const UnownedStringSlice& slice, StringBuilder& out) SLANG_OVERRIDE;
+ virtual SlangResult appendUnescaped(const UnownedStringSlice& slice, StringBuilder& out) SLANG_OVERRIDE;
+ virtual SlangResult lexQuoted(const char* cursor, const char** outCursor) SLANG_OVERRIDE;
+
+ SpaceStringEscapeHandler() : Super('"') {}
+};
+
+bool SpaceStringEscapeHandler::isEscapingNeeded(const UnownedStringSlice& slice)
+{
+ return slice.indexOf(' ') >= 0;
+}
+
+SlangResult SpaceStringEscapeHandler::appendUnescaped(const UnownedStringSlice& slice, StringBuilder& out)
+{
+ if (slice.indexOf('"') >= 0)
+ {
+ return SLANG_FAIL;
+ }
+
+ out.append(slice);
+ return SLANG_OK;
+}
+
+SlangResult SpaceStringEscapeHandler::appendEscaped(const UnownedStringSlice& slice, StringBuilder& out)
+{
+ if (slice.indexOf('"') >= 0)
+ {
+ return SLANG_FAIL;
+ }
+ out.append(slice);
+ return SLANG_OK;
+}
+
+/* static */SlangResult SpaceStringEscapeHandler::lexQuoted(const char* cursor, const char** outCursor)
+{
+ *outCursor = cursor;
+
+ if (*cursor != m_quoteChar)
+ {
+ return SLANG_FAIL;
+ }
+ cursor++;
+
+ for (;;)
+ {
+ const char c = *cursor;
+ if (c == m_quoteChar)
+ {
+ *outCursor = cursor + 1;
+ return SLANG_OK;
+ }
+ switch (c)
+ {
+ case 0:
+ case '\n':
+ case '\r':
+ {
+ // Didn't hit closing quote!
+ return SLANG_FAIL;
+ }
+ default:
+ {
+ ++cursor;
+ break;
+ }
+ }
+ }
+}
+
+// !!!!!!!!!!!!!!!!!!!!!!!!!! CppStringEscapeHandler !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+class CppStringEscapeHandler : public StringEscapeHandler
+{
+public:
+ typedef StringEscapeHandler Super;
+
+ virtual bool isQuotingNeeded(const UnownedStringSlice& slice) SLANG_OVERRIDE { SLANG_UNUSED(slice); return true; }
+ virtual bool isEscapingNeeded(const UnownedStringSlice& slice) SLANG_OVERRIDE;
+ virtual SlangResult appendEscaped(const UnownedStringSlice& slice, StringBuilder& out) SLANG_OVERRIDE;
+ virtual SlangResult appendUnescaped(const UnownedStringSlice& slice, StringBuilder& out) SLANG_OVERRIDE;
+ virtual SlangResult lexQuoted(const char* cursor, const char** outCursor) SLANG_OVERRIDE;
+
+ CppStringEscapeHandler() : Super('"') {}
+};
+
+static char _getHexChar(int v)
+{
+ return (v <= 9) ? char(v + '0') : char(v - 10 + 'A');
+}
+
+static int _getHexDigit(char c)
+{
+ if (c >= '0' && c <= '9')
+ {
+ return c - '0';
+ }
+ else if (c >= 'a' && c <= 'f')
+ {
+ return c - 'a' + 10;
+ }
+ else if (c >= 'A' && c <= 'F')
+ {
+ return c - 'A' + 10;
+ }
+ else
+ {
+ SLANG_ASSERT(!"Not a hex digit");
+ return 0;
+ }
+}
+
+static char _getCppEscapedChar(char c)
+{
+ switch (c)
+ {
+ case '\b': return 'b';
+ case '\f': return 'f';
+ case '\n': return 'n';
+ case '\r': return 'r';
+ case '\a': return 'a';
+ case '\t': return 't';
+ case '\v': return 'v';
+ case '\'': return '\'';
+ case '\"': return '"';
+ case '\\': return '\\';
+ default: return 0;
+ }
+}
+
+static char _getCppUnescapedChar(char c)
+{
+ switch (c)
+ {
+ case 'b': return '\b';
+ case 'f': return '\f';
+ case 'n': return '\n';
+ case 'r': return '\r';
+ case 'a': return '\a';
+ case 't': return '\t';
+ case 'v': return '\v';
+ case '\'': return '\'';
+ case '\"': return '"';
+ case '\\': return '\\';
+ default: return 0;
+ }
+}
+
+/* static */bool CppStringEscapeHandler::isEscapingNeeded(const UnownedStringSlice& slice)
+{
+ const char* cur = slice.begin();
+ const char*const end = slice.end();
+
+ for (; cur < end; ++cur)
+ {
+ const char c = *cur;
+
+ switch (c)
+ {
+ case '\'':
+ case '\"':
+ case '\\':
+ {
+ // Strictly speaking ' shouldn't need a quote if in a C style string.
+ return true;
+ }
+ default:
+ {
+ if (c < ' ' || c >= 0x7e)
+ {
+ return true;
+ }
+ break;
+ }
+ }
+ }
+ return false;
+}
+
+SlangResult CppStringEscapeHandler::appendEscaped(const UnownedStringSlice& slice, StringBuilder& out)
+{
+ const char* start = slice.begin();
+ const char* cur = start;
+ const char*const end = slice.end();
+
+ for (; cur < end; ++cur)
+ {
+ const char c = *cur;
+ const char escapedChar = _getCppEscapedChar(c);
+
+ if (escapedChar)
+ {
+ // Flush
+ if (start < cur)
+ {
+ out.append(start, cur);
+ }
+ out.appendChar('\\');
+ out.appendChar(escapedChar);
+
+ start = cur + 1;
+ }
+ else if (c < ' ' || c > 126)
+ {
+ // Flush
+ if (start < cur)
+ {
+ out.append(start, cur);
+ }
+
+ char buf[5] = "\\0x0";
+
+ buf[3] = _getHexChar((int(c) >> 4) & 0xf);
+ buf[4] = _getHexChar(c & 0xf);
+
+ out.append(buf, buf + 4);
+
+ start = cur + 1;
+ }
+ }
+
+ if (start < end)
+ {
+ out.append(start, end);
+ }
+ return SLANG_OK;
+}
+
+SlangResult CppStringEscapeHandler::appendUnescaped(const UnownedStringSlice& slice, StringBuilder& out)
+{
+ const char* start = slice.begin();
+ const char* cur = start;
+ const char*const end = slice.end();
+
+ for (; cur < end; ++cur)
+ {
+ const char c = *cur;
+
+ if (c == '\\')
+ {
+ // Flush
+ if (start < end)
+ {
+ out.append(start, end);
+ }
+
+ /// Next
+ cur++;
+
+ if (cur >= end)
+ {
+ return SLANG_FAIL;
+ }
+
+ // Need to handle various escape sequence cases
+ switch (*cur)
+ {
+ case '\'':
+ case '\"':
+ case '\\':
+ case '?':
+ case 'a':
+ case 'b':
+ case 'f':
+ case 'n':
+ case 'r':
+ case 't':
+ case 'v':
+ {
+ const char unescapedChar = _getCppUnescapedChar(*cur);
+ if (unescapedChar == 0)
+ {
+ // Don't know how to unescape that char
+ return SLANG_FAIL;
+ }
+ out.appendChar(unescapedChar);
+
+ start = cur + 1;
+ break;
+ }
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7':
+ {
+ // octal escape: up to 3 characters
+ ++cur;
+ int value = 0;
+
+ const char* octEnd = cur + 3;
+ octEnd = (octEnd > end) ? end : octEnd;
+
+ for (; cur < octEnd; ++cur)
+ {
+ const char d = *cur;
+ if (d >= '0' && d <= '7')
+ {
+ value = (value << 3) | (d - '0');
+ }
+ }
+ out.appendChar(char(value));
+
+ start = cur;
+ break;
+ }
+ case 'x':
+ {
+ uint32_t value = 0;
+ for (++cur; cur < end && CharUtil::isHexDigit(*cur); ++cur)
+ {
+ value = value << 4 | _getHexDigit(*cur);
+ }
+
+ // It's arguable what is appropriate. We only decode/encode 4, which the current spec has,
+ // but 6 are possible, so lets go large.
+ const Index maxUtf8EncodeCount = 6;
+
+ char* chars = out.prepareForAppend(maxUtf8EncodeCount);
+
+ int numChars = EncodeUnicodePointToUTF8(chars, int(value));
+ out.appendInPlace(chars, numChars);
+
+ start = cur;
+ break;
+ }
+ default:
+ {
+ return SLANG_FAIL;
+ }
+ }
+ }
+ }
+
+ if (start < end)
+ {
+ out.append(start, end);
+ }
+
+ return SLANG_OK;
+}
+
+SlangResult CppStringEscapeHandler::lexQuoted(const char* cursor, const char** outCursor)
+{
+ *outCursor = cursor;
+
+ if (*cursor != m_quoteChar)
+ {
+ return SLANG_FAIL;
+ }
+ cursor++;
+
+ for (;;)
+ {
+ const char c = *cursor;
+ if (c == m_quoteChar)
+ {
+ *outCursor = cursor + 1;
+ return SLANG_OK;
+ }
+ switch (c)
+ {
+ case 0:
+ case '\n':
+ case '\r':
+ {
+ // Didn't hit closing quote!
+ return SLANG_FAIL;
+ }
+ case '\\':
+ {
+ ++cursor;
+ // Need to handle various escape sequence cases
+ switch (*cursor)
+ {
+ case '\'':
+ case '\"':
+ case '\\':
+ case '?':
+ case 'a':
+ case 'b':
+ case 'f':
+ case 'n':
+ case 'r':
+ case 't':
+ case 'v':
+ {
+ ++cursor;
+ break;
+ }
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7':
+ {
+ // octal escape: up to 3 characters
+ ++cursor;
+ for (int ii = 0; ii < 3; ++ii)
+ {
+ const char d = *cursor;
+ if (('0' <= d) && (d <= '7'))
+ {
+ ++cursor;
+ continue;
+ }
+ else
+ {
+ break;
+ }
+ }
+ break;
+ }
+ case 'x':
+ {
+ // hexadecimal escape: any number of characters
+ ++cursor;
+ for (; CharUtil::isHexDigit(*cursor); ++cursor);
+
+ // TODO: Unicode escape sequences
+ break;
+ }
+ }
+ break;
+ }
+ default:
+ {
+ ++cursor;
+ break;
+ }
+ }
+ }
+}
+
+// !!!!!!!!!!!!!!!!!!!!!!!!!! StringEscapeUtil !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+static CppStringEscapeHandler g_cppHandler;
+static SpaceStringEscapeHandler g_spaceHandler;
+
+StringEscapeUtil::Handler* StringEscapeUtil::getHandler(Style style)
+{
+ switch (style)
+ {
+ case Style::Cpp: return &g_cppHandler;
+ case Style::Space: return &g_spaceHandler;
+ default: return nullptr;
+ }
+}
+
+/* static */void StringEscapeUtil::appendQuoted(Handler* handler, const UnownedStringSlice& slice, StringBuilder& out)
+{
+ const char quoteChar = handler->getQuoteChar();
+ out.appendChar(quoteChar);
+ handler->appendEscaped(slice, out);
+ out.appendChar(quoteChar);
+}
+
+/* static */SlangResult StringEscapeUtil::appendUnquoted(Handler* handler, const UnownedStringSlice& slice, StringBuilder& out)
+{
+ const Index len = slice.getLength();
+
+ const char quoteChar = handler->getQuoteChar();
+ SLANG_UNUSED(quoteChar);
+
+ // Must have quote characters around if
+ SLANG_ASSERT(len >= 2 && slice[0] == quoteChar && slice[len - 1] == quoteChar);
+
+ return handler->appendUnescaped(slice.subString(1, len - 2), out);
+}
+
+/* static */void StringEscapeUtil::appendMaybeQuoted(Handler* handler, const UnownedStringSlice& slice, StringBuilder& out)
+{
+ if (handler->isQuotingNeeded(slice))
+ {
+ appendQuoted(handler, slice, out);
+ }
+ else
+ {
+ out.append(slice);
+ }
+}
+
+/* static */SlangResult StringEscapeUtil::appendMaybeUnquoted(Handler* handler, const UnownedStringSlice& slice, StringBuilder& out)
+{
+ const char quoteChar = handler->getQuoteChar();
+
+ const Index len = slice.getLength();
+
+ if (len >= 2 && slice[0] == quoteChar && slice[len - 1] == quoteChar)
+ {
+ return appendUnquoted(handler, slice, out);
+ }
+ else
+ {
+ out.append(slice);
+ return SLANG_OK;
+ }
+}
+
+
+/* static */SlangResult StringEscapeUtil::unescapeShellLike(Handler* handler, const UnownedStringSlice& slice, StringBuilder& out)
+{
+ StringBuilder buf;
+ const char quoteChar = handler->getQuoteChar();
+
+ UnownedStringSlice remaining(slice);
+
+ while (remaining.getLength())
+ {
+ const Index index = remaining.indexOf(quoteChar);
+
+ if (index < 0)
+ {
+ out.append(remaining);
+ return SLANG_OK;
+ }
+
+ // Append the bit before
+ out.append(remaining.head(index));
+
+ // Okay we need to lex to the end
+
+ const char* quotedEnd = nullptr;
+ SLANG_RETURN_ON_FAIL(handler->lexQuoted(remaining.begin() + index, &quotedEnd));
+
+ // Unescape it
+ SLANG_RETURN_ON_FAIL(appendUnquoted(handler, UnownedStringSlice(remaining.begin() + index, quotedEnd), out));
+
+ // Fix up remaining
+ remaining = UnownedStringSlice(quotedEnd, remaining.end());
+ }
+
+ return SLANG_OK;
+}
+
+} // namespace Slang
diff --git a/source/core/slang-string-escape-util.h b/source/core/slang-string-escape-util.h
new file mode 100644
index 000000000..31f781dc6
--- /dev/null
+++ b/source/core/slang-string-escape-util.h
@@ -0,0 +1,77 @@
+#ifndef SLANG_CORE_STRING_ESCAPE_UTIL_H
+#define SLANG_CORE_STRING_ESCAPE_UTIL_H
+
+#include "slang-string.h"
+
+namespace Slang {
+
+class StringEscapeHandler
+{
+public:
+
+ /// True if quoting is needed
+ virtual bool isQuotingNeeded(const UnownedStringSlice& slice) = 0;
+ /// True if any escaping is needed. If not slice can be used (assuming appropriate quoting) as is
+ virtual bool isEscapingNeeded(const UnownedStringSlice& slice) = 0;
+ /// Takes slice and adds any appropriate escaping (for example C++/C type escaping for special characters like '\', '"' and if not ascii will write out as hex sequence)
+ /// Does not append quotes
+ virtual SlangResult appendEscaped(const UnownedStringSlice& slice, StringBuilder& out) = 0;
+ /// Given a slice append it unescaped
+ /// Does not consume surrounding quotes
+ virtual SlangResult appendUnescaped(const UnownedStringSlice& slice, StringBuilder& out) = 0;
+
+ /// Lex quoted text.
+ /// The first character of cursor should be the quoteCharacter.
+ /// cursor points to the string to be lexed - must typically be 0 terminated.
+ /// outCursor on successful lex will be at the next character after was processed.
+ virtual SlangResult lexQuoted(const char* cursor, const char** outCursor) = 0;
+
+ SLANG_FORCE_INLINE char getQuoteChar() const { return m_quoteChar; }
+
+ StringEscapeHandler(char quoteChar):
+ m_quoteChar(quoteChar)
+ {
+ }
+
+protected:
+ const char m_quoteChar;
+};
+
+/* A set of function that can be used for escaping/unescaping quoting/unquoting strings.
+
+The distinction between 'escaping' and 'quoting' here, is just that escaping is the 'payload' of quotes.
+In *principal* the Style can determine different styles of escaping that can be used.
+*/
+struct StringEscapeUtil
+{
+ typedef StringEscapeHandler Handler;
+
+ enum class Style
+ {
+ Cpp, ///< Cpp style quoting and escape handling
+ Space, ///< Applies quotes if there are spaces. Does not escape.
+ };
+
+ /// Given a style returns a handler
+ static Handler* getHandler(Style style);
+
+ /// If quoting is needed appends to out quoted
+ static void appendMaybeQuoted(Handler* handler, const UnownedStringSlice& slice, StringBuilder& out);
+
+ /// If the slice appears to be quoted for the style, unquote it, else just append to out
+ static SlangResult appendMaybeUnquoted(Handler* handler, const UnownedStringSlice& slice, StringBuilder& out);
+
+ /// Appends to out slice without quotes
+ static SlangResult appendUnquoted(Handler* handler, const UnownedStringSlice& slice, StringBuilder& out);
+
+ /// Append with quotes (even if not needed)
+ static void appendQuoted(Handler* handler, const UnownedStringSlice& slice, StringBuilder& out);
+
+ /// Shells can have multiple quoted sections. This function makes a string with out quoting
+ static SlangResult unescapeShellLike(Handler* handler, const UnownedStringSlice& slice, StringBuilder& out);
+};
+
+
+} // namespace Slang
+
+#endif // SLANG_CORE_STRING_ESCAPE_UTIL_H
diff --git a/source/core/slang-string-util.cpp b/source/core/slang-string-util.cpp
index 8108bdc98..cddee4bc4 100644
--- a/source/core/slang-string-util.cpp
+++ b/source/core/slang-string-util.cpp
@@ -2,6 +2,9 @@
#include "slang-blob.h"
+#include "slang-char-util.h"
+#include "slang-text-io.h"
+
namespace Slang {
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! StringUtil !!!!!!!!!!!!!!!!!!!!!!!!!!!
@@ -491,76 +494,4 @@ SLANG_FORCE_INLINE static bool _isDigit(char c)
return SLANG_OK;
}
-static char _getHexChar(int v)
-{
- return (v <= 9) ? char(v + '0') : char(v - 10 + 'A');
-}
-
-static char _getEscapedChar(char c)
-{
- switch (c)
- {
- case '\b': return 'b';
- case '\f': return 'f';
- case '\n': return 'n';
- case '\r': return 'r';
- case '\a': return 'a';
- case '\t': return 't';
- case '\v': return 'v';
- case '\'': return '\'';
- case '\"': return '"';
- case '\\': return '\\';
- default: return 0;
- }
-}
-
-/* static */void StringUtil::appendEscaped(const UnownedStringSlice& slice, StringBuilder& out)
-{
- const char* start = slice.begin();
- const char* cur = start;
- const char*const end = slice.end();
-
- for (; cur < end; ++cur)
- {
- const char c = *cur;
- const char escapedChar = _getEscapedChar(c);
-
- if (escapedChar)
- {
- // Flush
- if (start < cur)
- {
- out.append(start, end);
- }
- out.appendChar('\\');
- out.appendChar(escapedChar);
-
- start = cur + 1;
- }
- else if ( c < ' ' || c > 126)
- {
- // Flush
- if (start < cur)
- {
- out.append(start, end);
- }
-
- char buf[5] = "\\0x0";
-
- buf[3] = _getHexChar((int(c) >> 4) & 0xf);
- buf[4] = _getHexChar(c & 0xf);
-
- out.append(buf, buf + 4);
-
- start = cur + 1;
- }
- }
-
- if (start < end)
- {
- out.append(start, end);
- }
-}
-
-
} // namespace Slang
diff --git a/source/core/slang-string-util.h b/source/core/slang-string-util.h
index 8031f5c8c..5b375a09e 100644
--- a/source/core/slang-string-util.h
+++ b/source/core/slang-string-util.h
@@ -99,10 +99,6 @@ struct StringUtil
/// Convert in to int. Returns SLANG_FAIL on error
static SlangResult parseInt(const UnownedStringSlice& in, Int& outValue);
-
- /// Takes slice and adds C++/C type escaping for special characters (like '\', '"' and if not ascii will write out as hex sequence)
- /// Does not append double quotes around the output
- static void appendEscaped(const UnownedStringSlice& slice, StringBuilder& out);
};
/* A helper class that allows parsing of lines from text with iteration. Uses StringUtil::extractLine for the actual underlying implementation. */
diff --git a/source/core/unix/slang-unix-process-util.cpp b/source/core/unix/slang-unix-process-util.cpp
index 3f052b09d..a3b66af38 100644
--- a/source/core/unix/slang-unix-process-util.cpp
+++ b/source/core/unix/slang-unix-process-util.cpp
@@ -3,6 +3,7 @@
#include "../slang-common.h"
#include "../slang-string-util.h"
+#include "../slang-string-escape-util.h"
#include <stdio.h>
#include <stdlib.h>
@@ -29,52 +30,25 @@ namespace Slang {
#endif
}
-/* static */void ProcessUtil::appendCommandLineEscaped(const UnownedStringSlice& slice, StringBuilder& out)
+/* static */StringEscapeHandler* ProcessUtil::getEscapeHandler()
{
- // TODO(JS): This escaping is not complete... !
- if (slice.indexOf(' ') >= 0 || slice.indexOf('"') >= 0)
- {
- out << "\"";
-
- const char* cur = slice.begin();
- const char* end = slice.end();
-
- while (cur < end)
- {
- char c = *cur++;
- switch (c)
- {
- case '\"':
- {
- // Escape quotes.
- out << "\\\"";
- break;
- }
- default:
- out.append(c);
- }
- }
-
- out << "\"";
-
- return;
- }
-
- out << slice;
+ return StringEscapeUtil::getHandler(StringEscapeUtil::Style::Space);
}
/* static */String ProcessUtil::getCommandLineString(const CommandLine& commandLine)
{
+ auto escapeHandler = getEscapeHandler();
+
// When outputting the command line we potentially need to escape the path to the
// command and args - that aren't already explicitly marked as escaped.
StringBuilder cmd;
- appendCommandLineEscaped(commandLine.m_executable.getUnownedSlice(), cmd);
+ StringEscapeUtil::appendMaybeQuoted(escapeHandler, commandLine.m_executable.getUnownedSlice(), cmd);
for (const auto& arg : commandLine.m_args)
{
cmd << " ";
if (arg.type == CommandLine::ArgType::Unescaped)
{
- appendCommandLineEscaped(arg.value.getUnownedSlice(), cmd);
+ StringEscapeUtil::appendMaybeQuoted(escapeHandler, arg.value.getUnownedSlice(), cmd);
}
else
{
@@ -260,7 +234,6 @@ namespace Slang {
return SLANG_FAIL;
}
-
/* static */uint64_t ProcessUtil::getClockFrequency()
{
return 1000000000;
diff --git a/source/core/windows/slang-win-process-util.cpp b/source/core/windows/slang-win-process-util.cpp
index 3a5a01cb3..9cc567318 100644
--- a/source/core/windows/slang-win-process-util.cpp
+++ b/source/core/windows/slang-win-process-util.cpp
@@ -2,6 +2,7 @@
#include "../slang-process-util.h"
#include "../slang-string.h"
+#include "../slang-string-escape-util.h"
#ifdef _WIN32
// Include Windows header in a way that minimized namespace pollution.
@@ -148,58 +149,29 @@ static DWORD WINAPI _readerThreadProc(LPVOID threadParam)
return 0;
}
-
-/* static */UnownedStringSlice ProcessUtil::getExecutableSuffix()
+/* static */StringEscapeHandler* ProcessUtil::getEscapeHandler()
{
- return UnownedStringSlice::fromLiteral(".exe");
+ return StringEscapeUtil::getHandler(StringEscapeUtil::Style::Space);
}
-/* static */void ProcessUtil::appendCommandLineEscaped(const UnownedStringSlice& slice, StringBuilder& out)
+/* static */UnownedStringSlice ProcessUtil::getExecutableSuffix()
{
- // TODO(JS): This escaping is not complete... !
-
- if ((slice.indexOf(' ') >= 0 || slice.indexOf('"') >= 0))
- {
- out << "\"";
-
- const char* cur = slice.begin();
- const char* end = slice.end();
-
- while (cur < end)
- {
- char c = *cur++;
- switch (c)
- {
- case '\"':
- {
- // Escape quotes.
- out << "\\\"";
- break;
- }
- default:
- out.append(c);
- }
- }
-
- out << "\"";
- return;
- }
- else
- {
- out << slice;
- }
+ return UnownedStringSlice::fromLiteral(".exe");
}
/* static */String ProcessUtil::getCommandLineString(const CommandLine& commandLine)
{
+ auto escapeHandler = getEscapeHandler();
+
StringBuilder cmd;
- appendCommandLineEscaped(commandLine.m_executable.getUnownedSlice(), cmd);
+ StringEscapeUtil::appendMaybeQuoted(escapeHandler, commandLine.m_executable.getUnownedSlice(), cmd);
+
for (const auto& arg : commandLine.m_args)
{
cmd << " ";
if (arg.type == CommandLine::ArgType::Unescaped)
{
- appendCommandLineEscaped(arg.value.getUnownedSlice(), cmd);
+ StringEscapeUtil::appendMaybeQuoted(escapeHandler, arg.value.getUnownedSlice(), cmd);
}
else
{
@@ -269,7 +241,7 @@ static DWORD WINAPI _readerThreadProc(LPVOID threadParam)
if (commandLine.m_executableType == CommandLine::ExecutableType::Path)
{
StringBuilder cmd;
- appendCommandLineEscaped(commandLine.m_executable.getUnownedSlice(), cmd);
+ StringEscapeUtil::appendMaybeQuoted(getEscapeHandler(), commandLine.m_executable.getUnownedSlice(), cmd);
pathBuffer = cmd.toWString();
path = pathBuffer.begin();
diff --git a/source/slang/slang-options.cpp b/source/slang/slang-options.cpp
index 1cb222294..e0ad2163a 100644
--- a/source/slang/slang-options.cpp
+++ b/source/slang/slang-options.cpp
@@ -890,7 +890,7 @@ struct OptionsParser
SLANG_RETURN_ON_FAIL(tryReadCommandLineArgumentRaw(sink, arg, &argCursor, argEnd, &includeDirStr));
}
- compileRequest->addSearchPath(String(includeDirStr).begin());
+ compileRequest->addSearchPath(includeDirStr);
}
//
// A `-o` option is used to specify a desired output file.
diff --git a/source/slang/slang-preprocessor.cpp b/source/slang/slang-preprocessor.cpp
index bc78e4d31..7bee5afd2 100644
--- a/source/slang/slang-preprocessor.cpp
+++ b/source/slang/slang-preprocessor.cpp
@@ -1051,9 +1051,8 @@ static void MaybeBeginMacroExpansion(
// We need to escape to a string
newToken.type = TokenType::StringLiteral;
- buf.appendChar('"');
- StringUtil::appendEscaped(humaneSourceLoc.pathInfo.foundPath.getUnownedSlice(), buf);
- buf.appendChar('"');
+ auto escapeHandler = StringEscapeUtil::getHandler(StringEscapeUtil::Style::Cpp);
+ StringEscapeUtil::appendQuoted(escapeHandler, humaneSourceLoc.pathInfo.foundPath.getUnownedSlice(), buf);
}
// We are going to keep the actual text in the slice pool, so it stays in scope