1 /* 2 * Copyright (c) 2002-2019, the original author or authors. 3 * 4 * This software is distributable under the BSD license. See the terms of the 5 * BSD license in the documentation provided with this software. 6 * 7 * https://opensource.org/licenses/BSD-3-Clause 8 */ 9 package jdk.internal.org.jline.terminal.impl; 10 11 import jdk.internal.org.jline.terminal.Attributes; 12 import jdk.internal.org.jline.terminal.spi.Pty; 13 import jdk.internal.org.jline.utils.NonBlockingInputStream; 14 15 import java.io.IOError; 16 import java.io.IOException; 17 import java.io.InputStream; 18 import java.io.InterruptedIOException; 19 20 import static jdk.internal.org.jline.terminal.TerminalBuilder.PROP_NON_BLOCKING_READS; 21 22 public abstract class AbstractPty implements Pty { 23 24 private Attributes current; 25 26 @Override setAttr(Attributes attr)27 public void setAttr(Attributes attr) throws IOException { 28 current = new Attributes(attr); 29 doSetAttr(attr); 30 } 31 32 @Override getSlaveInput()33 public InputStream getSlaveInput() throws IOException { 34 InputStream si = doGetSlaveInput(); 35 if (Boolean.parseBoolean(System.getProperty(PROP_NON_BLOCKING_READS, "true"))) { 36 return new PtyInputStream(si); 37 } else { 38 return si; 39 } 40 } 41 doSetAttr(Attributes attr)42 protected abstract void doSetAttr(Attributes attr) throws IOException; 43 doGetSlaveInput()44 protected abstract InputStream doGetSlaveInput() throws IOException; 45 checkInterrupted()46 protected void checkInterrupted() throws InterruptedIOException { 47 if (Thread.interrupted()) { 48 throw new InterruptedIOException(); 49 } 50 } 51 52 class PtyInputStream extends NonBlockingInputStream { 53 final InputStream in; 54 int c = 0; 55 PtyInputStream(InputStream in)56 PtyInputStream(InputStream in) { 57 this.in = in; 58 } 59 60 @Override read(long timeout, boolean isPeek)61 public int read(long timeout, boolean isPeek) throws IOException { 62 checkInterrupted(); 63 if (c != 0) { 64 int r = c; 65 if (!isPeek) { 66 c = 0; 67 } 68 return r; 69 } else { 70 setNonBlocking(); 71 long start = System.currentTimeMillis(); 72 while (true) { 73 int r = in.read(); 74 if (r >= 0) { 75 if (isPeek) { 76 c = r; 77 } 78 return r; 79 } 80 checkInterrupted(); 81 long cur = System.currentTimeMillis(); 82 if (timeout > 0 && cur - start > timeout) { 83 return NonBlockingInputStream.READ_EXPIRED; 84 } 85 } 86 } 87 } 88 89 @Override readBuffered(byte[] b)90 public int readBuffered(byte[] b) throws IOException { 91 return in.read(b); 92 } 93 setNonBlocking()94 private void setNonBlocking() { 95 if (current == null 96 || current.getControlChar(Attributes.ControlChar.VMIN) != 0 97 || current.getControlChar(Attributes.ControlChar.VTIME) != 1) { 98 try { 99 Attributes attr = getAttr(); 100 attr.setControlChar(Attributes.ControlChar.VMIN, 0); 101 attr.setControlChar(Attributes.ControlChar.VTIME, 1); 102 setAttr(attr); 103 } catch (IOException e) { 104 throw new IOError(e); 105 } 106 } 107 } 108 } 109 110 } 111