Added SystemInfo and FileSystems to query system and file system information, respectively.

This commit is contained in:
Adam Murdoch
2012-08-12 06:17:58 +10:00
parent 5f3761dd41
commit 3a58e27eeb
18 changed files with 612 additions and 327 deletions

View File

@@ -56,6 +56,7 @@ task nativeHeaders {
args '-classpath', sourceSets.main.output.classesDir args '-classpath', sourceSets.main.output.classesDir
args 'net.rubygrapefruit.platform.internal.jni.NativeLibraryFunctions' args 'net.rubygrapefruit.platform.internal.jni.NativeLibraryFunctions'
args 'net.rubygrapefruit.platform.internal.jni.PosixFileFunctions' args 'net.rubygrapefruit.platform.internal.jni.PosixFileFunctions'
args 'net.rubygrapefruit.platform.internal.jni.PosixFileSystemFunctions'
args 'net.rubygrapefruit.platform.internal.jni.PosixProcessFunctions' args 'net.rubygrapefruit.platform.internal.jni.PosixProcessFunctions'
args 'net.rubygrapefruit.platform.internal.jni.PosixTerminalFunctions' args 'net.rubygrapefruit.platform.internal.jni.PosixTerminalFunctions'
args 'net.rubygrapefruit.platform.internal.jni.TerminfoFunctions' args 'net.rubygrapefruit.platform.internal.jni.TerminfoFunctions'

View File

@@ -17,5 +17,5 @@ void mark_failed_with_code(JNIEnv *env, const char* message, int error_code, job
JNIEXPORT jint JNICALL JNIEXPORT jint JNICALL
Java_net_rubygrapefruit_platform_internal_jni_NativeLibraryFunctions_getVersion(JNIEnv *env, jclass target) { Java_net_rubygrapefruit_platform_internal_jni_NativeLibraryFunctions_getVersion(JNIEnv *env, jclass target) {
return 4; return 5;
} }

View File

@@ -10,6 +10,13 @@
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <curses.h> #include <curses.h>
#include <term.h> #include <term.h>
#include <langinfo.h>
#include <sys/utsname.h>
#include <xlocale.h>
#include <locale.h>
#include <sys/param.h>
#include <sys/ucred.h>
#include <sys/mount.h>
/* /*
* Marks the given result as failed, using the current value of errno * Marks the given result as failed, using the current value of errno
@@ -18,6 +25,35 @@ void mark_failed_with_errno(JNIEnv *env, const char* message, jobject result) {
mark_failed_with_code(env, message, errno, result); mark_failed_with_code(env, message, errno, result);
} }
JNIEXPORT void JNICALL
Java_net_rubygrapefruit_platform_internal_jni_NativeLibraryFunctions_getSystemInfo(JNIEnv *env, jclass target, jobject info, jobject result) {
jclass infoClass = env->GetObjectClass(info);
// Empty string means load locale from environment.
locale_t locale = newlocale(LC_CTYPE_MASK, "", LC_GLOBAL_LOCALE);
if (locale == NULL) {
mark_failed_with_message(env, "could not create locale", result);
return;
}
jfieldID characterEncodingField = env->GetFieldID(infoClass, "characterEncoding", "Ljava/lang/String;");
env->SetObjectField(info, characterEncodingField, env->NewStringUTF(nl_langinfo_l(CODESET, locale)));
freelocale(locale);
struct utsname machine_info;
if (uname(&machine_info) != 0) {
mark_failed_with_errno(env, "could not query machine details", result);
return;
}
jfieldID osNameField = env->GetFieldID(infoClass, "osName", "Ljava/lang/String;");
env->SetObjectField(info, osNameField, env->NewStringUTF(machine_info.sysname));
jfieldID osVersionField = env->GetFieldID(infoClass, "osVersion", "Ljava/lang/String;");
env->SetObjectField(info, osVersionField, env->NewStringUTF(machine_info.release));
jfieldID machineArchitectureField = env->GetFieldID(infoClass, "machineArchitecture", "Ljava/lang/String;");
env->SetObjectField(info, machineArchitectureField, env->NewStringUTF(machine_info.machine));
}
/* /*
* File functions * File functions
*/ */
@@ -47,6 +83,38 @@ Java_net_rubygrapefruit_platform_internal_jni_PosixFileFunctions_stat(JNIEnv *en
env->SetIntField(dest, modeField, 0777 & fileInfo.st_mode); env->SetIntField(dest, modeField, 0777 & fileInfo.st_mode);
} }
/*
* File system functions
*/
JNIEXPORT void JNICALL
Java_net_rubygrapefruit_platform_internal_jni_PosixFileSystemFunctions_listFileSystems(JNIEnv *env, jclass target, jobject info, jobject result) {
int fs_count = getfsstat(NULL, 0, MNT_NOWAIT);
if (fs_count < 0) {
mark_failed_with_errno(env, "could not stat file systems", result);
return;
}
size_t len = fs_count * sizeof(struct statfs);
struct statfs* buf = (struct statfs*)malloc(len);
if (getfsstat(buf, len, MNT_NOWAIT) < 0 ) {
mark_failed_with_errno(env, "could not stat file systems", result);
free(buf);
return;
}
jclass info_class = env->GetObjectClass(info);
jmethodID method = env->GetMethodID(info_class, "add", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Z)V");
for (int i = 0; i < fs_count; i++) {
jstring mount_point = env->NewStringUTF(buf[i].f_mntonname);
jstring file_system_type = env->NewStringUTF(buf[i].f_fstypename);
jstring device_name = env->NewStringUTF(buf[i].f_mntfromname);
jboolean remote = (buf[i].f_flags & MNT_LOCAL) == 0;
env->CallVoidMethod(info, method, mount_point, file_system_type, device_name, remote);
}
free(buf);
}
/* /*
* Process functions * Process functions
*/ */

View File

@@ -1,236 +1,240 @@
#ifdef WIN32 #ifdef WIN32
#include "native.h" #include "native.h"
#include "generic.h" #include "generic.h"
#include <windows.h> #include <windows.h>
/* /*
* Marks the given result as failed, using the current value of GetLastError() * Marks the given result as failed, using the current value of GetLastError()
*/ */
void mark_failed_with_errno(JNIEnv *env, const char* message, jobject result) { void mark_failed_with_errno(JNIEnv *env, const char* message, jobject result) {
mark_failed_with_code(env, message, GetLastError(), result); mark_failed_with_code(env, message, GetLastError(), result);
} }
/* JNIEXPORT void JNICALL
* Process functions Java_net_rubygrapefruit_platform_internal_jni_NativeLibraryFunctions_getPlatform(JNIEnv *env, jclass target) {
*/ }
JNIEXPORT jint JNICALL /*
Java_net_rubygrapefruit_platform_internal_jni_PosixProcessFunctions_getPid(JNIEnv *env, jclass target) { * Process functions
return GetCurrentProcessId(); */
}
JNIEXPORT jint JNICALL
/* Java_net_rubygrapefruit_platform_internal_jni_PosixProcessFunctions_getPid(JNIEnv *env, jclass target) {
* Console functions return GetCurrentProcessId();
*/ }
HANDLE getHandle(JNIEnv *env, int output, jobject result) { /*
HANDLE handle = output == 1 ? GetStdHandle(STD_OUTPUT_HANDLE) : GetStdHandle(STD_ERROR_HANDLE); * Console functions
if (handle == INVALID_HANDLE_VALUE) { */
mark_failed_with_errno(env, "could not get console handle", result);
return NULL; HANDLE getHandle(JNIEnv *env, int output, jobject result) {
} HANDLE handle = output == 1 ? GetStdHandle(STD_OUTPUT_HANDLE) : GetStdHandle(STD_ERROR_HANDLE);
return handle; if (handle == INVALID_HANDLE_VALUE) {
} mark_failed_with_errno(env, "could not get console handle", result);
return NULL;
JNIEXPORT jboolean JNICALL }
Java_net_rubygrapefruit_platform_internal_jni_WindowsConsoleFunctions_isConsole(JNIEnv *env, jclass target, jint output, jobject result) { return handle;
CONSOLE_SCREEN_BUFFER_INFO console_info; }
HANDLE handle = getHandle(env, output, result);
if (handle == NULL) { JNIEXPORT jboolean JNICALL
return JNI_FALSE; Java_net_rubygrapefruit_platform_internal_jni_WindowsConsoleFunctions_isConsole(JNIEnv *env, jclass target, jint output, jobject result) {
} CONSOLE_SCREEN_BUFFER_INFO console_info;
if (!GetConsoleScreenBufferInfo(handle, &console_info)) { HANDLE handle = getHandle(env, output, result);
if (GetLastError() == ERROR_INVALID_HANDLE) { if (handle == NULL) {
return JNI_FALSE; return JNI_FALSE;
} }
mark_failed_with_errno(env, "could not get console buffer", result); if (!GetConsoleScreenBufferInfo(handle, &console_info)) {
return JNI_FALSE; if (GetLastError() == ERROR_INVALID_HANDLE) {
} return JNI_FALSE;
return JNI_TRUE; }
} mark_failed_with_errno(env, "could not get console buffer", result);
return JNI_FALSE;
JNIEXPORT void JNICALL }
Java_net_rubygrapefruit_platform_internal_jni_WindowsConsoleFunctions_getConsoleSize(JNIEnv *env, jclass target, jint output, jobject dimension, jobject result) { return JNI_TRUE;
CONSOLE_SCREEN_BUFFER_INFO console_info; }
HANDLE handle = getHandle(env, output, result);
if (handle == NULL) { JNIEXPORT void JNICALL
mark_failed_with_message(env, "not a console", result); Java_net_rubygrapefruit_platform_internal_jni_WindowsConsoleFunctions_getConsoleSize(JNIEnv *env, jclass target, jint output, jobject dimension, jobject result) {
return; CONSOLE_SCREEN_BUFFER_INFO console_info;
} HANDLE handle = getHandle(env, output, result);
if (!GetConsoleScreenBufferInfo(handle, &console_info)) { if (handle == NULL) {
mark_failed_with_errno(env, "could not get console buffer", result); mark_failed_with_message(env, "not a console", result);
return; return;
} }
if (!GetConsoleScreenBufferInfo(handle, &console_info)) {
jclass dimensionClass = env->GetObjectClass(dimension); mark_failed_with_errno(env, "could not get console buffer", result);
jfieldID widthField = env->GetFieldID(dimensionClass, "cols", "I"); return;
env->SetIntField(dimension, widthField, console_info.srWindow.Right - console_info.srWindow.Left + 1); }
jfieldID heightField = env->GetFieldID(dimensionClass, "rows", "I");
env->SetIntField(dimension, heightField, console_info.srWindow.Bottom - console_info.srWindow.Top + 1); jclass dimensionClass = env->GetObjectClass(dimension);
} jfieldID widthField = env->GetFieldID(dimensionClass, "cols", "I");
env->SetIntField(dimension, widthField, console_info.srWindow.Right - console_info.srWindow.Left + 1);
HANDLE current_console = NULL; jfieldID heightField = env->GetFieldID(dimensionClass, "rows", "I");
WORD original_attributes = 0; env->SetIntField(dimension, heightField, console_info.srWindow.Bottom - console_info.srWindow.Top + 1);
WORD current_attributes = 0; }
JNIEXPORT void JNICALL HANDLE current_console = NULL;
Java_net_rubygrapefruit_platform_internal_jni_WindowsConsoleFunctions_initConsole(JNIEnv *env, jclass target, jint output, jobject result) { WORD original_attributes = 0;
CONSOLE_SCREEN_BUFFER_INFO console_info; WORD current_attributes = 0;
HANDLE handle = getHandle(env, output, result);
if (handle == NULL) { JNIEXPORT void JNICALL
mark_failed_with_message(env, "not a terminal", result); Java_net_rubygrapefruit_platform_internal_jni_WindowsConsoleFunctions_initConsole(JNIEnv *env, jclass target, jint output, jobject result) {
return; CONSOLE_SCREEN_BUFFER_INFO console_info;
} HANDLE handle = getHandle(env, output, result);
if (!GetConsoleScreenBufferInfo(handle, &console_info)) { if (handle == NULL) {
if (GetLastError() == ERROR_INVALID_HANDLE) { mark_failed_with_message(env, "not a terminal", result);
mark_failed_with_message(env, "not a console", result); return;
} else { }
mark_failed_with_errno(env, "could not get console buffer", result); if (!GetConsoleScreenBufferInfo(handle, &console_info)) {
} if (GetLastError() == ERROR_INVALID_HANDLE) {
return; mark_failed_with_message(env, "not a console", result);
} } else {
current_console = handle; mark_failed_with_errno(env, "could not get console buffer", result);
original_attributes = console_info.wAttributes; }
current_attributes = original_attributes; return;
Java_net_rubygrapefruit_platform_internal_jni_WindowsConsoleFunctions_normal(env, target, result); }
} current_console = handle;
original_attributes = console_info.wAttributes;
JNIEXPORT void JNICALL current_attributes = original_attributes;
Java_net_rubygrapefruit_platform_internal_jni_WindowsConsoleFunctions_bold(JNIEnv *env, jclass target, jobject result) { Java_net_rubygrapefruit_platform_internal_jni_WindowsConsoleFunctions_normal(env, target, result);
current_attributes |= FOREGROUND_INTENSITY; }
if (!SetConsoleTextAttribute(current_console, current_attributes)) {
mark_failed_with_errno(env, "could not set text attributes", result); JNIEXPORT void JNICALL
} Java_net_rubygrapefruit_platform_internal_jni_WindowsConsoleFunctions_bold(JNIEnv *env, jclass target, jobject result) {
} current_attributes |= FOREGROUND_INTENSITY;
if (!SetConsoleTextAttribute(current_console, current_attributes)) {
JNIEXPORT void JNICALL mark_failed_with_errno(env, "could not set text attributes", result);
Java_net_rubygrapefruit_platform_internal_jni_WindowsConsoleFunctions_normal(JNIEnv *env, jclass target, jobject result) { }
current_attributes &= ~FOREGROUND_INTENSITY; }
SetConsoleTextAttribute(current_console, current_attributes);
if (!SetConsoleTextAttribute(current_console, current_attributes)) { JNIEXPORT void JNICALL
mark_failed_with_errno(env, "could not set text attributes", result); Java_net_rubygrapefruit_platform_internal_jni_WindowsConsoleFunctions_normal(JNIEnv *env, jclass target, jobject result) {
} current_attributes &= ~FOREGROUND_INTENSITY;
} SetConsoleTextAttribute(current_console, current_attributes);
if (!SetConsoleTextAttribute(current_console, current_attributes)) {
JNIEXPORT void JNICALL mark_failed_with_errno(env, "could not set text attributes", result);
Java_net_rubygrapefruit_platform_internal_jni_WindowsConsoleFunctions_reset(JNIEnv *env, jclass target, jobject result) { }
SetConsoleTextAttribute(current_console, original_attributes); }
if (!SetConsoleTextAttribute(current_console, current_attributes)) {
mark_failed_with_errno(env, "could not set text attributes", result); JNIEXPORT void JNICALL
} Java_net_rubygrapefruit_platform_internal_jni_WindowsConsoleFunctions_reset(JNIEnv *env, jclass target, jobject result) {
} SetConsoleTextAttribute(current_console, original_attributes);
if (!SetConsoleTextAttribute(current_console, current_attributes)) {
JNIEXPORT void JNICALL mark_failed_with_errno(env, "could not set text attributes", result);
Java_net_rubygrapefruit_platform_internal_jni_WindowsConsoleFunctions_foreground(JNIEnv *env, jclass target, jint color, jobject result) { }
current_attributes &= ~ (FOREGROUND_BLUE|FOREGROUND_RED|FOREGROUND_GREEN); }
switch (color) {
case 0: JNIEXPORT void JNICALL
break; Java_net_rubygrapefruit_platform_internal_jni_WindowsConsoleFunctions_foreground(JNIEnv *env, jclass target, jint color, jobject result) {
case 1: current_attributes &= ~ (FOREGROUND_BLUE|FOREGROUND_RED|FOREGROUND_GREEN);
current_attributes |= FOREGROUND_RED; switch (color) {
break; case 0:
case 2: break;
current_attributes |= FOREGROUND_GREEN; case 1:
break; current_attributes |= FOREGROUND_RED;
case 3: break;
current_attributes |= FOREGROUND_RED|FOREGROUND_GREEN; case 2:
break; current_attributes |= FOREGROUND_GREEN;
case 4: break;
current_attributes |= FOREGROUND_BLUE; case 3:
break; current_attributes |= FOREGROUND_RED|FOREGROUND_GREEN;
case 5: break;
current_attributes |= FOREGROUND_RED|FOREGROUND_BLUE; case 4:
break; current_attributes |= FOREGROUND_BLUE;
case 6: break;
current_attributes |= FOREGROUND_GREEN|FOREGROUND_BLUE; case 5:
break; current_attributes |= FOREGROUND_RED|FOREGROUND_BLUE;
default: break;
current_attributes |= FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE; case 6:
break; current_attributes |= FOREGROUND_GREEN|FOREGROUND_BLUE;
} break;
default:
SetConsoleTextAttribute(current_console, current_attributes); current_attributes |= FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE;
if (!SetConsoleTextAttribute(current_console, current_attributes)) { break;
mark_failed_with_errno(env, "could not set text attributes", result); }
}
} SetConsoleTextAttribute(current_console, current_attributes);
if (!SetConsoleTextAttribute(current_console, current_attributes)) {
JNIEXPORT void JNICALL mark_failed_with_errno(env, "could not set text attributes", result);
Java_net_rubygrapefruit_platform_internal_jni_WindowsConsoleFunctions_left(JNIEnv *env, jclass target, jint count, jobject result) { }
CONSOLE_SCREEN_BUFFER_INFO console_info; }
if (!GetConsoleScreenBufferInfo(current_console, &console_info)) {
mark_failed_with_errno(env, "could not get console buffer", result); JNIEXPORT void JNICALL
return; Java_net_rubygrapefruit_platform_internal_jni_WindowsConsoleFunctions_left(JNIEnv *env, jclass target, jint count, jobject result) {
} CONSOLE_SCREEN_BUFFER_INFO console_info;
console_info.dwCursorPosition.X -= count; if (!GetConsoleScreenBufferInfo(current_console, &console_info)) {
if (!SetConsoleCursorPosition(current_console, console_info.dwCursorPosition)) { mark_failed_with_errno(env, "could not get console buffer", result);
mark_failed_with_errno(env, "could not set cursor position", result); return;
} }
} console_info.dwCursorPosition.X -= count;
if (!SetConsoleCursorPosition(current_console, console_info.dwCursorPosition)) {
JNIEXPORT void JNICALL mark_failed_with_errno(env, "could not set cursor position", result);
Java_net_rubygrapefruit_platform_internal_jni_WindowsConsoleFunctions_right(JNIEnv *env, jclass target, jint count, jobject result) { }
CONSOLE_SCREEN_BUFFER_INFO console_info; }
if (!GetConsoleScreenBufferInfo(current_console, &console_info)) {
mark_failed_with_errno(env, "could not get console buffer", result); JNIEXPORT void JNICALL
return; Java_net_rubygrapefruit_platform_internal_jni_WindowsConsoleFunctions_right(JNIEnv *env, jclass target, jint count, jobject result) {
} CONSOLE_SCREEN_BUFFER_INFO console_info;
console_info.dwCursorPosition.X += count; if (!GetConsoleScreenBufferInfo(current_console, &console_info)) {
if (!SetConsoleCursorPosition(current_console, console_info.dwCursorPosition)) { mark_failed_with_errno(env, "could not get console buffer", result);
mark_failed_with_errno(env, "could not set cursor position", result); return;
} }
} console_info.dwCursorPosition.X += count;
if (!SetConsoleCursorPosition(current_console, console_info.dwCursorPosition)) {
JNIEXPORT void JNICALL mark_failed_with_errno(env, "could not set cursor position", result);
Java_net_rubygrapefruit_platform_internal_jni_WindowsConsoleFunctions_up(JNIEnv *env, jclass target, jint count, jobject result) { }
CONSOLE_SCREEN_BUFFER_INFO console_info; }
if (!GetConsoleScreenBufferInfo(current_console, &console_info)) {
mark_failed_with_errno(env, "could not get console buffer", result); JNIEXPORT void JNICALL
return; Java_net_rubygrapefruit_platform_internal_jni_WindowsConsoleFunctions_up(JNIEnv *env, jclass target, jint count, jobject result) {
} CONSOLE_SCREEN_BUFFER_INFO console_info;
console_info.dwCursorPosition.Y -= count; if (!GetConsoleScreenBufferInfo(current_console, &console_info)) {
if (!SetConsoleCursorPosition(current_console, console_info.dwCursorPosition)) { mark_failed_with_errno(env, "could not get console buffer", result);
mark_failed_with_errno(env, "could not set cursor position", result); return;
} }
} console_info.dwCursorPosition.Y -= count;
if (!SetConsoleCursorPosition(current_console, console_info.dwCursorPosition)) {
JNIEXPORT void JNICALL mark_failed_with_errno(env, "could not set cursor position", result);
Java_net_rubygrapefruit_platform_internal_jni_WindowsConsoleFunctions_down(JNIEnv *env, jclass target, jint count, jobject result) { }
CONSOLE_SCREEN_BUFFER_INFO console_info; }
if (!GetConsoleScreenBufferInfo(current_console, &console_info)) {
mark_failed_with_errno(env, "could not get console buffer", result); JNIEXPORT void JNICALL
return; Java_net_rubygrapefruit_platform_internal_jni_WindowsConsoleFunctions_down(JNIEnv *env, jclass target, jint count, jobject result) {
} CONSOLE_SCREEN_BUFFER_INFO console_info;
console_info.dwCursorPosition.Y += count; if (!GetConsoleScreenBufferInfo(current_console, &console_info)) {
if (!SetConsoleCursorPosition(current_console, console_info.dwCursorPosition)) { mark_failed_with_errno(env, "could not get console buffer", result);
mark_failed_with_errno(env, "could not set cursor position", result); return;
} }
} console_info.dwCursorPosition.Y += count;
if (!SetConsoleCursorPosition(current_console, console_info.dwCursorPosition)) {
JNIEXPORT void JNICALL mark_failed_with_errno(env, "could not set cursor position", result);
Java_net_rubygrapefruit_platform_internal_jni_WindowsConsoleFunctions_startLine(JNIEnv *env, jclass target, jobject result) { }
CONSOLE_SCREEN_BUFFER_INFO console_info; }
if (!GetConsoleScreenBufferInfo(current_console, &console_info)) {
mark_failed_with_errno(env, "could not get console buffer", result); JNIEXPORT void JNICALL
return; Java_net_rubygrapefruit_platform_internal_jni_WindowsConsoleFunctions_startLine(JNIEnv *env, jclass target, jobject result) {
} CONSOLE_SCREEN_BUFFER_INFO console_info;
console_info.dwCursorPosition.X = 0; if (!GetConsoleScreenBufferInfo(current_console, &console_info)) {
if (!SetConsoleCursorPosition(current_console, console_info.dwCursorPosition)) { mark_failed_with_errno(env, "could not get console buffer", result);
mark_failed_with_errno(env, "could not set cursor position", result); return;
} }
} console_info.dwCursorPosition.X = 0;
if (!SetConsoleCursorPosition(current_console, console_info.dwCursorPosition)) {
JNIEXPORT void JNICALL mark_failed_with_errno(env, "could not set cursor position", result);
Java_net_rubygrapefruit_platform_internal_jni_WindowsConsoleFunctions_clearToEndOfLine(JNIEnv *env, jclass target, jobject result) { }
CONSOLE_SCREEN_BUFFER_INFO console_info; }
if (!GetConsoleScreenBufferInfo(current_console, &console_info)) {
mark_failed_with_errno(env, "could not get console buffer", result); JNIEXPORT void JNICALL
return; Java_net_rubygrapefruit_platform_internal_jni_WindowsConsoleFunctions_clearToEndOfLine(JNIEnv *env, jclass target, jobject result) {
} CONSOLE_SCREEN_BUFFER_INFO console_info;
for (int i = console_info.dwCursorPosition.X; i < console_info.dwSize.X; i++) { if (!GetConsoleScreenBufferInfo(current_console, &console_info)) {
WriteConsole(current_console, " ", 1, NULL, NULL); mark_failed_with_errno(env, "could not get console buffer", result);
} return;
} }
for (int i = console_info.dwCursorPosition.X; i < console_info.dwSize.X; i++) {
#endif WriteConsole(current_console, " ", 1, NULL, NULL);
}
}
#endif

