I am trying to debug my call to termios
function tcgetattr()
. It returns -1 as the result and I searched internet to find out more details about what the call fails. I found that I can make a call to explain_tcgetattr() to get more details about the error. In the code below I added the method signature to my interface so that the proxy can implement it, but I get the exception I have added below.
My code:
package org.example;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Structure;
import java.io.IOException;
import java.util.Arrays;
public class App {
private static LibC.Termios originalAttributes;
private static int rows = 10;
private static int columns = 10;
public static void main(String[] args) throws IOException {
// System.out.println("Hello World");
/*System.out.println("\033[4;44;31mHello World\033[0mHello");
System.out.println("\033[2J");
System.out.println("\033[5H");*/
enableRawMode();
initEditor();
while (true){
refreshScreen();
int key = readKey();
handleKey(key);
}
}
private static void initEditor() {
LibC.Winsize windowSize = getWindowSize();
columns = windowSize.ws_col;
rows = windowSize.ws_row;
}
private static void refreshScreen() {
StringBuilder builder = new StringBuilder();
builder.append("\033[2J");
builder.append("\033[H");
for (int i = 0; i < rows - 1; i++) {
builder.append("~\r\n");
}
String statusMessage = "Marco Code's Editor - v0.0.1";
builder.append("\033[7m")
.append(statusMessage)
.append(" ".repeat(Math.max(0, columns - statusMessage.length())))
.append("\033[0m");
builder.append("\033[H");
System.out.print(builder);
}
private static int readKey() throws IOException {
return System.in.read();
}
private static void handleKey(int key) {
if (key == 'q') {
System.out.print("\033[2J");
System.out.print("\033[H");
LibC.INSTANCE.tcsetattr(LibC.SYSTEM_OUT_FD, LibC.TCSAFLUSH, originalAttributes);
System.exit(0);
}
}
private static void enableRawMode() {
LibC.Termios termios = new LibC.Termios();
int rc = LibC.INSTANCE.tcgetattr(LibC.SYSTEM_OUT_FD, termios);
if (rc != 0) {
System.err.println("There was a problem calling tcgetattr: "+rc);
System.out.println(LibC.INSTANCE.explain_tcgetattr(LibC.SYSTEM_OUT_FD, termios));
System.exit(rc);
}
originalAttributes = LibC.Termios.of(termios);
termios.c_lflag &= ~(LibC.ECHO | LibC.ICANON | LibC.IEXTEN | LibC.ISIG);
termios.c_iflag &= ~(LibC.IXON | LibC.ICRNL);
termios.c_oflag &= ~(LibC.OPOST);
/* termios.c_cc[LibC.VMIN] = 0;
termios.c_cc[LibC.VTIME] = 1;*/
LibC.INSTANCE.tcsetattr(LibC.SYSTEM_OUT_FD, LibC.TCSAFLUSH, termios);
}
private static LibC.Winsize getWindowSize() {
final LibC.Winsize winsize = new LibC.Winsize();
final int rc = LibC.INSTANCE.ioctl(LibC.SYSTEM_OUT_FD, LibC.TIOCGWINSZ, winsize);
if (rc != 0) {
System.err.println("ioctl failed with return code[={}]" + rc);
System.exit(1);
}
return winsize;
}
}
interface LibC extends Library {
int SYSTEM_OUT_FD = 0;
int ISIG = 1, ICANON = 2, ECHO = 10, TCSAFLUSH = 2,
IXON = 2000, ICRNL = 400, IEXTEN = 100000, OPOST = 1, VMIN = 6, VTIME = 5, TIOCGWINSZ = 0x5413;
// we're loading the C standard library for POSIX systems
LibC INSTANCE = Native.load("c", LibC.class);
@Structure.FieldOrder(value = {"ws_row", "ws_col", "ws_xpixel", "ws_ypixel"})
class Winsize extends Structure {
public short ws_row, ws_col, ws_xpixel, ws_ypixel;
}
@Structure.FieldOrder(value = {"c_iflag", "c_oflag", "c_cflag", "c_lflag", "c_cc"})
class Termios extends Structure {
public int c_iflag, c_oflag, c_cflag, c_lflag;
public byte[] c_cc = new byte[19];
public Termios() {
}
public static Termios of(Termios t) {
Termios copy = new Termios();
copy.c_iflag = t.c_iflag;
copy.c_oflag = t.c_oflag;
copy.c_cflag = t.c_cflag;
copy.c_lflag = t.c_lflag;
copy.c_cc = t.c_cc.clone();
return copy;
}
@Override
public String toString() {
return "Termios{" +
"c_iflag=" + c_iflag +
", c_oflag=" + c_oflag +
", c_cflag=" + c_cflag +
", c_lflag=" + c_lflag +
", c_cc=" + Arrays.toString(c_cc) +
'}';
}
}
int tcgetattr(int fd, Termios termios);
int tcsetattr(int fd, int optional_actions,
Termios termios);
int ioctl(int fd, int opt, Winsize winsize);
//THIS GIVES LINKAGE ERROR
int explain_tcgetattr(int fildes, Termios termios);
}
Exception:
There was a problem calling tcgetattr: -1
Exception in thread "main" java.lang.UnsatisfiedLinkError: Error looking up function 'explain_tcgetattr': /snap/openjdk/1465/jdk/bin/java: undefined symbol: explain_tcgetattr
at com.sun.jna.Function.<init>(Function.java:252)
at com.sun.jna.NativeLibrary.getFunction(NativeLibrary.java:620)
at com.sun.jna.NativeLibrary.getFunction(NativeLibrary.java:596)
at com.sun.jna.NativeLibrary.getFunction(NativeLibrary.java:582)
at com.sun.jna.Library$Handler.invoke(Library.java:248)
at org.example.$Proxy0.explain_tcgetattr(Unknown Source)
at org.example.App.enableRawMode(App.java:81)
at org.example.App.main(App.java:22)
Below is the description from man page:
Also I am not sure if String
is the Java equivalent of const char *
in C. Please advise.