All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jline.terminal.impl.jni.JniNativePty Maven / Gradle / Ivy

/*
 * Copyright (c) 2002-2020, the original author(s).
 *
 * This software is distributable under the BSD license. See the terms of the
 * BSD license in the documentation provided with this software.
 *
 * https://opensource.org/licenses/BSD-3-Clause
 */
package org.jline.terminal.impl.jni;

import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import org.jline.nativ.CLibrary;
import org.jline.nativ.Kernel32;
import org.jline.terminal.Attributes;
import org.jline.terminal.Size;
import org.jline.terminal.impl.AbstractPty;
import org.jline.terminal.impl.jni.win.NativeWinSysTerminal;
import org.jline.terminal.spi.Pty;
import org.jline.terminal.spi.SystemStream;
import org.jline.terminal.spi.TerminalProvider;
import org.jline.utils.OSUtils;

import static org.jline.nativ.CLibrary.TCSANOW;

public abstract class JniNativePty extends AbstractPty implements Pty {

    private final int master;
    private final int slave;
    private final int slaveOut;
    private final String name;
    private final FileDescriptor masterFD;
    private final FileDescriptor slaveFD;
    private final FileDescriptor slaveOutFD;

    public JniNativePty(
            TerminalProvider provider,
            SystemStream systemStream,
            int master,
            FileDescriptor masterFD,
            int slave,
            FileDescriptor slaveFD,
            String name) {
        this(provider, systemStream, master, masterFD, slave, slaveFD, slave, slaveFD, name);
    }

    public JniNativePty(
            TerminalProvider provider,
            SystemStream systemStream,
            int master,
            FileDescriptor masterFD,
            int slave,
            FileDescriptor slaveFD,
            int slaveOut,
            FileDescriptor slaveOutFD,
            String name) {
        super(provider, systemStream);
        this.master = master;
        this.slave = slave;
        this.slaveOut = slaveOut;
        this.name = name;
        this.masterFD = masterFD;
        this.slaveFD = slaveFD;
        this.slaveOutFD = slaveOutFD;
    }

    protected static String ttyname(int fd) throws IOException {
        String name = CLibrary.ttyname(fd);
        if (name != null) {
            name = name.trim();
        }
        if (name == null || name.isEmpty()) {
            throw new IOException("Not a tty");
        }
        return name;
    }

    @Override
    public void close() throws IOException {
        if (master > 0) {
            getMasterInput().close();
        }
        if (slave > 0) {
            getSlaveInput().close();
        }
    }

    public int getMaster() {
        return master;
    }

    public int getSlave() {
        return slave;
    }

    public int getSlaveOut() {
        return slaveOut;
    }

    public String getName() {
        return name;
    }

    public FileDescriptor getMasterFD() {
        return masterFD;
    }

    public FileDescriptor getSlaveFD() {
        return slaveFD;
    }

    public FileDescriptor getSlaveOutFD() {
        return slaveOutFD;
    }

    public InputStream getMasterInput() {
        return new FileInputStream(getMasterFD());
    }

    public OutputStream getMasterOutput() {
        return new FileOutputStream(getMasterFD());
    }

    protected InputStream doGetSlaveInput() {
        return new FileInputStream(getSlaveFD());
    }

    public OutputStream getSlaveOutput() {
        return new FileOutputStream(getSlaveOutFD());
    }

    @Override
    public Attributes getAttr() throws IOException {
        CLibrary.Termios tios = new CLibrary.Termios();
        CLibrary.tcgetattr(slave, tios);
        return toAttributes(tios);
    }

    @Override
    protected void doSetAttr(Attributes attr) throws IOException {
        CLibrary.Termios tios = toTermios(attr);
        CLibrary.tcsetattr(slave, TCSANOW, tios);
    }

    @Override
    public Size getSize() throws IOException {
        CLibrary.WinSize sz = new CLibrary.WinSize();
        int res = CLibrary.ioctl(slave, CLibrary.TIOCGWINSZ, sz);
        if (res != 0) {
            throw new IOException("Error calling ioctl(TIOCGWINSZ): return code is " + res);
        }
        return new Size(sz.ws_col, sz.ws_row);
    }

    @Override
    public void setSize(Size size) throws IOException {
        CLibrary.WinSize sz = new CLibrary.WinSize((short) size.getRows(), (short) size.getColumns());
        int res = CLibrary.ioctl(slave, CLibrary.TIOCSWINSZ, sz);
        if (res != 0) {
            throw new IOException("Error calling ioctl(TIOCSWINSZ): return code is " + res);
        }
    }

    protected abstract CLibrary.Termios toTermios(Attributes t);

    protected abstract Attributes toAttributes(CLibrary.Termios tios);

    @Override
    public String toString() {
        return "NativePty[" + getName() + "]";
    }

    public static boolean isPosixSystemStream(SystemStream stream) {
        return CLibrary.isatty(fd(stream)) == 1;
    }

    public static String posixSystemStreamName(SystemStream systemStream) {
        return CLibrary.ttyname(fd(systemStream));
    }

    public static int systemStreamWidth(SystemStream systemStream) {
        try {
            if (OSUtils.IS_WINDOWS) {
                Kernel32.CONSOLE_SCREEN_BUFFER_INFO info = new Kernel32.CONSOLE_SCREEN_BUFFER_INFO();
                long outConsole = NativeWinSysTerminal.getConsole(systemStream);
                Kernel32.GetConsoleScreenBufferInfo(outConsole, info);
                return info.windowWidth();
            } else {
                CLibrary.WinSize sz = new CLibrary.WinSize();
                int res = CLibrary.ioctl(fd(systemStream), CLibrary.TIOCGWINSZ, sz);
                if (res != 0) {
                    throw new IOException("Error calling ioctl(TIOCGWINSZ): return code is " + res);
                }
                return sz.ws_col;
            }
        } catch (Throwable t) {
            return -1;
        }
    }

    private static int fd(SystemStream systemStream) {
        switch (systemStream) {
            case Input:
                return 0;
            case Output:
                return 1;
            case Error:
                return 2;
            default:
                return -1;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy