in src/unix-adapter/main.cc [261:319]
static std::string findProgram(
const char *winptyProgName,
const std::string &prog)
{
std::string candidate;
if (prog.find('/') == std::string::npos &&
prog.find('\\') == std::string::npos) {
// XXX: It would be nice to use a lambda here (once/if old MSYS support
// is dropped).
// Search the PATH.
const char *const pathVar = getenv("PATH");
const std::string pathList(pathVar ? pathVar : "");
size_t elpos = 0;
while (true) {
const size_t elend = pathList.find(':', elpos);
candidate = pathList.substr(elpos, elend - elpos);
if (!candidate.empty() && *(candidate.end() - 1) != '/') {
candidate += '/';
}
candidate += prog;
candidate = resolvePath(candidate);
if (!candidate.empty()) {
int perm = X_OK;
if (endsWith(candidate, ".bat") || endsWith(candidate, ".cmd")) {
#ifdef __MSYS__
// In MSYS/MSYS2, batch files don't have the execute bit
// set, so just check that they're readable.
perm = R_OK;
#endif
} else if (endsWith(candidate, ".com") || endsWith(candidate, ".exe")) {
// Do nothing.
} else {
// Make the exe extension explicit so that we don't try to
// run shell scripts with CreateProcess/winpty_spawn.
candidate += ".exe";
}
if (!access(candidate.c_str(), perm)) {
break;
}
}
if (elend == std::string::npos) {
fprintf(stderr, "%s: error: cannot start '%s': Not found in PATH\n",
winptyProgName, prog.c_str());
exit(1);
} else {
elpos = elend + 1;
}
}
} else {
candidate = resolvePath(prog);
if (candidate.empty()) {
std::string errstr(strerror(errno));
fprintf(stderr, "%s: error: cannot start '%s': %s\n",
winptyProgName, prog.c_str(), errstr.c_str());
exit(1);
}
}
return convertPosixPathToWin(candidate);
}