View File

@@ -0,0 +1,13 @@
package net.rubygrapefruit.platform;
import java.io.File;
public interface FileSystem {
File getMountPoint();
String getFileSystemType();
boolean isRemote();
String getDeviceName();
}

View File

@@ -0,0 +1,12 @@
package net.rubygrapefruit.platform;
import java.util.List;
public interface FileSystems extends NativeIntegration {
/**
* Returns the set of all file systems for the current machine.
*
* @throws NativeException On failure.
*/
List<FileSystem> getFileSystems() throws NativeException;
}

View File

@@ -6,9 +6,18 @@ public class Main {
System.out.println("* OS: " + System.getProperty("os.name") + ' ' + System.getProperty("os.version") + ' ' + System.getProperty("os.arch")); System.out.println("* OS: " + System.getProperty("os.name") + ' ' + System.getProperty("os.version") + ' ' + System.getProperty("os.arch"));
System.out.println("* JVM: " + System.getProperty("java.vm.vendor") + ' ' + System.getProperty("java.version")); System.out.println("* JVM: " + System.getProperty("java.vm.vendor") + ' ' + System.getProperty("java.version"));
SystemInfo systemInfo = Native.get(SystemInfo.class);
System.out.println("* Kernel: " + systemInfo.getKernelName() + ' ' + systemInfo.getKernelVersion() + ' ' + systemInfo.getMachineArchitecture());
Process process = Native.get(Process.class); Process process = Native.get(Process.class);
System.out.println("* PID: " + process.getProcessId()); System.out.println("* PID: " + process.getProcessId());
FileSystems fileSystems = Native.get(FileSystems.class);
System.out.println("* File systems: ");
for (FileSystem fileSystem : fileSystems.getFileSystems()) {
System.out.println(" * " + fileSystem.getMountPoint() + ' ' + fileSystem.getFileSystemType() + ' ' + fileSystem.getDeviceName() + (fileSystem.isRemote() ? " remote" : " local"));
}
TerminalAccess terminalAccess = Native.get(TerminalAccess.class); TerminalAccess terminalAccess = Native.get(TerminalAccess.class);
boolean stdoutIsTerminal = terminalAccess.isTerminal(TerminalAccess.Output.Stdout); boolean stdoutIsTerminal = terminalAccess.isTerminal(TerminalAccess.Output.Stdout);
boolean stderrIsTerminal = terminalAccess.isTerminal(TerminalAccess.Output.Stderr); boolean stderrIsTerminal = terminalAccess.isTerminal(TerminalAccess.Output.Stderr);

View File

@@ -54,7 +54,6 @@ public class Native {
loaded = true; loaded = true;
} }
} }
} }
static <T extends NativeIntegration> T get(Class<T> type) { static <T extends NativeIntegration> T get(Class<T> type) {
@@ -70,6 +69,17 @@ public class Native {
if (type.equals(TerminalAccess.class)) { if (type.equals(TerminalAccess.class)) {
return type.cast(new TerminfoTerminalAccess()); return type.cast(new TerminfoTerminalAccess());
} }
if (type.equals(SystemInfo.class)) {
MutableSystemInfo systemInfo = new MutableSystemInfo();
FunctionResult result = new FunctionResult();
NativeLibraryFunctions.getSystemInfo(systemInfo, result);
if (result.isFailed()) {
throw new NativeException(String.format("Could not fetch system information: %s",
result.getMessage()));
}
System.out.println("=> CHARACTER ENCODING: " + systemInfo.characterEncoding);
return type.cast(systemInfo);
}
} else if (platform.isWindows()) { } else if (platform.isWindows()) {
if (type.equals(Process.class)) { if (type.equals(Process.class)) {
return type.cast(new DefaultProcess()); return type.cast(new DefaultProcess());
@@ -78,6 +88,11 @@ public class Native {
return type.cast(new WindowsTerminalAccess()); return type.cast(new WindowsTerminalAccess());
} }
} }
if (platform.isOsX()) {
if (type.equals(FileSystems.class)) {
return type.cast(new PosixFileSystems());
}
}
throw new UnsupportedOperationException(String.format("Cannot load unsupported native integration %s.", throw new UnsupportedOperationException(String.format("Cannot load unsupported native integration %s.",
type.getName())); type.getName()));
} }

