package jnr.posix.util;
import java.io.
File;
import java.util.*;
import jnr.posix.
FileStat;
import jnr.posix.
POSIX;
public class
Finder {
private static final
Collection<
String>
EXECUTABLE_EXTENSIONS
=
Collections.
unmodifiableSet(new
HashSet<
String>(
Arrays.
asList(".exe", ".com", ".cmd", ".bat")));
public static
String findFileInPath(
POSIX posix,
String name,
String path) {
if (
path == null ||
path.
length() == 0)
path =
System.
getenv("PATH");
// MRI sets up a bogus path which seems like it would violate security
// if nothing else since if I don't have /usr/bin in my path but I end
// up executing it anyways??? Returning original name and hoping for
// best.
if (
path == null ||
path.
length() == 0) return
name;
return
findFileCommon(
posix,
name,
path, true);
}
public static
String findFileCommon(
POSIX posix,
String name,
String path, boolean
executableOnly) {
// No point looking for nothing...
if (
name == null ||
name.
length() == 0) return
name;
int
length =
name.
length();
boolean
isAbsolute = false;
boolean
isPath = false;
int
i = 0;
if (
Platform.
IS_WINDOWS) {
if (
length > 1 &&
Character.
isLetter(
name.
charAt(0)) &&
name.
charAt(1) == ':') {
i = 2;
isAbsolute = true;
}
int
extensionIndex = -1;
char
c =
name.
charAt(
i);
if (
i == '/' ||
i == '\\') {
i++;
c =
name.
charAt(
i);
isAbsolute = true;
}
// Is this a partial path and does it contain an explicit
// file extension?
for (;
i <
length;
i++) {
switch (
c) {
case '/':
case '\\':
isPath = true;
extensionIndex = -1;
break;
case '.':
extensionIndex =
i - 1;
break;
}
c =
name.
charAt(
i);
}
if (
extensionIndex >= 0 && !
EXECUTABLE_EXTENSIONS.
contains(
name.
substring(
extensionIndex).
toLowerCase())) {
extensionIndex = -1;
}
if (!
executableOnly) {
if (
isAbsolute) return
name;
} else if (
isPath) {
if (
extensionIndex >= 0) return
name;
if (
executableOnly) {
return
addExtension(
name);
} else if (new
File(
name).
exists()) {
return
name;
}
return null;
}
String[]
paths =
path.
split(
File.
pathSeparator);
for (int
p = 0;
p <
paths.length;
p++) {
String currentPath =
paths[
p];
int
currentPathLength =
currentPath.
length();
if (
currentPath == null ||
currentPathLength == 0) continue;
if (
currentPath.
charAt(0) == '~' &&
(
currentPathLength == 1 ||
(
currentPathLength > 1 && (
currentPath.
charAt(1) == '/' ||
currentPath.
charAt(1) == '\\')))) {
String home =
System.
getenv("HOME");
if (
home != null) {
currentPath =
home + (
currentPathLength == 1 ? "" :
currentPath.
substring(1));
}
}
if (!
currentPath.
endsWith("/") && !
currentPath.
endsWith("\\")) {
currentPath += "\\";
}
String filename =
currentPath +
name;
if (
Platform.
IS_WINDOWS)
filename =
filename.
replace('/', '\\');
if (
Platform.
IS_WINDOWS &&
executableOnly &&
extensionIndex == -1) {
String extendedFilename =
addExtension(
filename);
if (
extendedFilename != null) return
extendedFilename;
continue;
}
try {
FileStat stat =
posix.
stat(
filename);
if (!
executableOnly || (!
stat.
isDirectory() &&
stat.
isExecutable())) return
filename;
} catch (
Throwable t) {}
}
}
return null;
}
public static
String addExtension(
String path) {
for (
String extension :
EXECUTABLE_EXTENSIONS) {
String newPath =
path +
extension;
if (new
File(
newPath).
exists()) return
newPath;
}
return null;
}
}