Remove unused code
This commit is contained in:
@@ -1,23 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012 Adam Murdoch
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.rubygrapefruit.platform.internal;
|
|
||||||
|
|
||||||
import net.rubygrapefruit.platform.Terminal;
|
|
||||||
|
|
||||||
public abstract class AbstractTerminal implements Terminal {
|
|
||||||
protected abstract void init();
|
|
||||||
}
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012 Adam Murdoch
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.rubygrapefruit.platform.internal;
|
|
||||||
|
|
||||||
import net.rubygrapefruit.platform.Terminal;
|
|
||||||
import net.rubygrapefruit.platform.Terminals;
|
|
||||||
|
|
||||||
public abstract class AbstractTerminals implements Terminals {
|
|
||||||
private final Object lock = new Object();
|
|
||||||
private Output currentlyOpen;
|
|
||||||
private AbstractTerminal current;
|
|
||||||
|
|
||||||
public Terminal getTerminal(Output output) {
|
|
||||||
synchronized (lock) {
|
|
||||||
if (currentlyOpen != null && currentlyOpen != output) {
|
|
||||||
throw new UnsupportedOperationException("Currently only one output can be used as a terminal.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (current == null) {
|
|
||||||
final AbstractTerminal terminal = createTerminal(output);
|
|
||||||
terminal.init();
|
|
||||||
Runtime.getRuntime().addShutdownHook(new Thread(){
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
terminal.reset();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
currentlyOpen = output;
|
|
||||||
current = terminal;
|
|
||||||
}
|
|
||||||
|
|
||||||
return current;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract AbstractTerminal createTerminal(Output output);
|
|
||||||
}
|
|
||||||
@@ -1,178 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012 Adam Murdoch
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.rubygrapefruit.platform.internal;
|
|
||||||
|
|
||||||
import net.rubygrapefruit.platform.NativeException;
|
|
||||||
import net.rubygrapefruit.platform.Terminal;
|
|
||||||
import net.rubygrapefruit.platform.TerminalSize;
|
|
||||||
import net.rubygrapefruit.platform.Terminals;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
|
|
||||||
public class AnsiTerminal extends AbstractTerminal {
|
|
||||||
private static final byte[] BOLD = "\u001b[1m".getBytes();
|
|
||||||
private static final byte[] RESET = "\u001b[0m".getBytes();
|
|
||||||
private static final byte[] START_OF_LINE = "\u001b[0E".getBytes();
|
|
||||||
private static final byte[] CLEAR_TO_END_OF_LINE = "\u001b[0K".getBytes();
|
|
||||||
private final Terminals.Output output;
|
|
||||||
private final OutputStream outputStream;
|
|
||||||
private Color foreground;
|
|
||||||
|
|
||||||
public AnsiTerminal(OutputStream outputStream, Terminals.Output output) {
|
|
||||||
this.outputStream = outputStream;
|
|
||||||
this.output = output;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return String.format("ANSI terminal on %s", getOutputDisplay());
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getOutputDisplay() {
|
|
||||||
return output.toString().toLowerCase();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void init() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean supportsTextAttributes() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean supportsColor() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean supportsCursorMotion() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TerminalSize getTerminalSize() throws NativeException {
|
|
||||||
return new MutableTerminalSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Terminal foreground(Color color) throws NativeException {
|
|
||||||
try {
|
|
||||||
String esc = String.format("\u001b[%sm", 30 + color.ordinal());
|
|
||||||
outputStream.write(esc.getBytes());
|
|
||||||
outputStream.flush();
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new NativeException(String.format("Could not set foreground color on %s.", getOutputDisplay()), e);
|
|
||||||
}
|
|
||||||
foreground = color;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Terminal bold() throws NativeException {
|
|
||||||
try {
|
|
||||||
outputStream.write(BOLD);
|
|
||||||
outputStream.flush();
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new NativeException(String.format("Could not switch to bold output on %s.", getOutputDisplay()), e);
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Terminal normal() throws NativeException {
|
|
||||||
try {
|
|
||||||
outputStream.write(RESET);
|
|
||||||
outputStream.flush();
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new NativeException(String.format("Could not switch to normal output on %s.", getOutputDisplay()), e);
|
|
||||||
}
|
|
||||||
if (foreground != null) {
|
|
||||||
foreground(foreground);
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Terminal reset() throws NativeException {
|
|
||||||
try {
|
|
||||||
outputStream.write(RESET);
|
|
||||||
outputStream.flush();
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new NativeException(String.format("Could not reset output on %s.", getOutputDisplay()), e);
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Terminal cursorLeft(int count) throws NativeException {
|
|
||||||
try {
|
|
||||||
String esc = String.format("\u001b[%sD", count);
|
|
||||||
outputStream.write(esc.getBytes());
|
|
||||||
outputStream.flush();
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new NativeException(String.format("Could not move cursor on %s.", getOutputDisplay()), e);
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Terminal cursorRight(int count) throws NativeException {
|
|
||||||
try {
|
|
||||||
String esc = String.format("\u001b[%sC", count);
|
|
||||||
outputStream.write(esc.getBytes());
|
|
||||||
outputStream.flush();
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new NativeException(String.format("Could not move cursor on %s.", getOutputDisplay()), e);
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Terminal cursorUp(int count) throws NativeException {
|
|
||||||
try {
|
|
||||||
String esc = String.format("\u001b[%sA", count);
|
|
||||||
outputStream.write(esc.getBytes());
|
|
||||||
outputStream.flush();
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new NativeException(String.format("Could not move cursor on %s.", getOutputDisplay()), e);
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Terminal cursorDown(int count) throws NativeException {
|
|
||||||
try {
|
|
||||||
String esc = String.format("\u001b[%sB", count);
|
|
||||||
outputStream.write(esc.getBytes());
|
|
||||||
outputStream.flush();
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new NativeException(String.format("Could not move cursor on %s.", getOutputDisplay()), e);
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Terminal cursorStartOfLine() throws NativeException {
|
|
||||||
try {
|
|
||||||
outputStream.write(START_OF_LINE);
|
|
||||||
outputStream.flush();
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new NativeException(String.format("Could not move cursor on %s.", getOutputDisplay()), e);
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Terminal clearToEndOfLine() throws NativeException {
|
|
||||||
try {
|
|
||||||
outputStream.write(CLEAR_TO_END_OF_LINE);
|
|
||||||
outputStream.flush();
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new NativeException(String.format("Could not clear to end of line on %s.", getOutputDisplay()), e);
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012 Adam Murdoch
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.rubygrapefruit.platform.internal;
|
|
||||||
|
|
||||||
import net.rubygrapefruit.platform.FileSystem;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
|
|
||||||
public class DefaultFileSystem implements FileSystem {
|
|
||||||
private final File mountPoint;
|
|
||||||
private final String fileSystemType;
|
|
||||||
private final String deviceName;
|
|
||||||
private final boolean remote;
|
|
||||||
private final boolean caseSensitive;
|
|
||||||
private final boolean casePreserving;
|
|
||||||
|
|
||||||
public DefaultFileSystem(File mountPoint, String fileSystemType, String deviceName, boolean remote, boolean caseSensitive, boolean casePreserving) {
|
|
||||||
this.mountPoint = mountPoint;
|
|
||||||
this.fileSystemType = fileSystemType;
|
|
||||||
this.deviceName = deviceName;
|
|
||||||
this.remote = remote;
|
|
||||||
this.caseSensitive = caseSensitive;
|
|
||||||
this.casePreserving = casePreserving;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDeviceName() {
|
|
||||||
return deviceName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public File getMountPoint() {
|
|
||||||
return mountPoint;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getFileSystemType() {
|
|
||||||
return fileSystemType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isRemote() {
|
|
||||||
return remote;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isCaseSensitive() {
|
|
||||||
return caseSensitive;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isCasePreserving() {
|
|
||||||
return casePreserving;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012 Adam Murdoch
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.rubygrapefruit.platform.internal;
|
|
||||||
|
|
||||||
import net.rubygrapefruit.platform.NativeException;
|
|
||||||
import net.rubygrapefruit.platform.PosixFile;
|
|
||||||
import net.rubygrapefruit.platform.PosixFiles;
|
|
||||||
import net.rubygrapefruit.platform.internal.jni.PosixFileFunctions;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
|
|
||||||
public class DefaultPosixFiles implements PosixFiles {
|
|
||||||
public PosixFile stat(File file) throws NativeException {
|
|
||||||
FunctionResult result = new FunctionResult();
|
|
||||||
FileStat stat = new FileStat();
|
|
||||||
PosixFileFunctions.stat(file.getPath(), stat, result);
|
|
||||||
if (result.isFailed()) {
|
|
||||||
throw new NativeException(String.format("Could not get posix file details of %s: %s", file, result.getMessage()));
|
|
||||||
}
|
|
||||||
return stat;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMode(File file, int perms) {
|
|
||||||
FunctionResult result = new FunctionResult();
|
|
||||||
PosixFileFunctions.chmod(file.getPath(), perms, result);
|
|
||||||
if (result.isFailed()) {
|
|
||||||
throw new NativeException(String.format("Could not set UNIX mode on %s: %s", file, result.getMessage()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getMode(File file) {
|
|
||||||
PosixFile stat = stat(file);
|
|
||||||
if (stat.getType() == PosixFile.Type.Missing) {
|
|
||||||
throw new NativeException(String.format("Could not get UNIX mode on %s: file does not exist.", file));
|
|
||||||
}
|
|
||||||
return stat.getMode();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String readLink(File link) throws NativeException {
|
|
||||||
FunctionResult result = new FunctionResult();
|
|
||||||
String contents = PosixFileFunctions.readlink(link.getPath(), result);
|
|
||||||
if (result.isFailed()) {
|
|
||||||
throw new NativeException(String.format("Could not read symlink %s: %s", link, result.getMessage()));
|
|
||||||
}
|
|
||||||
return contents;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void symlink(File link, String contents) throws NativeException {
|
|
||||||
FunctionResult result = new FunctionResult();
|
|
||||||
PosixFileFunctions.symlink(link.getPath(), contents, result);
|
|
||||||
if (result.isFailed()) {
|
|
||||||
throw new NativeException(String.format("Could not create symlink %s: %s", link, result.getMessage()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012 Adam Murdoch
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.rubygrapefruit.platform.internal;
|
|
||||||
|
|
||||||
import net.rubygrapefruit.platform.NativeException;
|
|
||||||
import net.rubygrapefruit.platform.Process;
|
|
||||||
import net.rubygrapefruit.platform.internal.jni.PosixProcessFunctions;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
|
|
||||||
public class DefaultProcess implements Process {
|
|
||||||
public int getProcessId() throws NativeException {
|
|
||||||
return PosixProcessFunctions.getPid();
|
|
||||||
}
|
|
||||||
|
|
||||||
public File getWorkingDirectory() throws NativeException {
|
|
||||||
FunctionResult result = new FunctionResult();
|
|
||||||
String dir = PosixProcessFunctions.getWorkingDirectory(result);
|
|
||||||
if (result.isFailed()) {
|
|
||||||
throw new NativeException(String.format("Could not get process working directory: %s",
|
|
||||||
result.getMessage()));
|
|
||||||
}
|
|
||||||
return new File(dir);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setWorkingDirectory(File directory) throws NativeException {
|
|
||||||
FunctionResult result = new FunctionResult();
|
|
||||||
PosixProcessFunctions.setWorkingDirectory(directory.getAbsolutePath(), result);
|
|
||||||
if (result.isFailed()) {
|
|
||||||
throw new NativeException(String.format("Could not set process working directory to '%s': %s",
|
|
||||||
directory.getAbsoluteFile(), result.getMessage()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getEnvironmentVariable(String name) throws NativeException {
|
|
||||||
FunctionResult result = new FunctionResult();
|
|
||||||
String value = PosixProcessFunctions.getEnvironmentVariable(name, result);
|
|
||||||
if (result.isFailed()) {
|
|
||||||
throw new NativeException(String.format("Could not get the value of environment variable '%s': %s", name,
|
|
||||||
result.getMessage()));
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setEnvironmentVariable(String name, String value) throws NativeException {
|
|
||||||
FunctionResult result = new FunctionResult();
|
|
||||||
PosixProcessFunctions.setEnvironmentVariable(name, value, result);
|
|
||||||
if (result.isFailed()) {
|
|
||||||
throw new NativeException(String.format("Could not set the value of environment variable '%s': %s", name,
|
|
||||||
result.getMessage()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012 Adam Murdoch
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.rubygrapefruit.platform.internal;
|
|
||||||
|
|
||||||
import net.rubygrapefruit.platform.NativeException;
|
|
||||||
import net.rubygrapefruit.platform.ProcessLauncher;
|
|
||||||
|
|
||||||
public class DefaultProcessLauncher implements ProcessLauncher {
|
|
||||||
public Process start(ProcessBuilder processBuilder) throws NativeException {
|
|
||||||
try {
|
|
||||||
return processBuilder.start();
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new NativeException(String.format("Could not start '%s'", processBuilder.command().get(0)), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012 Adam Murdoch
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.rubygrapefruit.platform.internal;
|
|
||||||
|
|
||||||
import net.rubygrapefruit.platform.NativeException;
|
|
||||||
import net.rubygrapefruit.platform.SystemInfo;
|
|
||||||
import net.rubygrapefruit.platform.internal.jni.NativeLibraryFunctions;
|
|
||||||
|
|
||||||
public class DefaultSystemInfo implements SystemInfo {
|
|
||||||
MutableSystemInfo systemInfo = new MutableSystemInfo();
|
|
||||||
|
|
||||||
public DefaultSystemInfo() {
|
|
||||||
FunctionResult result = new FunctionResult();
|
|
||||||
NativeLibraryFunctions.getSystemInfo(systemInfo, result);
|
|
||||||
if (result.isFailed()) {
|
|
||||||
throw new NativeException(String.format("Could not fetch system information: %s",
|
|
||||||
result.getMessage()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getKernelName() {
|
|
||||||
return systemInfo.getKernelName();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getKernelVersion() {
|
|
||||||
return systemInfo.getKernelVersion();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getArchitectureName() {
|
|
||||||
return systemInfo.getArchitectureName();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Architecture getArchitecture() {
|
|
||||||
return systemInfo.getArchitecture();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
package net.rubygrapefruit.platform.internal;
|
|
||||||
|
|
||||||
import net.rubygrapefruit.platform.MissingRegistryEntryException;
|
|
||||||
import net.rubygrapefruit.platform.NativeException;
|
|
||||||
import net.rubygrapefruit.platform.WindowsRegistry;
|
|
||||||
import net.rubygrapefruit.platform.internal.jni.WindowsRegistryFunctions;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class DefaultWindowsRegistry implements WindowsRegistry {
|
|
||||||
public String getStringValue(Key key, String subkey, String valueName) throws NativeException {
|
|
||||||
FunctionResult result = new FunctionResult();
|
|
||||||
String value = WindowsRegistryFunctions.getStringValue(key.ordinal(), subkey, valueName, result);
|
|
||||||
if (result.isFailed()) {
|
|
||||||
throw new NativeException(String.format("Could not get value '%s' of registry key '%s\\%s': %s", valueName,
|
|
||||||
key,
|
|
||||||
subkey, result.getMessage()));
|
|
||||||
}
|
|
||||||
if (value == null) {
|
|
||||||
throw new MissingRegistryEntryException(String.format(
|
|
||||||
"Could not get value '%s' of registry key '%s\\%s' as it does not exist.", valueName, key, subkey));
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> getSubkeys(Key key, String subkey) throws NativeException {
|
|
||||||
FunctionResult result = new FunctionResult();
|
|
||||||
ArrayList<String> subkeys = new ArrayList<String>();
|
|
||||||
boolean found = WindowsRegistryFunctions.getSubkeys(key.ordinal(), subkey, subkeys, result);
|
|
||||||
if (result.isFailed()) {
|
|
||||||
throw new NativeException(String.format("Could not list the subkeys of registry key '%s\\%s': %s", key,
|
|
||||||
subkey, result.getMessage()));
|
|
||||||
}
|
|
||||||
if (!found) {
|
|
||||||
throw new MissingRegistryEntryException(String.format(
|
|
||||||
"Could not list the subkeys of registry key '%s\\%s' as it does not exist.", key, subkey));
|
|
||||||
}
|
|
||||||
return subkeys;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> getValueNames(Key key, String subkey) throws NativeException {
|
|
||||||
FunctionResult result = new FunctionResult();
|
|
||||||
ArrayList<String> names = new ArrayList<String>();
|
|
||||||
boolean found = WindowsRegistryFunctions.getValueNames(key.ordinal(), subkey, names, result);
|
|
||||||
if (result.isFailed()) {
|
|
||||||
throw new NativeException(String.format("Could not list the values of registry key '%s\\%s': %s", key,
|
|
||||||
subkey, result.getMessage()));
|
|
||||||
}
|
|
||||||
if (!found) {
|
|
||||||
throw new MissingRegistryEntryException(String.format(
|
|
||||||
"Could not list the values of registry key '%s\\%s' as it does not exist.", key, subkey));
|
|
||||||
}
|
|
||||||
return names;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012 Adam Murdoch
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.rubygrapefruit.platform.internal;
|
|
||||||
|
|
||||||
import net.rubygrapefruit.platform.PosixFile;
|
|
||||||
|
|
||||||
public class FileStat implements PosixFile {
|
|
||||||
public int mode;
|
|
||||||
public int type;
|
|
||||||
|
|
||||||
public int getMode() {
|
|
||||||
return mode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Type getType() {
|
|
||||||
return Type.values()[type];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012 Adam Murdoch
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.rubygrapefruit.platform.internal;
|
|
||||||
|
|
||||||
import net.rubygrapefruit.platform.FileSystem;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class FileSystemList {
|
|
||||||
public final List<FileSystem> fileSystems = new ArrayList<FileSystem>();
|
|
||||||
|
|
||||||
public void add(String mountPoint, String fileSystemName, String deviceName, boolean remote, boolean caseSensitive, boolean casePreserving) {
|
|
||||||
fileSystems.add(new DefaultFileSystem(new File(mountPoint), fileSystemName, deviceName, remote, caseSensitive, casePreserving));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012 Adam Murdoch
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.rubygrapefruit.platform.internal;
|
|
||||||
|
|
||||||
public class FunctionResult {
|
|
||||||
String message;
|
|
||||||
int errno;
|
|
||||||
private String errorCodeDescription;
|
|
||||||
|
|
||||||
void failed(String message, int errno, String errorCodeDescription) {
|
|
||||||
this.message = message;
|
|
||||||
this.errno = errno;
|
|
||||||
this.errorCodeDescription = errorCodeDescription;
|
|
||||||
}
|
|
||||||
|
|
||||||
void failed(String message) {
|
|
||||||
this.message = message;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isFailed() {
|
|
||||||
return message != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getMessage() {
|
|
||||||
if (errorCodeDescription != null) {
|
|
||||||
return String.format("%s (%s errno %d)", message, errorCodeDescription, errno);
|
|
||||||
}
|
|
||||||
if (errno != 0) {
|
|
||||||
return String.format("%s (errno %d)", message, errno);
|
|
||||||
}
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,85 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012 Adam Murdoch
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.rubygrapefruit.platform.internal;
|
|
||||||
|
|
||||||
import net.rubygrapefruit.platform.NativeException;
|
|
||||||
import net.rubygrapefruit.platform.SystemInfo;
|
|
||||||
|
|
||||||
public class MutableSystemInfo implements SystemInfo {
|
|
||||||
// Fields set from native code
|
|
||||||
public String osName;
|
|
||||||
public String osVersion;
|
|
||||||
public String machineArchitecture;
|
|
||||||
|
|
||||||
public String getKernelName() {
|
|
||||||
return osName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getKernelVersion() {
|
|
||||||
return osVersion;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getArchitectureName() {
|
|
||||||
return machineArchitecture;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Architecture getArchitecture() {
|
|
||||||
if (machineArchitecture.equals("amd64") || machineArchitecture.equals("x86_64")) {
|
|
||||||
return Architecture.amd64;
|
|
||||||
}
|
|
||||||
if (machineArchitecture.equals("i386") || machineArchitecture.equals("x86") || machineArchitecture.equals("i686")) {
|
|
||||||
return Architecture.i386;
|
|
||||||
}
|
|
||||||
throw new NativeException(String.format("Cannot determine architecture from kernel architecture name '%s'.",
|
|
||||||
machineArchitecture));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Called from native code
|
|
||||||
void windows(int major, int minor, int build, boolean workstation, String arch) {
|
|
||||||
osName = toWindowsVersionName(major, minor, workstation);
|
|
||||||
osVersion = String.format("%s.%s (build %s)", major, minor, build);
|
|
||||||
machineArchitecture = arch;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String toWindowsVersionName(int major, int minor, boolean workstation) {
|
|
||||||
switch (major) {
|
|
||||||
case 5:
|
|
||||||
switch (minor) {
|
|
||||||
case 0:
|
|
||||||
return "Windows 2000";
|
|
||||||
case 1:
|
|
||||||
return "Windows XP";
|
|
||||||
case 2:
|
|
||||||
return workstation ? "Windows XP Professional" : "Windows Server 2003";
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 6:
|
|
||||||
switch (minor) {
|
|
||||||
case 0:
|
|
||||||
return workstation ? "Windows Vista" : "Windows Server 2008";
|
|
||||||
case 1:
|
|
||||||
return workstation ? "Windows 7" : "Windows Server 2008 R2";
|
|
||||||
case 2:
|
|
||||||
return workstation ? "Windows 8" : "Windows Server 2012";
|
|
||||||
case 3:
|
|
||||||
return workstation ? "Windows 8.1" : "Windows Server 2012 R2";
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return "Windows (unknown version)";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012 Adam Murdoch
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.rubygrapefruit.platform.internal;
|
|
||||||
|
|
||||||
import net.rubygrapefruit.platform.TerminalSize;
|
|
||||||
|
|
||||||
public class MutableTerminalSize implements TerminalSize {
|
|
||||||
int rows;
|
|
||||||
int cols;
|
|
||||||
|
|
||||||
public int getCols() {
|
|
||||||
return cols;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getRows() {
|
|
||||||
return rows;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -16,12 +16,15 @@
|
|||||||
|
|
||||||
package net.rubygrapefruit.platform.internal;
|
package net.rubygrapefruit.platform.internal;
|
||||||
|
|
||||||
import net.rubygrapefruit.platform.NativeException;
|
import java.io.File;
|
||||||
import net.rubygrapefruit.platform.internal.jni.NativeLibraryFunctions;
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
import java.io.*;
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.RandomAccessFile;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.nio.channels.FileLock;
|
|
||||||
|
import net.rubygrapefruit.platform.NativeException;
|
||||||
|
|
||||||
public class NativeLibraryLocator {
|
public class NativeLibraryLocator {
|
||||||
private final File extractDir;
|
private final File extractDir;
|
||||||
@@ -32,16 +35,13 @@ public class NativeLibraryLocator {
|
|||||||
|
|
||||||
public File find(LibraryDef libraryDef) throws IOException {
|
public File find(LibraryDef libraryDef) throws IOException {
|
||||||
String resourceName = String.format("%s/%s/%s", libraryDef.getGroupPath(), libraryDef.platform, libraryDef.name);
|
String resourceName = String.format("%s/%s/%s", libraryDef.getGroupPath(), libraryDef.platform, libraryDef.name);
|
||||||
System.out.println(resourceName);
|
|
||||||
if (extractDir != null) {
|
if (extractDir != null) {
|
||||||
File libFile = new File(extractDir, String.format("%s/%s/%s", NativeLibraryFunctions.VERSION, libraryDef.platform, libraryDef.name));
|
File libFile = new File(extractDir, String.format("%s/%s", libraryDef.platform, libraryDef.name));
|
||||||
File lockFile = new File(libFile.getParentFile(), libFile.getName() + ".lock");
|
File lockFile = new File(libFile.getParentFile(), libFile.getName() + ".lock");
|
||||||
lockFile.getParentFile().mkdirs();
|
lockFile.getParentFile().mkdirs();
|
||||||
lockFile.createNewFile();
|
lockFile.createNewFile();
|
||||||
RandomAccessFile lockFileAccess = new RandomAccessFile(lockFile, "rw");
|
RandomAccessFile lockFileAccess = new RandomAccessFile(lockFile, "rw");
|
||||||
try {
|
try {
|
||||||
// Take exclusive lock on lock file
|
|
||||||
FileLock lock = lockFileAccess.getChannel().lock();
|
|
||||||
if (lockFile.length() > 0 && lockFileAccess.readBoolean()) {
|
if (lockFile.length() > 0 && lockFileAccess.readBoolean()) {
|
||||||
// Library has been extracted
|
// Library has been extracted
|
||||||
return libFile;
|
return libFile;
|
||||||
@@ -111,4 +111,4 @@ public class NativeLibraryLocator {
|
|||||||
throw new NativeException(String.format("Could not extract native JNI library."), e);
|
throw new NativeException(String.format("Could not extract native JNI library."), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
package net.rubygrapefruit.platform.internal;
|
package net.rubygrapefruit.platform.internal;
|
||||||
|
|
||||||
import net.rubygrapefruit.platform.NativeIntegration;
|
|
||||||
import net.rubygrapefruit.platform.NativeLibraryUnavailableException;
|
import net.rubygrapefruit.platform.NativeLibraryUnavailableException;
|
||||||
|
|
||||||
public abstract class Platform {
|
public abstract class Platform {
|
||||||
@@ -74,12 +73,8 @@ public abstract class Platform {
|
|||||||
return String.format("%s %s", getOperatingSystem(), getArchitecture());
|
return String.format("%s %s", getOperatingSystem(), getArchitecture());
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T extends NativeIntegration> T get(Class<T> type, NativeLibraryLoader nativeLibraryLoader) {
|
|
||||||
throw new NativeLibraryUnavailableException(String.format("Native integration %s is not supported for %s.", type.getSimpleName(), toString()));
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getLibraryName(String name) {
|
public String getLibraryName(String name) {
|
||||||
throw new NativeLibraryUnavailableException(String.format("Native integration is not available for %s.", toString()));
|
throw new NativeLibraryUnavailableException(String.format("Native library is not available for %s.", toString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract String getId();
|
public abstract String getId();
|
||||||
@@ -102,11 +97,6 @@ public abstract class Platform {
|
|||||||
public String getLibraryName(String name) {
|
public String getLibraryName(String name) {
|
||||||
return String.format("%s.dll", name);
|
return String.format("%s.dll", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T extends NativeIntegration> T get(Class<T> type, NativeLibraryLoader nativeLibraryLoader) {
|
|
||||||
return super.get(type, nativeLibraryLoader);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class Window32Bit extends Windows {
|
private static class Window32Bit extends Windows {
|
||||||
@@ -123,12 +113,7 @@ public abstract class Platform {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static abstract class Posix extends Platform {
|
private static abstract class Posix extends Platform {}
|
||||||
@Override
|
|
||||||
public <T extends NativeIntegration> T get(Class<T> type, NativeLibraryLoader nativeLibraryLoader) {
|
|
||||||
return super.get(type, nativeLibraryLoader);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private abstract static class Unix extends Posix {
|
private abstract static class Unix extends Posix {
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -1,36 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012 Adam Murdoch
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.rubygrapefruit.platform.internal;
|
|
||||||
|
|
||||||
import net.rubygrapefruit.platform.FileSystem;
|
|
||||||
import net.rubygrapefruit.platform.FileSystems;
|
|
||||||
import net.rubygrapefruit.platform.NativeException;
|
|
||||||
import net.rubygrapefruit.platform.internal.jni.PosixFileSystemFunctions;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class PosixFileSystems implements FileSystems {
|
|
||||||
public List<FileSystem> getFileSystems() {
|
|
||||||
FunctionResult result = new FunctionResult();
|
|
||||||
FileSystemList fileSystems = new FileSystemList();
|
|
||||||
PosixFileSystemFunctions.listFileSystems(fileSystems, result);
|
|
||||||
if (result.isFailed()) {
|
|
||||||
throw new NativeException(String.format("Could not query file systems: %s", result.getMessage()));
|
|
||||||
}
|
|
||||||
return fileSystems.fileSystems;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012 Adam Murdoch
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.rubygrapefruit.platform.internal;
|
|
||||||
|
|
||||||
public class TerminalCapabilities {
|
|
||||||
String terminalName;
|
|
||||||
boolean textAttributes;
|
|
||||||
boolean colors;
|
|
||||||
boolean cursorMotion;
|
|
||||||
}
|
|
||||||
@@ -1,174 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012 Adam Murdoch
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.rubygrapefruit.platform.internal;
|
|
||||||
|
|
||||||
import net.rubygrapefruit.platform.NativeException;
|
|
||||||
import net.rubygrapefruit.platform.Terminal;
|
|
||||||
import net.rubygrapefruit.platform.TerminalSize;
|
|
||||||
import net.rubygrapefruit.platform.Terminals;
|
|
||||||
import net.rubygrapefruit.platform.internal.jni.PosixTerminalFunctions;
|
|
||||||
import net.rubygrapefruit.platform.internal.jni.TerminfoFunctions;
|
|
||||||
|
|
||||||
public class TerminfoTerminal extends AbstractTerminal {
|
|
||||||
private final Terminals.Output output;
|
|
||||||
private final TerminalCapabilities capabilities = new TerminalCapabilities();
|
|
||||||
private Color foreground;
|
|
||||||
|
|
||||||
public TerminfoTerminal(Terminals.Output output) {
|
|
||||||
this.output = output;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return String.format("Curses terminal on %s", getOutputDisplay());
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getOutputDisplay() {
|
|
||||||
return output.toString().toLowerCase();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void init() {
|
|
||||||
FunctionResult result = new FunctionResult();
|
|
||||||
TerminfoFunctions.initTerminal(output.ordinal(), capabilities, result);
|
|
||||||
if (result.isFailed()) {
|
|
||||||
throw new NativeException(String.format("Could not open terminal for %s: %s", getOutputDisplay(), result.getMessage()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public TerminalSize getTerminalSize() {
|
|
||||||
MutableTerminalSize terminalSize = new MutableTerminalSize();
|
|
||||||
FunctionResult result = new FunctionResult();
|
|
||||||
PosixTerminalFunctions.getTerminalSize(output.ordinal(), terminalSize, result);
|
|
||||||
if (result.isFailed()) {
|
|
||||||
throw new NativeException(String.format("Could not get terminal size for %s: %s", getOutputDisplay(), result.getMessage()));
|
|
||||||
}
|
|
||||||
return terminalSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean supportsColor() {
|
|
||||||
return capabilities.colors;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean supportsCursorMotion() {
|
|
||||||
return capabilities.cursorMotion;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean supportsTextAttributes() {
|
|
||||||
return capabilities.textAttributes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Terminal foreground(Color color) {
|
|
||||||
if (!capabilities.colors) {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
FunctionResult result = new FunctionResult();
|
|
||||||
TerminfoFunctions.foreground(color.ordinal(), result);
|
|
||||||
if (result.isFailed()) {
|
|
||||||
throw new NativeException(String.format("Could not switch foreground color for %s: %s", getOutputDisplay(),
|
|
||||||
result.getMessage()));
|
|
||||||
}
|
|
||||||
foreground = color;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Terminal bold() {
|
|
||||||
if (!capabilities.textAttributes) {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
FunctionResult result = new FunctionResult();
|
|
||||||
TerminfoFunctions.bold(result);
|
|
||||||
if (result.isFailed()) {
|
|
||||||
throw new NativeException(String.format("Could not switch to bold mode for %s: %s", getOutputDisplay(),
|
|
||||||
result.getMessage()));
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Terminal normal() {
|
|
||||||
reset();
|
|
||||||
if (foreground != null) {
|
|
||||||
foreground(foreground);
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Terminal reset() {
|
|
||||||
FunctionResult result = new FunctionResult();
|
|
||||||
TerminfoFunctions.reset(result);
|
|
||||||
if (result.isFailed()) {
|
|
||||||
throw new NativeException(String.format("Could not reset terminal for %s: %s", getOutputDisplay(), result.getMessage()));
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Terminal cursorDown(int count) {
|
|
||||||
FunctionResult result = new FunctionResult();
|
|
||||||
TerminfoFunctions.down(count, result);
|
|
||||||
if (result.isFailed()) {
|
|
||||||
throw new NativeException(String.format("Could not move cursor down for %s: %s", getOutputDisplay(), result.getMessage()));
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Terminal cursorUp(int count) {
|
|
||||||
FunctionResult result = new FunctionResult();
|
|
||||||
TerminfoFunctions.up(count, result);
|
|
||||||
if (result.isFailed()) {
|
|
||||||
throw new NativeException(String.format("Could not move cursor up for %s: %s", getOutputDisplay(), result.getMessage()));
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Terminal cursorLeft(int count) {
|
|
||||||
FunctionResult result = new FunctionResult();
|
|
||||||
TerminfoFunctions.left(count, result);
|
|
||||||
if (result.isFailed()) {
|
|
||||||
throw new NativeException(String.format("Could not move cursor left for %s: %s", getOutputDisplay(), result.getMessage()));
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Terminal cursorRight(int count) {
|
|
||||||
FunctionResult result = new FunctionResult();
|
|
||||||
TerminfoFunctions.right(count, result);
|
|
||||||
if (result.isFailed()) {
|
|
||||||
throw new NativeException(String.format("Could not move cursor right for %s: %s", getOutputDisplay(), result.getMessage()));
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Terminal cursorStartOfLine() throws NativeException {
|
|
||||||
FunctionResult result = new FunctionResult();
|
|
||||||
TerminfoFunctions.startLine(result);
|
|
||||||
if (result.isFailed()) {
|
|
||||||
throw new NativeException(String.format("Could not move cursor to start of line for %s: %s", getOutputDisplay(), result.getMessage()));
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Terminal clearToEndOfLine() throws NativeException {
|
|
||||||
FunctionResult result = new FunctionResult();
|
|
||||||
TerminfoFunctions.clearToEndOfLine(result);
|
|
||||||
if (result.isFailed()) {
|
|
||||||
throw new NativeException(String.format("Could not clear to end of line for %s: %s", getOutputDisplay(), result.getMessage()));
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012 Adam Murdoch
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.rubygrapefruit.platform.internal;
|
|
||||||
|
|
||||||
import net.rubygrapefruit.platform.Terminals;
|
|
||||||
import net.rubygrapefruit.platform.internal.jni.PosixTerminalFunctions;
|
|
||||||
|
|
||||||
import java.io.PrintStream;
|
|
||||||
|
|
||||||
public class TerminfoTerminals extends AbstractTerminals {
|
|
||||||
public boolean isTerminal(Output output) {
|
|
||||||
return PosixTerminalFunctions.isatty(output.ordinal());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected AbstractTerminal createTerminal(Output output) {
|
|
||||||
PrintStream stream = output == Terminals.Output.Stdout ? System.out : System.err;
|
|
||||||
return new WrapperTerminal(stream, new TerminfoTerminal(output));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
package net.rubygrapefruit.platform.internal;
|
|
||||||
|
|
||||||
import net.rubygrapefruit.platform.NativeException;
|
|
||||||
import net.rubygrapefruit.platform.ProcessLauncher;
|
|
||||||
import net.rubygrapefruit.platform.internal.jni.WindowsHandleFunctions;
|
|
||||||
|
|
||||||
public class WindowsProcessLauncher implements ProcessLauncher {
|
|
||||||
private final ProcessLauncher launcher;
|
|
||||||
|
|
||||||
public WindowsProcessLauncher(ProcessLauncher launcher) {
|
|
||||||
this.launcher = launcher;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Process start(ProcessBuilder processBuilder) throws NativeException {
|
|
||||||
FunctionResult result = new FunctionResult();
|
|
||||||
WindowsHandleFunctions.markStandardHandlesUninheritable(result);
|
|
||||||
if (result.isFailed()) {
|
|
||||||
throw new NativeException(String.format("Could not start '%s': %s", processBuilder.command().get(0),
|
|
||||||
result.getMessage()));
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return launcher.start(processBuilder);
|
|
||||||
} finally {
|
|
||||||
WindowsHandleFunctions.restoreStandardHandles(result);
|
|
||||||
if (result.isFailed()) {
|
|
||||||
throw new NativeException(String.format("Could not restore process handles: %s", result.getMessage()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,161 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012 Adam Murdoch
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.rubygrapefruit.platform.internal;
|
|
||||||
|
|
||||||
import net.rubygrapefruit.platform.NativeException;
|
|
||||||
import net.rubygrapefruit.platform.Terminal;
|
|
||||||
import net.rubygrapefruit.platform.Terminals;
|
|
||||||
import net.rubygrapefruit.platform.TerminalSize;
|
|
||||||
import net.rubygrapefruit.platform.internal.jni.WindowsConsoleFunctions;
|
|
||||||
|
|
||||||
public class WindowsTerminal extends AbstractTerminal {
|
|
||||||
private final Terminals.Output output;
|
|
||||||
|
|
||||||
public WindowsTerminal(Terminals.Output output) {
|
|
||||||
this.output = output;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return String.format("Windows console on %s", getOutputDisplay());
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getOutputDisplay() {
|
|
||||||
return output.toString().toLowerCase();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void init() {
|
|
||||||
FunctionResult result = new FunctionResult();
|
|
||||||
WindowsConsoleFunctions.initConsole(output.ordinal(), result);
|
|
||||||
if (result.isFailed()) {
|
|
||||||
throw new NativeException(String.format("Could not open console for %s: %s", getOutputDisplay(), result.getMessage()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean supportsColor() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean supportsTextAttributes() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean supportsCursorMotion() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TerminalSize getTerminalSize() {
|
|
||||||
FunctionResult result = new FunctionResult();
|
|
||||||
MutableTerminalSize size = new MutableTerminalSize();
|
|
||||||
WindowsConsoleFunctions.getConsoleSize(output.ordinal(), size, result);
|
|
||||||
if (result.isFailed()) {
|
|
||||||
throw new NativeException(String.format("Could not determine console size for %s: %s", getOutputDisplay(), result.getMessage()));
|
|
||||||
}
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Terminal bold() {
|
|
||||||
FunctionResult result = new FunctionResult();
|
|
||||||
WindowsConsoleFunctions.bold(result);
|
|
||||||
if (result.isFailed()) {
|
|
||||||
throw new NativeException(String.format("Could not switch console to bold mode for %s: %s", getOutputDisplay(), result.getMessage()));
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Terminal foreground(Color color) {
|
|
||||||
FunctionResult result = new FunctionResult();
|
|
||||||
WindowsConsoleFunctions.foreground(color.ordinal(), result);
|
|
||||||
if (result.isFailed()) {
|
|
||||||
throw new NativeException(String.format("Could not change console foreground color for %s: %s", getOutputDisplay(), result.getMessage()));
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Terminal normal() {
|
|
||||||
FunctionResult result = new FunctionResult();
|
|
||||||
WindowsConsoleFunctions.normal(result);
|
|
||||||
if (result.isFailed()) {
|
|
||||||
throw new NativeException(String.format("Could not switch console to normal mode for %s: %s", getOutputDisplay(), result.getMessage()));
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Terminal reset() {
|
|
||||||
FunctionResult result = new FunctionResult();
|
|
||||||
WindowsConsoleFunctions.reset(result);
|
|
||||||
if (result.isFailed()) {
|
|
||||||
throw new NativeException(String.format("Could not reset console for %s: %s", getOutputDisplay(), result.getMessage()));
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Terminal cursorDown(int count) throws NativeException {
|
|
||||||
FunctionResult result = new FunctionResult();
|
|
||||||
WindowsConsoleFunctions.down(count, result);
|
|
||||||
if (result.isFailed()) {
|
|
||||||
throw new NativeException(String.format("Could not move cursor down for %s: %s", getOutputDisplay(), result.getMessage()));
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Terminal cursorUp(int count) throws NativeException {
|
|
||||||
FunctionResult result = new FunctionResult();
|
|
||||||
WindowsConsoleFunctions.up(count, result);
|
|
||||||
if (result.isFailed()) {
|
|
||||||
throw new NativeException(String.format("Could not move cursor up for %s: %s", getOutputDisplay(), result.getMessage()));
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Terminal cursorLeft(int count) throws NativeException {
|
|
||||||
FunctionResult result = new FunctionResult();
|
|
||||||
WindowsConsoleFunctions.left(count, result);
|
|
||||||
if (result.isFailed()) {
|
|
||||||
throw new NativeException(String.format("Could not move cursor left for %s: %s", getOutputDisplay(), result.getMessage()));
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Terminal cursorRight(int count) throws NativeException {
|
|
||||||
FunctionResult result = new FunctionResult();
|
|
||||||
WindowsConsoleFunctions.right(count, result);
|
|
||||||
if (result.isFailed()) {
|
|
||||||
throw new NativeException(String.format("Could not move cursor right for %s: %s", getOutputDisplay(), result.getMessage()));
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Terminal cursorStartOfLine() throws NativeException {
|
|
||||||
FunctionResult result = new FunctionResult();
|
|
||||||
WindowsConsoleFunctions.startLine(result);
|
|
||||||
if (result.isFailed()) {
|
|
||||||
throw new NativeException(String.format("Could not move cursor to start of line for %s: %s", getOutputDisplay(), result.getMessage()));
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Terminal clearToEndOfLine() throws NativeException {
|
|
||||||
FunctionResult result = new FunctionResult();
|
|
||||||
WindowsConsoleFunctions.clearToEndOfLine(result);
|
|
||||||
if (result.isFailed()) {
|
|
||||||
throw new NativeException(String.format("Could clear to end of line for %s: %s", getOutputDisplay(), result.getMessage()));
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012 Adam Murdoch
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.rubygrapefruit.platform.internal;
|
|
||||||
|
|
||||||
import net.rubygrapefruit.platform.NativeException;
|
|
||||||
import net.rubygrapefruit.platform.Terminals;
|
|
||||||
import net.rubygrapefruit.platform.internal.jni.WindowsConsoleFunctions;
|
|
||||||
|
|
||||||
import java.io.PrintStream;
|
|
||||||
|
|
||||||
public class WindowsTerminals extends AbstractTerminals {
|
|
||||||
public boolean isTerminal(Output output) {
|
|
||||||
FunctionResult result = new FunctionResult();
|
|
||||||
boolean console = WindowsConsoleFunctions.isConsole(output.ordinal(), result);
|
|
||||||
if (result.isFailed()) {
|
|
||||||
throw new NativeException(String.format("Could not determine if %s is a console: %s", output,
|
|
||||||
result.getMessage()));
|
|
||||||
}
|
|
||||||
return console;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected AbstractTerminal createTerminal(Output output) {
|
|
||||||
PrintStream stream = output == Terminals.Output.Stdout ? System.out : System.err;
|
|
||||||
return new WrapperTerminal(stream, new WindowsTerminal(output));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,128 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012 Adam Murdoch
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.rubygrapefruit.platform.internal;
|
|
||||||
|
|
||||||
import net.rubygrapefruit.platform.NativeException;
|
|
||||||
import net.rubygrapefruit.platform.Process;
|
|
||||||
import net.rubygrapefruit.platform.ThreadSafe;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A {@link Process} implementation that wraps another to add thread-safety and to update the JVM's internal view of
|
|
||||||
* various process properties.
|
|
||||||
*/
|
|
||||||
@ThreadSafe
|
|
||||||
public class WrapperProcess implements Process {
|
|
||||||
private final Process process;
|
|
||||||
private final boolean windows;
|
|
||||||
private final Object workingDirectoryLock = new Object();
|
|
||||||
private final Object environmentLock = new Object();
|
|
||||||
private Map<String, String> environment;
|
|
||||||
private Map<String, String> windowsEnvironment;
|
|
||||||
|
|
||||||
public WrapperProcess(Process process, boolean windows) {
|
|
||||||
this.process = process;
|
|
||||||
this.windows = windows;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return process.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getProcessId() throws NativeException {
|
|
||||||
return process.getProcessId();
|
|
||||||
}
|
|
||||||
|
|
||||||
public File getWorkingDirectory() throws NativeException {
|
|
||||||
synchronized (workingDirectoryLock) {
|
|
||||||
return process.getWorkingDirectory();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setWorkingDirectory(File directory) throws NativeException {
|
|
||||||
synchronized (workingDirectoryLock) {
|
|
||||||
process.setWorkingDirectory(directory);
|
|
||||||
System.setProperty("user.dir", directory.getAbsolutePath());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getEnvironmentVariable(String name) throws NativeException {
|
|
||||||
synchronized (environmentLock) {
|
|
||||||
String value = process.getEnvironmentVariable(name);
|
|
||||||
return value == null || value.length() == 0 ? null : value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setEnvironmentVariable(String name, String value) throws NativeException {
|
|
||||||
synchronized (environmentLock) {
|
|
||||||
if (value == null || value.length() == 0) {
|
|
||||||
process.setEnvironmentVariable(name, null);
|
|
||||||
removeEnvInternal(name);
|
|
||||||
} else {
|
|
||||||
process.setEnvironmentVariable(name, value);
|
|
||||||
setEnvInternal(name, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void removeEnvInternal(String name) {
|
|
||||||
getEnv().remove(name);
|
|
||||||
if (windows) {
|
|
||||||
getWindowsEnv().remove(name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setEnvInternal(String name, String value) {
|
|
||||||
getEnv().put(name, value);
|
|
||||||
if (windows) {
|
|
||||||
getWindowsEnv().put(name, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map<String, String> getEnv() {
|
|
||||||
if (environment == null) {
|
|
||||||
try {
|
|
||||||
Map<String, String> theUnmodifiableEnvironment = System.getenv();
|
|
||||||
Class<?> cu = theUnmodifiableEnvironment.getClass();
|
|
||||||
Field m = cu.getDeclaredField("m");
|
|
||||||
m.setAccessible(true);
|
|
||||||
environment = (Map<String, String>) m.get(theUnmodifiableEnvironment);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new NativeException("Unable to get mutable environment variable map.", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return environment;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map<String, String> getWindowsEnv() {
|
|
||||||
if (windowsEnvironment == null) {
|
|
||||||
try {
|
|
||||||
Class<?> sc = Class.forName("java.lang.ProcessEnvironment");
|
|
||||||
Field caseinsensitive = sc.getDeclaredField("theCaseInsensitiveEnvironment");
|
|
||||||
caseinsensitive.setAccessible(true);
|
|
||||||
windowsEnvironment = (Map<String, String>) caseinsensitive.get(null);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new NativeException("Unable to get mutable Windows environment variable map", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return windowsEnvironment;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012 Adam Murdoch
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.rubygrapefruit.platform.internal;
|
|
||||||
|
|
||||||
import net.rubygrapefruit.platform.NativeException;
|
|
||||||
import net.rubygrapefruit.platform.ProcessLauncher;
|
|
||||||
import net.rubygrapefruit.platform.ThreadSafe;
|
|
||||||
|
|
||||||
@ThreadSafe
|
|
||||||
public class WrapperProcessLauncher implements ProcessLauncher {
|
|
||||||
private final Object startLock = new Object();
|
|
||||||
private final ProcessLauncher launcher;
|
|
||||||
|
|
||||||
public WrapperProcessLauncher(ProcessLauncher launcher) {
|
|
||||||
this.launcher = launcher;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Process start(ProcessBuilder processBuilder) throws NativeException {
|
|
||||||
synchronized (startLock) {
|
|
||||||
// Start a single process at a time, to avoid streams to child process being inherited by other
|
|
||||||
// children before the parent can close them
|
|
||||||
return launcher.start(processBuilder);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,144 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012 Adam Murdoch
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.rubygrapefruit.platform.internal;
|
|
||||||
|
|
||||||
import net.rubygrapefruit.platform.NativeException;
|
|
||||||
import net.rubygrapefruit.platform.Terminal;
|
|
||||||
import net.rubygrapefruit.platform.TerminalSize;
|
|
||||||
|
|
||||||
import java.io.PrintStream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A {@link Terminal} implementation that wraps another to add thread safety.
|
|
||||||
*/
|
|
||||||
public class WrapperTerminal extends AbstractTerminal {
|
|
||||||
private final AbstractTerminal terminal;
|
|
||||||
private final PrintStream stream;
|
|
||||||
private final Object lock = new Object();
|
|
||||||
|
|
||||||
public WrapperTerminal(PrintStream stream, AbstractTerminal terminal) {
|
|
||||||
this.stream = stream;
|
|
||||||
this.terminal = terminal;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void init() {
|
|
||||||
stream.flush();
|
|
||||||
terminal.init();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return terminal.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public TerminalSize getTerminalSize() throws NativeException {
|
|
||||||
return terminal.getTerminalSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean supportsColor() {
|
|
||||||
return terminal.supportsColor();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean supportsCursorMotion() {
|
|
||||||
return terminal.supportsCursorMotion();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean supportsTextAttributes() {
|
|
||||||
return terminal.supportsTextAttributes();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Terminal normal() throws NativeException {
|
|
||||||
stream.flush();
|
|
||||||
synchronized (lock) {
|
|
||||||
terminal.normal();
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Terminal bold() throws NativeException {
|
|
||||||
stream.flush();
|
|
||||||
synchronized (lock) {
|
|
||||||
terminal.bold();
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Terminal reset() throws NativeException {
|
|
||||||
stream.flush();
|
|
||||||
synchronized (lock) {
|
|
||||||
terminal.reset();
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Terminal foreground(Color color) throws NativeException {
|
|
||||||
stream.flush();
|
|
||||||
synchronized (lock) {
|
|
||||||
terminal.foreground(color);
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Terminal cursorLeft(int count) throws NativeException {
|
|
||||||
stream.flush();
|
|
||||||
synchronized (lock) {
|
|
||||||
terminal.cursorLeft(count);
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Terminal cursorRight(int count) throws NativeException {
|
|
||||||
stream.flush();
|
|
||||||
synchronized (lock) {
|
|
||||||
terminal.cursorRight(count);
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Terminal cursorUp(int count) throws NativeException {
|
|
||||||
stream.flush();
|
|
||||||
synchronized (lock) {
|
|
||||||
terminal.cursorUp(count);
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Terminal cursorDown(int count) throws NativeException {
|
|
||||||
stream.flush();
|
|
||||||
synchronized (lock) {
|
|
||||||
terminal.cursorDown(count);
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Terminal cursorStartOfLine() throws NativeException {
|
|
||||||
stream.flush();
|
|
||||||
synchronized (lock) {
|
|
||||||
terminal.cursorStartOfLine();
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Terminal clearToEndOfLine() throws NativeException {
|
|
||||||
stream.flush();
|
|
||||||
synchronized (lock) {
|
|
||||||
terminal.clearToEndOfLine();
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012 Adam Murdoch
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.rubygrapefruit.platform.internal.jni;
|
|
||||||
|
|
||||||
import net.rubygrapefruit.platform.internal.FunctionResult;
|
|
||||||
import net.rubygrapefruit.platform.internal.MutableSystemInfo;
|
|
||||||
|
|
||||||
public class NativeLibraryFunctions {
|
|
||||||
public static final int VERSION = 20;
|
|
||||||
|
|
||||||
public static native int getVersion();
|
|
||||||
|
|
||||||
public static native void getSystemInfo(MutableSystemInfo systemInfo, FunctionResult result);
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012 Adam Murdoch
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.rubygrapefruit.platform.internal.jni;
|
|
||||||
|
|
||||||
import net.rubygrapefruit.platform.internal.FileStat;
|
|
||||||
import net.rubygrapefruit.platform.internal.FunctionResult;
|
|
||||||
|
|
||||||
public class PosixFileFunctions {
|
|
||||||
public static native void chmod(String file, int perms, FunctionResult result);
|
|
||||||
|
|
||||||
public static native void stat(String file, FileStat stat, FunctionResult result);
|
|
||||||
|
|
||||||
public static native void symlink(String file, String content, FunctionResult result);
|
|
||||||
|
|
||||||
public static native String readlink(String file, FunctionResult result);
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012 Adam Murdoch
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.rubygrapefruit.platform.internal.jni;
|
|
||||||
|
|
||||||
import net.rubygrapefruit.platform.internal.FileSystemList;
|
|
||||||
import net.rubygrapefruit.platform.internal.FunctionResult;
|
|
||||||
|
|
||||||
public class PosixFileSystemFunctions {
|
|
||||||
public static native void listFileSystems(FileSystemList fileSystems, FunctionResult result);
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012 Adam Murdoch
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.rubygrapefruit.platform.internal.jni;
|
|
||||||
|
|
||||||
import net.rubygrapefruit.platform.internal.FunctionResult;
|
|
||||||
|
|
||||||
public class PosixProcessFunctions {
|
|
||||||
public static native int getPid();
|
|
||||||
|
|
||||||
public static native String getWorkingDirectory(FunctionResult result);
|
|
||||||
|
|
||||||
public static native void setWorkingDirectory(String dir, FunctionResult result);
|
|
||||||
|
|
||||||
public static native String getEnvironmentVariable(String var, FunctionResult result);
|
|
||||||
|
|
||||||
public static native void setEnvironmentVariable(String var, String value, FunctionResult result);
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012 Adam Murdoch
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.rubygrapefruit.platform.internal.jni;
|
|
||||||
|
|
||||||
import net.rubygrapefruit.platform.internal.FunctionResult;
|
|
||||||
import net.rubygrapefruit.platform.internal.MutableTerminalSize;
|
|
||||||
|
|
||||||
public class PosixTerminalFunctions {
|
|
||||||
public static native boolean isatty(int filedes);
|
|
||||||
|
|
||||||
public static native void getTerminalSize(int filedes, MutableTerminalSize size, FunctionResult result);
|
|
||||||
}
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012 Adam Murdoch
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.rubygrapefruit.platform.internal.jni;
|
|
||||||
|
|
||||||
import net.rubygrapefruit.platform.internal.FunctionResult;
|
|
||||||
import net.rubygrapefruit.platform.internal.TerminalCapabilities;
|
|
||||||
|
|
||||||
public class TerminfoFunctions {
|
|
||||||
public static native int getVersion();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets up terminal info and switches output to normal mode.
|
|
||||||
*/
|
|
||||||
public static native void initTerminal(int filedes, TerminalCapabilities terminalCapabilities, FunctionResult result);
|
|
||||||
|
|
||||||
public static native void bold(FunctionResult result);
|
|
||||||
|
|
||||||
public static native void reset(FunctionResult result);
|
|
||||||
|
|
||||||
public static native void foreground(int ansiColor, FunctionResult result);
|
|
||||||
|
|
||||||
public static native void left(int count, FunctionResult result);
|
|
||||||
|
|
||||||
public static native void right(int count, FunctionResult result);
|
|
||||||
|
|
||||||
public static native void up(int count, FunctionResult result);
|
|
||||||
|
|
||||||
public static native void down(int count, FunctionResult result);
|
|
||||||
|
|
||||||
public static native void startLine(FunctionResult result);
|
|
||||||
|
|
||||||
public static native void clearToEndOfLine(FunctionResult result);
|
|
||||||
}
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012 Adam Murdoch
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.rubygrapefruit.platform.internal.jni;
|
|
||||||
|
|
||||||
import net.rubygrapefruit.platform.internal.FunctionResult;
|
|
||||||
import net.rubygrapefruit.platform.internal.MutableTerminalSize;
|
|
||||||
|
|
||||||
public class WindowsConsoleFunctions {
|
|
||||||
public static native boolean isConsole(int filedes, FunctionResult result);
|
|
||||||
|
|
||||||
public static native void getConsoleSize(int filedes, MutableTerminalSize size, FunctionResult result);
|
|
||||||
|
|
||||||
public static native void initConsole(int filedes, FunctionResult result);
|
|
||||||
|
|
||||||
public static native void bold(FunctionResult result);
|
|
||||||
|
|
||||||
public static native void normal(FunctionResult result);
|
|
||||||
|
|
||||||
public static native void reset(FunctionResult result);
|
|
||||||
|
|
||||||
public static native void foreground(int ansiColor, FunctionResult result);
|
|
||||||
|
|
||||||
public static native void left(int count, FunctionResult result);
|
|
||||||
|
|
||||||
public static native void right(int count, FunctionResult result);
|
|
||||||
|
|
||||||
public static native void up(int count, FunctionResult result);
|
|
||||||
|
|
||||||
public static native void down(int count, FunctionResult result);
|
|
||||||
|
|
||||||
public static native void startLine(FunctionResult result);
|
|
||||||
|
|
||||||
public static native void clearToEndOfLine(FunctionResult result);
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
package net.rubygrapefruit.platform.internal.jni;
|
|
||||||
|
|
||||||
import net.rubygrapefruit.platform.internal.FunctionResult;
|
|
||||||
|
|
||||||
public class WindowsHandleFunctions {
|
|
||||||
public static native void markStandardHandlesUninheritable(FunctionResult result);
|
|
||||||
|
|
||||||
public static native void restoreStandardHandles(FunctionResult result);
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
package net.rubygrapefruit.platform.internal.jni;
|
|
||||||
|
|
||||||
import net.rubygrapefruit.platform.internal.FunctionResult;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class WindowsRegistryFunctions {
|
|
||||||
// Returns null for unknown key or value
|
|
||||||
public static native String getStringValue(int key, String subkey, String value, FunctionResult result);
|
|
||||||
|
|
||||||
// Returns false for unknown key
|
|
||||||
public static native boolean getSubkeys(int key, String subkey, List<String> subkeys, FunctionResult result);
|
|
||||||
|
|
||||||
// Returns false for unknown key
|
|
||||||
public static native boolean getValueNames(int key, String subkey, List<String> names, FunctionResult result);
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user