View File

@@ -0,0 +1,9 @@
package net.rubygrapefruit.platform;
public interface SystemInfo extends NativeIntegration {
String getKernelName();
String getKernelVersion();
String getMachineArchitecture();
}

View File

@@ -0,0 +1,39 @@
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;
public DefaultFileSystem(File mountPoint, String fileSystemType, String deviceName, boolean remote) {
this.mountPoint = mountPoint;
this.fileSystemType = fileSystemType;
this.deviceName = deviceName;
this.remote = remote;
}
@Override
public String getDeviceName() {
return deviceName;
}
@Override
public File getMountPoint() {
return mountPoint;
}
@Override
public String getFileSystemType() {
return fileSystemType;
}
@Override
public boolean isRemote() {
return remote;
}
}

View File

@@ -0,0 +1,15 @@
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) {
fileSystems.add(new DefaultFileSystem(new File(mountPoint), fileSystemName, deviceName, remote));
}
}

View File

@@ -0,0 +1,25 @@
package net.rubygrapefruit.platform.internal;
import net.rubygrapefruit.platform.SystemInfo;
public class MutableSystemInfo implements SystemInfo {
public String osName;
public String osVersion;
public String characterEncoding;
public String machineArchitecture;
@Override
public String getKernelName() {
return osName;
}
@Override
public String getKernelVersion() {
return osVersion;
}
@Override
public String getMachineArchitecture() {
return machineArchitecture;
}
}

