@@ -95,19 +95,46 @@ auto search_in_path(std::string_view name) -> std::string {
9595
9696#ifdef _WIN32
9797 constexpr char path_sep = ' ;' ;
98- constexpr auto is_executable = [](const std::filesystem::path& p) {
99- return std::filesystem::exists (p) && !std::filesystem::is_directory (p);
98+
99+ // Get PATHEXT or use default extensions
100+ std::vector<std::string> extensions;
101+ const char * pathext_env = std::getenv (" PATHEXT" );
102+ if (pathext_env) {
103+ std::string_view pathext_view (pathext_env);
104+ size_t ext_start = 0 ;
105+ while (ext_start < pathext_view.size ()) {
106+ size_t ext_end = pathext_view.find (' ;' , ext_start);
107+ if (ext_end == std::string_view::npos) {
108+ ext_end = pathext_view.size ();
109+ }
110+ std::string_view ext = pathext_view.substr (ext_start, ext_end - ext_start);
111+ if (!ext.empty ()) {
112+ extensions.emplace_back (ext);
113+ }
114+ ext_start = ext_end + 1 ;
115+ }
116+ } else {
117+ extensions = {" .exe" , " .cmd" , " .bat" , " .com" };
118+ }
119+
120+ // Check if name already has an extension
121+ bool has_extension = name.find (' .' ) != std::string_view::npos;
122+
123+ auto is_executable = [](const std::filesystem::path& p) {
124+ std::error_code ec;
125+ auto status = std::filesystem::status (p, ec);
126+ return !ec && std::filesystem::exists (status) && !std::filesystem::is_directory (status);
100127 };
101128#else
102129 constexpr char path_sep = ' :' ;
103- constexpr auto is_executable = [](const std::filesystem::path& p) {
130+ auto is_executable = [](const std::filesystem::path& p) {
104131 std::error_code ec;
105132 auto status = std::filesystem::status (p, ec);
106133 if (ec || !std::filesystem::exists (status) || std::filesystem::is_directory (status)) {
107134 return false ;
108135 }
109- return (status.permissions () & (std::filesystem::perms::owner_exec |
110- std::filesystem::perms::group_exec |
136+ return (status.permissions () & (std::filesystem::perms::owner_exec |
137+ std::filesystem::perms::group_exec |
111138 std::filesystem::perms::others_exec)) != std::filesystem::perms::none;
112139 };
113140#endif
@@ -119,20 +146,42 @@ auto search_in_path(std::string_view name) -> std::string {
119146 if (end == std::string_view::npos) {
120147 end = path_view.size ();
121148 }
122-
149+
123150 std::string_view dir = path_view.substr (start, end - start);
124151 if (!dir.empty ()) {
152+ #ifdef _WIN32
153+ // Try the name as-is first
125154 std::filesystem::path full_path = std::filesystem::path (dir) / name;
126155 std::error_code ec;
127156 auto canonical = std::filesystem::canonical (full_path, ec);
128157 if (!ec && is_executable (canonical)) {
129158 return canonical.string ();
130159 }
160+
161+ // If name doesn't have an extension, try each PATHEXT extension
162+ if (!has_extension) {
163+ for (const auto & ext : extensions) {
164+ std::string name_with_ext = std::string (name) + ext;
165+ full_path = std::filesystem::path (dir) / name_with_ext;
166+ canonical = std::filesystem::canonical (full_path, ec);
167+ if (!ec && is_executable (canonical)) {
168+ return canonical.string ();
169+ }
170+ }
171+ }
172+ #else
173+ std::filesystem::path full_path = std::filesystem::path (dir) / name;
174+ std::error_code ec;
175+ auto canonical = std::filesystem::canonical (full_path, ec);
176+ if (!ec && is_executable (canonical)) {
177+ return canonical.string ();
178+ }
179+ #endif
131180 }
132-
181+
133182 start = end + 1 ;
134183 }
135-
184+
136185 return std::string (name);
137186}
138187
0 commit comments