Cleaned up input console to use my own growing-byte buffers. Also made one that is fast (but unsynchronized)
This commit is contained in:
parent
24efc75f7b
commit
890d73e8aa
|
@ -34,23 +34,23 @@ public class ByteBuffer2 {
|
||||||
public ByteBuffer2(byte[] bytes) {
|
public ByteBuffer2(byte[] bytes) {
|
||||||
this.bytes = bytes;
|
this.bytes = bytes;
|
||||||
clear();
|
clear();
|
||||||
position = bytes.length;
|
this.position = bytes.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte getByte() {
|
public byte getByte() {
|
||||||
if (position > limit) {
|
if (this.position > this.limit) {
|
||||||
throw new BufferUnderflowException();
|
throw new BufferUnderflowException();
|
||||||
}
|
}
|
||||||
|
|
||||||
return bytes[position++];
|
return this.bytes[this.position++];
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte getByte(int i) {
|
public byte getByte(int i) {
|
||||||
if (i > limit) {
|
if (i > this.limit) {
|
||||||
throw new BufferUnderflowException();
|
throw new BufferUnderflowException();
|
||||||
}
|
}
|
||||||
|
|
||||||
return bytes[i];
|
return this.bytes[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
public void getBytes(byte[] buffer) {
|
public void getBytes(byte[] buffer) {
|
||||||
|
@ -62,12 +62,12 @@ public class ByteBuffer2 {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void getBytes(byte[] buffer, int offset, int length) {
|
public void getBytes(byte[] buffer, int offset, int length) {
|
||||||
if (position + length - offset > limit) {
|
if (this.position + length - offset > this.limit) {
|
||||||
throw new BufferUnderflowException();
|
throw new BufferUnderflowException();
|
||||||
}
|
}
|
||||||
|
|
||||||
System.arraycopy(bytes, position, buffer, 0, length-offset);
|
System.arraycopy(this.bytes, this.position, buffer, 0, length-offset);
|
||||||
position += length-offset;
|
this.position += length-offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -76,18 +76,18 @@ public class ByteBuffer2 {
|
||||||
* NOT PROTECTED
|
* NOT PROTECTED
|
||||||
*/
|
*/
|
||||||
private final void _put(byte b) {
|
private final void _put(byte b) {
|
||||||
bytes[position++] = b;
|
this.bytes[this.position++] = b;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** NOT PROTECTED! */
|
/** NOT PROTECTED! */
|
||||||
private final void checkBuffer(int threshold) {
|
private final void checkBuffer(int threshold) {
|
||||||
if (bytes.length < threshold) {
|
if (this.bytes.length < threshold) {
|
||||||
byte[] t = new byte[threshold];
|
byte[] t = new byte[threshold];
|
||||||
// grow at back of array
|
// grow at back of array
|
||||||
System.arraycopy(bytes, 0, t, 0, bytes.length);
|
System.arraycopy(this.bytes, 0, t, 0, this.bytes.length);
|
||||||
limit = t.length;
|
this.limit = t.length;
|
||||||
|
|
||||||
bytes = t;
|
this.bytes = t;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,16 +101,16 @@ public class ByteBuffer2 {
|
||||||
}
|
}
|
||||||
|
|
||||||
public final synchronized ByteBuffer2 putBytes(byte[] src, int offset, int length) {
|
public final synchronized ByteBuffer2 putBytes(byte[] src, int offset, int length) {
|
||||||
checkBuffer(position + length - offset);
|
checkBuffer(this.position + length - offset);
|
||||||
|
|
||||||
System.arraycopy(src, offset, bytes, position, length);
|
System.arraycopy(src, offset, this.bytes, this.position, length);
|
||||||
position += length;
|
this.position += length;
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final synchronized ByteBuffer2 putByte(byte b) {
|
public final synchronized ByteBuffer2 putByte(byte b) {
|
||||||
checkBuffer(position + 1);
|
checkBuffer(this.position + 1);
|
||||||
|
|
||||||
_put(b);
|
_put(b);
|
||||||
return this;
|
return this;
|
||||||
|
@ -122,7 +122,7 @@ public class ByteBuffer2 {
|
||||||
}
|
}
|
||||||
|
|
||||||
public final synchronized void putChar(char c) {
|
public final synchronized void putChar(char c) {
|
||||||
checkBuffer(position + 2);
|
checkBuffer(this.position + 2);
|
||||||
|
|
||||||
putBytes(BigEndian.Char_.toBytes(c));
|
putBytes(BigEndian.Char_.toBytes(c));
|
||||||
}
|
}
|
||||||
|
@ -131,8 +131,19 @@ public class ByteBuffer2 {
|
||||||
return BigEndian.Char_.fromBytes(getByte(), getByte());
|
return BigEndian.Char_.fromBytes(getByte(), getByte());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final char getChar(int i) {
|
||||||
|
return BigEndian.Char_.fromBytes(getByte(i++), getByte(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void getChars(int srcStart, int srcLength, char[] dest, int destStart) {
|
||||||
|
for (int i=srcStart;i<srcLength;i+=2) {
|
||||||
|
char c = BigEndian.Char_.fromBytes(getByte(), getByte());
|
||||||
|
dest[destStart++] = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public final synchronized ByteBuffer2 putShort(short x) {
|
public final synchronized ByteBuffer2 putShort(short x) {
|
||||||
checkBuffer(position + 2);
|
checkBuffer(this.position + 2);
|
||||||
|
|
||||||
putBytes(BigEndian.Short_.toBytes(x));
|
putBytes(BigEndian.Short_.toBytes(x));
|
||||||
|
|
||||||
|
@ -143,21 +154,26 @@ public class ByteBuffer2 {
|
||||||
return BigEndian.Short_.fromBytes(getByte(), getByte());
|
return BigEndian.Short_.fromBytes(getByte(), getByte());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final short getShort(int i) {
|
||||||
|
return BigEndian.Short_.fromBytes(getByte(i++), getByte(i));
|
||||||
|
}
|
||||||
|
|
||||||
public final synchronized void putInt(int x) {
|
public final synchronized void putInt(int x) {
|
||||||
checkBuffer(position + 4);
|
checkBuffer(this.position + 4);
|
||||||
|
|
||||||
putBytes(BigEndian.Int_.toBytes(x));
|
putBytes(BigEndian.Int_.toBytes(x));
|
||||||
}
|
}
|
||||||
|
|
||||||
public final synchronized int getInt() {
|
public final synchronized int getInt() {
|
||||||
byte b3 = getByte();
|
return BigEndian.Int_.fromBytes(getByte(), getByte(), getByte(), getByte());
|
||||||
byte b2 = getByte();
|
}
|
||||||
byte b1 = getByte();
|
|
||||||
return BigEndian.Int_.fromBytes(getByte(), b1, b2, b3);
|
public final int getInt(int i) {
|
||||||
|
return BigEndian.Int_.fromBytes(getByte(i++), getByte(i++), getByte(i++), getByte(i++));
|
||||||
}
|
}
|
||||||
|
|
||||||
public final synchronized void putLong(long x) {
|
public final synchronized void putLong(long x) {
|
||||||
checkBuffer(position + 8);
|
checkBuffer(this.position + 8);
|
||||||
|
|
||||||
putBytes(BigEndian.Long_.toBytes(x));
|
putBytes(BigEndian.Long_.toBytes(x));
|
||||||
}
|
}
|
||||||
|
@ -166,21 +182,25 @@ public class ByteBuffer2 {
|
||||||
return BigEndian.Long_.fromBytes(getByte(), getByte(), getByte(), getByte(), getByte(), getByte(), getByte(), getByte());
|
return BigEndian.Long_.fromBytes(getByte(), getByte(), getByte(), getByte(), getByte(), getByte(), getByte(), getByte());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final long getLong(int i) {
|
||||||
|
return BigEndian.Long_.fromBytes(getByte(i++), getByte(i++), getByte(i++), getByte(i++), getByte(i++), getByte(i++), getByte(i++), getByte(i++));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the backing array of this buffer
|
* Returns the backing array of this buffer
|
||||||
*/
|
*/
|
||||||
public byte[] array() {
|
public byte[] array() {
|
||||||
return bytes;
|
return this.bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a copy of the backing array of this buffer
|
* Returns a copy of the backing array of this buffer
|
||||||
*/
|
*/
|
||||||
public final synchronized byte[] arrayCopy() {
|
public final synchronized byte[] arrayCopy() {
|
||||||
int length = bytes.length - position;
|
int length = this.bytes.length - this.position;
|
||||||
|
|
||||||
byte[] b = new byte[length];
|
byte[] b = new byte[length];
|
||||||
System.arraycopy(bytes, position, b, 0, length);
|
System.arraycopy(this.bytes, this.position, b, 0, length);
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,20 +208,20 @@ public class ByteBuffer2 {
|
||||||
* Returns this buffer's position.
|
* Returns this buffer's position.
|
||||||
*/
|
*/
|
||||||
public int position() {
|
public int position() {
|
||||||
return position;
|
return this.position;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets this buffer's position.
|
* Sets this buffer's position.
|
||||||
*/
|
*/
|
||||||
public final synchronized ByteBuffer2 position(int position) {
|
public final synchronized ByteBuffer2 position(int position) {
|
||||||
if (position > bytes.length || position < 0) {
|
if (position > this.bytes.length || position < 0) {
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.position = position;
|
this.position = position;
|
||||||
if (mark > position) {
|
if (this.mark > position) {
|
||||||
mark = -1;
|
this.mark = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
|
@ -212,7 +232,7 @@ public class ByteBuffer2 {
|
||||||
* limit.
|
* limit.
|
||||||
*/
|
*/
|
||||||
public final synchronized int remaining() {
|
public final synchronized int remaining() {
|
||||||
return limit - position;
|
return this.limit - this.position;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -220,7 +240,7 @@ public class ByteBuffer2 {
|
||||||
* the limit.
|
* the limit.
|
||||||
*/
|
*/
|
||||||
public final synchronized boolean hasRemaining() {
|
public final synchronized boolean hasRemaining() {
|
||||||
return position < limit;
|
return this.position < this.limit;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -228,11 +248,11 @@ public class ByteBuffer2 {
|
||||||
*/
|
*/
|
||||||
public final synchronized void limit(int limit) {
|
public final synchronized void limit(int limit) {
|
||||||
this.limit = limit;
|
this.limit = limit;
|
||||||
if (position > limit) {
|
if (this.position > limit) {
|
||||||
position = limit;
|
this.position = limit;
|
||||||
}
|
}
|
||||||
if (mark > limit) {
|
if (this.mark > limit) {
|
||||||
mark = -1;
|
this.mark = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -240,14 +260,14 @@ public class ByteBuffer2 {
|
||||||
* Returns this buffer's limit.
|
* Returns this buffer's limit.
|
||||||
*/
|
*/
|
||||||
public int limit() {
|
public int limit() {
|
||||||
return limit;
|
return this.limit;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns this buffer's capacity.
|
* Returns this buffer's capacity.
|
||||||
*/
|
*/
|
||||||
public int capacity() {
|
public int capacity() {
|
||||||
return bytes.length;
|
return this.bytes.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -260,8 +280,8 @@ public class ByteBuffer2 {
|
||||||
* can be followed immediately by an invocation of another relative put method.
|
* can be followed immediately by an invocation of another relative put method.
|
||||||
*/
|
*/
|
||||||
public final synchronized void compact() {
|
public final synchronized void compact() {
|
||||||
mark = -1;
|
this.mark = -1;
|
||||||
System.arraycopy(bytes, position, bytes, 0, remaining());
|
System.arraycopy(this.bytes, this.position, this.bytes, 0, remaining());
|
||||||
|
|
||||||
position(remaining());
|
position(remaining());
|
||||||
limit(capacity());
|
limit(capacity());
|
||||||
|
@ -275,9 +295,9 @@ public class ByteBuffer2 {
|
||||||
* discarded.
|
* discarded.
|
||||||
*/
|
*/
|
||||||
public final synchronized void flip() {
|
public final synchronized void flip() {
|
||||||
limit = position;
|
this.limit = this.position;
|
||||||
position = 0;
|
this.position = 0;
|
||||||
mark = -1;
|
this.mark = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -285,9 +305,9 @@ public class ByteBuffer2 {
|
||||||
* the capacity, and the mark is discarded.
|
* the capacity, and the mark is discarded.
|
||||||
*/
|
*/
|
||||||
public final synchronized void clear() {
|
public final synchronized void clear() {
|
||||||
position = 0;
|
this.position = 0;
|
||||||
limit = capacity();
|
this.limit = capacity();
|
||||||
mark = -1;
|
this.mark = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -295,15 +315,15 @@ public class ByteBuffer2 {
|
||||||
* discarded.
|
* discarded.
|
||||||
*/
|
*/
|
||||||
public final synchronized void rewind() {
|
public final synchronized void rewind() {
|
||||||
position = 0;
|
this.position = 0;
|
||||||
mark = -1;
|
this.mark = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets this buffer's mark at its position.
|
* Sets this buffer's mark at its position.
|
||||||
*/
|
*/
|
||||||
public final synchronized void mark() {
|
public final synchronized void mark() {
|
||||||
mark = position;
|
this.mark = this.position;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -313,6 +333,6 @@ public class ByteBuffer2 {
|
||||||
* value. </p>
|
* value. </p>
|
||||||
*/
|
*/
|
||||||
public void reset() {
|
public void reset() {
|
||||||
position = mark;
|
this.position = this.mark;
|
||||||
}
|
}
|
||||||
}
|
}
|
338
Dorkbox-Util/src/dorkbox/util/bytes/ByteBuffer2Fast.java
Normal file
338
Dorkbox-Util/src/dorkbox/util/bytes/ByteBuffer2Fast.java
Normal file
|
@ -0,0 +1,338 @@
|
||||||
|
package dorkbox.util.bytes;
|
||||||
|
|
||||||
|
import java.nio.BufferUnderflowException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cleanroom implementation of a self-growing bytebuffer. NOT SYNCHRONIZED!
|
||||||
|
*/
|
||||||
|
public class ByteBuffer2Fast {
|
||||||
|
|
||||||
|
private byte[] bytes;
|
||||||
|
|
||||||
|
private int position = 0;
|
||||||
|
private int mark = -1;
|
||||||
|
private int limit = 0;
|
||||||
|
|
||||||
|
public static ByteBuffer2Fast wrap(byte[] buffer) {
|
||||||
|
return new ByteBuffer2Fast(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ByteBuffer2Fast allocate(int capacity) {
|
||||||
|
ByteBuffer2Fast byteBuffer2 = new ByteBuffer2Fast(new byte[capacity]);
|
||||||
|
byteBuffer2.clear();
|
||||||
|
return byteBuffer2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ByteBuffer2Fast() {
|
||||||
|
this(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ByteBuffer2Fast(int size) {
|
||||||
|
this(new byte[size]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ByteBuffer2Fast(byte[] bytes) {
|
||||||
|
this.bytes = bytes;
|
||||||
|
clear();
|
||||||
|
this.position = bytes.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getByte() {
|
||||||
|
if (this.position > this.limit) {
|
||||||
|
throw new BufferUnderflowException();
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.bytes[this.position++];
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getByte(int i) {
|
||||||
|
if (i > this.limit) {
|
||||||
|
throw new BufferUnderflowException();
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.bytes[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
public void getBytes(byte[] buffer) {
|
||||||
|
getBytes(buffer, 0, buffer.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void getBytes(byte[] buffer, int length) {
|
||||||
|
getBytes(buffer, 0, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void getBytes(byte[] buffer, int offset, int length) {
|
||||||
|
if (this.position + length - offset > this.limit) {
|
||||||
|
throw new BufferUnderflowException();
|
||||||
|
}
|
||||||
|
|
||||||
|
System.arraycopy(this.bytes, this.position, buffer, 0, length-offset);
|
||||||
|
this.position += length-offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MUST call checkBuffer before calling this!
|
||||||
|
*
|
||||||
|
* NOT PROTECTED
|
||||||
|
*/
|
||||||
|
private final void _put(byte b) {
|
||||||
|
this.bytes[this.position++] = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** NOT PROTECTED! */
|
||||||
|
private final void checkBuffer(int threshold) {
|
||||||
|
if (this.bytes.length < threshold) {
|
||||||
|
byte[] t = new byte[threshold];
|
||||||
|
// grow at back of array
|
||||||
|
System.arraycopy(this.bytes, 0, t, 0, this.bytes.length);
|
||||||
|
this.limit = t.length;
|
||||||
|
|
||||||
|
this.bytes = t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void put(ByteBuffer2Fast buffer) {
|
||||||
|
putBytes(buffer.array(), buffer.position, buffer.limit);
|
||||||
|
buffer.position = buffer.limit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final ByteBuffer2Fast putBytes(byte[] src) {
|
||||||
|
return putBytes(src, 0, src.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final ByteBuffer2Fast putBytes(byte[] src, int offset, int length) {
|
||||||
|
checkBuffer(this.position + length - offset);
|
||||||
|
|
||||||
|
System.arraycopy(src, offset, this.bytes, this.position, length);
|
||||||
|
this.position += length;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final ByteBuffer2Fast putByte(byte b) {
|
||||||
|
checkBuffer(this.position + 1);
|
||||||
|
|
||||||
|
_put(b);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void putByte(int position, byte b) {
|
||||||
|
this.position = position;
|
||||||
|
putByte(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void putChar(char c) {
|
||||||
|
checkBuffer(this.position + 2);
|
||||||
|
|
||||||
|
putBytes(BigEndian.Char_.toBytes(c));
|
||||||
|
}
|
||||||
|
|
||||||
|
public final char getChar() {
|
||||||
|
return BigEndian.Char_.fromBytes(getByte(), getByte());
|
||||||
|
}
|
||||||
|
|
||||||
|
public final char getChar(int i) {
|
||||||
|
return BigEndian.Char_.fromBytes(getByte(i++), getByte(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void getChars(int srcStart, int srcLength, char[] dest, int destStart) {
|
||||||
|
for (int i=srcStart;i<srcLength;i+=2) {
|
||||||
|
char c = BigEndian.Char_.fromBytes(getByte(i), getByte(i+1));
|
||||||
|
dest[destStart++] = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public final ByteBuffer2Fast putShort(short x) {
|
||||||
|
checkBuffer(this.position + 2);
|
||||||
|
|
||||||
|
putBytes(BigEndian.Short_.toBytes(x));
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final short getShort() {
|
||||||
|
return BigEndian.Short_.fromBytes(getByte(), getByte());
|
||||||
|
}
|
||||||
|
|
||||||
|
public final short getShort(int i) {
|
||||||
|
return BigEndian.Short_.fromBytes(getByte(i++), getByte(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void putInt(int x) {
|
||||||
|
checkBuffer(this.position + 4);
|
||||||
|
|
||||||
|
putBytes(BigEndian.Int_.toBytes(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
public final int getInt() {
|
||||||
|
return BigEndian.Int_.fromBytes(getByte(), getByte(), getByte(), getByte());
|
||||||
|
}
|
||||||
|
|
||||||
|
public final int getInt(int i) {
|
||||||
|
return BigEndian.Int_.fromBytes(getByte(i++), getByte(i++), getByte(i++), getByte(i++));
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void putLong(long x) {
|
||||||
|
checkBuffer(this.position + 8);
|
||||||
|
|
||||||
|
putBytes(BigEndian.Long_.toBytes(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
public final long getLong() {
|
||||||
|
return BigEndian.Long_.fromBytes(getByte(), getByte(), getByte(), getByte(), getByte(), getByte(), getByte(), getByte());
|
||||||
|
}
|
||||||
|
|
||||||
|
public final long getLong(int i) {
|
||||||
|
return BigEndian.Long_.fromBytes(getByte(i++), getByte(i++), getByte(i++), getByte(i++), getByte(i++), getByte(i++), getByte(i++), getByte(i++));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the backing array of this buffer
|
||||||
|
*/
|
||||||
|
public byte[] array() {
|
||||||
|
return this.bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a copy of the backing array of this buffer
|
||||||
|
*/
|
||||||
|
public final byte[] arrayCopy() {
|
||||||
|
int length = this.bytes.length - this.position;
|
||||||
|
|
||||||
|
byte[] b = new byte[length];
|
||||||
|
System.arraycopy(this.bytes, this.position, b, 0, length);
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns this buffer's position.
|
||||||
|
*/
|
||||||
|
public int position() {
|
||||||
|
return this.position;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets this buffer's position.
|
||||||
|
*/
|
||||||
|
public final ByteBuffer2Fast position(int position) {
|
||||||
|
if (position > this.bytes.length || position < 0) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.position = position;
|
||||||
|
if (this.mark > position) {
|
||||||
|
this.mark = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of elements between the current position and the
|
||||||
|
* limit.
|
||||||
|
*/
|
||||||
|
public final int remaining() {
|
||||||
|
return this.limit - this.position;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tells whether there are any elements between the current position and
|
||||||
|
* the limit.
|
||||||
|
*/
|
||||||
|
public final boolean hasRemaining() {
|
||||||
|
return this.position < this.limit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets this buffer's limit.
|
||||||
|
*/
|
||||||
|
public final void limit(int limit) {
|
||||||
|
this.limit = limit;
|
||||||
|
if (this.position > limit) {
|
||||||
|
this.position = limit;
|
||||||
|
}
|
||||||
|
if (this.mark > limit) {
|
||||||
|
this.mark = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns this buffer's limit.
|
||||||
|
*/
|
||||||
|
public int limit() {
|
||||||
|
return this.limit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns this buffer's capacity.
|
||||||
|
*/
|
||||||
|
public int capacity() {
|
||||||
|
return this.bytes.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The bytes between the buffer's current position and its limit, if any, are copied to the beginning of the buffer.
|
||||||
|
* That is, the byte at index p = position() is copied to index zero, the byte at index p + 1 is copied to index one,
|
||||||
|
* and so forth until the byte at index limit() - 1 is copied to index n = limit() - 1 - p. The buffer's position is
|
||||||
|
* then set to n+1 and its limit is set to its capacity. The mark, if defined, is discarded.
|
||||||
|
*
|
||||||
|
* The buffer's position is set to the number of bytes copied, rather than to zero, so that an invocation of this method
|
||||||
|
* can be followed immediately by an invocation of another relative put method.
|
||||||
|
*/
|
||||||
|
public final void compact() {
|
||||||
|
this.mark = -1;
|
||||||
|
System.arraycopy(this.bytes, this.position, this.bytes, 0, remaining());
|
||||||
|
|
||||||
|
position(remaining());
|
||||||
|
limit(capacity());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Readies the buffer for reading.
|
||||||
|
*
|
||||||
|
* Flips this buffer. The limit is set to the current position and then
|
||||||
|
* the position is set to zero. If the mark is defined then it is
|
||||||
|
* discarded.
|
||||||
|
*/
|
||||||
|
public final void flip() {
|
||||||
|
this.limit = this.position;
|
||||||
|
this.position = 0;
|
||||||
|
this.mark = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears this buffer. The position is set to zero, the limit is set to
|
||||||
|
* the capacity, and the mark is discarded.
|
||||||
|
*/
|
||||||
|
public final void clear() {
|
||||||
|
this.position = 0;
|
||||||
|
this.limit = capacity();
|
||||||
|
this.mark = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rewinds this buffer. The position is set to zero and the mark is
|
||||||
|
* discarded.
|
||||||
|
*/
|
||||||
|
public final void rewind() {
|
||||||
|
this.position = 0;
|
||||||
|
this.mark = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets this buffer's mark at its position.
|
||||||
|
*/
|
||||||
|
public final void mark() {
|
||||||
|
this.mark = this.position;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets this buffer's position to the previously-marked position.
|
||||||
|
*
|
||||||
|
* <p> Invoking this method neither changes nor discards the mark's
|
||||||
|
* value. </p>
|
||||||
|
*/
|
||||||
|
public void reset() {
|
||||||
|
this.position = this.mark;
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,18 +5,21 @@ import java.io.BufferedReader;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.io.PrintStream;
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.security.CodeSource;
|
import java.security.CodeSource;
|
||||||
import java.security.ProtectionDomain;
|
import java.security.ProtectionDomain;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
|
||||||
import org.fusesource.jansi.Ansi;
|
import org.fusesource.jansi.Ansi;
|
||||||
import org.fusesource.jansi.AnsiConsole;
|
import org.fusesource.jansi.AnsiConsole;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
import dorkbox.util.OS;
|
import dorkbox.util.OS;
|
||||||
|
import dorkbox.util.Sys;
|
||||||
|
import dorkbox.util.bytes.ByteBuffer2Fast;
|
||||||
import dorkbox.util.input.posix.UnixTerminal;
|
import dorkbox.util.input.posix.UnixTerminal;
|
||||||
import dorkbox.util.input.unsupported.UnsupportedTerminal;
|
import dorkbox.util.input.unsupported.UnsupportedTerminal;
|
||||||
import dorkbox.util.input.windows.WindowsTerminal;
|
import dorkbox.util.input.windows.WindowsTerminal;
|
||||||
|
@ -36,20 +39,31 @@ public class InputConsole {
|
||||||
{
|
{
|
||||||
AnsiConsole.systemInstall();
|
AnsiConsole.systemInstall();
|
||||||
|
|
||||||
|
Thread consoleThread = new Thread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
consoleProxyReader.run();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
consoleThread.setDaemon(true);
|
||||||
|
consoleThread.setName("Console Input Reader");
|
||||||
|
|
||||||
|
consoleThread.start();
|
||||||
|
|
||||||
|
// has to be NOT DAEMON thread, since it must run before the app closes.
|
||||||
|
|
||||||
// don't forget we have to shut down the ansi console as well
|
// don't forget we have to shut down the ansi console as well
|
||||||
// alternatively, shut everything down when the JVM closes.
|
// alternatively, shut everything down when the JVM closes.
|
||||||
Runtime.getRuntime().addShutdownHook(new Thread() {
|
Thread shutdownThread = new Thread() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
AnsiConsole.systemUninstall();
|
AnsiConsole.systemUninstall();
|
||||||
InputConsole.destroy();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// called by our shutdown thread
|
consoleProxyReader.shutdown0();
|
||||||
private static final void destroy() {
|
}
|
||||||
consoleProxyReader.destroy0();
|
};
|
||||||
|
shutdownThread.setName("Console Input Shutdown");
|
||||||
|
Runtime.getRuntime().addShutdownHook(shutdownThread);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** return null if no data */
|
/** return null if no data */
|
||||||
|
@ -94,9 +108,17 @@ public class InputConsole {
|
||||||
private final Object inputLockSingle = new Object();
|
private final Object inputLockSingle = new Object();
|
||||||
private final Object inputLockLine = new Object();
|
private final Object inputLockLine = new Object();
|
||||||
|
|
||||||
private AtomicBoolean isRunning = new AtomicBoolean(false);
|
private ThreadLocal<ByteBuffer2Fast> threadBufferForRead = new ThreadLocal<ByteBuffer2Fast>();
|
||||||
private AtomicBoolean isInShutdown = new AtomicBoolean(false);
|
private CopyOnWriteArrayList<ByteBuffer2Fast> threadBuffersForRead = new CopyOnWriteArrayList<ByteBuffer2Fast>();
|
||||||
private volatile char[] readLine = null;
|
|
||||||
|
ThreadLocal<Integer> indexOfStringForReadChar = new ThreadLocal<Integer>() {
|
||||||
|
@Override
|
||||||
|
protected Integer initialValue() {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
private volatile int readChar = -1;
|
private volatile int readChar = -1;
|
||||||
|
|
||||||
private final boolean unsupported;
|
private final boolean unsupported;
|
||||||
|
@ -119,7 +141,7 @@ public class InputConsole {
|
||||||
|
|
||||||
logger.debug("Creating terminal; type={}", type);
|
logger.debug("Creating terminal; type={}", type);
|
||||||
|
|
||||||
Terminal t;
|
Terminal t;
|
||||||
try {
|
try {
|
||||||
if (type.equals(TerminalType.UNIX)) {
|
if (type.equals(TerminalType.UNIX)) {
|
||||||
t = new UnixTerminal();
|
t = new UnixTerminal();
|
||||||
|
@ -182,36 +204,8 @@ public class InputConsole {
|
||||||
logger.debug("Created Terminal: {}", this.terminal);
|
logger.debug("Created Terminal: {}", this.terminal);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// called when the JVM is shutting down.
|
||||||
* make sure the input console reader thread is started.
|
private void shutdown0() {
|
||||||
*/
|
|
||||||
private void startInputConsole() {
|
|
||||||
// protected by atomic!
|
|
||||||
if (!this.isRunning.compareAndSet(false, true) || this.isInShutdown.get()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Thread consoleThread = new Thread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
consoleProxyReader.run();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
consoleThread.setDaemon(true);
|
|
||||||
consoleThread.setName("Console Input Reader");
|
|
||||||
|
|
||||||
consoleThread.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void destroy0() {
|
|
||||||
// Don't change this, because we don't want to enable reading, etc from this once it's destroyed.
|
|
||||||
// so we pretend that it's still running
|
|
||||||
// isRunning.set(false);
|
|
||||||
|
|
||||||
if (this.isInShutdown.compareAndSet(true, true)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
synchronized (this.inputLockSingle) {
|
synchronized (this.inputLockSingle) {
|
||||||
this.inputLockSingle.notifyAll();
|
this.inputLockSingle.notifyAll();
|
||||||
}
|
}
|
||||||
|
@ -224,7 +218,8 @@ public class InputConsole {
|
||||||
InputConsole inputConsole = InputConsole.this;
|
InputConsole inputConsole = InputConsole.this;
|
||||||
|
|
||||||
inputConsole.terminal.restore();
|
inputConsole.terminal.restore();
|
||||||
inputConsole.reader.close();
|
// this will 'hang' our shutdown, and honestly, who cares? We're shutting down anyways.
|
||||||
|
// inputConsole.reader.close(); // hangs on shutdown
|
||||||
} catch (IOException ignored) {
|
} catch (IOException ignored) {
|
||||||
ignored.printStackTrace();
|
ignored.printStackTrace();
|
||||||
}
|
}
|
||||||
|
@ -241,7 +236,11 @@ public class InputConsole {
|
||||||
|
|
||||||
/** return null if no data */
|
/** return null if no data */
|
||||||
private final char[] readLine0() {
|
private final char[] readLine0() {
|
||||||
startInputConsole();
|
if (this.threadBufferForRead.get() == null) {
|
||||||
|
ByteBuffer2Fast buffer = ByteBuffer2Fast.allocate(0);
|
||||||
|
this.threadBufferForRead.set(buffer);
|
||||||
|
this.threadBuffersForRead.add(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
synchronized (this.inputLockLine) {
|
synchronized (this.inputLockLine) {
|
||||||
try {
|
try {
|
||||||
|
@ -250,34 +249,53 @@ public class InputConsole {
|
||||||
return emptyLine;
|
return emptyLine;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return this.readLine;
|
|
||||||
|
ByteBuffer2Fast stringBuffer = this.threadBufferForRead.get();
|
||||||
|
int len = stringBuffer.position();
|
||||||
|
if (len == 0) {
|
||||||
|
return emptyLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
char[] chars = new char[len/2]; // because 2 chars is 1 bytes
|
||||||
|
stringBuffer.getChars(0, len, chars, 0);
|
||||||
|
|
||||||
|
// dump the chars in the buffer (safer for passwords, etc)
|
||||||
|
stringBuffer.clear();
|
||||||
|
stringBuffer.putBytes(new byte[0]);
|
||||||
|
|
||||||
|
this.threadBufferForRead.set(null);
|
||||||
|
this.threadBuffersForRead.remove(stringBuffer); // TODO: use object pool!
|
||||||
|
|
||||||
|
return chars;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** return null if no data */
|
/** return null if no data */
|
||||||
private final char[] readLinePassword0() {
|
private final char[] readLinePassword0() {
|
||||||
// don't bother in an IDE. it won't work.
|
if (this.threadBufferForRead.get() == null) {
|
||||||
return readLine0();
|
ByteBuffer2Fast buffer = ByteBuffer2Fast.allocate(0);
|
||||||
}
|
this.threadBufferForRead.set(buffer);
|
||||||
|
this.threadBuffersForRead.add(buffer);
|
||||||
ThreadLocal<Integer> indexOfStringForReadChar = new ThreadLocal<Integer>() {
|
|
||||||
@Override
|
|
||||||
protected Integer initialValue() {
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
// don't bother in an IDE. it won't work.
|
||||||
|
boolean echoEnabled = this.terminal.isEchoEnabled();
|
||||||
|
this.terminal.setEchoEnabled(false);
|
||||||
|
char[] readLine0 = readLine0();
|
||||||
|
this.terminal.setEchoEnabled(echoEnabled);
|
||||||
|
|
||||||
|
return readLine0;
|
||||||
|
}
|
||||||
|
|
||||||
/** return -1 if no data */
|
/** return -1 if no data */
|
||||||
private final int read0() {
|
private final int read0() {
|
||||||
startInputConsole();
|
|
||||||
|
|
||||||
// if we are reading data (because we are in IDE mode), we want to return ALL
|
// if we are reading data (because we are in IDE mode), we want to return ALL
|
||||||
// the chars of the line!
|
// the chars of the line!
|
||||||
|
|
||||||
// so, readChar is REALLY the index at which we return letters (until the whole string is returned
|
// so, readChar is REALLY the index at which we return letters (until the whole string is returned
|
||||||
if (this.unsupported) {
|
if (this.unsupported) {
|
||||||
int integer = this.indexOfStringForReadChar.get();
|
int readerCount = this.indexOfStringForReadChar.get();
|
||||||
|
|
||||||
if (integer == -1) {
|
if (readerCount == -1) {
|
||||||
// we have to wait for more data.
|
// we have to wait for more data.
|
||||||
synchronized (this.inputLockLine) {
|
synchronized (this.inputLockLine) {
|
||||||
try {
|
try {
|
||||||
|
@ -285,24 +303,23 @@ public class InputConsole {
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
integer = 0;
|
readerCount = 0;
|
||||||
this.indexOfStringForReadChar.set(0);
|
this.indexOfStringForReadChar.set(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// EACH thread will have it's own count!
|
|
||||||
char[] readLine2 = this.readLine;
|
|
||||||
|
|
||||||
if (readLine2 == null) {
|
// EACH thread will have it's own count!
|
||||||
return -1;
|
ByteBuffer2Fast stringBuffer = this.threadBufferForRead.get();
|
||||||
} else if (integer == readLine2.length) {
|
|
||||||
|
if (readerCount == stringBuffer.position()) {
|
||||||
this.indexOfStringForReadChar.set(-1);
|
this.indexOfStringForReadChar.set(-1);
|
||||||
return '\n';
|
return '\n';
|
||||||
} else {
|
} else {
|
||||||
this.indexOfStringForReadChar.set(integer+1);
|
this.indexOfStringForReadChar.set(readerCount+1);
|
||||||
}
|
}
|
||||||
|
|
||||||
char c = readLine2[integer];
|
char c = stringBuffer.getChar(readerCount);
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -339,19 +356,30 @@ public class InputConsole {
|
||||||
// it just waits until \n until it triggers
|
// it just waits until \n until it triggers
|
||||||
if (this.unsupported) {
|
if (this.unsupported) {
|
||||||
BufferedReader reader = (BufferedReader) this.reader;
|
BufferedReader reader = (BufferedReader) this.reader;
|
||||||
|
String line = null;
|
||||||
|
char[] readLine = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
while ((this.readLine = reader.readLine().toCharArray()) != null) {
|
while ((line = reader.readLine()) != null) {
|
||||||
|
readLine = line.toCharArray();
|
||||||
|
|
||||||
// notify everyone waiting for a line of text.
|
// notify everyone waiting for a line of text.
|
||||||
synchronized (this.inputLockSingle) {
|
synchronized (this.inputLockSingle) {
|
||||||
if (this.readLine.length > 0) {
|
if (readLine.length > 0) {
|
||||||
this.readChar = this.readLine[0];
|
this.readChar = readLine[0];
|
||||||
} else {
|
} else {
|
||||||
this.readChar = -1;
|
this.readChar = -1;
|
||||||
}
|
}
|
||||||
this.inputLockSingle.notifyAll();
|
this.inputLockSingle.notifyAll();
|
||||||
}
|
}
|
||||||
synchronized (this.inputLockLine) {
|
synchronized (this.inputLockLine) {
|
||||||
|
byte[] charToBytes = Sys.charToBytes(readLine);
|
||||||
|
|
||||||
|
for (ByteBuffer2Fast buffer : this.threadBuffersForRead) {
|
||||||
|
buffer.clear();
|
||||||
|
buffer.putBytes(charToBytes);
|
||||||
|
}
|
||||||
|
|
||||||
this.inputLockLine.notifyAll();
|
this.inputLockLine.notifyAll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -360,12 +388,13 @@ public class InputConsole {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
// from a 'regular' console
|
||||||
try {
|
try {
|
||||||
final boolean ansiEnabled = Ansi.isEnabled();
|
final boolean ansiEnabled = Ansi.isEnabled();
|
||||||
Ansi ansi = Ansi.ansi();
|
Ansi ansi = Ansi.ansi();
|
||||||
|
PrintStream out = AnsiConsole.out;
|
||||||
|
|
||||||
int typedChar;
|
int typedChar;
|
||||||
StringBuilder buf = new StringBuilder();
|
|
||||||
|
|
||||||
// don't type ; in a bash shell, it quits everything
|
// don't type ; in a bash shell, it quits everything
|
||||||
// \n is replaced by \r in unix terminal?
|
// \n is replaced by \r in unix terminal?
|
||||||
|
@ -388,65 +417,57 @@ public class InputConsole {
|
||||||
|
|
||||||
// clear ourself + one extra.
|
// clear ourself + one extra.
|
||||||
if (ansiEnabled) {
|
if (ansiEnabled) {
|
||||||
// size of the buffer BEFORE our backspace was typed
|
for (ByteBuffer2Fast buffer : this.threadBuffersForRead) {
|
||||||
int length = buf.length();
|
// size of the buffer BEFORE our backspace was typed
|
||||||
int amtToOverwrite = 2; // backspace is always 2 chars (^?)
|
int length = buffer.position();
|
||||||
|
int amtToOverwrite = 2 * 2; // backspace is always 2 chars (^?) * 2 because it's bytes
|
||||||
|
|
||||||
if (length > 1) {
|
if (length > 1) {
|
||||||
char charAt = buf.charAt(length-1);
|
char charAt = buffer.getChar(length-2);
|
||||||
amtToOverwrite += getPrintableCharacters(charAt);
|
amtToOverwrite += getPrintableCharacters(charAt);
|
||||||
|
|
||||||
// delete last item in our buffer
|
// delete last item in our buffer
|
||||||
buf.setLength(--length);
|
length -= 2;
|
||||||
|
buffer.position(length);
|
||||||
|
|
||||||
// now figure out where the cursor is really at.
|
// now figure out where the cursor is really at.
|
||||||
// this is more memory friendly than buf.toString.length
|
// this is more memory friendly than buf.toString.length
|
||||||
for (int i=0;i<length;i++) {
|
for (int i=0;i<length;i+=2) {
|
||||||
charAt = buf.charAt(i);
|
charAt = buffer.getChar(i);
|
||||||
position += getPrintableCharacters(charAt);
|
position += getPrintableCharacters(charAt);
|
||||||
|
}
|
||||||
|
|
||||||
|
position++;
|
||||||
}
|
}
|
||||||
position++;
|
|
||||||
}
|
|
||||||
|
|
||||||
char[] overwrite = new char[amtToOverwrite];
|
char[] overwrite = new char[amtToOverwrite];
|
||||||
char c = ' ';
|
char c = ' ';
|
||||||
for (int i=0;i<amtToOverwrite;i++) {
|
for (int i=0;i<amtToOverwrite;i++) {
|
||||||
overwrite[i] = c;
|
overwrite[i] = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
// move back however many, over write, then go back again
|
// move back however many, over write, then go back again
|
||||||
AnsiConsole.out.print(ansi.cursorToColumn(position));
|
out.print(ansi.cursorToColumn(position));
|
||||||
AnsiConsole.out.print(overwrite);
|
out.print(overwrite);
|
||||||
AnsiConsole.out.print(ansi.cursorToColumn(position));
|
out.print(ansi.cursorToColumn(position));
|
||||||
AnsiConsole.out.flush();
|
out.flush();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// readline will ignore backspace
|
// read-line will ignore backspace
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ignoring \r, because \n is ALWAYS the last character in a new line sequence. (even for windows)
|
// ignoring \r, because \n is ALWAYS the last character in a new line sequence. (even for windows)
|
||||||
if (asChar == '\n') {
|
if (asChar == '\n') {
|
||||||
int length = buf.length();
|
|
||||||
|
|
||||||
synchronized (this.inputLockLine) {
|
synchronized (this.inputLockLine) {
|
||||||
if (length > 0) {
|
|
||||||
this.readLine = new char[length];
|
|
||||||
buf.getChars(0, length, this.readLine, 0);
|
|
||||||
} else {
|
|
||||||
this.readLine = emptyLine;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.inputLockLine.notifyAll();
|
this.inputLockLine.notifyAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
// dump the characters in the backing array (slightly safer for passwords when using this method)
|
|
||||||
if (length > 0) {
|
|
||||||
buf.delete(0, buf.length());
|
|
||||||
}
|
|
||||||
} else if (asChar != '\r') {
|
} else if (asChar != '\r') {
|
||||||
// only append if we are not a new line.
|
// only append if we are not a new line.
|
||||||
buf.append(asChar);
|
for (ByteBuffer2Fast buffer : this.threadBuffersForRead) {
|
||||||
|
buffer.putChar(asChar);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (IOException ignored) {
|
} catch (IOException ignored) {
|
||||||
|
@ -455,11 +476,11 @@ public class InputConsole {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
+ * Get the default encoding. Will first look at the LC_CTYPE environment variable, then the input.encoding
|
* Get the default encoding. Will first look at the LC_CTYPE environment variable, then the input.encoding
|
||||||
+ * system property, then the default charset according to the JVM.
|
* system property, then the default charset according to the JVM.
|
||||||
+ *
|
*
|
||||||
+ * @return The default encoding to use when none is specified.
|
* @return The default encoding to use when none is specified.
|
||||||
+ */
|
*/
|
||||||
public static String getEncoding() {
|
public static String getEncoding() {
|
||||||
// LC_CTYPE is usually in the form en_US.UTF-8
|
// LC_CTYPE is usually in the form en_US.UTF-8
|
||||||
String envEncoding = extractEncodingFromCtype(System.getenv("LC_CTYPE"));
|
String envEncoding = extractEncodingFromCtype(System.getenv("LC_CTYPE"));
|
||||||
|
@ -481,9 +502,8 @@ public class InputConsole {
|
||||||
String encodingAndModifier = ctype.substring(ctype.indexOf('.') + 1);
|
String encodingAndModifier = ctype.substring(ctype.indexOf('.') + 1);
|
||||||
if (encodingAndModifier.indexOf('@') > 0) {
|
if (encodingAndModifier.indexOf('@') > 0) {
|
||||||
return encodingAndModifier.substring(0, encodingAndModifier.indexOf('@'));
|
return encodingAndModifier.substring(0, encodingAndModifier.indexOf('@'));
|
||||||
} else {
|
|
||||||
return encodingAndModifier;
|
|
||||||
}
|
}
|
||||||
|
return encodingAndModifier;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,6 @@ public class WindowsTerminal extends Terminal
|
||||||
public void init() throws IOException {
|
public void init() throws IOException {
|
||||||
this.originalMode = WindowsSupport.getConsoleMode();
|
this.originalMode = WindowsSupport.getConsoleMode();
|
||||||
WindowsSupport.setConsoleMode(this.originalMode & ~ConsoleMode.ENABLE_ECHO_INPUT.code);
|
WindowsSupport.setConsoleMode(this.originalMode & ~ConsoleMode.ENABLE_ECHO_INPUT.code);
|
||||||
setEchoEnabled(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue
Block a user