View File

@@ -1,89 +1,98 @@
package net.rubygrapefruit.platform.internal; package net.rubygrapefruit.platform.internal;
public abstract class Platform {
private static Platform platform;
public static Platform current() {
synchronized (Platform.class) {
if (platform == null) {
String osName = System.getProperty("os.name").toLowerCase();
if (osName.contains("windows")) {
platform = new Windows();
} else if (osName.contains("linux")) {
platform = new Linux();
} else if (osName.contains("os x")) {
platform = new OsX();
} else if (osName.contains("sunos")) {
platform = new Solaris();
} else {
platform = new Unsupported();
}
}
return platform;
}
}
public boolean isSupported() {
return true;
}
public boolean isPosix() {
return false;
}
public boolean isWindows() {
return false;
}
public abstract String getLibraryName();
private static class Windows extends Platform {
@Override
public boolean isWindows() {
return true;
}
@Override
public String getLibraryName() {
return "native-platform.dll";
}
}
private static abstract class Posix extends Platform {
@Override
public boolean isPosix() {
return true;
}
}
private static class Unix extends Posix {
@Override
public String getLibraryName() {
return "libnative-platform.so";
}
}
private static class Linux extends Unix { public abstract class Platform {
} private static Platform platform;
private static class Solaris extends Unix { public static Platform current() {
} synchronized (Platform.class) {
if (platform == null) {
private static class OsX extends Posix { String osName = System.getProperty("os.name").toLowerCase();
@Override if (osName.contains("windows")) {
public String getLibraryName() { platform = new Windows();
return "libnative-platform.dylib"; } else if (osName.contains("linux")) {
} platform = new Linux();
} } else if (osName.contains("os x")) {
platform = new OsX();
private static class Unsupported extends Platform { } else if (osName.contains("sunos")) {
@Override platform = new Solaris();
public boolean isSupported() { } else {
return false; platform = new Unsupported();
} }
}
public String getLibraryName() { return platform;
throw new UnsupportedOperationException(); }
} }
}
} public boolean isSupported() {
return true;
}
public boolean isPosix() {
return false;
}
public boolean isWindows() {
return false;
}
public boolean isOsX() {
return false;
}
public abstract String getLibraryName();
private static class Windows extends Platform {
@Override
public boolean isWindows() {
return true;
}
@Override
public String getLibraryName() {
return "native-platform.dll";
}
}
private static abstract class Posix extends Platform {
@Override
public boolean isPosix() {
return true;
}
}
private static class Unix extends Posix {
@Override
public String getLibraryName() {
return "libnative-platform.so";
}
}
private static class Linux extends Unix {
}
private static class Solaris extends Unix {
}
private static class OsX extends Posix {
@Override
public boolean isOsX() {
return true;
}
@Override
public String getLibraryName() {
return "libnative-platform.dylib";
}
}
private static class Unsupported extends Platform {
@Override
public boolean isSupported() {
return false;
}
public String getLibraryName() {
throw new UnsupportedOperationException();
}
}
}

