diff options
author | Vedran Miletić <[email protected]> | 2016-09-28 17:11:43 +0200 |
---|---|---|
committer | Francisco Jerez <[email protected]> | 2016-10-30 12:14:59 -0700 |
commit | e3272865c216933168e6c08766d266a33d0e1497 (patch) | |
tree | e985ca5c03785c57557fcd7f08f2029ccf04c76a /src/gallium | |
parent | 2a4a86862c949055c71637429f6d5f2e725d07d8 (diff) |
clover: Pass unquoted compiler arguments to Clang
OpenCL apps can quote arguments they pass to the OpenCL compiler, most
commonly include paths containing spaces.
If the Clang OpenCL compiler was called via a shell, the shell would
split the arguments with respect to to quotes and then remove quotes
before passing the arguments to the compiler. Since we call Clang as a
library, we have to split the argument with respect to quotes and then
remove quotes before passing the arguments.
v2: move to tokenize(), remove throwing of CL_INVALID_COMPILER_OPTIONS
v3: simplify parsing logic, use more C++11
v4: restore error throwing, clarify a comment
Signed-off-by: Vedran Miletić <[email protected]>
Reviewed-by: Francisco Jerez <[email protected]>
Diffstat (limited to 'src/gallium')
-rw-r--r-- | src/gallium/state_trackers/clover/llvm/util.hpp | 40 |
1 files changed, 36 insertions, 4 deletions
diff --git a/src/gallium/state_trackers/clover/llvm/util.hpp b/src/gallium/state_trackers/clover/llvm/util.hpp index 8db6f20e5a7..222becd614e 100644 --- a/src/gallium/state_trackers/clover/llvm/util.hpp +++ b/src/gallium/state_trackers/clover/llvm/util.hpp @@ -24,6 +24,7 @@ #ifndef CLOVER_LLVM_UTIL_HPP #define CLOVER_LLVM_UTIL_HPP +#include "core/error.hpp" #include "util/u_debug.h" #include <vector> @@ -42,11 +43,42 @@ namespace clover { inline std::vector<std::string> tokenize(const std::string &s) { std::vector<std::string> ss; - std::istringstream iss(s); - std::string t; + std::ostringstream oss; - while (getline(iss, t, ' ')) - ss.push_back(t); + // OpenCL programs can pass a quoted argument, most frequently the + // include path. This is useful so that path containing spaces is + // treated as a single argument instead of being split by the spaces. + // Additionally, the argument should also be unquoted before being + // passed to the compiler. We avoid using std::string::replace here to + // remove quotes, as the single and double quote characters can be a + // part of the file name. + bool escape_next = false; + bool in_quote_double = false; + bool in_quote_single = false; + + for (auto c : s) { + if (escape_next) { + oss.put(c); + escape_next = false; + } else if (c == '\\') { + escape_next = true; + } else if (c == '"' && !in_quote_single) { + in_quote_double = !in_quote_double; + } else if (c == '\'' && !in_quote_double) { + in_quote_single = !in_quote_single; + } else if (c != ' ' || in_quote_single || in_quote_double) { + oss.put(c); + } else if (oss.tellp() > 0) { + ss.emplace_back(oss.str()); + oss.str(""); + } + } + + if (oss.tellp() > 0) + ss.emplace_back(oss.str()); + + if (in_quote_double || in_quote_single) + throw invalid_build_options_error(); return ss; } |