diff options
| author | jsmall-nvidia <jsmall@nvidia.com> | 2021-04-29 09:01:46 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-04-29 09:01:46 -0400 |
| commit | 972bd3c4c24b06501c52127416afb763a066b8ad (patch) | |
| tree | e3874d4952ac557d5c323bb1e43be4584c100afc /source | |
| parent | 541d1cab81d895c406fc33cb476e37ce8a6a9702 (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.cpp | 2 | ||||
| -rw-r--r-- | source/compiler-core/slang-source-loc.cpp | 6 | ||||
| -rw-r--r-- | source/core/slang-process-util.h | 17 | ||||
| -rw-r--r-- | source/core/slang-string-escape-util.cpp | 548 | ||||
| -rw-r--r-- | source/core/slang-string-escape-util.h | 77 | ||||
| -rw-r--r-- | source/core/slang-string-util.cpp | 75 | ||||
| -rw-r--r-- | source/core/slang-string-util.h | 4 | ||||
| -rw-r--r-- | source/core/unix/slang-unix-process-util.cpp | 41 | ||||
| -rw-r--r-- | source/core/windows/slang-win-process-util.cpp | 50 | ||||
| -rw-r--r-- | source/slang/slang-options.cpp | 2 | ||||
| -rw-r--r-- | source/slang/slang-preprocessor.cpp | 5 |
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, "edEnd)); + + // 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 |