View File

@@ -0,0 +1,21 @@
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 {
@Override
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;
}
}

View File

@@ -1,7 +1,12 @@
package net.rubygrapefruit.platform.internal.jni; package net.rubygrapefruit.platform.internal.jni;
import net.rubygrapefruit.platform.internal.FunctionResult;
import net.rubygrapefruit.platform.internal.MutableSystemInfo;
public class NativeLibraryFunctions { public class NativeLibraryFunctions {
public static final int VERSION = 4; public static final int VERSION = 5;
public static native int getVersion(); public static native int getVersion();
public static native void getSystemInfo(MutableSystemInfo systemInfo, FunctionResult result);
} }

View File

@@ -0,0 +1,8 @@
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);
}

View File

@@ -0,0 +1,15 @@
package net.rubygrapefruit.platform
import org.junit.Rule
import org.junit.rules.TemporaryFolder
import spock.lang.Specification
class FileSystemsTest extends Specification {
@Rule TemporaryFolder tmpDir
final FileSystems fileSystems = Native.get(FileSystems.class)
def "can query filesystem details"() {
expect:
fileSystems.fileSystems.collect() { it.mountPoint }.containsAll(File.listRoots())
}
}

View File

@@ -0,0 +1,17 @@
package net.rubygrapefruit.platform
import org.junit.Rule
import org.junit.rules.TemporaryFolder
import spock.lang.Specification
class SystemInfoTest extends Specification {
@Rule TemporaryFolder tmpDir
final SystemInfo systemInfo = Native.get(SystemInfo.class)
def "can query OS details"() {
expect:
systemInfo.kernelName
systemInfo.kernelVersion
systemInfo.machineArchitecture
}
}