aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorStefan Boberg <[email protected]>2026-04-20 11:02:38 +0200
committerGitHub Enterprise <[email protected]>2026-04-20 11:02:38 +0200
commit4d828df648b9e5093f3509cbeeb5887de8920ede (patch)
treeee8f8cf94d7a598bb773d6aa5d3f9d24b0635a47 /src
parentzencore: CreateProc stdin pipes + BuildArgV quote stripping (#983) (diff)
downloadarchived-zen-4d828df648b9e5093f3509cbeeb5887de8920ede.tar.xz
archived-zen-4d828df648b9e5093f3509cbeeb5887de8920ede.zip
zencore: implement SearchPathForExecutable on POSIX (#981)
- The Linux/macOS branch of `SearchPathForExecutable` was previously a no-op that returned the input unchanged. Callers passing a bare executable name (e.g. `llvm-symbolizer`) got the same bare name back even when the binary lived elsewhere on `PATH`. - Now walks `$PATH` like `execvp` does: skip the search if the input contains a `/`, try each colon-separated entry (empty entry == cwd), and return the first candidate that is both a regular file and executable by the current user. Falls back to returning the input unchanged if nothing matches, preserving the previous behavior for the no-match case. - Windows branch is unchanged (still uses `SearchPathW`).
Diffstat (limited to 'src')
-rw-r--r--src/zencore/filesystem.cpp33
1 files changed, 32 insertions, 1 deletions
diff --git a/src/zencore/filesystem.cpp b/src/zencore/filesystem.cpp
index 08e921293..03e04c77c 100644
--- a/src/zencore/filesystem.cpp
+++ b/src/zencore/filesystem.cpp
@@ -3183,7 +3183,38 @@ SearchPathForExecutable(std::string_view ExecutableName)
return PathBuffer.get();
#else
- return ExecutableName;
+ // If the name already contains a path separator, don't search PATH
+ // (matches the shell / execvp semantics).
+ if (ExecutableName.find('/') != std::string_view::npos)
+ {
+ return std::filesystem::path(ExecutableName);
+ }
+
+ const char* PathEnv = ::getenv("PATH");
+ if (PathEnv == nullptr || *PathEnv == '\0')
+ {
+ return std::filesystem::path(ExecutableName);
+ }
+
+ std::string_view PathView(PathEnv);
+ while (!PathView.empty())
+ {
+ size_t Sep = PathView.find(':');
+ std::string_view Dir = (Sep == std::string_view::npos) ? PathView : PathView.substr(0, Sep);
+ PathView = (Sep == std::string_view::npos) ? std::string_view{} : PathView.substr(Sep + 1);
+
+ // An empty entry in PATH is interpreted as the current directory.
+ std::filesystem::path Candidate = Dir.empty() ? std::filesystem::path(".") : std::filesystem::path(Dir);
+ Candidate /= ExecutableName;
+
+ std::error_code Ec;
+ if (std::filesystem::is_regular_file(Candidate, Ec) && ::access(Candidate.c_str(), X_OK) == 0)
+ {
+ return Candidate;
+ }
+ }
+
+ return std::filesystem::path(ExecutableName);
#endif
}