--- a/.hgtags-top-repo Thu Jul 09 13:49:32 2015 -0700
+++ b/.hgtags-top-repo Wed Jul 05 20:41:12 2017 +0200
@@ -314,3 +314,4 @@
1bcfd6b8726582cff5a42dbfc75903e36f9dd4fe jdk9-b69
eed77fcd77711fcdba05f18fc22f37d86efb243c jdk9-b70
c706ef5ea5da00078dc5e4334660315f7d99c15b jdk9-b71
+8582c35016fb6211b373810b6b172feccf9c483b jdk9-b72
--- a/hotspot/.hgtags Thu Jul 09 13:49:32 2015 -0700
+++ b/hotspot/.hgtags Wed Jul 05 20:41:12 2017 +0200
@@ -474,3 +474,4 @@
ff0929a59ced0e144201aa05819ae2e47d6f2c61 jdk9-b69
8672e9264db30c21504063932dbc374eabc287a1 jdk9-b70
07c6b035d68b0c41b1dcd442157b50b41a2551e9 jdk9-b71
+c1b2825ef47e75cb34dd18450d1c4280b7c5853c jdk9-b72
--- a/hotspot/src/cpu/aarch64/vm/aarch64.ad Thu Jul 09 13:49:32 2015 -0700
+++ b/hotspot/src/cpu/aarch64/vm/aarch64.ad Wed Jul 05 20:41:12 2017 +0200
@@ -865,6 +865,42 @@
V31, V31_H
);
+// Class for all 64bit vector registers
+reg_class vectord_reg(
+ V0, V0_H,
+ V1, V1_H,
+ V2, V2_H,
+ V3, V3_H,
+ V4, V4_H,
+ V5, V5_H,
+ V6, V6_H,
+ V7, V7_H,
+ V8, V8_H,
+ V9, V9_H,
+ V10, V10_H,
+ V11, V11_H,
+ V12, V12_H,
+ V13, V13_H,
+ V14, V14_H,
+ V15, V15_H,
+ V16, V16_H,
+ V17, V17_H,
+ V18, V18_H,
+ V19, V19_H,
+ V20, V20_H,
+ V21, V21_H,
+ V22, V22_H,
+ V23, V23_H,
+ V24, V24_H,
+ V25, V25_H,
+ V26, V26_H,
+ V27, V27_H,
+ V28, V28_H,
+ V29, V29_H,
+ V30, V30_H,
+ V31, V31_H
+);
+
// Class for all 128bit vector registers
reg_class vectorx_reg(
V0, V0_H, V0_J, V0_K,
@@ -2133,40 +2169,48 @@
if (bottom_type()->isa_vect() != NULL) {
uint len = 4;
+ uint ireg = ideal_reg();
+ assert(ireg == Op_VecD || ireg == Op_VecX, "must be 64 bit or 128 bit vector");
if (cbuf) {
MacroAssembler _masm(cbuf);
- uint ireg = ideal_reg();
assert((src_lo_rc != rc_int && dst_lo_rc != rc_int), "sanity");
- assert(ireg == Op_VecX, "sanity");
if (src_lo_rc == rc_stack && dst_lo_rc == rc_stack) {
// stack->stack
int src_offset = ra_->reg2offset(src_lo);
int dst_offset = ra_->reg2offset(dst_lo);
assert((src_offset & 7) && (dst_offset & 7), "unaligned stack offset");
len = 8;
- if (src_offset < 512) {
- __ ldp(rscratch1, rscratch2, Address(sp, src_offset));
- } else {
+ if (ireg == Op_VecD) {
__ ldr(rscratch1, Address(sp, src_offset));
- __ ldr(rscratch2, Address(sp, src_offset+4));
- len += 4;
- }
- if (dst_offset < 512) {
- __ stp(rscratch1, rscratch2, Address(sp, dst_offset));
+ __ str(rscratch1, Address(sp, dst_offset));
} else {
- __ str(rscratch1, Address(sp, dst_offset));
- __ str(rscratch2, Address(sp, dst_offset+4));
- len += 4;
+ if (src_offset < 512) {
+ __ ldp(rscratch1, rscratch2, Address(sp, src_offset));
+ } else {
+ __ ldr(rscratch1, Address(sp, src_offset));
+ __ ldr(rscratch2, Address(sp, src_offset+4));
+ len += 4;
+ }
+ if (dst_offset < 512) {
+ __ stp(rscratch1, rscratch2, Address(sp, dst_offset));
+ } else {
+ __ str(rscratch1, Address(sp, dst_offset));
+ __ str(rscratch2, Address(sp, dst_offset+4));
+ len += 4;
+ }
}
} else if (src_lo_rc == rc_float && dst_lo_rc == rc_float) {
- __ orr(as_FloatRegister(Matcher::_regEncode[dst_lo]), __ T16B,
+ __ orr(as_FloatRegister(Matcher::_regEncode[dst_lo]),
+ ireg == Op_VecD ? __ T8B : __ T16B,
as_FloatRegister(Matcher::_regEncode[src_lo]),
as_FloatRegister(Matcher::_regEncode[src_lo]));
} else if (src_lo_rc == rc_float && dst_lo_rc == rc_stack) {
- __ str(as_FloatRegister(Matcher::_regEncode[src_lo]), __ Q,
+ __ str(as_FloatRegister(Matcher::_regEncode[src_lo]),
+ ireg == Op_VecD ? __ D : __ Q,
Address(sp, ra_->reg2offset(dst_lo)));
} else if (src_lo_rc == rc_stack && dst_lo_rc == rc_float) {
- __ ldr(as_FloatRegister(Matcher::_regEncode[dst_lo]), __ Q,
+ __ ldr(as_FloatRegister(Matcher::_regEncode[dst_lo]),
+ ireg == Op_VecD ? __ D : __ Q,
Address(sp, ra_->reg2offset(src_lo)));
} else {
ShouldNotReachHere();
@@ -2176,17 +2220,22 @@
// stack->stack
int src_offset = ra_->reg2offset(src_lo);
int dst_offset = ra_->reg2offset(dst_lo);
- if (src_offset < 512) {
- st->print("ldp rscratch1, rscratch2, [sp, #%d]", src_offset);
- } else {
+ if (ireg == Op_VecD) {
st->print("ldr rscratch1, [sp, #%d]", src_offset);
- st->print("\nldr rscratch2, [sp, #%d]", src_offset+4);
- }
- if (dst_offset < 512) {
- st->print("\nstp rscratch1, rscratch2, [sp, #%d]", dst_offset);
+ st->print("str rscratch1, [sp, #%d]", dst_offset);
} else {
- st->print("\nstr rscratch1, [sp, #%d]", dst_offset);
- st->print("\nstr rscratch2, [sp, #%d]", dst_offset+4);
+ if (src_offset < 512) {
+ st->print("ldp rscratch1, rscratch2, [sp, #%d]", src_offset);
+ } else {
+ st->print("ldr rscratch1, [sp, #%d]", src_offset);
+ st->print("\nldr rscratch2, [sp, #%d]", src_offset+4);
+ }
+ if (dst_offset < 512) {
+ st->print("\nstp rscratch1, rscratch2, [sp, #%d]", dst_offset);
+ } else {
+ st->print("\nstr rscratch1, [sp, #%d]", dst_offset);
+ st->print("\nstr rscratch2, [sp, #%d]", dst_offset+4);
+ }
}
st->print("\t# vector spill, stack to stack");
} else if (src_lo_rc == rc_float && dst_lo_rc == rc_float) {
@@ -2638,17 +2687,22 @@
return vector_width_in_bytes(bt)/type2aelembytes(bt);
}
const int Matcher::min_vector_size(const BasicType bt) {
- //return (type2aelembytes(bt) == 1) ? 4 : 2;
- // For the moment, only support 1 vector size, 128 bits
- return max_vector_size(bt);
+// For the moment limit the vector size to 8 bytes
+ int size = 8 / type2aelembytes(bt);
+ if (size < 2) size = 2;
+ return size;
}
// Vector ideal reg.
const int Matcher::vector_ideal_reg(int len) {
- return Op_VecX;
+ switch(len) {
+ case 8: return Op_VecD;
+ case 16: return Op_VecX;
+ }
+ ShouldNotReachHere();
+ return 0;
}
-// Only lowest bits of xmm reg are used for vector shift count.
const int Matcher::vector_shift_count_ideal_reg(int size) {
return Op_VecX;
}
@@ -2660,9 +2714,7 @@
// x86 supports misaligned vectors store/load.
const bool Matcher::misaligned_vectors_ok() {
- // TODO fixme
- // return !AlignVector; // can be changed by flag
- return false;
+ return !AlignVector; // can be changed by flag
}
// false => size gets scaled to BytesPerLong, ok.
@@ -3073,13 +3125,13 @@
as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp);
%}
- enc_class aarch64_enc_ldrvS(vecX dst, memory mem) %{
+ enc_class aarch64_enc_ldrvS(vecD dst, memory mem) %{
FloatRegister dst_reg = as_FloatRegister($dst$$reg);
loadStore(MacroAssembler(&cbuf), &MacroAssembler::ldr, dst_reg, MacroAssembler::S,
$mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp);
%}
- enc_class aarch64_enc_ldrvD(vecX dst, memory mem) %{
+ enc_class aarch64_enc_ldrvD(vecD dst, memory mem) %{
FloatRegister dst_reg = as_FloatRegister($dst$$reg);
loadStore(MacroAssembler(&cbuf), &MacroAssembler::ldr, dst_reg, MacroAssembler::D,
$mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp);
@@ -3159,13 +3211,13 @@
as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp);
%}
- enc_class aarch64_enc_strvS(vecX src, memory mem) %{
+ enc_class aarch64_enc_strvS(vecD src, memory mem) %{
FloatRegister src_reg = as_FloatRegister($src$$reg);
loadStore(MacroAssembler(&cbuf), &MacroAssembler::str, src_reg, MacroAssembler::S,
$mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp);
%}
- enc_class aarch64_enc_strvD(vecX src, memory mem) %{
+ enc_class aarch64_enc_strvD(vecD src, memory mem) %{
FloatRegister src_reg = as_FloatRegister($src$$reg);
loadStore(MacroAssembler(&cbuf), &MacroAssembler::str, src_reg, MacroAssembler::D,
$mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp);
@@ -5187,6 +5239,16 @@
interface(REG_INTER);
%}
+operand vecD()
+%{
+ constraint(ALLOC_IN_RC(vectord_reg));
+ match(VecD);
+
+ op_cost(0);
+ format %{ %}
+ interface(REG_INTER);
+%}
+
operand vecX()
%{
constraint(ALLOC_IN_RC(vectorx_reg));
@@ -7402,6 +7464,96 @@
ins_pipe(ialu_reg);
%}
+//---------- Population Count Instructions -------------------------------------
+//
+
+instruct popCountI(iRegINoSp dst, iRegIorL2I src, vRegF tmp) %{
+ predicate(UsePopCountInstruction);
+ match(Set dst (PopCountI src));
+ effect(TEMP tmp);
+ ins_cost(INSN_COST * 13);
+
+ format %{ "movw $src, $src\n\t"
+ "mov $tmp, $src\t# vector (1D)\n\t"
+ "cnt $tmp, $tmp\t# vector (8B)\n\t"
+ "addv $tmp, $tmp\t# vector (8B)\n\t"
+ "mov $dst, $tmp\t# vector (1D)" %}
+ ins_encode %{
+ __ movw($src$$Register, $src$$Register); // ensure top 32 bits 0
+ __ mov($tmp$$FloatRegister, __ T1D, 0, $src$$Register);
+ __ cnt($tmp$$FloatRegister, __ T8B, $tmp$$FloatRegister);
+ __ addv($tmp$$FloatRegister, __ T8B, $tmp$$FloatRegister);
+ __ mov($dst$$Register, $tmp$$FloatRegister, __ T1D, 0);
+ %}
+
+ ins_pipe(pipe_class_default);
+%}
+
+instruct popCountI_mem(iRegINoSp dst, memory mem, vRegF tmp) %{
+ predicate(UsePopCountInstruction);
+ match(Set dst (PopCountI (LoadI mem)));
+ effect(TEMP tmp);
+ ins_cost(INSN_COST * 13);
+
+ format %{ "ldrs $tmp, $mem\n\t"
+ "cnt $tmp, $tmp\t# vector (8B)\n\t"
+ "addv $tmp, $tmp\t# vector (8B)\n\t"
+ "mov $dst, $tmp\t# vector (1D)" %}
+ ins_encode %{
+ FloatRegister tmp_reg = as_FloatRegister($tmp$$reg);
+ loadStore(MacroAssembler(&cbuf), &MacroAssembler::ldrs, tmp_reg, $mem->opcode(),
+ as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp);
+ __ cnt($tmp$$FloatRegister, __ T8B, $tmp$$FloatRegister);
+ __ addv($tmp$$FloatRegister, __ T8B, $tmp$$FloatRegister);
+ __ mov($dst$$Register, $tmp$$FloatRegister, __ T1D, 0);
+ %}
+
+ ins_pipe(pipe_class_default);
+%}
+
+// Note: Long.bitCount(long) returns an int.
+instruct popCountL(iRegINoSp dst, iRegL src, vRegD tmp) %{
+ predicate(UsePopCountInstruction);
+ match(Set dst (PopCountL src));
+ effect(TEMP tmp);
+ ins_cost(INSN_COST * 13);
+
+ format %{ "mov $tmp, $src\t# vector (1D)\n\t"
+ "cnt $tmp, $tmp\t# vector (8B)\n\t"
+ "addv $tmp, $tmp\t# vector (8B)\n\t"
+ "mov $dst, $tmp\t# vector (1D)" %}
+ ins_encode %{
+ __ mov($tmp$$FloatRegister, __ T1D, 0, $src$$Register);
+ __ cnt($tmp$$FloatRegister, __ T8B, $tmp$$FloatRegister);
+ __ addv($tmp$$FloatRegister, __ T8B, $tmp$$FloatRegister);
+ __ mov($dst$$Register, $tmp$$FloatRegister, __ T1D, 0);
+ %}
+
+ ins_pipe(pipe_class_default);
+%}
+
+instruct popCountL_mem(iRegINoSp dst, memory mem, vRegD tmp) %{
+ predicate(UsePopCountInstruction);
+ match(Set dst (PopCountL (LoadL mem)));
+ effect(TEMP tmp);
+ ins_cost(INSN_COST * 13);
+
+ format %{ "ldrd $tmp, $mem\n\t"
+ "cnt $tmp, $tmp\t# vector (8B)\n\t"
+ "addv $tmp, $tmp\t# vector (8B)\n\t"
+ "mov $dst, $tmp\t# vector (1D)" %}
+ ins_encode %{
+ FloatRegister tmp_reg = as_FloatRegister($tmp$$reg);
+ loadStore(MacroAssembler(&cbuf), &MacroAssembler::ldrd, tmp_reg, $mem->opcode(),
+ as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp);
+ __ cnt($tmp$$FloatRegister, __ T8B, $tmp$$FloatRegister);
+ __ addv($tmp$$FloatRegister, __ T8B, $tmp$$FloatRegister);
+ __ mov($dst$$Register, $tmp$$FloatRegister, __ T1D, 0);
+ %}
+
+ ins_pipe(pipe_class_default);
+%}
+
// ============================================================================
// MemBar Instruction
@@ -13194,7 +13346,7 @@
// ====================VECTOR INSTRUCTIONS=====================================
// Load vector (32 bits)
-instruct loadV4(vecX dst, vmem mem)
+instruct loadV4(vecD dst, vmem mem)
%{
predicate(n->as_LoadVector()->memory_size() == 4);
match(Set dst (LoadVector mem));
@@ -13205,7 +13357,7 @@
%}
// Load vector (64 bits)
-instruct loadV8(vecX dst, vmem mem)
+instruct loadV8(vecD dst, vmem mem)
%{
predicate(n->as_LoadVector()->memory_size() == 8);
match(Set dst (LoadVector mem));
@@ -13227,7 +13379,7 @@
%}
// Store Vector (32 bits)
-instruct storeV4(vecX src, vmem mem)
+instruct storeV4(vecD src, vmem mem)
%{
predicate(n->as_StoreVector()->memory_size() == 4);
match(Set mem (StoreVector mem src));
@@ -13238,7 +13390,7 @@
%}
// Store Vector (64 bits)
-instruct storeV8(vecX src, vmem mem)
+instruct storeV8(vecD src, vmem mem)
%{
predicate(n->as_StoreVector()->memory_size() == 8);
match(Set mem (StoreVector mem src));
@@ -13259,8 +13411,22 @@
ins_pipe(pipe_class_memory);
%}
+instruct replicate8B(vecD dst, iRegIorL2I src)
+%{
+ predicate(n->as_Vector()->length() == 4 ||
+ n->as_Vector()->length() == 8);
+ match(Set dst (ReplicateB src));
+ ins_cost(INSN_COST);
+ format %{ "dup $dst, $src\t# vector (8B)" %}
+ ins_encode %{
+ __ dup(as_FloatRegister($dst$$reg), __ T8B, as_Register($src$$reg));
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
instruct replicate16B(vecX dst, iRegIorL2I src)
%{
+ predicate(n->as_Vector()->length() == 16);
match(Set dst (ReplicateB src));
ins_cost(INSN_COST);
format %{ "dup $dst, $src\t# vector (16B)" %}
@@ -13270,8 +13436,22 @@
ins_pipe(pipe_class_default);
%}
+instruct replicate8B_imm(vecD dst, immI con)
+%{
+ predicate(n->as_Vector()->length() == 4 ||
+ n->as_Vector()->length() == 8);
+ match(Set dst (ReplicateB con));
+ ins_cost(INSN_COST);
+ format %{ "movi $dst, $con\t# vector(8B)" %}
+ ins_encode %{
+ __ mov(as_FloatRegister($dst$$reg), __ T8B, $con$$constant & 0xff);
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
instruct replicate16B_imm(vecX dst, immI con)
%{
+ predicate(n->as_Vector()->length() == 16);
match(Set dst (ReplicateB con));
ins_cost(INSN_COST);
format %{ "movi $dst, $con\t# vector(16B)" %}
@@ -13281,8 +13461,22 @@
ins_pipe(pipe_class_default);
%}
+instruct replicate4S(vecD dst, iRegIorL2I src)
+%{
+ predicate(n->as_Vector()->length() == 2 ||
+ n->as_Vector()->length() == 4);
+ match(Set dst (ReplicateS src));
+ ins_cost(INSN_COST);
+ format %{ "dup $dst, $src\t# vector (4S)" %}
+ ins_encode %{
+ __ dup(as_FloatRegister($dst$$reg), __ T4H, as_Register($src$$reg));
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
instruct replicate8S(vecX dst, iRegIorL2I src)
%{
+ predicate(n->as_Vector()->length() == 8);
match(Set dst (ReplicateS src));
ins_cost(INSN_COST);
format %{ "dup $dst, $src\t# vector (8S)" %}
@@ -13292,8 +13486,22 @@
ins_pipe(pipe_class_default);
%}
+instruct replicate4S_imm(vecD dst, immI con)
+%{
+ predicate(n->as_Vector()->length() == 2 ||
+ n->as_Vector()->length() == 4);
+ match(Set dst (ReplicateS con));
+ ins_cost(INSN_COST);
+ format %{ "movi $dst, $con\t# vector(4H)" %}
+ ins_encode %{
+ __ mov(as_FloatRegister($dst$$reg), __ T4H, $con$$constant & 0xffff);
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
instruct replicate8S_imm(vecX dst, immI con)
%{
+ predicate(n->as_Vector()->length() == 8);
match(Set dst (ReplicateS con));
ins_cost(INSN_COST);
format %{ "movi $dst, $con\t# vector(8H)" %}
@@ -13303,8 +13511,21 @@
ins_pipe(pipe_class_default);
%}
+instruct replicate2I(vecD dst, iRegIorL2I src)
+%{
+ predicate(n->as_Vector()->length() == 2);
+ match(Set dst (ReplicateI src));
+ ins_cost(INSN_COST);
+ format %{ "dup $dst, $src\t# vector (2I)" %}
+ ins_encode %{
+ __ dup(as_FloatRegister($dst$$reg), __ T2S, as_Register($src$$reg));
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
instruct replicate4I(vecX dst, iRegIorL2I src)
%{
+ predicate(n->as_Vector()->length() == 4);
match(Set dst (ReplicateI src));
ins_cost(INSN_COST);
format %{ "dup $dst, $src\t# vector (4I)" %}
@@ -13314,8 +13535,21 @@
ins_pipe(pipe_class_default);
%}
+instruct replicate2I_imm(vecD dst, immI con)
+%{
+ predicate(n->as_Vector()->length() == 2);
+ match(Set dst (ReplicateI con));
+ ins_cost(INSN_COST);
+ format %{ "movi $dst, $con\t# vector(2I)" %}
+ ins_encode %{
+ __ mov(as_FloatRegister($dst$$reg), __ T2S, $con$$constant);
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
instruct replicate4I_imm(vecX dst, immI con)
%{
+ predicate(n->as_Vector()->length() == 4);
match(Set dst (ReplicateI con));
ins_cost(INSN_COST);
format %{ "movi $dst, $con\t# vector(4I)" %}
@@ -13327,6 +13561,7 @@
instruct replicate2L(vecX dst, iRegL src)
%{
+ predicate(n->as_Vector()->length() == 2);
match(Set dst (ReplicateL src));
ins_cost(INSN_COST);
format %{ "dup $dst, $src\t# vector (2L)" %}
@@ -13338,6 +13573,7 @@
instruct replicate2L_zero(vecX dst, immI0 zero)
%{
+ predicate(n->as_Vector()->length() == 2);
match(Set dst (ReplicateI zero));
ins_cost(INSN_COST);
format %{ "movi $dst, $zero\t# vector(4I)" %}
@@ -13349,8 +13585,22 @@
ins_pipe(pipe_class_default);
%}
+instruct replicate2F(vecD dst, vRegF src)
+%{
+ predicate(n->as_Vector()->length() == 2);
+ match(Set dst (ReplicateF src));
+ ins_cost(INSN_COST);
+ format %{ "dup $dst, $src\t# vector (2F)" %}
+ ins_encode %{
+ __ dup(as_FloatRegister($dst$$reg), __ T2S,
+ as_FloatRegister($src$$reg));
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
instruct replicate4F(vecX dst, vRegF src)
%{
+ predicate(n->as_Vector()->length() == 4);
match(Set dst (ReplicateF src));
ins_cost(INSN_COST);
format %{ "dup $dst, $src\t# vector (4F)" %}
@@ -13363,6 +13613,7 @@
instruct replicate2D(vecX dst, vRegD src)
%{
+ predicate(n->as_Vector()->length() == 2);
match(Set dst (ReplicateD src));
ins_cost(INSN_COST);
format %{ "dup $dst, $src\t# vector (2D)" %}
@@ -13375,6 +13626,25 @@
// ====================REDUCTION ARITHMETIC====================================
+instruct reduce_add2I(iRegINoSp dst, iRegIorL2I src1, vecD src2, iRegI tmp, iRegI tmp2)
+%{
+ match(Set dst (AddReductionVI src1 src2));
+ ins_cost(INSN_COST);
+ effect(TEMP tmp, TEMP tmp2);
+ format %{ "umov $tmp, $src2, S, 0\n\t"
+ "umov $tmp2, $src2, S, 1\n\t"
+ "addw $dst, $src1, $tmp\n\t"
+ "addw $dst, $dst, $tmp2\t add reduction2i"
+ %}
+ ins_encode %{
+ __ umov($tmp$$Register, as_FloatRegister($src2$$reg), __ S, 0);
+ __ umov($tmp2$$Register, as_FloatRegister($src2$$reg), __ S, 1);
+ __ addw($dst$$Register, $src1$$Register, $tmp$$Register);
+ __ addw($dst$$Register, $dst$$Register, $tmp2$$Register);
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
instruct reduce_add4I(iRegINoSp dst, iRegIorL2I src1, vecX src2, vecX tmp, iRegI tmp2)
%{
match(Set dst (AddReductionVI src1 src2));
@@ -13393,6 +13663,25 @@
ins_pipe(pipe_class_default);
%}
+instruct reduce_mul2I(iRegINoSp dst, iRegIorL2I src1, vecD src2, iRegI tmp)
+%{
+ match(Set dst (MulReductionVI src1 src2));
+ ins_cost(INSN_COST);
+ effect(TEMP tmp, TEMP dst);
+ format %{ "umov $tmp, $src2, S, 0\n\t"
+ "mul $dst, $tmp, $src1\n\t"
+ "umov $tmp, $src2, S, 1\n\t"
+ "mul $dst, $tmp, $dst\t mul reduction2i\n\t"
+ %}
+ ins_encode %{
+ __ umov($tmp$$Register, as_FloatRegister($src2$$reg), __ S, 0);
+ __ mul($dst$$Register, $tmp$$Register, $src1$$Register);
+ __ umov($tmp$$Register, as_FloatRegister($src2$$reg), __ S, 1);
+ __ mul($dst$$Register, $tmp$$Register, $dst$$Register);
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
instruct reduce_mul4I(iRegINoSp dst, iRegIorL2I src1, vecX src2, vecX tmp, iRegI tmp2)
%{
match(Set dst (MulReductionVI src1 src2));
@@ -13418,6 +13707,26 @@
ins_pipe(pipe_class_default);
%}
+instruct reduce_add2F(vRegF dst, vRegF src1, vecD src2, vecD tmp)
+%{
+ match(Set dst (AddReductionVF src1 src2));
+ ins_cost(INSN_COST);
+ effect(TEMP tmp, TEMP dst);
+ format %{ "fadds $dst, $src1, $src2\n\t"
+ "ins $tmp, S, $src2, 0, 1\n\t"
+ "fadds $dst, $dst, $tmp\t add reduction2f"
+ %}
+ ins_encode %{
+ __ fadds(as_FloatRegister($dst$$reg),
+ as_FloatRegister($src1$$reg), as_FloatRegister($src2$$reg));
+ __ ins(as_FloatRegister($tmp$$reg), __ S,
+ as_FloatRegister($src2$$reg), 0, 1);
+ __ fadds(as_FloatRegister($dst$$reg),
+ as_FloatRegister($dst$$reg), as_FloatRegister($tmp$$reg));
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
instruct reduce_add4F(vRegF dst, vRegF src1, vecX src2, vecX tmp)
%{
match(Set dst (AddReductionVF src1 src2));
@@ -13450,6 +13759,26 @@
ins_pipe(pipe_class_default);
%}
+instruct reduce_mul2F(vRegF dst, vRegF src1, vecD src2, vecD tmp)
+%{
+ match(Set dst (MulReductionVF src1 src2));
+ ins_cost(INSN_COST);
+ effect(TEMP tmp, TEMP dst);
+ format %{ "fmuls $dst, $src1, $src2\n\t"
+ "ins $tmp, S, $src2, 0, 1\n\t"
+ "fmuls $dst, $dst, $tmp\t add reduction4f"
+ %}
+ ins_encode %{
+ __ fmuls(as_FloatRegister($dst$$reg),
+ as_FloatRegister($src1$$reg), as_FloatRegister($src2$$reg));
+ __ ins(as_FloatRegister($tmp$$reg), __ S,
+ as_FloatRegister($src2$$reg), 0, 1);
+ __ fmuls(as_FloatRegister($dst$$reg),
+ as_FloatRegister($dst$$reg), as_FloatRegister($tmp$$reg));
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
instruct reduce_mul4F(vRegF dst, vRegF src1, vecX src2, vecX tmp)
%{
match(Set dst (MulReductionVF src1 src2));
@@ -13526,8 +13855,24 @@
// --------------------------------- ADD --------------------------------------
+instruct vadd8B(vecD dst, vecD src1, vecD src2)
+%{
+ predicate(n->as_Vector()->length() == 4 ||
+ n->as_Vector()->length() == 8);
+ match(Set dst (AddVB src1 src2));
+ ins_cost(INSN_COST);
+ format %{ "addv $dst,$src1,$src2\t# vector (8B)" %}
+ ins_encode %{
+ __ addv(as_FloatRegister($dst$$reg), __ T8B,
+ as_FloatRegister($src1$$reg),
+ as_FloatRegister($src2$$reg));
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
instruct vadd16B(vecX dst, vecX src1, vecX src2)
%{
+ predicate(n->as_Vector()->length() == 16);
match(Set dst (AddVB src1 src2));
ins_cost(INSN_COST);
format %{ "addv $dst,$src1,$src2\t# vector (16B)" %}
@@ -13539,8 +13884,24 @@
ins_pipe(pipe_class_default);
%}
+instruct vadd4S(vecD dst, vecD src1, vecD src2)
+%{
+ predicate(n->as_Vector()->length() == 2 ||
+ n->as_Vector()->length() == 4);
+ match(Set dst (AddVS src1 src2));
+ ins_cost(INSN_COST);
+ format %{ "addv $dst,$src1,$src2\t# vector (4H)" %}
+ ins_encode %{
+ __ addv(as_FloatRegister($dst$$reg), __ T4H,
+ as_FloatRegister($src1$$reg),
+ as_FloatRegister($src2$$reg));
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
instruct vadd8S(vecX dst, vecX src1, vecX src2)
%{
+ predicate(n->as_Vector()->length() == 8);
match(Set dst (AddVS src1 src2));
ins_cost(INSN_COST);
format %{ "addv $dst,$src1,$src2\t# vector (8H)" %}
@@ -13552,8 +13913,23 @@
ins_pipe(pipe_class_default);
%}
+instruct vadd2I(vecD dst, vecD src1, vecD src2)
+%{
+ predicate(n->as_Vector()->length() == 2);
+ match(Set dst (AddVI src1 src2));
+ ins_cost(INSN_COST);
+ format %{ "addv $dst,$src1,$src2\t# vector (2S)" %}
+ ins_encode %{
+ __ addv(as_FloatRegister($dst$$reg), __ T2S,
+ as_FloatRegister($src1$$reg),
+ as_FloatRegister($src2$$reg));
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
instruct vadd4I(vecX dst, vecX src1, vecX src2)
%{
+ predicate(n->as_Vector()->length() == 4);
match(Set dst (AddVI src1 src2));
ins_cost(INSN_COST);
format %{ "addv $dst,$src1,$src2\t# vector (4S)" %}
@@ -13567,6 +13943,7 @@
instruct vadd2L(vecX dst, vecX src1, vecX src2)
%{
+ predicate(n->as_Vector()->length() == 2);
match(Set dst (AddVL src1 src2));
ins_cost(INSN_COST);
format %{ "addv $dst,$src1,$src2\t# vector (2L)" %}
@@ -13578,8 +13955,23 @@
ins_pipe(pipe_class_default);
%}
+instruct vadd2F(vecD dst, vecD src1, vecD src2)
+%{
+ predicate(n->as_Vector()->length() == 2);
+ match(Set dst (AddVF src1 src2));
+ ins_cost(INSN_COST);
+ format %{ "fadd $dst,$src1,$src2\t# vector (2S)" %}
+ ins_encode %{
+ __ fadd(as_FloatRegister($dst$$reg), __ T2S,
+ as_FloatRegister($src1$$reg),
+ as_FloatRegister($src2$$reg));
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
instruct vadd4F(vecX dst, vecX src1, vecX src2)
%{
+ predicate(n->as_Vector()->length() == 4);
match(Set dst (AddVF src1 src2));
ins_cost(INSN_COST);
format %{ "fadd $dst,$src1,$src2\t# vector (4S)" %}
@@ -13606,8 +13998,24 @@
// --------------------------------- SUB --------------------------------------
+instruct vsub8B(vecD dst, vecD src1, vecD src2)
+%{
+ predicate(n->as_Vector()->length() == 4 ||
+ n->as_Vector()->length() == 8);
+ match(Set dst (SubVB src1 src2));
+ ins_cost(INSN_COST);
+ format %{ "subv $dst,$src1,$src2\t# vector (8B)" %}
+ ins_encode %{
+ __ subv(as_FloatRegister($dst$$reg), __ T8B,
+ as_FloatRegister($src1$$reg),
+ as_FloatRegister($src2$$reg));
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
instruct vsub16B(vecX dst, vecX src1, vecX src2)
%{
+ predicate(n->as_Vector()->length() == 16);
match(Set dst (SubVB src1 src2));
ins_cost(INSN_COST);
format %{ "subv $dst,$src1,$src2\t# vector (16B)" %}
@@ -13619,8 +14027,24 @@
ins_pipe(pipe_class_default);
%}
+instruct vsub4S(vecD dst, vecD src1, vecD src2)
+%{
+ predicate(n->as_Vector()->length() == 2 ||
+ n->as_Vector()->length() == 4);
+ match(Set dst (SubVS src1 src2));
+ ins_cost(INSN_COST);
+ format %{ "subv $dst,$src1,$src2\t# vector (4H)" %}
+ ins_encode %{
+ __ subv(as_FloatRegister($dst$$reg), __ T4H,
+ as_FloatRegister($src1$$reg),
+ as_FloatRegister($src2$$reg));
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
instruct vsub8S(vecX dst, vecX src1, vecX src2)
%{
+ predicate(n->as_Vector()->length() == 8);
match(Set dst (SubVS src1 src2));
ins_cost(INSN_COST);
format %{ "subv $dst,$src1,$src2\t# vector (8H)" %}
@@ -13632,8 +14056,23 @@
ins_pipe(pipe_class_default);
%}
+instruct vsub2I(vecD dst, vecD src1, vecD src2)
+%{
+ predicate(n->as_Vector()->length() == 2);
+ match(Set dst (SubVI src1 src2));
+ ins_cost(INSN_COST);
+ format %{ "subv $dst,$src1,$src2\t# vector (2S)" %}
+ ins_encode %{
+ __ subv(as_FloatRegister($dst$$reg), __ T2S,
+ as_FloatRegister($src1$$reg),
+ as_FloatRegister($src2$$reg));
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
instruct vsub4I(vecX dst, vecX src1, vecX src2)
%{
+ predicate(n->as_Vector()->length() == 4);
match(Set dst (SubVI src1 src2));
ins_cost(INSN_COST);
format %{ "subv $dst,$src1,$src2\t# vector (4S)" %}
@@ -13647,6 +14086,7 @@
instruct vsub2L(vecX dst, vecX src1, vecX src2)
%{
+ predicate(n->as_Vector()->length() == 2);
match(Set dst (SubVL src1 src2));
ins_cost(INSN_COST);
format %{ "subv $dst,$src1,$src2\t# vector (2L)" %}
@@ -13658,8 +14098,23 @@
ins_pipe(pipe_class_default);
%}
+instruct vsub2F(vecD dst, vecD src1, vecD src2)
+%{
+ predicate(n->as_Vector()->length() == 2);
+ match(Set dst (AddVF src1 src2));
+ ins_cost(INSN_COST);
+ format %{ "fsub $dst,$src1,$src2\t# vector (2S)" %}
+ ins_encode %{
+ __ fsub(as_FloatRegister($dst$$reg), __ T2S,
+ as_FloatRegister($src1$$reg),
+ as_FloatRegister($src2$$reg));
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
instruct vsub4F(vecX dst, vecX src1, vecX src2)
%{
+ predicate(n->as_Vector()->length() == 4);
match(Set dst (SubVF src1 src2));
ins_cost(INSN_COST);
format %{ "fsub $dst,$src1,$src2\t# vector (4S)" %}
@@ -13673,6 +14128,7 @@
instruct vsub2D(vecX dst, vecX src1, vecX src2)
%{
+ predicate(n->as_Vector()->length() == 2);
match(Set dst (SubVD src1 src2));
ins_cost(INSN_COST);
format %{ "fsub $dst,$src1,$src2\t# vector (2D)" %}
@@ -13686,8 +14142,24 @@
// --------------------------------- MUL --------------------------------------
+instruct vmul4S(vecD dst, vecD src1, vecD src2)
+%{
+ predicate(n->as_Vector()->length() == 2 ||
+ n->as_Vector()->length() == 4);
+ match(Set dst (MulVS src1 src2));
+ ins_cost(INSN_COST);
+ format %{ "mulv $dst,$src1,$src2\t# vector (4H)" %}
+ ins_encode %{
+ __ mulv(as_FloatRegister($dst$$reg), __ T4H,
+ as_FloatRegister($src1$$reg),
+ as_FloatRegister($src2$$reg));
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
instruct vmul8S(vecX dst, vecX src1, vecX src2)
%{
+ predicate(n->as_Vector()->length() == 8);
match(Set dst (MulVS src1 src2));
ins_cost(INSN_COST);
format %{ "mulv $dst,$src1,$src2\t# vector (8H)" %}
@@ -13699,8 +14171,23 @@
ins_pipe(pipe_class_default);
%}
+instruct vmul2I(vecD dst, vecD src1, vecD src2)
+%{
+ predicate(n->as_Vector()->length() == 2);
+ match(Set dst (MulVI src1 src2));
+ ins_cost(INSN_COST);
+ format %{ "mulv $dst,$src1,$src2\t# vector (2S)" %}
+ ins_encode %{
+ __ mulv(as_FloatRegister($dst$$reg), __ T2S,
+ as_FloatRegister($src1$$reg),
+ as_FloatRegister($src2$$reg));
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
instruct vmul4I(vecX dst, vecX src1, vecX src2)
%{
+ predicate(n->as_Vector()->length() == 4);
match(Set dst (MulVI src1 src2));
ins_cost(INSN_COST);
format %{ "mulv $dst,$src1,$src2\t# vector (4S)" %}
@@ -13712,8 +14199,23 @@
ins_pipe(pipe_class_default);
%}
+instruct vmul2F(vecD dst, vecD src1, vecD src2)
+%{
+ predicate(n->as_Vector()->length() == 2);
+ match(Set dst (MulVF src1 src2));
+ ins_cost(INSN_COST);
+ format %{ "fmul $dst,$src1,$src2\t# vector (2S)" %}
+ ins_encode %{
+ __ fmul(as_FloatRegister($dst$$reg), __ T2S,
+ as_FloatRegister($src1$$reg),
+ as_FloatRegister($src2$$reg));
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
instruct vmul4F(vecX dst, vecX src1, vecX src2)
%{
+ predicate(n->as_Vector()->length() == 4);
match(Set dst (MulVF src1 src2));
ins_cost(INSN_COST);
format %{ "fmul $dst,$src1,$src2\t# vector (4S)" %}
@@ -13727,6 +14229,7 @@
instruct vmul2D(vecX dst, vecX src1, vecX src2)
%{
+ predicate(n->as_Vector()->length() == 2);
match(Set dst (MulVD src1 src2));
ins_cost(INSN_COST);
format %{ "fmul $dst,$src1,$src2\t# vector (2D)" %}
@@ -13740,8 +14243,23 @@
// --------------------------------- DIV --------------------------------------
+instruct vdiv2F(vecD dst, vecD src1, vecD src2)
+%{
+ predicate(n->as_Vector()->length() == 2);
+ match(Set dst (DivVF src1 src2));
+ ins_cost(INSN_COST);
+ format %{ "fdiv $dst,$src1,$src2\t# vector (2S)" %}
+ ins_encode %{
+ __ fdiv(as_FloatRegister($dst$$reg), __ T2S,
+ as_FloatRegister($src1$$reg),
+ as_FloatRegister($src2$$reg));
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
instruct vdiv4F(vecX dst, vecX src1, vecX src2)
%{
+ predicate(n->as_Vector()->length() == 4);
match(Set dst (DivVF src1 src2));
ins_cost(INSN_COST);
format %{ "fdiv $dst,$src1,$src2\t# vector (4S)" %}
@@ -13755,6 +14273,7 @@
instruct vdiv2D(vecX dst, vecX src1, vecX src2)
%{
+ predicate(n->as_Vector()->length() == 2);
match(Set dst (DivVD src1 src2));
ins_cost(INSN_COST);
format %{ "fdiv $dst,$src1,$src2\t# vector (2D)" %}
@@ -13768,8 +14287,24 @@
// --------------------------------- AND --------------------------------------
+instruct vand8B(vecD dst, vecD src1, vecD src2)
+%{
+ predicate(n->as_Vector()->length_in_bytes() == 4 ||
+ n->as_Vector()->length_in_bytes() == 8);
+ match(Set dst (AndV src1 src2));
+ ins_cost(INSN_COST);
+ format %{ "and $dst,$src1,$src2\t# vector (8B)" %}
+ ins_encode %{
+ __ andr(as_FloatRegister($dst$$reg), __ T8B,
+ as_FloatRegister($src1$$reg),
+ as_FloatRegister($src2$$reg));
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
instruct vand16B(vecX dst, vecX src1, vecX src2)
%{
+ predicate(n->as_Vector()->length_in_bytes() == 16);
match(Set dst (AndV src1 src2));
ins_cost(INSN_COST);
format %{ "and $dst,$src1,$src2\t# vector (16B)" %}
@@ -13783,8 +14318,24 @@
// --------------------------------- OR ---------------------------------------
+instruct vor8B(vecD dst, vecD src1, vecD src2)
+%{
+ predicate(n->as_Vector()->length_in_bytes() == 4 ||
+ n->as_Vector()->length_in_bytes() == 8);
+ match(Set dst (OrV src1 src2));
+ ins_cost(INSN_COST);
+ format %{ "and $dst,$src1,$src2\t# vector (8B)" %}
+ ins_encode %{
+ __ orr(as_FloatRegister($dst$$reg), __ T8B,
+ as_FloatRegister($src1$$reg),
+ as_FloatRegister($src2$$reg));
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
instruct vor16B(vecX dst, vecX src1, vecX src2)
%{
+ predicate(n->as_Vector()->length_in_bytes() == 16);
match(Set dst (OrV src1 src2));
ins_cost(INSN_COST);
format %{ "orr $dst,$src1,$src2\t# vector (16B)" %}
@@ -13798,8 +14349,24 @@
// --------------------------------- XOR --------------------------------------
+instruct vxor8B(vecD dst, vecD src1, vecD src2)
+%{
+ predicate(n->as_Vector()->length_in_bytes() == 4 ||
+ n->as_Vector()->length_in_bytes() == 8);
+ match(Set dst (XorV src1 src2));
+ ins_cost(INSN_COST);
+ format %{ "xor $dst,$src1,$src2\t# vector (8B)" %}
+ ins_encode %{
+ __ eor(as_FloatRegister($dst$$reg), __ T8B,
+ as_FloatRegister($src1$$reg),
+ as_FloatRegister($src2$$reg));
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
instruct vxor16B(vecX dst, vecX src1, vecX src2)
%{
+ predicate(n->as_Vector()->length_in_bytes() == 16);
match(Set dst (XorV src1 src2));
ins_cost(INSN_COST);
format %{ "xor $dst,$src1,$src2\t# vector (16B)" %}
@@ -13833,7 +14400,23 @@
ins_pipe(pipe_class_default);
%}
+instruct vsll8B(vecD dst, vecD src, vecX shift) %{
+ predicate(n->as_Vector()->length() == 4 ||
+ n->as_Vector()->length() == 8);
+ match(Set dst (LShiftVB src shift));
+ match(Set dst (RShiftVB src shift));
+ ins_cost(INSN_COST);
+ format %{ "sshl $dst,$src,$shift\t# vector (8B)" %}
+ ins_encode %{
+ __ sshl(as_FloatRegister($dst$$reg), __ T8B,
+ as_FloatRegister($src$$reg),
+ as_FloatRegister($shift$$reg));
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
instruct vsll16B(vecX dst, vecX src, vecX shift) %{
+ predicate(n->as_Vector()->length() == 16);
match(Set dst (LShiftVB src shift));
match(Set dst (RShiftVB src shift));
ins_cost(INSN_COST);
@@ -13846,7 +14429,22 @@
ins_pipe(pipe_class_default);
%}
+instruct vsrl8B(vecD dst, vecD src, vecX shift) %{
+ predicate(n->as_Vector()->length() == 4 ||
+ n->as_Vector()->length() == 8);
+ match(Set dst (URShiftVB src shift));
+ ins_cost(INSN_COST);
+ format %{ "ushl $dst,$src,$shift\t# vector (8B)" %}
+ ins_encode %{
+ __ ushl(as_FloatRegister($dst$$reg), __ T8B,
+ as_FloatRegister($src$$reg),
+ as_FloatRegister($shift$$reg));
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
instruct vsrl16B(vecX dst, vecX src, vecX shift) %{
+ predicate(n->as_Vector()->length() == 16);
match(Set dst (URShiftVB src shift));
ins_cost(INSN_COST);
format %{ "ushl $dst,$src,$shift\t# vector (16B)" %}
@@ -13858,7 +14456,28 @@
ins_pipe(pipe_class_default);
%}
+instruct vsll8B_imm(vecD dst, vecD src, immI shift) %{
+ predicate(n->as_Vector()->length() == 4 ||
+ n->as_Vector()->length() == 8);
+ match(Set dst (LShiftVB src shift));
+ ins_cost(INSN_COST);
+ format %{ "shl $dst, $src, $shift\t# vector (8B)" %}
+ ins_encode %{
+ int sh = (int)$shift$$constant & 31;
+ if (sh >= 8) {
+ __ eor(as_FloatRegister($dst$$reg), __ T8B,
+ as_FloatRegister($src$$reg),
+ as_FloatRegister($src$$reg));
+ } else {
+ __ shl(as_FloatRegister($dst$$reg), __ T8B,
+ as_FloatRegister($src$$reg), sh);
+ }
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
instruct vsll16B_imm(vecX dst, vecX src, immI shift) %{
+ predicate(n->as_Vector()->length() == 16);
match(Set dst (LShiftVB src shift));
ins_cost(INSN_COST);
format %{ "shl $dst, $src, $shift\t# vector (16B)" %}
@@ -13876,7 +14495,24 @@
ins_pipe(pipe_class_default);
%}
+instruct vsra8B_imm(vecD dst, vecD src, immI shift) %{
+ predicate(n->as_Vector()->length() == 4 ||
+ n->as_Vector()->length() == 8);
+ match(Set dst (RShiftVB src shift));
+ ins_cost(INSN_COST);
+ format %{ "sshr $dst, $src, $shift\t# vector (8B)" %}
+ ins_encode %{
+ int sh = (int)$shift$$constant & 31;
+ if (sh >= 8) sh = 7;
+ sh = -sh & 7;
+ __ sshr(as_FloatRegister($dst$$reg), __ T8B,
+ as_FloatRegister($src$$reg), sh);
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
instruct vsra16B_imm(vecX dst, vecX src, immI shift) %{
+ predicate(n->as_Vector()->length() == 16);
match(Set dst (RShiftVB src shift));
ins_cost(INSN_COST);
format %{ "sshr $dst, $src, $shift\t# vector (16B)" %}
@@ -13890,7 +14526,28 @@
ins_pipe(pipe_class_default);
%}
+instruct vsrl8B_imm(vecD dst, vecD src, immI shift) %{
+ predicate(n->as_Vector()->length() == 4 ||
+ n->as_Vector()->length() == 8);
+ match(Set dst (URShiftVB src shift));
+ ins_cost(INSN_COST);
+ format %{ "ushr $dst, $src, $shift\t# vector (8B)" %}
+ ins_encode %{
+ int sh = (int)$shift$$constant & 31;
+ if (sh >= 8) {
+ __ eor(as_FloatRegister($dst$$reg), __ T8B,
+ as_FloatRegister($src$$reg),
+ as_FloatRegister($src$$reg));
+ } else {
+ __ ushr(as_FloatRegister($dst$$reg), __ T8B,
+ as_FloatRegister($src$$reg), -sh & 7);
+ }
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
instruct vsrl16B_imm(vecX dst, vecX src, immI shift) %{
+ predicate(n->as_Vector()->length() == 16);
match(Set dst (URShiftVB src shift));
ins_cost(INSN_COST);
format %{ "ushr $dst, $src, $shift\t# vector (16B)" %}
@@ -13908,7 +14565,23 @@
ins_pipe(pipe_class_default);
%}
+instruct vsll4S(vecD dst, vecD src, vecX shift) %{
+ predicate(n->as_Vector()->length() == 2 ||
+ n->as_Vector()->length() == 4);
+ match(Set dst (LShiftVS src shift));
+ match(Set dst (RShiftVS src shift));
+ ins_cost(INSN_COST);
+ format %{ "sshl $dst,$src,$shift\t# vector (4H)" %}
+ ins_encode %{
+ __ sshl(as_FloatRegister($dst$$reg), __ T4H,
+ as_FloatRegister($src$$reg),
+ as_FloatRegister($shift$$reg));
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
instruct vsll8S(vecX dst, vecX src, vecX shift) %{
+ predicate(n->as_Vector()->length() == 8);
match(Set dst (LShiftVS src shift));
match(Set dst (RShiftVS src shift));
ins_cost(INSN_COST);
@@ -13921,7 +14594,22 @@
ins_pipe(pipe_class_default);
%}
+instruct vsrl4S(vecD dst, vecD src, vecX shift) %{
+ predicate(n->as_Vector()->length() == 2 ||
+ n->as_Vector()->length() == 4);
+ match(Set dst (URShiftVS src shift));
+ ins_cost(INSN_COST);
+ format %{ "ushl $dst,$src,$shift\t# vector (4H)" %}
+ ins_encode %{
+ __ ushl(as_FloatRegister($dst$$reg), __ T4H,
+ as_FloatRegister($src$$reg),
+ as_FloatRegister($shift$$reg));
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
instruct vsrl8S(vecX dst, vecX src, vecX shift) %{
+ predicate(n->as_Vector()->length() == 8);
match(Set dst (URShiftVS src shift));
ins_cost(INSN_COST);
format %{ "ushl $dst,$src,$shift\t# vector (8H)" %}
@@ -13933,7 +14621,28 @@
ins_pipe(pipe_class_default);
%}
+instruct vsll4S_imm(vecD dst, vecD src, immI shift) %{
+ predicate(n->as_Vector()->length() == 2 ||
+ n->as_Vector()->length() == 4);
+ match(Set dst (LShiftVS src shift));
+ ins_cost(INSN_COST);
+ format %{ "shl $dst, $src, $shift\t# vector (4H)" %}
+ ins_encode %{
+ int sh = (int)$shift$$constant & 31;
+ if (sh >= 16) {
+ __ eor(as_FloatRegister($dst$$reg), __ T8B,
+ as_FloatRegister($src$$reg),
+ as_FloatRegister($src$$reg));
+ } else {
+ __ shl(as_FloatRegister($dst$$reg), __ T4H,
+ as_FloatRegister($src$$reg), sh);
+ }
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
instruct vsll8S_imm(vecX dst, vecX src, immI shift) %{
+ predicate(n->as_Vector()->length() == 8);
match(Set dst (LShiftVS src shift));
ins_cost(INSN_COST);
format %{ "shl $dst, $src, $shift\t# vector (8H)" %}
@@ -13951,7 +14660,24 @@
ins_pipe(pipe_class_default);
%}
+instruct vsra4S_imm(vecD dst, vecD src, immI shift) %{
+ predicate(n->as_Vector()->length() == 2 ||
+ n->as_Vector()->length() == 4);
+ match(Set dst (RShiftVS src shift));
+ ins_cost(INSN_COST);
+ format %{ "sshr $dst, $src, $shift\t# vector (4H)" %}
+ ins_encode %{
+ int sh = (int)$shift$$constant & 31;
+ if (sh >= 16) sh = 15;
+ sh = -sh & 15;
+ __ sshr(as_FloatRegister($dst$$reg), __ T4H,
+ as_FloatRegister($src$$reg), sh);
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
instruct vsra8S_imm(vecX dst, vecX src, immI shift) %{
+ predicate(n->as_Vector()->length() == 8);
match(Set dst (RShiftVS src shift));
ins_cost(INSN_COST);
format %{ "sshr $dst, $src, $shift\t# vector (8H)" %}
@@ -13965,7 +14691,28 @@
ins_pipe(pipe_class_default);
%}
+instruct vsrl4S_imm(vecD dst, vecD src, immI shift) %{
+ predicate(n->as_Vector()->length() == 2 ||
+ n->as_Vector()->length() == 4);
+ match(Set dst (URShiftVS src shift));
+ ins_cost(INSN_COST);
+ format %{ "ushr $dst, $src, $shift\t# vector (4H)" %}
+ ins_encode %{
+ int sh = (int)$shift$$constant & 31;
+ if (sh >= 16) {
+ __ eor(as_FloatRegister($dst$$reg), __ T8B,
+ as_FloatRegister($src$$reg),
+ as_FloatRegister($src$$reg));
+ } else {
+ __ ushr(as_FloatRegister($dst$$reg), __ T4H,
+ as_FloatRegister($src$$reg), -sh & 15);
+ }
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
instruct vsrl8S_imm(vecX dst, vecX src, immI shift) %{
+ predicate(n->as_Vector()->length() == 8);
match(Set dst (URShiftVS src shift));
ins_cost(INSN_COST);
format %{ "ushr $dst, $src, $shift\t# vector (8H)" %}
@@ -13983,7 +14730,22 @@
ins_pipe(pipe_class_default);
%}
+instruct vsll2I(vecD dst, vecD src, vecX shift) %{
+ predicate(n->as_Vector()->length() == 2);
+ match(Set dst (LShiftVI src shift));
+ match(Set dst (RShiftVI src shift));
+ ins_cost(INSN_COST);
+ format %{ "sshl $dst,$src,$shift\t# vector (2S)" %}
+ ins_encode %{
+ __ sshl(as_FloatRegister($dst$$reg), __ T2S,
+ as_FloatRegister($src$$reg),
+ as_FloatRegister($shift$$reg));
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
instruct vsll4I(vecX dst, vecX src, vecX shift) %{
+ predicate(n->as_Vector()->length() == 4);
match(Set dst (LShiftVI src shift));
match(Set dst (RShiftVI src shift));
ins_cost(INSN_COST);
@@ -13996,7 +14758,21 @@
ins_pipe(pipe_class_default);
%}
+instruct vsrl2I(vecD dst, vecD src, vecX shift) %{
+ predicate(n->as_Vector()->length() == 2);
+ match(Set dst (URShiftVI src shift));
+ ins_cost(INSN_COST);
+ format %{ "ushl $dst,$src,$shift\t# vector (2S)" %}
+ ins_encode %{
+ __ ushl(as_FloatRegister($dst$$reg), __ T2S,
+ as_FloatRegister($src$$reg),
+ as_FloatRegister($shift$$reg));
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
instruct vsrl4I(vecX dst, vecX src, vecX shift) %{
+ predicate(n->as_Vector()->length() == 4);
match(Set dst (URShiftVI src shift));
ins_cost(INSN_COST);
format %{ "ushl $dst,$src,$shift\t# vector (4S)" %}
@@ -14008,7 +14784,21 @@
ins_pipe(pipe_class_default);
%}
+instruct vsll2I_imm(vecD dst, vecD src, immI shift) %{
+ predicate(n->as_Vector()->length() == 2);
+ match(Set dst (LShiftVI src shift));
+ ins_cost(INSN_COST);
+ format %{ "shl $dst, $src, $shift\t# vector (2S)" %}
+ ins_encode %{
+ __ shl(as_FloatRegister($dst$$reg), __ T2S,
+ as_FloatRegister($src$$reg),
+ (int)$shift$$constant & 31);
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
instruct vsll4I_imm(vecX dst, vecX src, immI shift) %{
+ predicate(n->as_Vector()->length() == 4);
match(Set dst (LShiftVI src shift));
ins_cost(INSN_COST);
format %{ "shl $dst, $src, $shift\t# vector (4S)" %}
@@ -14020,7 +14810,21 @@
ins_pipe(pipe_class_default);
%}
+instruct vsra2I_imm(vecD dst, vecD src, immI shift) %{
+ predicate(n->as_Vector()->length() == 2);
+ match(Set dst (RShiftVI src shift));
+ ins_cost(INSN_COST);
+ format %{ "sshr $dst, $src, $shift\t# vector (2S)" %}
+ ins_encode %{
+ __ sshr(as_FloatRegister($dst$$reg), __ T2S,
+ as_FloatRegister($src$$reg),
+ -(int)$shift$$constant & 31);
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
instruct vsra4I_imm(vecX dst, vecX src, immI shift) %{
+ predicate(n->as_Vector()->length() == 4);
match(Set dst (RShiftVI src shift));
ins_cost(INSN_COST);
format %{ "sshr $dst, $src, $shift\t# vector (4S)" %}
@@ -14032,7 +14836,21 @@
ins_pipe(pipe_class_default);
%}
+instruct vsrl2I_imm(vecD dst, vecD src, immI shift) %{
+ predicate(n->as_Vector()->length() == 2);
+ match(Set dst (URShiftVI src shift));
+ ins_cost(INSN_COST);
+ format %{ "ushr $dst, $src, $shift\t# vector (2S)" %}
+ ins_encode %{
+ __ ushr(as_FloatRegister($dst$$reg), __ T2S,
+ as_FloatRegister($src$$reg),
+ -(int)$shift$$constant & 31);
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
instruct vsrl4I_imm(vecX dst, vecX src, immI shift) %{
+ predicate(n->as_Vector()->length() == 4);
match(Set dst (URShiftVI src shift));
ins_cost(INSN_COST);
format %{ "ushr $dst, $src, $shift\t# vector (4S)" %}
@@ -14045,6 +14863,7 @@
%}
instruct vsll2L(vecX dst, vecX src, vecX shift) %{
+ predicate(n->as_Vector()->length() == 2);
match(Set dst (LShiftVL src shift));
match(Set dst (RShiftVL src shift));
ins_cost(INSN_COST);
@@ -14058,6 +14877,7 @@
%}
instruct vsrl2L(vecX dst, vecX src, vecX shift) %{
+ predicate(n->as_Vector()->length() == 2);
match(Set dst (URShiftVL src shift));
ins_cost(INSN_COST);
format %{ "ushl $dst,$src,$shift\t# vector (2D)" %}
@@ -14070,6 +14890,7 @@
%}
instruct vsll2L_imm(vecX dst, vecX src, immI shift) %{
+ predicate(n->as_Vector()->length() == 2);
match(Set dst (LShiftVL src shift));
ins_cost(INSN_COST);
format %{ "shl $dst, $src, $shift\t# vector (2D)" %}
@@ -14082,6 +14903,7 @@
%}
instruct vsra2L_imm(vecX dst, vecX src, immI shift) %{
+ predicate(n->as_Vector()->length() == 2);
match(Set dst (RShiftVL src shift));
ins_cost(INSN_COST);
format %{ "sshr $dst, $src, $shift\t# vector (2D)" %}
@@ -14094,6 +14916,7 @@
%}
instruct vsrl2L_imm(vecX dst, vecX src, immI shift) %{
+ predicate(n->as_Vector()->length() == 2);
match(Set dst (URShiftVL src shift));
ins_cost(INSN_COST);
format %{ "ushr $dst, $src, $shift\t# vector (2D)" %}
--- a/hotspot/src/cpu/aarch64/vm/assembler_aarch64.hpp Thu Jul 09 13:49:32 2015 -0700
+++ b/hotspot/src/cpu/aarch64/vm/assembler_aarch64.hpp Wed Jul 05 20:41:12 2017 +0200
@@ -2055,6 +2055,9 @@
INSN(negr, 1, 0b100000101110);
INSN(notr, 1, 0b100000010110);
INSN(addv, 0, 0b110001101110);
+ INSN(cls, 0, 0b100000010010);
+ INSN(clz, 1, 0b100000010010);
+ INSN(cnt, 0, 0b100000010110);
#undef INSN
--- a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp Thu Jul 09 13:49:32 2015 -0700
+++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp Wed Jul 05 20:41:12 2017 +0200
@@ -36,6 +36,7 @@
class MacroAssembler: public Assembler {
friend class LIR_Assembler;
+ public:
using Assembler::mov;
using Assembler::movi;
--- a/hotspot/src/cpu/aarch64/vm/vm_version_aarch64.cpp Thu Jul 09 13:49:32 2015 -0700
+++ b/hotspot/src/cpu/aarch64/vm/vm_version_aarch64.cpp Wed Jul 05 20:41:12 2017 +0200
@@ -199,6 +199,12 @@
UseCRC32Intrinsics = true;
}
+ if (UseCRC32CIntrinsics) {
+ if (!FLAG_IS_DEFAULT(UseCRC32CIntrinsics))
+ warning("CRC32C intrinsics are not available on this CPU");
+ FLAG_SET_DEFAULT(UseCRC32CIntrinsics, false);
+ }
+
if (auxv & (HWCAP_SHA1 | HWCAP_SHA2)) {
if (FLAG_IS_DEFAULT(UseSHA)) {
FLAG_SET_DEFAULT(UseSHA, true);
@@ -251,6 +257,10 @@
UseBarriersForVolatile = (_cpuFeatures & CPU_DMB_ATOMICS) != 0;
}
+ if (FLAG_IS_DEFAULT(UsePopCountInstruction)) {
+ UsePopCountInstruction = true;
+ }
+
#ifdef COMPILER2
if (FLAG_IS_DEFAULT(OptoScheduling)) {
OptoScheduling = true;
--- a/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp Thu Jul 09 13:49:32 2015 -0700
+++ b/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp Wed Jul 05 20:41:12 2017 +0200
@@ -191,6 +191,13 @@
FLAG_SET_DEFAULT(UseSHA256Intrinsics, false);
FLAG_SET_DEFAULT(UseSHA512Intrinsics, false);
}
+
+ if (UseCRC32CIntrinsics) {
+ if (!FLAG_IS_DEFAULT(UseCRC32CIntrinsics))
+ warning("CRC32C intrinsics are not available on this CPU");
+ FLAG_SET_DEFAULT(UseCRC32CIntrinsics, false);
+ }
+
// Adjust RTM (Restricted Transactional Memory) flags.
if (!has_tcheck() && UseRTMLocking) {
// Can't continue because UseRTMLocking affects UseBiasedLocking flag
--- a/hotspot/src/cpu/sparc/vm/assembler_sparc.hpp Thu Jul 09 13:49:32 2015 -0700
+++ b/hotspot/src/cpu/sparc/vm/assembler_sparc.hpp Wed Jul 05 20:41:12 2017 +0200
@@ -128,8 +128,11 @@
faligndata_op3 = 0x36,
flog3_op3 = 0x36,
edge_op3 = 0x36,
+ fzero_op3 = 0x36,
fsrc_op3 = 0x36,
+ fnot_op3 = 0x36,
xmulx_op3 = 0x36,
+ crc32c_op3 = 0x36,
impdep2_op3 = 0x37,
stpartialf_op3 = 0x37,
jmpl_op3 = 0x38,
@@ -231,7 +234,9 @@
sha1_opf = 0x141,
sha256_opf = 0x142,
- sha512_opf = 0x143
+ sha512_opf = 0x143,
+
+ crc32c_opf = 0x147
};
enum op5s {
@@ -600,6 +605,11 @@
return x & ((1 << 10) - 1);
}
+ // create a low12 __value__ (not a field) for a given a 32-bit constant
+ static int low12( int x ) {
+ return x & ((1 << 12) - 1);
+ }
+
// AES crypto instructions supported only on certain processors
static void aes_only() { assert( VM_Version::has_aes(), "This instruction only works on SPARC with AES instructions support"); }
@@ -608,6 +618,9 @@
static void sha256_only() { assert( VM_Version::has_sha256(), "This instruction only works on SPARC with SHA256"); }
static void sha512_only() { assert( VM_Version::has_sha512(), "This instruction only works on SPARC with SHA512"); }
+ // CRC32C instruction supported only on certain processors
+ static void crc32c_only() { assert( VM_Version::has_crc32c(), "This instruction only works on SPARC with CRC32C"); }
+
// instruction only in VIS1
static void vis1_only() { assert( VM_Version::has_vis1(), "This instruction only works on SPARC with VIS1"); }
@@ -1022,6 +1035,7 @@
void nop() { emit_int32( op(branch_op) | op2(sethi_op2) ); }
+ void sw_count() { emit_int32( op(branch_op) | op2(sethi_op2) | 0x3f0 ); }
// pp 202
@@ -1198,8 +1212,14 @@
void faligndata( FloatRegister s1, FloatRegister s2, FloatRegister d ) { vis1_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(faligndata_op3) | fs1(s1, FloatRegisterImpl::D) | opf(faligndata_opf) | fs2(s2, FloatRegisterImpl::D)); }
+ void fzero( FloatRegisterImpl::Width w, FloatRegister d ) { vis1_only(); emit_int32( op(arith_op) | fd(d, w) | op3(fzero_op3) | opf(0x62 - w)); }
+
void fsrc2( FloatRegisterImpl::Width w, FloatRegister s2, FloatRegister d ) { vis1_only(); emit_int32( op(arith_op) | fd(d, w) | op3(fsrc_op3) | opf(0x7A - w) | fs2(s2, w)); }
+ void fnot1( FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister d ) { vis1_only(); emit_int32( op(arith_op) | fd(d, w) | op3(fnot_op3) | fs1(s1, w) | opf(0x6C - w)); }
+
+ void fpmerge( FloatRegister s1, FloatRegister s2, FloatRegister d ) { vis1_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(0x36) | fs1(s1, FloatRegisterImpl::S) | opf(0x4b) | fs2(s2, FloatRegisterImpl::S)); }
+
void stpartialf( Register s1, Register s2, FloatRegister d, int ia = -1 ) { vis1_only(); emit_int32( op(ldst_op) | fd(d, FloatRegisterImpl::D) | op3(stpartialf_op3) | rs1(s1) | imm_asi(ia) | rs2(s2)); }
// VIS2 instructions
@@ -1224,6 +1244,10 @@
void sha256() { sha256_only(); emit_int32( op(arith_op) | op3(sha_op3) | opf(sha256_opf)); }
void sha512() { sha512_only(); emit_int32( op(arith_op) | op3(sha_op3) | opf(sha512_opf)); }
+ // CRC32C instruction
+
+ void crc32c( FloatRegister s1, FloatRegister s2, FloatRegister d ) { crc32c_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(crc32c_op3) | fs1(s1, FloatRegisterImpl::D) | opf(crc32c_opf) | fs2(s2, FloatRegisterImpl::D)); }
+
// Creation
Assembler(CodeBuffer* code) : AbstractAssembler(code) {
#ifdef CHECK_DELAY
--- a/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp Thu Jul 09 13:49:32 2015 -0700
+++ b/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp Wed Jul 05 20:41:12 2017 +0200
@@ -956,6 +956,7 @@
int hi = (int)(value >> 32);
int lo = (int)(value & ~0);
+ int bits_33to2 = (int)((value >> 2) & ~0);
// (Matcher::isSimpleConstant64 knows about the following optimizations.)
if (Assembler::is_simm13(lo) && value == lo) {
or3(G0, lo, d);
@@ -964,6 +965,12 @@
if (low10(lo) != 0)
or3(d, low10(lo), d);
}
+ else if ((hi >> 2) == 0) {
+ Assembler::sethi(bits_33to2, d); // hardware version zero-extends to upper 32
+ sllx(d, 2, d);
+ if (low12(lo) != 0)
+ or3(d, low12(lo), d);
+ }
else if (hi == -1) {
Assembler::sethi(~lo, d); // hardware version zero-extends to upper 32
xor3(d, low10(lo) ^ ~low10(~0), d);
@@ -4351,3 +4358,52 @@
cmp_and_brx_short(to, end, Assembler::lessUnsigned, Assembler::pt, small_loop);
nop(); // Separate short branches
}
+
+/**
+ * Update CRC-32[C] with a byte value according to constants in table
+ *
+ * @param [in,out]crc Register containing the crc.
+ * @param [in]val Register containing the byte to fold into the CRC.
+ * @param [in]table Register containing the table of crc constants.
+ *
+ * uint32_t crc;
+ * val = crc_table[(val ^ crc) & 0xFF];
+ * crc = val ^ (crc >> 8);
+ */
+void MacroAssembler::update_byte_crc32(Register crc, Register val, Register table) {
+ xor3(val, crc, val);
+ and3(val, 0xFF, val);
+ sllx(val, 2, val);
+ lduw(table, val, val);
+ srlx(crc, 8, crc);
+ xor3(val, crc, crc);
+}
+
+// Reverse byte order of lower 32 bits, assuming upper 32 bits all zeros
+void MacroAssembler::reverse_bytes_32(Register src, Register dst, Register tmp) {
+ srlx(src, 24, dst);
+
+ sllx(src, 32+8, tmp);
+ srlx(tmp, 32+24, tmp);
+ sllx(tmp, 8, tmp);
+ or3(dst, tmp, dst);
+
+ sllx(src, 32+16, tmp);
+ srlx(tmp, 32+24, tmp);
+ sllx(tmp, 16, tmp);
+ or3(dst, tmp, dst);
+
+ sllx(src, 32+24, tmp);
+ srlx(tmp, 32, tmp);
+ or3(dst, tmp, dst);
+}
+
+void MacroAssembler::movitof_revbytes(Register src, FloatRegister dst, Register tmp1, Register tmp2) {
+ reverse_bytes_32(src, tmp1, tmp2);
+ movxtod(tmp1, dst);
+}
+
+void MacroAssembler::movftoi_revbytes(FloatRegister src, Register dst, Register tmp1, Register tmp2) {
+ movdtox(src, tmp1);
+ reverse_bytes_32(tmp1, dst, tmp2);
+}
--- a/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.hpp Thu Jul 09 13:49:32 2015 -0700
+++ b/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.hpp Wed Jul 05 20:41:12 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -903,6 +903,10 @@
inline void ldf(FloatRegisterImpl::Width w, Register s1, RegisterOrConstant s2, FloatRegister d);
inline void ldf(FloatRegisterImpl::Width w, const Address& a, FloatRegister d, int offset = 0);
+ // little-endian
+ inline void ldxl(Register s1, Register s2, Register d) { ldxa(s1, s2, ASI_PRIMARY_LITTLE, d); }
+ inline void ldfl(FloatRegisterImpl::Width w, Register s1, Register s2, FloatRegister d) { ldfa(w, s1, s2, ASI_PRIMARY_LITTLE, d); }
+
// membar psuedo instruction. takes into account target memory model.
inline void membar( Assembler::Membar_mask_bits const7a );
@@ -1436,6 +1440,14 @@
// Use BIS for zeroing
void bis_zeroing(Register to, Register count, Register temp, Label& Ldone);
+ // Update CRC-32[C] with a byte value according to constants in table
+ void update_byte_crc32(Register crc, Register val, Register table);
+
+ // Reverse byte order of lower 32 bits, assuming upper 32 bits all zeros
+ void reverse_bytes_32(Register src, Register dst, Register tmp);
+ void movitof_revbytes(Register src, FloatRegister dst, Register tmp1, Register tmp2);
+ void movftoi_revbytes(FloatRegister src, Register dst, Register tmp1, Register tmp2);
+
#undef VIRTUAL
};
--- a/hotspot/src/cpu/sparc/vm/stubGenerator_sparc.cpp Thu Jul 09 13:49:32 2015 -0700
+++ b/hotspot/src/cpu/sparc/vm/stubGenerator_sparc.cpp Wed Jul 05 20:41:12 2017 +0200
@@ -4910,6 +4910,206 @@
return start;
}
+#define CHUNK_LEN 128 /* 128 x 8B = 1KB */
+#define CHUNK_K1 0x1307a0206 /* reverseBits(pow(x, CHUNK_LEN*8*8*3 - 32) mod P(x)) << 1 */
+#define CHUNK_K2 0x1a0f717c4 /* reverseBits(pow(x, CHUNK_LEN*8*8*2 - 32) mod P(x)) << 1 */
+#define CHUNK_K3 0x0170076fa /* reverseBits(pow(x, CHUNK_LEN*8*8*1 - 32) mod P(x)) << 1 */
+
+ /**
+ * Arguments:
+ *
+ * Inputs:
+ * O0 - int crc
+ * O1 - byte* buf
+ * O2 - int len
+ * O3 - int* table
+ *
+ * Output:
+ * O0 - int crc result
+ */
+ address generate_updateBytesCRC32C() {
+ assert(UseCRC32CIntrinsics, "need CRC32C instruction");
+
+ __ align(CodeEntryAlignment);
+ StubCodeMark mark(this, "StubRoutines", "updateBytesCRC32C");
+ address start = __ pc();
+
+ const Register crc = O0; // crc
+ const Register buf = O1; // source java byte array address
+ const Register len = O2; // number of bytes
+ const Register table = O3; // byteTable
+
+ Label L_crc32c_head, L_crc32c_aligned;
+ Label L_crc32c_parallel, L_crc32c_parallel_loop;
+ Label L_crc32c_serial, L_crc32c_x32_loop, L_crc32c_x8, L_crc32c_x8_loop;
+ Label L_crc32c_done, L_crc32c_tail, L_crc32c_return;
+
+ __ cmp_and_br_short(len, 0, Assembler::lessEqual, Assembler::pn, L_crc32c_return);
+
+ // clear upper 32 bits of crc
+ __ clruwu(crc);
+
+ __ and3(buf, 7, G4);
+ __ cmp_and_brx_short(G4, 0, Assembler::equal, Assembler::pt, L_crc32c_aligned);
+
+ __ mov(8, G1);
+ __ sub(G1, G4, G4);
+
+ // ------ process the misaligned head (7 bytes or less) ------
+ __ BIND(L_crc32c_head);
+
+ // crc = (crc >>> 8) ^ byteTable[(crc ^ b) & 0xFF];
+ __ ldub(buf, 0, G1);
+ __ update_byte_crc32(crc, G1, table);
+
+ __ inc(buf);
+ __ dec(len);
+ __ cmp_and_br_short(len, 0, Assembler::equal, Assembler::pn, L_crc32c_return);
+ __ dec(G4);
+ __ cmp_and_br_short(G4, 0, Assembler::greater, Assembler::pt, L_crc32c_head);
+
+ // ------ process the 8-byte-aligned body ------
+ __ BIND(L_crc32c_aligned);
+ __ nop();
+ __ cmp_and_br_short(len, 8, Assembler::less, Assembler::pn, L_crc32c_tail);
+
+ // reverse the byte order of lower 32 bits to big endian, and move to FP side
+ __ movitof_revbytes(crc, F0, G1, G3);
+
+ __ set(CHUNK_LEN*8*4, G4);
+ __ cmp_and_br_short(len, G4, Assembler::less, Assembler::pt, L_crc32c_serial);
+
+ // ------ process four 1KB chunks in parallel ------
+ __ BIND(L_crc32c_parallel);
+
+ __ fzero(FloatRegisterImpl::D, F2);
+ __ fzero(FloatRegisterImpl::D, F4);
+ __ fzero(FloatRegisterImpl::D, F6);
+
+ __ mov(CHUNK_LEN - 1, G4);
+ __ BIND(L_crc32c_parallel_loop);
+ // schedule ldf's ahead of crc32c's to hide the load-use latency
+ __ ldf(FloatRegisterImpl::D, buf, 0, F8);
+ __ ldf(FloatRegisterImpl::D, buf, CHUNK_LEN*8, F10);
+ __ ldf(FloatRegisterImpl::D, buf, CHUNK_LEN*16, F12);
+ __ ldf(FloatRegisterImpl::D, buf, CHUNK_LEN*24, F14);
+ __ crc32c(F0, F8, F0);
+ __ crc32c(F2, F10, F2);
+ __ crc32c(F4, F12, F4);
+ __ crc32c(F6, F14, F6);
+ __ inc(buf, 8);
+ __ dec(G4);
+ __ cmp_and_br_short(G4, 0, Assembler::greater, Assembler::pt, L_crc32c_parallel_loop);
+
+ __ ldf(FloatRegisterImpl::D, buf, 0, F8);
+ __ ldf(FloatRegisterImpl::D, buf, CHUNK_LEN*8, F10);
+ __ ldf(FloatRegisterImpl::D, buf, CHUNK_LEN*16, F12);
+ __ crc32c(F0, F8, F0);
+ __ crc32c(F2, F10, F2);
+ __ crc32c(F4, F12, F4);
+
+ __ inc(buf, CHUNK_LEN*24);
+ __ ldfl(FloatRegisterImpl::D, buf, G0, F14); // load in little endian
+ __ inc(buf, 8);
+
+ __ prefetch(buf, 0, Assembler::severalReads);
+ __ prefetch(buf, CHUNK_LEN*8, Assembler::severalReads);
+ __ prefetch(buf, CHUNK_LEN*16, Assembler::severalReads);
+ __ prefetch(buf, CHUNK_LEN*24, Assembler::severalReads);
+
+ // move to INT side, and reverse the byte order of lower 32 bits to little endian
+ __ movftoi_revbytes(F0, O4, G1, G4);
+ __ movftoi_revbytes(F2, O5, G1, G4);
+ __ movftoi_revbytes(F4, G5, G1, G4);
+
+ // combine the results of 4 chunks
+ __ set64(CHUNK_K1, G3, G1);
+ __ xmulx(O4, G3, O4);
+ __ set64(CHUNK_K2, G3, G1);
+ __ xmulx(O5, G3, O5);
+ __ set64(CHUNK_K3, G3, G1);
+ __ xmulx(G5, G3, G5);
+
+ __ movdtox(F14, G4);
+ __ xor3(O4, O5, O5);
+ __ xor3(G5, O5, O5);
+ __ xor3(G4, O5, O5);
+
+ // reverse the byte order to big endian, via stack, and move to FP side
+ __ add(SP, -8, G1);
+ __ srlx(G1, 3, G1);
+ __ sllx(G1, 3, G1);
+ __ stx(O5, G1, G0);
+ __ ldfl(FloatRegisterImpl::D, G1, G0, F2); // load in little endian
+
+ __ crc32c(F6, F2, F0);
+
+ __ set(CHUNK_LEN*8*4, G4);
+ __ sub(len, G4, len);
+ __ cmp_and_br_short(len, G4, Assembler::greaterEqual, Assembler::pt, L_crc32c_parallel);
+ __ nop();
+ __ cmp_and_br_short(len, 0, Assembler::equal, Assembler::pt, L_crc32c_done);
+
+ __ BIND(L_crc32c_serial);
+
+ __ mov(32, G4);
+ __ cmp_and_br_short(len, G4, Assembler::less, Assembler::pn, L_crc32c_x8);
+
+ // ------ process 32B chunks ------
+ __ BIND(L_crc32c_x32_loop);
+ __ ldf(FloatRegisterImpl::D, buf, 0, F2);
+ __ inc(buf, 8);
+ __ crc32c(F0, F2, F0);
+ __ ldf(FloatRegisterImpl::D, buf, 0, F2);
+ __ inc(buf, 8);
+ __ crc32c(F0, F2, F0);
+ __ ldf(FloatRegisterImpl::D, buf, 0, F2);
+ __ inc(buf, 8);
+ __ crc32c(F0, F2, F0);
+ __ ldf(FloatRegisterImpl::D, buf, 0, F2);
+ __ inc(buf, 8);
+ __ crc32c(F0, F2, F0);
+ __ dec(len, 32);
+ __ cmp_and_br_short(len, G4, Assembler::greaterEqual, Assembler::pt, L_crc32c_x32_loop);
+
+ __ BIND(L_crc32c_x8);
+ __ nop();
+ __ cmp_and_br_short(len, 8, Assembler::less, Assembler::pt, L_crc32c_done);
+
+ // ------ process 8B chunks ------
+ __ BIND(L_crc32c_x8_loop);
+ __ ldf(FloatRegisterImpl::D, buf, 0, F2);
+ __ inc(buf, 8);
+ __ crc32c(F0, F2, F0);
+ __ dec(len, 8);
+ __ cmp_and_br_short(len, 8, Assembler::greaterEqual, Assembler::pt, L_crc32c_x8_loop);
+
+ __ BIND(L_crc32c_done);
+
+ // move to INT side, and reverse the byte order of lower 32 bits to little endian
+ __ movftoi_revbytes(F0, crc, G1, G3);
+
+ __ cmp_and_br_short(len, 0, Assembler::equal, Assembler::pt, L_crc32c_return);
+
+ // ------ process the misaligned tail (7 bytes or less) ------
+ __ BIND(L_crc32c_tail);
+
+ // crc = (crc >>> 8) ^ byteTable[(crc ^ b) & 0xFF];
+ __ ldub(buf, 0, G1);
+ __ update_byte_crc32(crc, G1, table);
+
+ __ inc(buf);
+ __ dec(len);
+ __ cmp_and_br_short(len, 0, Assembler::greater, Assembler::pt, L_crc32c_tail);
+
+ __ BIND(L_crc32c_return);
+ __ nop();
+ __ retl();
+ __ delayed()->nop();
+
+ return start;
+ }
+
void generate_initial() {
// Generates all stubs and initializes the entry points
@@ -5001,6 +5201,11 @@
StubRoutines::_sha512_implCompress = generate_sha512_implCompress(false, "sha512_implCompress");
StubRoutines::_sha512_implCompressMB = generate_sha512_implCompress(true, "sha512_implCompressMB");
}
+
+ // generate CRC32C intrinsic code
+ if (UseCRC32CIntrinsics) {
+ StubRoutines::_updateBytesCRC32C = generate_updateBytesCRC32C();
+ }
}
--- a/hotspot/src/cpu/sparc/vm/stubRoutines_sparc.hpp Thu Jul 09 13:49:32 2015 -0700
+++ b/hotspot/src/cpu/sparc/vm/stubRoutines_sparc.hpp Wed Jul 05 20:41:12 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -41,7 +41,7 @@
enum /* platform_dependent_constants */ {
// %%%%%%%% May be able to shrink this a lot
code_size1 = 20000, // simply increase if too small (assembler will crash if too small)
- code_size2 = 23000 // simply increase if too small (assembler will crash if too small)
+ code_size2 = 24000 // simply increase if too small (assembler will crash if too small)
};
class Sparc {
--- a/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp Thu Jul 09 13:49:32 2015 -0700
+++ b/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp Wed Jul 05 20:41:12 2017 +0200
@@ -230,7 +230,7 @@
assert((OptoLoopAlignment % relocInfo::addr_unit()) == 0, "alignment is not a multiple of NOP size");
char buf[512];
- jio_snprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+ jio_snprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
(has_v9() ? ", v9" : (has_v8() ? ", v8" : "")),
(has_hardware_popc() ? ", popc" : ""),
(has_vis1() ? ", vis1" : ""),
@@ -242,6 +242,7 @@
(has_sha1() ? ", sha1" : ""),
(has_sha256() ? ", sha256" : ""),
(has_sha512() ? ", sha512" : ""),
+ (has_crc32c() ? ", crc32c" : ""),
(is_ultra3() ? ", ultra3" : ""),
(is_sun4v() ? ", sun4v" : ""),
(is_niagara_plus() ? ", niagara_plus" : (is_niagara() ? ", niagara" : "")),
@@ -363,6 +364,23 @@
}
}
+ // SPARC T4 and above should have support for CRC32C instruction
+ if (has_crc32c()) {
+ if (UseVIS > 2) { // CRC32C intrinsics use VIS3 instructions
+ if (FLAG_IS_DEFAULT(UseCRC32CIntrinsics)) {
+ FLAG_SET_DEFAULT(UseCRC32CIntrinsics, true);
+ }
+ } else {
+ if (UseCRC32CIntrinsics) {
+ warning("SPARC CRC32C intrinsics require VIS3 instruction support. Intrinsics will be disabled.");
+ FLAG_SET_DEFAULT(UseCRC32CIntrinsics, false);
+ }
+ }
+ } else if (UseCRC32CIntrinsics) {
+ warning("CRC32C instruction is not available on this CPU");
+ FLAG_SET_DEFAULT(UseCRC32CIntrinsics, false);
+ }
+
if (FLAG_IS_DEFAULT(ContendedPaddingWidth) &&
(cache_line_size > ContendedPaddingWidth))
ContendedPaddingWidth = cache_line_size;
--- a/hotspot/src/cpu/sparc/vm/vm_version_sparc.hpp Thu Jul 09 13:49:32 2015 -0700
+++ b/hotspot/src/cpu/sparc/vm/vm_version_sparc.hpp Wed Jul 05 20:41:12 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -53,7 +53,8 @@
aes_instructions = 19,
sha1_instruction = 20,
sha256_instruction = 21,
- sha512_instruction = 22
+ sha512_instruction = 22,
+ crc32c_instruction = 23
};
enum Feature_Flag_Set {
@@ -83,6 +84,7 @@
sha1_instruction_m = 1 << sha1_instruction,
sha256_instruction_m = 1 << sha256_instruction,
sha512_instruction_m = 1 << sha512_instruction,
+ crc32c_instruction_m = 1 << crc32c_instruction,
generic_v8_m = v8_instructions_m | hardware_mul32_m | hardware_div32_m | hardware_fsmuld_m,
generic_v9_m = generic_v8_m | v9_instructions_m,
@@ -141,6 +143,7 @@
static bool has_sha1() { return (_features & sha1_instruction_m) != 0; }
static bool has_sha256() { return (_features & sha256_instruction_m) != 0; }
static bool has_sha512() { return (_features & sha512_instruction_m) != 0; }
+ static bool has_crc32c() { return (_features & crc32c_instruction_m) != 0; }
static bool supports_compare_and_exchange()
{ return has_v9(); }
--- a/hotspot/src/cpu/x86/vm/vm_version_x86.cpp Thu Jul 09 13:49:32 2015 -0700
+++ b/hotspot/src/cpu/x86/vm/vm_version_x86.cpp Wed Jul 05 20:41:12 2017 +0200
@@ -699,6 +699,12 @@
FLAG_SET_DEFAULT(UseSHA512Intrinsics, false);
}
+ if (UseCRC32CIntrinsics) {
+ if (!FLAG_IS_DEFAULT(UseCRC32CIntrinsics))
+ warning("CRC32C intrinsics are not available on this CPU");
+ FLAG_SET_DEFAULT(UseCRC32CIntrinsics, false);
+ }
+
// Adjust RTM (Restricted Transactional Memory) flags
if (!supports_rtm() && UseRTMLocking) {
// Can't continue because UseRTMLocking affects UseBiasedLocking flag
--- a/hotspot/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp Thu Jul 09 13:49:32 2015 -0700
+++ b/hotspot/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp Wed Jul 05 20:41:12 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -363,6 +363,11 @@
#endif
if (av & AV_SPARC_CBCOND) features |= cbcond_instructions_m;
+#ifndef AV_SPARC_CRC32C
+#define AV_SPARC_CRC32C 0x20000000 /* crc32c instruction supported */
+#endif
+ if (av & AV_SPARC_CRC32C) features |= crc32c_instruction_m;
+
#ifndef AV_SPARC_AES
#define AV_SPARC_AES 0x00020000 /* aes instrs supported */
#endif
--- a/hotspot/src/share/vm/ci/ciField.cpp Thu Jul 09 13:49:32 2015 -0700
+++ b/hotspot/src/share/vm/ci/ciField.cpp Wed Jul 05 20:41:12 2017 +0200
@@ -186,6 +186,10 @@
// Even if general trusting is disabled, trust system-built closures in these packages.
if (holder->is_in_package("java/lang/invoke") || holder->is_in_package("sun/invoke"))
return true;
+ // Trust VM anonymous classes. They are private API (sun.misc.Unsafe) and can't be serialized,
+ // so there is no hacking of finals going on with them.
+ if (holder->is_anonymous())
+ return true;
return TrustFinalNonStaticFields;
}
--- a/hotspot/src/share/vm/ci/ciInstanceKlass.cpp Thu Jul 09 13:49:32 2015 -0700
+++ b/hotspot/src/share/vm/ci/ciInstanceKlass.cpp Wed Jul 05 20:41:12 2017 +0200
@@ -58,6 +58,7 @@
_nonstatic_field_size = ik->nonstatic_field_size();
_has_nonstatic_fields = ik->has_nonstatic_fields();
_has_default_methods = ik->has_default_methods();
+ _is_anonymous = ik->is_anonymous();
_nonstatic_fields = NULL; // initialized lazily by compute_nonstatic_fields:
_has_injected_fields = -1;
_implementor = NULL; // we will fill these lazily
@@ -101,6 +102,7 @@
_has_nonstatic_fields = false;
_nonstatic_fields = NULL;
_has_injected_fields = -1;
+ _is_anonymous = false;
_loader = loader;
_protection_domain = protection_domain;
_is_shared = false;
--- a/hotspot/src/share/vm/ci/ciInstanceKlass.hpp Thu Jul 09 13:49:32 2015 -0700
+++ b/hotspot/src/share/vm/ci/ciInstanceKlass.hpp Wed Jul 05 20:41:12 2017 +0200
@@ -53,6 +53,7 @@
bool _has_subklass;
bool _has_nonstatic_fields;
bool _has_default_methods;
+ bool _is_anonymous;
ciFlags _flags;
jint _nonstatic_field_size;
@@ -179,6 +180,10 @@
return _has_default_methods;
}
+ bool is_anonymous() {
+ return _is_anonymous;
+ }
+
ciInstanceKlass* get_canonical_holder(int offset);
ciField* get_field_by_offset(int field_offset, bool is_static);
ciField* get_field_by_name(ciSymbol* name, ciSymbol* signature, bool is_static);
--- a/hotspot/src/share/vm/classfile/vmSymbols.hpp Thu Jul 09 13:49:32 2015 -0700
+++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp Wed Jul 05 20:41:12 2017 +0200
@@ -863,6 +863,12 @@
do_name( updateByteBuffer_name, "updateByteBuffer") \
do_signature(updateByteBuffer_signature, "(IJII)I") \
\
+ /* support for java.util.zip.CRC32C */ \
+ do_class(java_util_zip_CRC32C, "java/util/zip/CRC32C") \
+ do_intrinsic(_updateBytesCRC32C, java_util_zip_CRC32C, updateBytes_name, updateBytes_signature, F_S) \
+ do_intrinsic(_updateDirectByteBufferCRC32C, java_util_zip_CRC32C, updateDirectByteBuffer_name, updateByteBuffer_signature, F_S) \
+ do_name( updateDirectByteBuffer_name, "updateDirectByteBuffer") \
+ \
/* support for sun.misc.Unsafe */ \
do_class(sun_misc_Unsafe, "sun/misc/Unsafe") \
\
--- a/hotspot/src/share/vm/opto/escape.cpp Thu Jul 09 13:49:32 2015 -0700
+++ b/hotspot/src/share/vm/opto/escape.cpp Wed Jul 05 20:41:12 2017 +0200
@@ -962,6 +962,7 @@
(strcmp(call->as_CallLeaf()->_name, "g1_wb_pre") == 0 ||
strcmp(call->as_CallLeaf()->_name, "g1_wb_post") == 0 ||
strcmp(call->as_CallLeaf()->_name, "updateBytesCRC32") == 0 ||
+ strcmp(call->as_CallLeaf()->_name, "updateBytesCRC32C") == 0 ||
strcmp(call->as_CallLeaf()->_name, "aescrypt_encryptBlock") == 0 ||
strcmp(call->as_CallLeaf()->_name, "aescrypt_decryptBlock") == 0 ||
strcmp(call->as_CallLeaf()->_name, "cipherBlockChaining_encryptAESCrypt") == 0 ||
--- a/hotspot/src/share/vm/opto/library_call.cpp Thu Jul 09 13:49:32 2015 -0700
+++ b/hotspot/src/share/vm/opto/library_call.cpp Wed Jul 05 20:41:12 2017 +0200
@@ -197,7 +197,7 @@
CallJavaNode* generate_method_call_virtual(vmIntrinsics::ID method_id) {
return generate_method_call(method_id, true, false);
}
- Node * load_field_from_object(Node * fromObj, const char * fieldName, const char * fieldTypeString, bool is_exact, bool is_static);
+ Node * load_field_from_object(Node * fromObj, const char * fieldName, const char * fieldTypeString, bool is_exact, bool is_static, ciInstanceKlass * fromKls);
Node* make_string_method_node(int opcode, Node* str1_start, Node* cnt1, Node* str2_start, Node* cnt2);
Node* make_string_method_node(int opcode, Node* str1, Node* str2);
@@ -291,6 +291,9 @@
bool inline_updateCRC32();
bool inline_updateBytesCRC32();
bool inline_updateByteBufferCRC32();
+ Node* get_table_from_crc32c_class(ciInstanceKlass *crc32c_class);
+ bool inline_updateBytesCRC32C();
+ bool inline_updateDirectByteBufferCRC32C();
bool inline_multiplyToLen();
bool inline_squareToLen();
bool inline_mulAdd();
@@ -539,6 +542,11 @@
if (!UseCRC32Intrinsics) return NULL;
break;
+ case vmIntrinsics::_updateBytesCRC32C:
+ case vmIntrinsics::_updateDirectByteBufferCRC32C:
+ if (!UseCRC32CIntrinsics) return NULL;
+ break;
+
case vmIntrinsics::_incrementExactI:
case vmIntrinsics::_addExactI:
if (!Matcher::match_rule_supported(Op_OverflowAddI) || !UseMathExactIntrinsics) return NULL;
@@ -947,6 +955,11 @@
case vmIntrinsics::_updateByteBufferCRC32:
return inline_updateByteBufferCRC32();
+ case vmIntrinsics::_updateBytesCRC32C:
+ return inline_updateBytesCRC32C();
+ case vmIntrinsics::_updateDirectByteBufferCRC32C:
+ return inline_updateDirectByteBufferCRC32C();
+
case vmIntrinsics::_profileBoolean:
return inline_profileBoolean();
case vmIntrinsics::_isCompileConstant:
@@ -5536,6 +5549,106 @@
return true;
}
+//------------------------------get_table_from_crc32c_class-----------------------
+Node * LibraryCallKit::get_table_from_crc32c_class(ciInstanceKlass *crc32c_class) {
+ Node* table = load_field_from_object(NULL, "byteTable", "[I", /*is_exact*/ false, /*is_static*/ true, crc32c_class);
+ assert (table != NULL, "wrong version of java.util.zip.CRC32C");
+
+ return table;
+}
+
+//------------------------------inline_updateBytesCRC32C-----------------------
+//
+// Calculate CRC32C for byte[] array.
+// int java.util.zip.CRC32C.updateBytes(int crc, byte[] buf, int off, int end)
+//
+bool LibraryCallKit::inline_updateBytesCRC32C() {
+ assert(UseCRC32CIntrinsics, "need CRC32C instruction support");
+ assert(callee()->signature()->size() == 4, "updateBytes has 4 parameters");
+ assert(callee()->holder()->is_loaded(), "CRC32C class must be loaded");
+ // no receiver since it is a static method
+ Node* crc = argument(0); // type: int
+ Node* src = argument(1); // type: oop
+ Node* offset = argument(2); // type: int
+ Node* end = argument(3); // type: int
+
+ Node* length = _gvn.transform(new SubINode(end, offset));
+
+ const Type* src_type = src->Value(&_gvn);
+ const TypeAryPtr* top_src = src_type->isa_aryptr();
+ if (top_src == NULL || top_src->klass() == NULL) {
+ // failed array check
+ return false;
+ }
+
+ // Figure out the size and type of the elements we will be copying.
+ BasicType src_elem = src_type->isa_aryptr()->klass()->as_array_klass()->element_type()->basic_type();
+ if (src_elem != T_BYTE) {
+ return false;
+ }
+
+ // 'src_start' points to src array + scaled offset
+ Node* src_start = array_element_address(src, offset, src_elem);
+
+ // static final int[] byteTable in class CRC32C
+ Node* table = get_table_from_crc32c_class(callee()->holder());
+ Node* table_start = array_element_address(table, intcon(0), T_INT);
+
+ // We assume that range check is done by caller.
+ // TODO: generate range check (offset+length < src.length) in debug VM.
+
+ // Call the stub.
+ address stubAddr = StubRoutines::updateBytesCRC32C();
+ const char *stubName = "updateBytesCRC32C";
+
+ Node* call = make_runtime_call(RC_LEAF, OptoRuntime::updateBytesCRC32C_Type(),
+ stubAddr, stubName, TypePtr::BOTTOM,
+ crc, src_start, length, table_start);
+ Node* result = _gvn.transform(new ProjNode(call, TypeFunc::Parms));
+ set_result(result);
+ return true;
+}
+
+//------------------------------inline_updateDirectByteBufferCRC32C-----------------------
+//
+// Calculate CRC32C for DirectByteBuffer.
+// int java.util.zip.CRC32C.updateDirectByteBuffer(int crc, long buf, int off, int end)
+//
+bool LibraryCallKit::inline_updateDirectByteBufferCRC32C() {
+ assert(UseCRC32CIntrinsics, "need CRC32C instruction support");
+ assert(callee()->signature()->size() == 5, "updateDirectByteBuffer has 4 parameters and one is long");
+ assert(callee()->holder()->is_loaded(), "CRC32C class must be loaded");
+ // no receiver since it is a static method
+ Node* crc = argument(0); // type: int
+ Node* src = argument(1); // type: long
+ Node* offset = argument(3); // type: int
+ Node* end = argument(4); // type: int
+
+ Node* length = _gvn.transform(new SubINode(end, offset));
+
+ src = ConvL2X(src); // adjust Java long to machine word
+ Node* base = _gvn.transform(new CastX2PNode(src));
+ offset = ConvI2X(offset);
+
+ // 'src_start' points to src array + scaled offset
+ Node* src_start = basic_plus_adr(top(), base, offset);
+
+ // static final int[] byteTable in class CRC32C
+ Node* table = get_table_from_crc32c_class(callee()->holder());
+ Node* table_start = array_element_address(table, intcon(0), T_INT);
+
+ // Call the stub.
+ address stubAddr = StubRoutines::updateBytesCRC32C();
+ const char *stubName = "updateBytesCRC32C";
+
+ Node* call = make_runtime_call(RC_LEAF, OptoRuntime::updateBytesCRC32C_Type(),
+ stubAddr, stubName, TypePtr::BOTTOM,
+ crc, src_start, length, table_start);
+ Node* result = _gvn.transform(new ProjNode(call, TypeFunc::Parms));
+ set_result(result);
+ return true;
+}
+
//----------------------------inline_reference_get----------------------------
// public T java.lang.ref.Reference.get();
bool LibraryCallKit::inline_reference_get() {
@@ -5571,18 +5684,28 @@
Node * LibraryCallKit::load_field_from_object(Node * fromObj, const char * fieldName, const char * fieldTypeString,
- bool is_exact=true, bool is_static=false) {
-
- const TypeInstPtr* tinst = _gvn.type(fromObj)->isa_instptr();
- assert(tinst != NULL, "obj is null");
- assert(tinst->klass()->is_loaded(), "obj is not loaded");
- assert(!is_exact || tinst->klass_is_exact(), "klass not exact");
-
- ciField* field = tinst->klass()->as_instance_klass()->get_field_by_name(ciSymbol::make(fieldName),
- ciSymbol::make(fieldTypeString),
- is_static);
+ bool is_exact=true, bool is_static=false,
+ ciInstanceKlass * fromKls=NULL) {
+ if (fromKls == NULL) {
+ const TypeInstPtr* tinst = _gvn.type(fromObj)->isa_instptr();
+ assert(tinst != NULL, "obj is null");
+ assert(tinst->klass()->is_loaded(), "obj is not loaded");
+ assert(!is_exact || tinst->klass_is_exact(), "klass not exact");
+ fromKls = tinst->klass()->as_instance_klass();
+ } else {
+ assert(is_static, "only for static field access");
+ }
+ ciField* field = fromKls->get_field_by_name(ciSymbol::make(fieldName),
+ ciSymbol::make(fieldTypeString),
+ is_static);
+
+ assert (field != NULL, "undefined field");
if (field == NULL) return (Node *) NULL;
- assert (field != NULL, "undefined field");
+
+ if (is_static) {
+ const TypeInstPtr* tip = TypeInstPtr::make(fromKls->java_mirror());
+ fromObj = makecon(tip);
+ }
// Next code copied from Parse::do_get_xxx():
--- a/hotspot/src/share/vm/opto/runtime.cpp Thu Jul 09 13:49:32 2015 -0700
+++ b/hotspot/src/share/vm/opto/runtime.cpp Wed Jul 05 20:41:12 2017 +0200
@@ -851,6 +851,29 @@
return TypeFunc::make(domain, range);
}
+/**
+ * int updateBytesCRC32C(int crc, byte* buf, int len, int* table)
+ */
+const TypeFunc* OptoRuntime::updateBytesCRC32C_Type() {
+ // create input type (domain)
+ int num_args = 4;
+ int argcnt = num_args;
+ const Type** fields = TypeTuple::fields(argcnt);
+ int argp = TypeFunc::Parms;
+ fields[argp++] = TypeInt::INT; // crc
+ fields[argp++] = TypePtr::NOTNULL; // buf
+ fields[argp++] = TypeInt::INT; // len
+ fields[argp++] = TypePtr::NOTNULL; // table
+ assert(argp == TypeFunc::Parms+argcnt, "correct decoding");
+ const TypeTuple* domain = TypeTuple::make(TypeFunc::Parms+argcnt, fields);
+
+ // result type needed
+ fields = TypeTuple::fields(1);
+ fields[TypeFunc::Parms+0] = TypeInt::INT; // crc result
+ const TypeTuple* range = TypeTuple::make(TypeFunc::Parms+1, fields);
+ return TypeFunc::make(domain, range);
+}
+
// for cipherBlockChaining calls of aescrypt encrypt/decrypt, four pointers and a length, returning int
const TypeFunc* OptoRuntime::cipherBlockChaining_aescrypt_Type() {
// create input type (domain)
--- a/hotspot/src/share/vm/opto/runtime.hpp Thu Jul 09 13:49:32 2015 -0700
+++ b/hotspot/src/share/vm/opto/runtime.hpp Wed Jul 05 20:41:12 2017 +0200
@@ -319,6 +319,7 @@
static const TypeFunc* ghash_processBlocks_Type();
static const TypeFunc* updateBytesCRC32_Type();
+ static const TypeFunc* updateBytesCRC32C_Type();
// leaf on stack replacement interpreter accessor types
static const TypeFunc* osr_end_Type();
--- a/hotspot/src/share/vm/opto/superword.cpp Thu Jul 09 13:49:32 2015 -0700
+++ b/hotspot/src/share/vm/opto/superword.cpp Wed Jul 05 20:41:12 2017 +0200
@@ -183,13 +183,20 @@
break;
}
+ // Ignore nodes with non-primitive type.
+ BasicType bt;
+ if (n->is_Mem()) {
+ bt = n->as_Mem()->memory_type();
+ } else {
+ bt = n->bottom_type()->basic_type();
+ }
+ if (is_java_primitive(bt) == false) {
+ ignored_loop_nodes[i] = n->_idx;
+ continue;
+ }
+
if (n->is_Mem()) {
MemNode* current = n->as_Mem();
- BasicType bt = current->memory_type();
- if (is_java_primitive(bt) == false) {
- ignored_loop_nodes[i] = n->_idx;
- continue;
- }
Node* adr = n->in(MemNode::Address);
Node* n_ctrl = _phase->get_ctrl(adr);
@@ -231,11 +238,12 @@
BasicType bt;
Node* n = lpt()->_body.at(i);
- if (n->is_Store()) {
+ if (n->is_Mem()) {
bt = n->as_Mem()->memory_type();
} else {
bt = n->bottom_type()->basic_type();
}
+ if (is_java_primitive(bt) == false) continue;
int cur_max_vector = Matcher::max_vector_size(bt);
--- a/hotspot/src/share/vm/runtime/arguments.cpp Thu Jul 09 13:49:32 2015 -0700
+++ b/hotspot/src/share/vm/runtime/arguments.cpp Wed Jul 05 20:41:12 2017 +0200
@@ -3753,8 +3753,12 @@
if (TieredCompilation) {
set_tiered_flags();
} else {
- // Check if the policy is valid. Policies 0 and 1 are valid for non-tiered setup.
- if (CompilationPolicyChoice >= 2) {
+ int max_compilation_policy_choice = 1;
+#ifdef COMPILER2
+ max_compilation_policy_choice = 2;
+#endif
+ // Check if the policy is valid.
+ if (CompilationPolicyChoice >= max_compilation_policy_choice) {
vm_exit_during_initialization(
"Incompatible compilation policy selected", NULL);
}
--- a/hotspot/src/share/vm/runtime/compilationPolicy.cpp Thu Jul 09 13:49:32 2015 -0700
+++ b/hotspot/src/share/vm/runtime/compilationPolicy.cpp Wed Jul 05 20:41:12 2017 +0200
@@ -512,7 +512,7 @@
RegisterMap reg_map(thread, false);
javaVFrame* triggerVF = thread->last_java_vframe(®_map);
// triggerVF is the frame that triggered its counter
- RFrame* first = new InterpretedRFrame(triggerVF->fr(), thread, m);
+ RFrame* first = new InterpretedRFrame(triggerVF->fr(), thread, m());
if (first->top_method()->code() != NULL) {
// called obsolete method/nmethod -- no need to recompile
@@ -557,8 +557,8 @@
if( !next ) // No next frame up the stack?
break; // Then compile with current frame
- methodHandle m = current->top_method();
- methodHandle next_m = next->top_method();
+ Method* m = current->top_method();
+ Method* next_m = next->top_method();
if (TraceCompilationPolicy && Verbose) {
tty->print("[caller: ");
@@ -644,7 +644,7 @@
if (TraceCompilationPolicy && Verbose) {
tty->print("\n\t check caller: ");
next_m->print_short_name(tty);
- tty->print(" ( interpreted " INTPTR_FORMAT ", size=%d ) ", p2i((address)next_m()), next_m->code_size());
+ tty->print(" ( interpreted " INTPTR_FORMAT ", size=%d ) ", p2i((address)next_m), next_m->code_size());
}
current = next;
--- a/hotspot/src/share/vm/runtime/globals.hpp Thu Jul 09 13:49:32 2015 -0700
+++ b/hotspot/src/share/vm/runtime/globals.hpp Wed Jul 05 20:41:12 2017 +0200
@@ -848,6 +848,9 @@
product(bool, UseCRC32Intrinsics, false, \
"use intrinsics for java.util.zip.CRC32") \
\
+ product(bool, UseCRC32CIntrinsics, false, \
+ "use intrinsics for java.util.zip.CRC32C") \
+ \
develop(bool, TraceCallFixup, false, \
"Trace all call fixups") \
\
--- a/hotspot/src/share/vm/runtime/rframe.cpp Thu Jul 09 13:49:32 2015 -0700
+++ b/hotspot/src/share/vm/runtime/rframe.cpp Wed Jul 05 20:41:12 2017 +0200
@@ -52,12 +52,12 @@
: RFrame(fr, thread, callee) {
RegisterMap map(thread, false);
_vf = javaVFrame::cast(vframe::new_vframe(&_fr, &map, thread));
- _method = methodHandle(thread, _vf->method());
+ _method = _vf->method();
assert( _vf->is_interpreted_frame(), "must be interpreted");
init();
}
-InterpretedRFrame::InterpretedRFrame(frame fr, JavaThread* thread, methodHandle m)
+InterpretedRFrame::InterpretedRFrame(frame fr, JavaThread* thread, Method* m)
: RFrame(fr, thread, NULL) {
RegisterMap map(thread, false);
_vf = javaVFrame::cast(vframe::new_vframe(&_fr, &map, thread));
@@ -140,8 +140,8 @@
_nm = compiledVFrame::cast(vf)->code();
vf = vf->top();
_vf = javaVFrame::cast(vf);
- _method = methodHandle(thread(), CodeCache::find_nmethod(_fr.pc())->method());
- assert(_method(), "should have found a method");
+ _method = CodeCache::find_nmethod(_fr.pc())->method();
+ assert(_method, "should have found a method");
#ifndef PRODUCT
_invocations = _method->compiled_invocation_count();
#endif
--- a/hotspot/src/share/vm/runtime/rframe.hpp Thu Jul 09 13:49:32 2015 -0700
+++ b/hotspot/src/share/vm/runtime/rframe.hpp Wed Jul 05 20:41:12 2017 +0200
@@ -60,7 +60,7 @@
frame fr() const { return _fr; }
JavaThread* thread() const { return _thread; }
virtual int cost() const = 0; // estimated inlining cost (size)
- virtual methodHandle top_method() const = 0;
+ virtual Method* top_method() const = 0;
virtual javaVFrame* top_vframe() const = 0;
virtual nmethod* nm() const { ShouldNotCallThis(); return NULL; }
@@ -79,7 +79,7 @@
protected:
nmethod* _nm;
javaVFrame* _vf; // top vframe; may be NULL (for most recent frame)
- methodHandle _method; // top method
+ Method* _method; // top method
CompiledRFrame(frame fr, JavaThread* thread, RFrame*const callee);
void init();
@@ -88,7 +88,7 @@
public:
CompiledRFrame(frame fr, JavaThread* thread); // for nmethod triggering its counter (callee == NULL)
bool is_compiled() const { return true; }
- methodHandle top_method() const { return _method; }
+ Method* top_method() const { return _method; }
javaVFrame* top_vframe() const { return _vf; }
nmethod* nm() const { return _nm; }
int cost() const;
@@ -98,16 +98,16 @@
class InterpretedRFrame : public RFrame { // interpreter frame
protected:
javaVFrame* _vf; // may be NULL (for most recent frame)
- methodHandle _method;
+ Method* _method;
InterpretedRFrame(frame fr, JavaThread* thread, RFrame*const callee);
void init();
friend class RFrame;
public:
- InterpretedRFrame(frame fr, JavaThread* thread, methodHandle m); // constructor for method triggering its invocation counter
+ InterpretedRFrame(frame fr, JavaThread* thread, Method* m); // constructor for method triggering its invocation counter
bool is_interpreted() const { return true; }
- methodHandle top_method() const { return _method; }
+ Method* top_method() const { return _method; }
javaVFrame* top_vframe() const { return _vf; }
int cost() const;
void print();
--- a/hotspot/src/share/vm/runtime/stubRoutines.cpp Thu Jul 09 13:49:32 2015 -0700
+++ b/hotspot/src/share/vm/runtime/stubRoutines.cpp Wed Jul 05 20:41:12 2017 +0200
@@ -137,6 +137,8 @@
address StubRoutines::_updateBytesCRC32 = NULL;
address StubRoutines::_crc_table_adr = NULL;
+address StubRoutines::_updateBytesCRC32C = NULL;
+
address StubRoutines::_multiplyToLen = NULL;
address StubRoutines::_squareToLen = NULL;
address StubRoutines::_mulAdd = NULL;
--- a/hotspot/src/share/vm/runtime/stubRoutines.hpp Thu Jul 09 13:49:32 2015 -0700
+++ b/hotspot/src/share/vm/runtime/stubRoutines.hpp Wed Jul 05 20:41:12 2017 +0200
@@ -197,6 +197,8 @@
static address _updateBytesCRC32;
static address _crc_table_adr;
+ static address _updateBytesCRC32C;
+
static address _multiplyToLen;
static address _squareToLen;
static address _mulAdd;
@@ -359,6 +361,8 @@
static address updateBytesCRC32() { return _updateBytesCRC32; }
static address crc_table_addr() { return _crc_table_adr; }
+ static address updateBytesCRC32C() { return _updateBytesCRC32C; }
+
static address multiplyToLen() {return _multiplyToLen; }
static address squareToLen() {return _squareToLen; }
static address mulAdd() {return _mulAdd; }
--- a/hotspot/src/share/vm/runtime/vmStructs.cpp Thu Jul 09 13:49:32 2015 -0700
+++ b/hotspot/src/share/vm/runtime/vmStructs.cpp Wed Jul 05 20:41:12 2017 +0200
@@ -830,6 +830,7 @@
static_field(StubRoutines, _ghash_processBlocks, address) \
static_field(StubRoutines, _updateBytesCRC32, address) \
static_field(StubRoutines, _crc_table_adr, address) \
+ static_field(StubRoutines, _updateBytesCRC32C, address) \
static_field(StubRoutines, _multiplyToLen, address) \
static_field(StubRoutines, _squareToLen, address) \
static_field(StubRoutines, _mulAdd, address) \
--- a/hotspot/test/TEST.groups Thu Jul 09 13:49:32 2015 -0700
+++ b/hotspot/test/TEST.groups Wed Jul 05 20:41:12 2017 +0200
@@ -147,12 +147,16 @@
gc/survivorAlignment \
gc/TestGCLogRotationViaJcmd.java \
runtime/InternalApi/ThreadCpuTimesDeadlock.java \
+ runtime/NMT/JcmdSummaryDiff.java \
+ runtime/RedefineTests/RedefineAnnotations.java
serviceability/sa/jmap-hashcode/Test8028623.java \
serviceability/threads/TestFalseDeadLock.java \
compiler/codecache/jmx \
compiler/jsr292/RedefineMethodUsedByMultipleMethodHandles.java \
compiler/rangechecks/TestRangeCheckSmearing.java \
- serviceability/dcmd
+ compiler/whitebox/DeoptimizeMultipleOSRTest.java \
+ serviceability/dcmd \
+ testlibrary_tests/whitebox/vm_flags
# Compact 2 adds full VM tests
compact2 = \
--- a/hotspot/test/compiler/codecache/jmx/CodeCacheUtils.java Thu Jul 09 13:49:32 2015 -0700
+++ b/hotspot/test/compiler/codecache/jmx/CodeCacheUtils.java Wed Jul 05 20:41:12 2017 +0200
@@ -21,6 +21,7 @@
* questions.
*/
+import jdk.test.lib.Asserts;
import jdk.test.lib.Utils;
import java.lang.management.MemoryPoolMXBean;
import javax.management.Notification;
@@ -80,19 +81,42 @@
}
/**
- * A "non-nmethods" code heap is used by interpreter during bytecode
- * execution, thus, it can't be predicted if this code heap usage will be
- * increased or not. Same goes for 'All'.
+ * Checks if the usage of the code heap corresponding to 'btype' can be
+ * predicted at runtime if we disable compilation. The usage of the
+ * 'NonNMethod' code heap can not be predicted because we generate adapters
+ * and buffers at runtime. The 'MethodNonProfiled' code heap is also not
+ * predictable because we may generate compiled versions of method handle
+ * intrinsics while resolving methods at runtime. Same applies to 'All'.
*
* @param btype BlobType to be checked
* @return boolean value, true if respective code heap is predictable
*/
public static boolean isCodeHeapPredictable(BlobType btype) {
- return btype == BlobType.MethodNonProfiled
- || btype == BlobType.MethodProfiled;
+ return btype == BlobType.MethodProfiled;
}
- public static void disableCollectionUsageThresholds(){
+ /**
+ * Verifies that 'newValue' is equal to 'oldValue' if usage of the
+ * corresponding code heap is predictable. Checks the weaker condition
+ * 'newValue >= oldValue' if usage is not predictable because intermediate
+ * allocations may happen.
+ *
+ * @param btype BlobType of the code heap to be checked
+ * @param newValue New value to be verified
+ * @param oldValue Old value to be verified
+ * @param msg Error message if verification fails
+ */
+ public static void assertEQorGTE(BlobType btype, long newValue, long oldValue, String msg) {
+ if (CodeCacheUtils.isCodeHeapPredictable(btype)) {
+ // Usage is predictable, check strong == condition
+ Asserts.assertEQ(newValue, oldValue, msg);
+ } else {
+ // Usage is not predictable, check weaker >= condition
+ Asserts.assertGTE(newValue, oldValue, msg);
+ }
+ }
+
+ public static void disableCollectionUsageThresholds() {
BlobType.getAvailable().stream()
.map(BlobType::getMemoryPool)
.filter(MemoryPoolMXBean::isCollectionUsageThresholdSupported)
--- a/hotspot/test/compiler/codecache/jmx/GetUsageTest.java Thu Jul 09 13:49:32 2015 -0700
+++ b/hotspot/test/compiler/codecache/jmx/GetUsageTest.java Wed Jul 05 20:41:12 2017 +0200
@@ -52,10 +52,8 @@
public static void main(String[] args) throws Exception {
for (BlobType btype : BlobType.getAvailable()) {
- if (CodeCacheUtils.isCodeHeapPredictable(btype)) {
- for (int allocSize = 10; allocSize < 100000; allocSize *= 10) {
- new GetUsageTest(btype, allocSize).runTest();
- }
+ for (int allocSize = 10; allocSize < 100000; allocSize *= 10) {
+ new GetUsageTest(btype, allocSize).runTest();
}
}
}
@@ -87,13 +85,15 @@
for (MemoryPoolMXBean entry : predictableBeans) {
long diff = current.get(entry) - initial.get(entry);
if (entry.equals(btype.getMemoryPool())) {
- Asserts.assertFalse(diff <= 0L || diff > usageUpperEstimate,
- String.format("Pool %s usage increase was reported "
- + "unexpectedly as increased by %d using "
- + "allocation size %d", entry.getName(),
- diff, allocateSize));
+ if (CodeCacheUtils.isCodeHeapPredictable(btype)) {
+ Asserts.assertFalse(diff <= 0L || diff > usageUpperEstimate,
+ String.format("Pool %s usage increase was reported "
+ + "unexpectedly as increased by %d using "
+ + "allocation size %d", entry.getName(),
+ diff, allocateSize));
+ }
} else {
- Asserts.assertEQ(diff, 0L,
+ CodeCacheUtils.assertEQorGTE(btype, diff, 0L,
String.format("Pool %s usage changed unexpectedly while"
+ " trying to increase: %s using allocation "
+ "size %d", entry.getName(),
--- a/hotspot/test/compiler/codecache/jmx/PeakUsageTest.java Thu Jul 09 13:49:32 2015 -0700
+++ b/hotspot/test/compiler/codecache/jmx/PeakUsageTest.java Wed Jul 05 20:41:12 2017 +0200
@@ -52,9 +52,7 @@
public static void main(String[] args) {
for (BlobType btype : BlobType.getAvailable()) {
- if (CodeCacheUtils.isCodeHeapPredictable(btype)) {
- new PeakUsageTest(btype).runTest();
- }
+ new PeakUsageTest(btype).runTest();
}
}
@@ -65,7 +63,7 @@
CodeCacheUtils.ALLOCATION_SIZE, btype.id);
long newPeakUsage = bean.getPeakUsage().getUsed();
try {
- Asserts.assertEQ(newPeakUsage, bean.getUsage().getUsed(),
+ CodeCacheUtils.assertEQorGTE(btype, newPeakUsage, bean.getUsage().getUsed(),
"Peak usage does not match usage after allocation for "
+ bean.getName());
} finally {
@@ -73,18 +71,18 @@
CodeCacheUtils.WB.freeCodeBlob(addr);
}
}
- Asserts.assertEQ(newPeakUsage, bean.getPeakUsage().getUsed(),
+ CodeCacheUtils.assertEQorGTE(btype, newPeakUsage, bean.getPeakUsage().getUsed(),
"Code cache peak usage has changed after usage decreased for "
+ bean.getName());
bean.resetPeakUsage();
- Asserts.assertEQ(bean.getPeakUsage().getUsed(),
+ CodeCacheUtils.assertEQorGTE(btype, bean.getPeakUsage().getUsed(),
bean.getUsage().getUsed(),
"Code cache peak usage is not equal to usage after reset for "
+ bean.getName());
long addr2 = CodeCacheUtils.WB.allocateCodeBlob(
CodeCacheUtils.ALLOCATION_SIZE, btype.id);
try {
- Asserts.assertEQ(bean.getPeakUsage().getUsed(),
+ CodeCacheUtils.assertEQorGTE(btype, bean.getPeakUsage().getUsed(),
bean.getUsage().getUsed(),
"Code cache peak usage is not equal to usage after fresh "
+ "allocation for " + bean.getName());
--- a/hotspot/test/compiler/codecache/jmx/PoolsIndependenceTest.java Thu Jul 09 13:49:32 2015 -0700
+++ b/hotspot/test/compiler/codecache/jmx/PoolsIndependenceTest.java Wed Jul 05 20:41:12 2017 +0200
@@ -97,13 +97,11 @@
return false;
});
for (BlobType bt : BlobType.getAvailable()) {
- if (CodeCacheUtils.isCodeHeapPredictable(bt)) {
- int expectedNotificationsAmount = bt.equals(btype) ? 1 : 0;
- Asserts.assertEQ(counters.get(bt.getMemoryPool().getName()).get(),
- expectedNotificationsAmount, String.format("Unexpected "
- + "amount of notifications for pool: %s",
- bt.getMemoryPool().getName()));
- }
+ int expectedNotificationsAmount = bt.equals(btype) ? 1 : 0;
+ CodeCacheUtils.assertEQorGTE(btype, counters.get(bt.getMemoryPool().getName()).get(),
+ expectedNotificationsAmount, String.format("Unexpected "
+ + "amount of notifications for pool: %s",
+ bt.getMemoryPool().getName()));
}
try {
((NotificationEmitter) ManagementFactory.getMemoryMXBean()).
--- a/hotspot/test/compiler/codecache/jmx/ThresholdNotificationsTest.java Thu Jul 09 13:49:32 2015 -0700
+++ b/hotspot/test/compiler/codecache/jmx/ThresholdNotificationsTest.java Wed Jul 05 20:41:12 2017 +0200
@@ -54,9 +54,7 @@
public static void main(String[] args) {
for (BlobType bt : BlobType.getAvailable()) {
- if (CodeCacheUtils.isCodeHeapPredictable(bt)) {
- new ThresholdNotificationsTest(bt).runTest();
- }
+ new ThresholdNotificationsTest(bt).runTest();
}
}
@@ -92,7 +90,9 @@
}
Asserts.assertTrue(
Utils.waitForCondition(
- () -> counter == iterationsCount, WAIT_TIME),
+ () -> (CodeCacheUtils.isCodeHeapPredictable(btype) ?
+ (counter == iterationsCount) : (counter >= iterationsCount)),
+ WAIT_TIME),
"Couldn't receive expected notifications count");
try {
((NotificationEmitter) ManagementFactory.getMemoryMXBean()).
--- a/hotspot/test/compiler/codecache/jmx/UsageThresholdExceededTest.java Thu Jul 09 13:49:32 2015 -0700
+++ b/hotspot/test/compiler/codecache/jmx/UsageThresholdExceededTest.java Wed Jul 05 20:41:12 2017 +0200
@@ -51,13 +51,9 @@
}
public static void main(String[] args) {
- int iterationsCount =
- Integer.getInteger("jdk.test.lib.iterations", 1);
+ int iterationsCount = Integer.getInteger("jdk.test.lib.iterations", 1);
for (BlobType btype : BlobType.getAvailable()) {
- if (CodeCacheUtils.isCodeHeapPredictable(btype)) {
- new UsageThresholdExceededTest(btype, iterationsCount)
- .runTest();
- }
+ new UsageThresholdExceededTest(btype, iterationsCount).runTest();
}
}
@@ -67,9 +63,8 @@
for (int i = 0; i < iterations; i++) {
CodeCacheUtils.hitUsageThreshold(bean, btype);
}
- Asserts.assertEQ(bean.getUsageThresholdCount(), oldValue + iterations,
+ CodeCacheUtils.assertEQorGTE(btype, bean.getUsageThresholdCount(), oldValue + iterations,
"Unexpected threshold usage count");
- System.out.printf("INFO: Scenario finished successfully for %s%n",
- bean.getName());
+ System.out.printf("INFO: Scenario finished successfully for %s%n", bean.getName());
}
}
--- a/hotspot/test/compiler/codecache/jmx/UsageThresholdIncreasedTest.java Thu Jul 09 13:49:32 2015 -0700
+++ b/hotspot/test/compiler/codecache/jmx/UsageThresholdIncreasedTest.java Wed Jul 05 20:41:12 2017 +0200
@@ -27,7 +27,6 @@
/*
* @test UsageThresholdIncreasedTest
- * @ignore 8129937
* @library /testlibrary /../../test/lib
* @modules java.base/sun.misc
* java.management
@@ -54,14 +53,12 @@
public static void main(String[] args) {
for (BlobType btype : BlobType.getAvailable()) {
- if (CodeCacheUtils.isCodeHeapPredictable(btype)) {
- new UsageThresholdIncreasedTest(btype).runTest();
- }
+ new UsageThresholdIncreasedTest(btype).runTest();
}
}
private void checkUsageThresholdCount(MemoryPoolMXBean bean, long count){
- Asserts.assertEQ(bean.getUsageThresholdCount(), count,
+ CodeCacheUtils.assertEQorGTE(btype, bean.getUsageThresholdCount(), count,
String.format("Usage threshold was hit: %d times for %s "
+ "Threshold value: %d with current usage: %d",
bean.getUsageThresholdCount(), bean.getName(),
--- a/hotspot/test/compiler/codecache/jmx/UsageThresholdNotExceededTest.java Thu Jul 09 13:49:32 2015 -0700
+++ b/hotspot/test/compiler/codecache/jmx/UsageThresholdNotExceededTest.java Wed Jul 05 20:41:12 2017 +0200
@@ -50,9 +50,7 @@
public static void main(String[] args) {
for (BlobType btype : BlobType.getAvailable()) {
- if (CodeCacheUtils.isCodeHeapPredictable(btype)) {
- new UsageThresholdNotExceededTest(btype).runTest();
- }
+ new UsageThresholdNotExceededTest(btype).runTest();
}
}
@@ -65,13 +63,11 @@
- CodeCacheUtils.getHeaderSize(btype), btype.id);
// a gc cycle triggers usage threshold recalculation
CodeCacheUtils.WB.fullGC();
- Asserts.assertEQ(bean.getUsageThresholdCount(), initialThresholdCount,
- String.format("Usage threshold was hit: %d times for %s. "
+ CodeCacheUtils.assertEQorGTE(btype, bean.getUsageThresholdCount(), initialThresholdCount,
+ String.format("Usage threshold was hit: %d times for %s. "
+ "Threshold value: %d with current usage: %d",
bean.getUsageThresholdCount(), bean.getName(),
bean.getUsageThreshold(), bean.getUsage().getUsed()));
-
- System.out.println("INFO: Case finished successfully for "
- + bean.getName());
+ System.out.println("INFO: Case finished successfully for " + bean.getName());
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/intrinsics/crc32c/TestCRC32C.java Wed Jul 05 20:41:12 2017 +0200
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 8073583
+ * @summary C2 support for CRC32C on SPARC
+ *
+ * @run main/othervm/timeout=600 -Xbatch TestCRC32C -m
+ */
+
+import java.nio.ByteBuffer;
+import java.util.zip.Checksum;
+import java.util.zip.CRC32C;
+
+public class TestCRC32C {
+ public static void main(String[] args) {
+ int offset = Integer.getInteger("offset", 0);
+ int msgSize = Integer.getInteger("msgSize", 512);
+ boolean multi = false;
+ int iters = 20000;
+ int warmupIters = 20000;
+
+ if (args.length > 0) {
+ if (args[0].equals("-m")) {
+ multi = true;
+ } else {
+ iters = Integer.valueOf(args[0]);
+ }
+ if (args.length > 1) {
+ warmupIters = Integer.valueOf(args[1]);
+ }
+ }
+
+ if (multi) {
+ test_multi(warmupIters);
+ return;
+ }
+
+ System.out.println(" offset = " + offset);
+ System.out.println("msgSize = " + msgSize + " bytes");
+ System.out.println(" iters = " + iters);
+
+ byte[] b = initializedBytes(msgSize, offset);
+
+ CRC32C crc0 = new CRC32C();
+ CRC32C crc1 = new CRC32C();
+ CRC32C crc2 = new CRC32C();
+
+ crc0.update(b, offset, msgSize);
+
+ System.out.println("-------------------------------------------------------");
+
+ /* warm up */
+ for (int i = 0; i < warmupIters; i++) {
+ crc1.reset();
+ crc1.update(b, offset, msgSize);
+ }
+
+ /* measure performance */
+ long start = System.nanoTime();
+ for (int i = 0; i < iters; i++) {
+ crc1.reset();
+ crc1.update(b, offset, msgSize);
+ }
+ long end = System.nanoTime();
+ double total = (double)(end - start)/1e9; // in seconds
+ double thruput = (double)msgSize*iters/1e6/total; // in MB/s
+ System.out.println("CRC32C.update(byte[]) runtime = " + total + " seconds");
+ System.out.println("CRC32C.update(byte[]) throughput = " + thruput + " MB/s");
+
+ /* check correctness */
+ for (int i = 0; i < iters; i++) {
+ crc1.reset();
+ crc1.update(b, offset, msgSize);
+ if (!check(crc0, crc1)) break;
+ }
+ report("CRCs", crc0, crc1);
+
+ System.out.println("-------------------------------------------------------");
+
+ ByteBuffer buf = ByteBuffer.allocateDirect(msgSize);
+ buf.put(b, offset, msgSize);
+ buf.flip();
+
+ /* warm up */
+ for (int i = 0; i < warmupIters; i++) {
+ crc2.reset();
+ crc2.update(buf);
+ buf.rewind();
+ }
+
+ /* measure performance */
+ start = System.nanoTime();
+ for (int i = 0; i < iters; i++) {
+ crc2.reset();
+ crc2.update(buf);
+ buf.rewind();
+ }
+ end = System.nanoTime();
+ total = (double)(end - start)/1e9; // in seconds
+ thruput = (double)msgSize*iters/1e6/total; // in MB/s
+ System.out.println("CRC32C.update(ByteBuffer) runtime = " + total + " seconds");
+ System.out.println("CRC32C.update(ByteBuffer) throughput = " + thruput + " MB/s");
+
+ /* check correctness */
+ for (int i = 0; i < iters; i++) {
+ crc2.reset();
+ crc2.update(buf);
+ buf.rewind();
+ if (!check(crc0, crc2)) break;
+ }
+ report("CRCs", crc0, crc2);
+
+ System.out.println("-------------------------------------------------------");
+ }
+
+ private static void report(String s, Checksum crc0, Checksum crc1) {
+ System.out.printf("%s: crc0 = %08x, crc1 = %08x\n",
+ s, crc0.getValue(), crc1.getValue());
+ }
+
+ private static boolean check(Checksum crc0, Checksum crc1) {
+ if (crc0.getValue() != crc1.getValue()) {
+ System.err.printf("ERROR: crc0 = %08x, crc1 = %08x\n",
+ crc0.getValue(), crc1.getValue());
+ return false;
+ }
+ return true;
+ }
+
+ private static byte[] initializedBytes(int M, int offset) {
+ byte[] bytes = new byte[M + offset];
+ for (int i = 0; i < offset; i++) {
+ bytes[i] = (byte) i;
+ }
+ for (int i = offset; i < bytes.length; i++) {
+ bytes[i] = (byte) (i - offset);
+ }
+ return bytes;
+ }
+
+ private static void test_multi(int iters) {
+ int len1 = 8; // the 8B/iteration loop
+ int len2 = 32; // the 32B/iteration loop
+ int len3 = 4096; // the 4KB/iteration loop
+
+ byte[] b = initializedBytes(len3*16, 0);
+ int[] offsets = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 16, 32, 64, 128, 256, 512 };
+ int[] sizes = { 0, 1, 2, 3, 4, 5, 6, 7,
+ len1, len1+1, len1+2, len1+3, len1+4, len1+5, len1+6, len1+7,
+ len1*2, len1*2+1, len1*2+3, len1*2+5, len1*2+7,
+ len2, len2+1, len2+3, len2+5, len2+7,
+ len2*2, len2*4, len2*8, len2*16, len2*32, len2*64,
+ len3, len3+1, len3+3, len3+5, len3+7,
+ len3*2, len3*4, len3*8,
+ len1+len2, len1+len2+1, len1+len2+3, len1+len2+5, len1+len2+7,
+ len1+len3, len1+len3+1, len1+len3+3, len1+len3+5, len1+len3+7,
+ len2+len3, len2+len3+1, len2+len3+3, len2+len3+5, len2+len3+7,
+ len1+len2+len3, len1+len2+len3+1, len1+len2+len3+3,
+ len1+len2+len3+5, len1+len2+len3+7,
+ (len1+len2+len3)*2, (len1+len2+len3)*2+1, (len1+len2+len3)*2+3,
+ (len1+len2+len3)*2+5, (len1+len2+len3)*2+7,
+ (len1+len2+len3)*3, (len1+len2+len3)*3-1, (len1+len2+len3)*3-3,
+ (len1+len2+len3)*3-5, (len1+len2+len3)*3-7 };
+ CRC32C[] crc0 = new CRC32C[offsets.length*sizes.length];
+ CRC32C[] crc1 = new CRC32C[offsets.length*sizes.length];
+ int i, j, k;
+
+ System.out.printf("testing %d cases ...\n", offsets.length*sizes.length);
+
+ /* set the result from interpreter as reference */
+ for (i = 0; i < offsets.length; i++) {
+ for (j = 0; j < sizes.length; j++) {
+ crc0[i*sizes.length + j] = new CRC32C();
+ crc1[i*sizes.length + j] = new CRC32C();
+ crc0[i*sizes.length + j].update(b, offsets[i], sizes[j]);
+ }
+ }
+
+ /* warm up the JIT compiler and get result */
+ for (k = 0; k < iters; k++) {
+ for (i = 0; i < offsets.length; i++) {
+ for (j = 0; j < sizes.length; j++) {
+ crc1[i*sizes.length + j].reset();
+ crc1[i*sizes.length + j].update(b, offsets[i], sizes[j]);
+ }
+ }
+ }
+
+ /* check correctness */
+ for (i = 0; i < offsets.length; i++) {
+ for (j = 0; j < sizes.length; j++) {
+ if (!check(crc0[i*sizes.length + j], crc1[i*sizes.length + j])) {
+ System.out.printf("offsets[%d] = %d", i, offsets[i]);
+ System.out.printf("\tsizes[%d] = %d\n", j, sizes[j]);
+ }
+ }
+ }
+ }
+}
--- a/jdk/.hgtags Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/.hgtags Wed Jul 05 20:41:12 2017 +0200
@@ -314,3 +314,4 @@
551323004d0ce2f1d4b0e99552f7e0cdcebc6fca jdk9-b69
a7f731125b7fb0e4b0186172f85a21e2d5139f7e jdk9-b70
e47d3bfbc61accc3fbd372a674fdce2933b54f31 jdk9-b71
+f376824d4940f45719d91838f3f6249f873440db jdk9-b72
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/make/lib/Lib-jdk.internal.le.gmk Wed Jul 05 20:41:12 2017 +0200
@@ -0,0 +1,60 @@
+#
+# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation. Oracle designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the LICENSE file that accompanied this code.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+include LibCommon.gmk
+
+################################################################################
+
+ifeq ($(OPENJDK_TARGET_OS), windows)
+
+ LIBLE_SRC := $(JDK_TOPDIR)/src/jdk.internal.le/$(OPENJDK_TARGET_OS_TYPE)/native/lible \
+ #
+ LIBLE_CPPFLAGS := \
+ $(addprefix -I, $(LIBLE_SRC)) \
+ -I$(SUPPORT_OUTPUTDIR)/headers/jdk.internal.le \
+ #
+
+ $(eval $(call SetupNativeCompilation,BUILD_LIBLE, \
+ LIBRARY := le, \
+ OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \
+ SRC := $(LIBLE_SRC), \
+ OPTIMIZATION := LOW, \
+ CFLAGS := $(CFLAGS_JDKLIB) $(LIBJAVA_HEADER_FLAGS)\
+ $(LIBLE_CPPFLAGS), \
+ LDFLAGS := $(LDFLAGS_JDKLIB), \
+ LDFLAGS_SUFFIX := $(LDFLAGS_JDKLIB_SUFFIX) user32.lib, \
+ VERSIONINFO_RESOURCE := $(GLOBAL_VERSION_INFO_RESOURCE), \
+ RC_FLAGS := $(RC_FLAGS) \
+ -D "JDK_FNAME=le.dll" \
+ -D "JDK_INTERNAL_NAME=le" \
+ -D "JDK_FTYPE=0x2L", \
+ OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/lible, \
+ DEBUG_SYMBOLS := $(DEBUG_ALL_BINARIES)))
+
+ TARGETS += $(BUILD_LIBLE)
+
+endif # OPENJDK_TARGET_OS
+
+################################################################################
--- a/jdk/make/non-build-utils/sharing/README.txt Thu Jul 09 13:49:32 2015 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,34 +0,0 @@
-This directory contains tools and tests associated with creating the
-class list for class data sharing.
-
-The class list is produced by running the refWorkload startup3 benchmark with
-the -XX:+TraceClassLoadingPreorder option. The -Xshare:off option must also be
-used so that bootclasspath classes are loaded from rt.jar. The MakeClasslist
-program should be built into the jar file makeclasslist.jar and is run
-on one of the logs from each of the benchmarks in the following fashion:
-
-cd .../<resultsdir>/results.startup3
-$JAVA_HOME/bin/java -jar makeclasslist.jar results.Noop/results_1/log results.Framer/results_1/log results.XFramer/results_1/log results.JEdit/results_1/log results.LimeWire/results_1/log results.NetBeans50/results_1/log
-
-Presently, $JAVA_HOME must be the same path used to run the startup3 benchmark.
-
-The logs are deliberately concatenated in roughly smallest to largest order
-based on application size. The resulting output is redirected into a file
-and results in one of classlist.solaris, classlist.linux, classlist.macosx,
-or classlist.windows. These files are checked in to the workspace. A
-necessary checksum (AddJsum.java) is added to the final classlist
-(installed in lib/ or jre/lib/) during the build process by the
-makefiles in make/java/redist.
-
-In a forthcoming JDK build we plan to manually add the dependent
-classes for the calendar manager Glow, which pulls in the Preferences
-classes and, on Unix platforms, the XML parsing classes.
-
-The properties file supplied to the refworkload is approximately the
-following:
-
-javahome=/usr/java/j2sdk1.8.0
-resultsdir=classlist-run
-iterations=1
-benchmarks=startup3
-globalvmoptions=-client -Xshare:off -XX:+TraceClassLoadingPreorder
--- a/jdk/make/non-build-utils/sharing/tests/GHello.java Thu Jul 09 13:49:32 2015 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-/*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-import java.awt.Font;
-import java.awt.Frame;
-import java.awt.Label;
-
-public class GHello extends Frame {
-
- public static void main(String[] args) {
- System.out.println("Hello");
-
- new GHello().show();
- if (args.length == 1 && args[0].equals("quit")) {
- try {
- Thread.currentThread().sleep(200);
- } catch (InterruptedException e) {
- }
- System.exit(0);
- }
- }
-
-
- GHello() {
- Label label = new Label("Hello");
- label.setFont(new Font("Monospaced", Font.PLAIN, 144));
- add(label);
- pack();
- }
-}
--- a/jdk/make/non-build-utils/sharing/tests/Hello.java Thu Jul 09 13:49:32 2015 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,32 +0,0 @@
-/*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-
-public class Hello {
- public static void main(String[] args) {
- System.out.println("Hello, World!");
- }
-}
--- a/jdk/make/non-build-utils/sharing/tests/JHello.java Thu Jul 09 13:49:32 2015 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-/*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-import java.awt.Font;
-import javax.swing.JFrame;
-import javax.swing.JLabel;
-
-public class JHello extends JFrame {
-
- public static void main(String[] args) {
- System.out.println("Hello");
-
- new JHello().show();
- if (args.length == 1 && args[0].equals("quit")) {
- try {
- Thread.currentThread().sleep(1000);
- } catch (InterruptedException e) {
- }
- System.exit(0);
- }
- }
-
-
- JHello() {
- JLabel jlabel = new JLabel("Hello");
- jlabel.setFont(new Font("Monospaced", Font.PLAIN, 144));
- getContentPane().add(jlabel);
- pack();
- }
-}
--- a/jdk/make/non-build-utils/src/build/tools/makeclasslist/MakeClasslist.java Thu Jul 09 13:49:32 2015 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,130 +0,0 @@
-/*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package build.tools.makeclasslist;
-
-import java.io.*;
-import java.util.*;
-import java.util.jar.*;
-
-/** Reads a set of files containing the output of java
- -XX:+TraceClassLoadingPreorder runs. Finds all classes that were
- loaded from the bootstrap class path by comparing the prefix of
- the load path to the current JRE's java.home system property.
- Prints the names of these classes to stdout.
-*/
-
-public class MakeClasslist {
- public static void main(String[] args) throws IOException {
- List<String> classes = new ArrayList<>();
- String origJavaHome = System.getProperty("java.home");
- String javaHome = origJavaHome.toLowerCase();
- if (javaHome.endsWith("jre")) {
- origJavaHome = origJavaHome.substring(0, origJavaHome.length() - 4);
- javaHome = javaHome.substring(0, javaHome.length() - 4);
- }
- for (int i = 0; i < args.length; i++) {
- try {
- File file = new File(args[i]);
- BufferedReader reader = new BufferedReader(new FileReader(file));
- String line = null;
- while ((line = reader.readLine()) != null) {
- StringTokenizer tok = new StringTokenizer(line, "[ \t\n\r\f");
- if (tok.hasMoreTokens()) {
- String t = tok.nextToken();
- // Understand only "Loading" from -XX:+TraceClassLoadingPreorder.
- // This ignores old "Loaded" from -verbose:class to force correct
- // classlist generation on Mustang.
- if (t.equals("Loading")) {
- t = tok.nextToken();
- t = t.replace('.', '/');
-
- // Check to make sure it came from the boot class path
- if (tok.hasMoreTokens()) {
- String tmp = tok.nextToken();
- if (tmp.equals("from")) {
- if (tok.hasMoreTokens()) {
- tmp = tok.nextToken().toLowerCase();
- // System.err.println("Loaded " + t + " from " + tmp);
- if (tmp.startsWith(javaHome)) {
- // OK, remember this class for later
- classes.add(t);
- }
- }
- }
- }
- }
- }
- }
- } catch (IOException e) {
- System.err.println("Error reading file " + args[i]);
- throw(e);
- }
- }
-
- Set<String> seenClasses = new HashSet<>();
-
- for (String str : classes) {
- if (seenClasses.add(str)) {
- System.out.println(str);
- }
- }
-
- // Try to complete certain packages
- // Note: not using this new code yet; need to consider whether the
- // footprint increase is worth any startup gains
- // Note also that the packages considered below for completion are
- // (obviously) platform-specific
- // JarFile rtJar = new JarFile(origJavaHome + File.separator +
- // "jre" + File.separator +
- // "lib" + File.separator +
- // "rt.jar");
- // completePackage(seenClasses, rtJar, "java/awt");
- // completePackage(seenClasses, rtJar, "sun/awt");
- // completePackage(seenClasses, rtJar, "sun/awt/X11");
- // completePackage(seenClasses, rtJar, "java/awt/im/spi");
- // completePackage(seenClasses, rtJar, "java/lang");
- }
-
- private static void completePackage(Set<String> seenClasses,
- JarFile jar,
- String packageName) {
- int len = packageName.length();
- Enumeration<JarEntry> entries = jar.entries();
- while (entries.hasMoreElements()) {
- JarEntry entry = entries.nextElement();
- String name = entry.getName();
- if (name.startsWith(packageName) &&
- name.endsWith(".class") &&
- name.lastIndexOf('/') == len) {
- // Trim ".class" from end
- name = name.substring(0, name.length() - 6);
- if (seenClasses.add(name)) {
- System.out.println(name);
- }
- }
- }
- }
-}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/make/non-build-utils/src/build/tools/makeclasslist/makeClasslist.js Wed Jul 05 20:41:12 2017 +0200
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * This tool is used to help create the class list for class data sharing.
+ *
+ * The classlist is produced internally by first running a select number of
+ * startup benchmarks with the -XX:DumpLoadedClassList=<file> option, then
+ * running this tool in the following fashion to produce a complete classlist:
+ *
+ * jjs -scripting makeClasslist.js -- list1 list2 list3 > classlist.platform
+ *
+ * The lists should be listed in roughly smallest to largest order based on
+ * application size.
+ *
+ * After generating the classlist it's necessary to add a checksum (using
+ * AddJsum.java) before checking it into the workspace as the corresponding
+ * platform-specific classlist, such as make/data/classlist/classlist.linux
+ */
+"use strict";
+var classlist = [];
+var seenClasses = {};
+
+for (var a in $ARG) {
+ var arg = $ARG[a];
+
+ var classes = readFully(arg).replace(/[\r\n]+/g, "\n").split("\n");
+
+ for (var c in classes) {
+ var clazz = classes[c];
+ if (clazz !== "" && seenClasses[clazz] === undefined) {
+ seenClasses[clazz] = clazz;
+ classlist.push(clazz);
+ }
+ }
+}
+
+for (c in classlist) {
+ print(classlist[c]);
+}
--- a/jdk/src/java.base/share/classes/java/net/SocksSocketImpl.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/net/SocksSocketImpl.java Wed Jul 05 20:41:12 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -31,6 +31,7 @@
import java.security.PrivilegedAction;
import java.security.PrivilegedExceptionAction;
import sun.net.SocksProxy;
+import sun.net.spi.DefaultProxySelector;
import sun.net.www.ParseUtil;
/* import org.ietf.jgss.*; */
@@ -69,12 +70,21 @@
server = ad.getHostString();
serverPort = ad.getPort();
}
+ useV4 = useV4(proxy);
}
void setV4() {
useV4 = true;
}
+ private static boolean useV4(Proxy proxy) {
+ if (proxy instanceof SocksProxy
+ && ((SocksProxy)proxy).protocolVersion() == 4) {
+ return true;
+ }
+ return DefaultProxySelector.socksProxyVersion() == 4;
+ }
+
private synchronized void privilegedConnect(final String host,
final int port,
final int timeout)
@@ -398,11 +408,7 @@
// Use getHostString() to avoid reverse lookups
server = ((InetSocketAddress) p.address()).getHostString();
serverPort = ((InetSocketAddress) p.address()).getPort();
- if (p instanceof SocksProxy) {
- if (((SocksProxy)p).protocolVersion() == 4) {
- useV4 = true;
- }
- }
+ useV4 = useV4(p);
// Connects to the SOCKS server
try {
@@ -715,11 +721,7 @@
// Use getHostString() to avoid reverse lookups
server = ((InetSocketAddress) p.address()).getHostString();
serverPort = ((InetSocketAddress) p.address()).getPort();
- if (p instanceof SocksProxy) {
- if (((SocksProxy)p).protocolVersion() == 4) {
- useV4 = true;
- }
- }
+ useV4 = useV4(p);
// Connects to the SOCKS server
try {
--- a/jdk/src/java.base/share/classes/java/security/AccessControlContext.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/security/AccessControlContext.java Wed Jul 05 20:41:12 2017 +0200
@@ -76,7 +76,7 @@
public final class AccessControlContext {
- private ProtectionDomain context[];
+ private ProtectionDomain[] context;
// isPrivileged and isAuthorized are referenced by the VM - do not remove
// or change their names
private boolean isPrivileged;
@@ -89,13 +89,13 @@
private DomainCombiner combiner = null;
// limited privilege scope
- private Permission permissions[];
+ private Permission[] permissions;
private AccessControlContext parent;
private boolean isWrapped;
// is constrained by limited privilege scope?
private boolean isLimited;
- private ProtectionDomain limitedContext[];
+ private ProtectionDomain[] limitedContext;
private static boolean debugInit = false;
private static Debug debug = null;
@@ -123,7 +123,7 @@
* changes to the array will not affect this AccessControlContext.
* @throws NullPointerException if {@code context} is {@code null}
*/
- public AccessControlContext(ProtectionDomain context[])
+ public AccessControlContext(ProtectionDomain[] context)
{
if (context.length == 0) {
this.context = null;
@@ -282,7 +282,7 @@
* package private constructor for AccessController.getContext()
*/
- AccessControlContext(ProtectionDomain context[],
+ AccessControlContext(ProtectionDomain[] context,
boolean isPrivileged)
{
this.context = context;
@@ -643,7 +643,7 @@
/*
* Combine the current (stack) and assigned domains.
*/
- private static ProtectionDomain[] combine(ProtectionDomain[]current,
+ private static ProtectionDomain[] combine(ProtectionDomain[] current,
ProtectionDomain[] assigned) {
// current could be null if only system code is on the stack;
@@ -666,7 +666,7 @@
int n = (skipAssigned) ? 0 : assigned.length;
// now we combine both of them, and create a new context
- ProtectionDomain pd[] = new ProtectionDomain[slen + n];
+ ProtectionDomain[] pd = new ProtectionDomain[slen + n];
// first copy in the assigned context domains, no need to compress
if (!skipAssigned) {
@@ -695,7 +695,7 @@
} else if (skipAssigned && n == slen) {
return current;
}
- ProtectionDomain tmp[] = new ProtectionDomain[n];
+ ProtectionDomain[] tmp = new ProtectionDomain[n];
System.arraycopy(pd, 0, tmp, 0, n);
pd = tmp;
}
--- a/jdk/src/java.base/share/classes/java/security/CodeSource.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/security/CodeSource.java Wed Jul 05 20:41:12 2017 +0200
@@ -65,7 +65,7 @@
/*
* The code signers. Certificate chains are concatenated.
*/
- private transient java.security.cert.Certificate certs[] = null;
+ private transient java.security.cert.Certificate[] certs = null;
// cached SocketPermission used for matchLocation
private transient SocketPermission sp;
@@ -91,7 +91,7 @@
* @param certs the certificate(s). It may be null. The contents of the
* array are copied to protect against subsequent modification.
*/
- public CodeSource(URL url, java.security.cert.Certificate certs[]) {
+ public CodeSource(URL url, java.security.cert.Certificate[] certs) {
this.location = url;
if (url != null) {
this.locationNoFragString = URLUtil.urlNoFragString(url);
--- a/jdk/src/java.base/share/classes/java/security/Permissions.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/security/Permissions.java Wed Jul 05 20:41:12 2017 +0200
@@ -289,9 +289,9 @@
if (unresolvedPerms == null)
return null;
- java.security.cert.Certificate certs[] = null;
+ java.security.cert.Certificate[] certs = null;
- Object signers[] = p.getClass().getSigners();
+ Object[] signers = p.getClass().getSigners();
int n = 0;
if (signers != null) {
--- a/jdk/src/java.base/share/classes/java/security/SecureRandom.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/security/SecureRandom.java Wed Jul 05 20:41:12 2017 +0200
@@ -69,7 +69,7 @@
*
* <pre>
* SecureRandom random = new SecureRandom();
- * byte bytes[] = new byte[20];
+ * byte[] bytes = new byte[20];
* random.nextBytes(bytes);
* </pre>
*
@@ -77,7 +77,7 @@
* to generate a given number of seed bytes (to seed other random number
* generators, for example):
* <pre>
- * byte seed[] = random.generateSeed(20);
+ * byte[] seed = random.generateSeed(20);
* </pre>
*
* Note: Depending on the implementation, the {@code generateSeed} and
@@ -186,7 +186,7 @@
*
* @param seed the seed.
*/
- public SecureRandom(byte seed[]) {
+ public SecureRandom(byte[] seed) {
super(0);
getDefaultPRNG(true, seed);
}
@@ -486,7 +486,7 @@
@Override
final protected int next(int numBits) {
int numBytes = (numBits+7)/8;
- byte b[] = new byte[numBytes];
+ byte[] b = new byte[numBytes];
int next = 0;
nextBytes(b);
--- a/jdk/src/java.base/share/classes/java/security/UnresolvedPermission.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/security/UnresolvedPermission.java Wed Jul 05 20:41:12 2017 +0200
@@ -130,7 +130,7 @@
*/
private String actions;
- private transient java.security.cert.Certificate certs[];
+ private transient java.security.cert.Certificate[] certs;
/**
* Creates a new UnresolvedPermission containing the permission
@@ -152,7 +152,7 @@
public UnresolvedPermission(String type,
String name,
String actions,
- java.security.cert.Certificate certs[])
+ java.security.cert.Certificate[] certs)
{
super(type);
@@ -224,7 +224,7 @@
* try and resolve this permission using the class loader of the permission
* that was passed in.
*/
- Permission resolve(Permission p, java.security.cert.Certificate certs[]) {
+ Permission resolve(Permission p, java.security.cert.Certificate[] certs) {
if (this.certs != null) {
// if p wasn't signed, we don't have a match
if (certs == null) {
--- a/jdk/src/java.base/share/classes/java/security/spec/RSAMultiPrimePrivateCrtKeySpec.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/security/spec/RSAMultiPrimePrivateCrtKeySpec.java Wed Jul 05 20:41:12 2017 +0200
@@ -54,7 +54,7 @@
private final BigInteger primeExponentP;
private final BigInteger primeExponentQ;
private final BigInteger crtCoefficient;
- private final RSAOtherPrimeInfo otherPrimeInfo[];
+ private final RSAOtherPrimeInfo[] otherPrimeInfo;
/**
* Creates a new {@code RSAMultiPrimePrivateCrtKeySpec}
--- a/jdk/src/java.base/share/classes/java/util/ArrayList.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/ArrayList.java Wed Jul 05 20:41:12 2017 +0200
@@ -178,7 +178,8 @@
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
- // c.toArray might (incorrectly) not return Object[] (see 6260652)
+ // defend against c.toArray (incorrectly) not returning Object[]
+ // (see e.g. https://bugs.openjdk.java.net/browse/JDK-6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
--- a/jdk/src/java.base/share/classes/java/util/Arrays.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/Arrays.java Wed Jul 05 20:41:12 2017 +0200
@@ -3820,7 +3820,7 @@
@Override
public Object[] toArray() {
- return a.clone();
+ return Arrays.copyOf(a, a.length, Object[].class);
}
@Override
--- a/jdk/src/java.base/share/classes/java/util/Vector.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/Vector.java Wed Jul 05 20:41:12 2017 +0200
@@ -174,7 +174,8 @@
public Vector(Collection<? extends E> c) {
elementData = c.toArray();
elementCount = elementData.length;
- // c.toArray might (incorrectly) not return Object[] (see 6260652)
+ // defend against c.toArray (incorrectly) not returning Object[]
+ // (see e.g. https://bugs.openjdk.java.net/browse/JDK-6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, elementCount, Object[].class);
}
--- a/jdk/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArrayList.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArrayList.java Wed Jul 05 20:41:12 2017 +0200
@@ -134,7 +134,8 @@
elements = ((CopyOnWriteArrayList<?>)c).getArray();
else {
elements = c.toArray();
- // c.toArray might (incorrectly) not return Object[] (see 6260652)
+ // defend against c.toArray (incorrectly) not returning Object[]
+ // (see e.g. https://bugs.openjdk.java.net/browse/JDK-6260652)
if (elements.getClass() != Object[].class)
elements = Arrays.copyOf(elements, elements.length, Object[].class);
}
--- a/jdk/src/java.base/share/classes/sun/net/spi/DefaultProxySelector.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/net/spi/DefaultProxySelector.java Wed Jul 05 20:41:12 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -106,6 +106,15 @@
}
}
+ public static int socksProxyVersion() {
+ return AccessController.doPrivileged(
+ new PrivilegedAction<Integer>() {
+ @Override public Integer run() {
+ return NetProperties.getInteger(SOCKS_PROXY_VERSION, 5);
+ }
+ });
+ }
+
/**
* How to deal with "non proxy hosts":
* since we do have to generate a pattern we don't want to do that if
@@ -302,8 +311,7 @@
saddr = InetSocketAddress.createUnresolved(phost, pport);
// Socks is *always* the last on the list.
if (j == (props[i].length - 1)) {
- int version = NetProperties.getInteger(SOCKS_PROXY_VERSION, 5).intValue();
- return SocksProxy.create(saddr, version);
+ return SocksProxy.create(saddr, socksProxyVersion());
} else {
return new Proxy(Proxy.Type.HTTP, saddr);
}
--- a/jdk/src/java.base/share/classes/sun/security/pkcs/PKCS7.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/pkcs/PKCS7.java Wed Jul 05 20:41:12 2017 +0200
@@ -507,7 +507,7 @@
// certificates (optional)
if (certificates != null && certificates.length != 0) {
// cast to X509CertImpl[] since X509CertImpl implements DerEncoder
- X509CertImpl implCerts[] = new X509CertImpl[certificates.length];
+ X509CertImpl[] implCerts = new X509CertImpl[certificates.length];
for (int i = 0; i < certificates.length; i++) {
if (certificates[i] instanceof X509CertImpl)
implCerts[i] = (X509CertImpl) certificates[i];
--- a/jdk/src/java.base/share/classes/sun/security/pkcs/PKCS8Key.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/pkcs/PKCS8Key.java Wed Jul 05 20:41:12 2017 +0200
@@ -78,7 +78,7 @@
* data is stored and transmitted losslessly, but no knowledge
* about this particular algorithm is available.
*/
- private PKCS8Key (AlgorithmId algid, byte key [])
+ private PKCS8Key (AlgorithmId algid, byte[] key)
throws InvalidKeyException {
this.algid = algid;
this.key = key;
--- a/jdk/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java Wed Jul 05 20:41:12 2017 +0200
@@ -154,28 +154,28 @@
private static final Debug debug = Debug.getInstance("pkcs12");
- private static final int keyBag[] = {1, 2, 840, 113549, 1, 12, 10, 1, 2};
- private static final int certBag[] = {1, 2, 840, 113549, 1, 12, 10, 1, 3};
- private static final int secretBag[] = {1, 2, 840, 113549, 1, 12, 10, 1, 5};
+ private static final int[] keyBag = {1, 2, 840, 113549, 1, 12, 10, 1, 2};
+ private static final int[] certBag = {1, 2, 840, 113549, 1, 12, 10, 1, 3};
+ private static final int[] secretBag = {1, 2, 840, 113549, 1, 12, 10, 1, 5};
- private static final int pkcs9Name[] = {1, 2, 840, 113549, 1, 9, 20};
- private static final int pkcs9KeyId[] = {1, 2, 840, 113549, 1, 9, 21};
+ private static final int[] pkcs9Name = {1, 2, 840, 113549, 1, 9, 20};
+ private static final int[] pkcs9KeyId = {1, 2, 840, 113549, 1, 9, 21};
- private static final int pkcs9certType[] = {1, 2, 840, 113549, 1, 9, 22, 1};
+ private static final int[] pkcs9certType = {1, 2, 840, 113549, 1, 9, 22, 1};
- private static final int pbeWithSHAAnd40BitRC2CBC[] =
+ private static final int[] pbeWithSHAAnd40BitRC2CBC =
{1, 2, 840, 113549, 1, 12, 1, 6};
- private static final int pbeWithSHAAnd3KeyTripleDESCBC[] =
+ private static final int[] pbeWithSHAAnd3KeyTripleDESCBC =
{1, 2, 840, 113549, 1, 12, 1, 3};
- private static final int pbes2[] = {1, 2, 840, 113549, 1, 5, 13};
+ private static final int[] pbes2 = {1, 2, 840, 113549, 1, 5, 13};
// TODO: temporary Oracle OID
/*
* { joint-iso-itu-t(2) country(16) us(840) organization(1) oracle(113894)
* jdk(746875) crypto(1) id-at-trustedKeyUsage(1) }
*/
- private static final int TrustedKeyUsage[] =
+ private static final int[] TrustedKeyUsage =
{2, 16, 840, 1, 113894, 746875, 1, 1};
- private static final int AnyExtendedKeyUsage[] = {2, 5, 29, 37, 0};
+ private static final int[] AnyExtendedKeyUsage = {2, 5, 29, 37, 0};
private static ObjectIdentifier PKCS8ShroudedKeyBag_OID;
private static ObjectIdentifier CertBag_OID;
@@ -243,7 +243,7 @@
// A private key entry and its supporting certificate chain
private static class PrivateKeyEntry extends KeyEntry {
byte[] protectedPrivKey;
- Certificate chain[];
+ Certificate[] chain;
};
// A secret key
--- a/jdk/src/java.base/share/classes/sun/security/provider/AuthPolicyFile.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/provider/AuthPolicyFile.java Wed Jul 05 20:41:12 2017 +0200
@@ -403,7 +403,7 @@
debug.println(" "+perm);
}
} catch (ClassNotFoundException cnfe) {
- Certificate certs[];
+ Certificate[] certs;
if (pe.signedBy != null) {
certs = getCertificates(keyStore, pe.signedBy);
} else {
@@ -623,7 +623,7 @@
init();
}
- final CodeSource codesource[] = {null};
+ final CodeSource[] codesource = {null};
codesource[0] = canonicalizeCodebase(cs, true);
@@ -666,7 +666,7 @@
// now see if any of the keys are trusted ids.
if (!ignoreIdentityScope) {
- Certificate certs[] = codesource[0].getCertificates();
+ Certificate[] certs = codesource[0].getCertificates();
if (certs != null) {
for (int k=0; k < certs.length; k++) {
if (aliasMapping.get(certs[k]) == null &&
--- a/jdk/src/java.base/share/classes/sun/security/provider/DSAParameterGenerator.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/provider/DSAParameterGenerator.java Wed Jul 05 20:41:12 2017 +0200
@@ -237,7 +237,7 @@
BigInteger offset = ONE;
/* Step 11 */
for (counter = 0; counter < 4*valueL; counter++) {
- BigInteger V[] = new BigInteger[n + 1];
+ BigInteger[] V = new BigInteger[n + 1];
/* Step 11.1 */
for (int j = 0; j <= n; j++) {
BigInteger J = BigInteger.valueOf(j);
--- a/jdk/src/java.base/share/classes/sun/security/provider/JavaKeyStore.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/provider/JavaKeyStore.java Wed Jul 05 20:41:12 2017 +0200
@@ -82,7 +82,7 @@
private static class KeyEntry {
Date date; // the creation date of this entry
byte[] protectedPrivKey;
- Certificate chain[];
+ Certificate[] chain;
};
// Trusted certificates
@@ -604,7 +604,7 @@
* the keystore (such as deleting or modifying key or
* certificate entries).
*/
- byte digest[] = md.digest();
+ byte[] digest = md.digest();
dos.write(digest);
dos.flush();
@@ -770,9 +770,8 @@
* with
*/
if (password != null) {
- byte computed[], actual[];
- computed = md.digest();
- actual = new byte[computed.length];
+ byte[] computed = md.digest();
+ byte[] actual = new byte[computed.length];
dis.readFully(actual);
for (int i = 0; i < computed.length; i++) {
if (computed[i] != actual[i]) {
--- a/jdk/src/java.base/share/classes/sun/security/provider/PolicyFile.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/provider/PolicyFile.java Wed Jul 05 20:41:12 2017 +0200
@@ -795,7 +795,7 @@
// an unresolved permission which will be resolved
// when implies is called
// Add it to entry
- Certificate certs[];
+ Certificate[] certs;
if (pe.signedBy != null) {
certs = getCertificates(keyStore,
pe.signedBy,
@@ -817,7 +817,7 @@
debug.println(" "+perm);
}
} catch (ClassNotFoundException cnfe) {
- Certificate certs[];
+ Certificate[] certs;
if (pe.signedBy != null) {
certs = getCertificates(keyStore,
pe.signedBy,
@@ -2032,7 +2032,7 @@
*
* @serial
*/
- private Certificate certs[];
+ private Certificate[] certs;
/**
* Creates a new SelfPermission containing the permission
@@ -2048,7 +2048,7 @@
* certificate first and the (root) certificate authority last).
*/
public SelfPermission(String type, String name, String actions,
- Certificate certs[])
+ Certificate[] certs)
{
super(type);
if (type == null) {
--- a/jdk/src/java.base/share/classes/sun/security/provider/PolicyParser.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/provider/PolicyParser.java Wed Jul 05 20:41:12 2017 +0200
@@ -1353,7 +1353,7 @@
}
}
- public static void main(String arg[]) throws Exception {
+ public static void main(String[] arg) throws Exception {
try (FileReader fr = new FileReader(arg[0]);
FileWriter fw = new FileWriter(arg[1])) {
PolicyParser pp = new PolicyParser(true);
--- a/jdk/src/java.base/share/classes/sun/security/provider/SecureRandom.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/provider/SecureRandom.java Wed Jul 05 20:41:12 2017 +0200
@@ -85,7 +85,7 @@
*
* @param seed the seed.
*/
- private SecureRandom(byte seed[]) {
+ private SecureRandom(byte[] seed) {
init(seed);
}
--- a/jdk/src/java.base/share/classes/sun/security/ssl/ByteBufferInputStream.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/ByteBufferInputStream.java Wed Jul 05 20:41:12 2017 +0200
@@ -70,7 +70,7 @@
* Increments position().
*/
@Override
- public int read(byte b[]) throws IOException {
+ public int read(byte[] b) throws IOException {
if (bb == null) {
throw new IOException("read on a closed InputStream");
@@ -85,7 +85,7 @@
* Increments position().
*/
@Override
- public int read(byte b[], int off, int len) throws IOException {
+ public int read(byte[] b, int off, int len) throws IOException {
if (bb == null) {
throw new IOException("read on a closed InputStream");
--- a/jdk/src/java.base/share/classes/sun/security/ssl/ClientHandshaker.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/ClientHandshaker.java Wed Jul 05 20:41:12 2017 +0200
@@ -810,7 +810,7 @@
String alias = null;
int keytypesTmpSize = keytypesTmp.size();
if (keytypesTmpSize != 0) {
- String keytypes[] =
+ String[] keytypes =
keytypesTmp.toArray(new String[keytypesTmpSize]);
if (conn != null) {
--- a/jdk/src/java.base/share/classes/sun/security/ssl/DHClientKeyExchange.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/DHClientKeyExchange.java Wed Jul 05 20:41:12 2017 +0200
@@ -48,7 +48,7 @@
* This value may be empty if it was included in the
* client's certificate ...
*/
- private byte dh_Yc[]; // 1 to 2^16 -1 bytes
+ private byte[] dh_Yc; // 1 to 2^16 -1 bytes
BigInteger getClientPublicKey() {
return dh_Yc == null ? null : new BigInteger(1, dh_Yc);
--- a/jdk/src/java.base/share/classes/sun/security/ssl/HandshakeInStream.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/HandshakeInStream.java Wed Jul 05 20:41:12 2017 +0200
@@ -146,7 +146,7 @@
byte[] getBytes8() throws IOException {
int len = getInt8();
verifyLength(len);
- byte b[] = new byte[len];
+ byte[] b = new byte[len];
read(b);
return b;
@@ -155,7 +155,7 @@
public byte[] getBytes16() throws IOException {
int len = getInt16();
verifyLength(len);
- byte b[] = new byte[len];
+ byte[] b = new byte[len];
read(b);
return b;
@@ -164,7 +164,7 @@
byte[] getBytes24() throws IOException {
int len = getInt24();
verifyLength(len);
- byte b[] = new byte[len];
+ byte[] b = new byte[len];
read(b);
return b;
--- a/jdk/src/java.base/share/classes/sun/security/ssl/HandshakeMessage.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/HandshakeMessage.java Wed Jul 05 20:41:12 2017 +0200
@@ -689,8 +689,8 @@
static final
class RSA_ServerKeyExchange extends ServerKeyExchange
{
- private byte rsa_modulus[]; // 1 to 2^16 - 1 bytes
- private byte rsa_exponent[]; // 1 to 2^16 - 1 bytes
+ private byte[] rsa_modulus; // 1 to 2^16 - 1 bytes
+ private byte[] rsa_exponent; // 1 to 2^16 - 1 bytes
private Signature signature;
private byte[] signatureBytes;
@@ -698,7 +698,7 @@
/*
* Hash the nonces and the ephemeral RSA public key.
*/
- private void updateSignature(byte clntNonce[], byte svrNonce[])
+ private void updateSignature(byte[] clntNonce, byte[] svrNonce)
throws SignatureException {
int tmp;
@@ -827,11 +827,11 @@
private final static boolean dhKeyExchangeFix =
Debug.getBooleanProperty("com.sun.net.ssl.dhKeyExchangeFix", true);
- private byte dh_p []; // 1 to 2^16 - 1 bytes
- private byte dh_g []; // 1 to 2^16 - 1 bytes
- private byte dh_Ys []; // 1 to 2^16 - 1 bytes
+ private byte[] dh_p; // 1 to 2^16 - 1 bytes
+ private byte[] dh_g; // 1 to 2^16 - 1 bytes
+ private byte[] dh_Ys; // 1 to 2^16 - 1 bytes
- private byte signature [];
+ private byte[] signature;
// protocol version being established using this ServerKeyExchange message
ProtocolVersion protocolVersion;
@@ -857,8 +857,8 @@
* with the cert chain which was sent ... for DHE_DSS and DHE_RSA
* key exchange. (Constructor called by server.)
*/
- DH_ServerKeyExchange(DHCrypt obj, PrivateKey key, byte clntNonce[],
- byte svrNonce[], SecureRandom sr,
+ DH_ServerKeyExchange(DHCrypt obj, PrivateKey key, byte[] clntNonce,
+ byte[] svrNonce, SecureRandom sr,
SignatureAndHashAlgorithm signAlgorithm,
ProtocolVersion protocolVersion) throws GeneralSecurityException {
@@ -913,7 +913,7 @@
* DHE_DSS or DHE_RSA key exchange. (Called by client.)
*/
DH_ServerKeyExchange(HandshakeInStream input, PublicKey publicKey,
- byte clntNonce[], byte svrNonce[], int messageSize,
+ byte[] clntNonce, byte[] svrNonce, int messageSize,
Collection<SignatureAndHashAlgorithm> localSupportedSignAlgs,
ProtocolVersion protocolVersion)
throws IOException, GeneralSecurityException {
@@ -948,7 +948,7 @@
}
// read the signature
- byte signature[];
+ byte[] signature;
if (dhKeyExchangeFix) {
signature = input.getBytes16();
} else {
@@ -1004,8 +1004,8 @@
/*
* Update sig with nonces and Diffie-Hellman public key.
*/
- private void updateSignature(Signature sig, byte clntNonce[],
- byte svrNonce[]) throws SignatureException {
+ private void updateSignature(Signature sig, byte[] clntNonce,
+ byte[] svrNonce) throws SignatureException {
int tmp;
sig.update(clntNonce);
@@ -1268,8 +1268,8 @@
}
}
- private void updateSignature(Signature sig, byte clntNonce[],
- byte svrNonce[]) throws SignatureException {
+ private void updateSignature(Signature sig, byte[] clntNonce,
+ byte[] svrNonce) throws SignatureException {
sig.update(clntNonce);
sig.update(svrNonce);
@@ -1334,7 +1334,7 @@
* DER encoded distinguished name.
* TLS requires that its not longer than 65535 bytes.
*/
- byte name[];
+ byte[] name;
DistinguishedName(HandshakeInStream input) throws IOException {
name = input.getBytes16();
@@ -1411,8 +1411,8 @@
private final static byte[] TYPES_ECC =
{ cct_rsa_sign, cct_dss_sign, cct_ecdsa_sign };
- byte types []; // 1 to 255 types
- DistinguishedName authorities []; // 3 to 2^16 - 1
+ byte[] types; // 1 to 255 types
+ DistinguishedName[] authorities; // 3 to 2^16 - 1
// ... "3" because that's the smallest DER-encoded X500 DN
// protocol version being established using this CertificateRequest message
@@ -1424,7 +1424,7 @@
// length of supported_signature_algorithms
private int algorithmsLen;
- CertificateRequest(X509Certificate ca[], KeyExchange keyExchange,
+ CertificateRequest(X509Certificate[] ca, KeyExchange keyExchange,
Collection<SignatureAndHashAlgorithm> signAlgs,
ProtocolVersion protocolVersion) throws IOException {
@@ -2063,7 +2063,7 @@
if (protocolVersion.useTLS10PlusSpec()) {
// TLS 1.0+
try {
- byte [] seed;
+ byte[] seed;
String prfAlg;
PRF prf;
--- a/jdk/src/java.base/share/classes/sun/security/ssl/HandshakeOutStream.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/HandshakeOutStream.java Wed Jul 05 20:41:12 2017 +0200
@@ -119,7 +119,7 @@
}
}
- public void putBytes16(byte b[]) throws IOException {
+ public void putBytes16(byte[] b) throws IOException {
if (b == null) {
putInt16(0);
} else {
@@ -128,7 +128,7 @@
}
}
- void putBytes24(byte b[]) throws IOException {
+ void putBytes24(byte[] b) throws IOException {
if (b == null) {
putInt24(0);
} else {
--- a/jdk/src/java.base/share/classes/sun/security/ssl/MAC.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/MAC.java Wed Jul 05 20:41:12 2017 +0200
@@ -52,7 +52,7 @@
final static MAC TLS_NULL = new MAC(false);
// Value of the null MAC is fixed
- private static final byte nullMAC[] = new byte[0];
+ private static final byte[] nullMAC = new byte[0];
// internal identifier for the MAC algorithm
private final MacAlg macAlg;
--- a/jdk/src/java.base/share/classes/sun/security/ssl/RandomCookie.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/RandomCookie.java Wed Jul 05 20:41:12 2017 +0200
@@ -38,7 +38,7 @@
*/
final class RandomCookie {
- byte random_bytes[]; // exactly 32 bytes
+ byte[] random_bytes; // exactly 32 bytes
RandomCookie(SecureRandom generator) {
long temp = System.currentTimeMillis() / 1000;
--- a/jdk/src/java.base/share/classes/sun/security/ssl/ServerHandshaker.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/ServerHandshaker.java Wed Jul 05 20:41:12 2017 +0200
@@ -986,7 +986,7 @@
ClientKeyExchangeService.find(keyExchange.name) == null) {
CertificateRequest m4;
- X509Certificate caCerts[];
+ X509Certificate[] caCerts;
Collection<SignatureAndHashAlgorithm> localSignAlgs = null;
if (protocolVersion.useTLS12PlusSpec()) {
--- a/jdk/src/java.base/share/classes/sun/security/ssl/SessionId.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/SessionId.java Wed Jul 05 20:41:12 2017 +0200
@@ -43,7 +43,7 @@
class SessionId
{
static int MAX_LENGTH = 32;
- private byte sessionId []; // max 32 bytes
+ private byte[] sessionId; // max 32 bytes
/** Constructs a new session ID ... perhaps for a rejoinable session */
SessionId (boolean isRejoinable, SecureRandom generator)
@@ -56,7 +56,7 @@
}
/** Constructs a session ID from a byte array (max size 32 bytes) */
- SessionId (byte sessionId [])
+ SessionId (byte[] sessionId)
{ this.sessionId = sessionId; }
/** Returns the length of the ID, in bytes */
@@ -64,7 +64,7 @@
{ return sessionId.length; }
/** Returns the bytes in the ID. May be an empty array. */
- byte [] getId ()
+ byte[] getId ()
{
return sessionId.clone ();
}
@@ -106,7 +106,7 @@
return false;
SessionId s = (SessionId) obj;
- byte b [] = s.getId ();
+ byte[] b = s.getId ();
if (b.length != sessionId.length)
return false;
--- a/jdk/src/java.base/share/classes/sun/security/ssl/X509TrustManagerImpl.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/X509TrustManagerImpl.java Wed Jul 05 20:41:12 2017 +0200
@@ -94,13 +94,13 @@
}
@Override
- public void checkClientTrusted(X509Certificate chain[], String authType)
+ public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
checkTrusted(chain, authType, (Socket)null, true);
}
@Override
- public void checkServerTrusted(X509Certificate chain[], String authType)
+ public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
checkTrusted(chain, authType, (Socket)null, false);
}
--- a/jdk/src/java.base/share/classes/sun/security/util/ManifestDigester.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/util/ManifestDigester.java Wed Jul 05 20:41:12 2017 +0200
@@ -37,7 +37,7 @@
public static final String MF_MAIN_ATTRS = "Manifest-Main-Attributes";
/** the raw bytes of the manifest */
- private byte rawBytes[];
+ private byte[] rawBytes;
/** the offset/length pair for a section */
private HashMap<String, Entry> entries; // key is a UTF-8 string
@@ -107,7 +107,7 @@
return false;
}
- public ManifestDigester(byte bytes[])
+ public ManifestDigester(byte[] bytes)
{
rawBytes = bytes;
entries = new HashMap<>();
@@ -181,7 +181,7 @@
}
}
- private boolean isNameAttr(byte bytes[], int start)
+ private boolean isNameAttr(byte[] bytes, int start)
{
return ((bytes[start] == 'N') || (bytes[start] == 'n')) &&
((bytes[start+1] == 'a') || (bytes[start+1] == 'A')) &&
@@ -261,11 +261,10 @@
return e;
}
- public byte[] manifestDigest(MessageDigest md)
- {
- md.reset();
- md.update(rawBytes, 0, rawBytes.length);
- return md.digest();
- }
+ public byte[] manifestDigest(MessageDigest md) {
+ md.reset();
+ md.update(rawBytes, 0, rawBytes.length);
+ return md.digest();
+ }
}
--- a/jdk/src/java.base/share/classes/sun/security/util/ManifestEntryVerifier.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/util/ManifestEntryVerifier.java Wed Jul 05 20:41:12 2017 +0200
@@ -165,7 +165,7 @@
/**
* update the digests for the digests we are interested in
*/
- public void update(byte buffer[], int off, int len) {
+ public void update(byte[] buffer, int off, int len) {
if (skip) return;
for (int i=0; i < digests.size(); i++) {
--- a/jdk/src/java.base/share/classes/sun/security/util/ObjectIdentifier.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/util/ObjectIdentifier.java Wed Jul 05 20:41:12 2017 +0200
@@ -212,7 +212,7 @@
* Constructor, from an array of integers.
* Validity check included.
*/
- public ObjectIdentifier (int values []) throws IOException
+ public ObjectIdentifier(int[] values) throws IOException
{
checkCount(values.length);
checkFirstComponent(values[0]);
--- a/jdk/src/java.base/share/classes/sun/security/util/SignatureFileVerifier.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/util/SignatureFileVerifier.java Wed Jul 05 20:41:12 2017 +0200
@@ -55,7 +55,7 @@
private PKCS7 block;
/** the raw bytes of the .SF file */
- private byte sfBytes[];
+ private byte[] sfBytes;
/** the name of the signature block file, uppercased and without
* the extension (.DSA/.RSA/.EC)
@@ -84,7 +84,7 @@
public SignatureFileVerifier(ArrayList<CodeSigner[]> signerCache,
ManifestDigester md,
String name,
- byte rawBytes[])
+ byte[] rawBytes)
throws IOException, CertificateException
{
// new PKCS7() calls CertificateFactory.getInstance()
@@ -129,7 +129,7 @@
* used to set the raw bytes of the .SF file when it
* is external to the signature block file.
*/
- public void setSignatureFile(byte sfBytes[])
+ public void setSignatureFile(byte[] sfBytes)
{
this.sfBytes = sfBytes;
}
@@ -511,7 +511,7 @@
* CodeSigner objects. We do this only *once* for a given
* signature block file.
*/
- private CodeSigner[] getSigners(SignerInfo infos[], PKCS7 block)
+ private CodeSigner[] getSigners(SignerInfo[] infos, PKCS7 block)
throws IOException, NoSuchAlgorithmException, SignatureException,
CertificateException {
--- a/jdk/src/java.base/share/classes/sun/security/x509/AVA.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/x509/AVA.java Wed Jul 05 20:41:12 2017 +0200
@@ -967,7 +967,7 @@
previousWhite = false;
- byte valueBytes[] = null;
+ byte[] valueBytes = null;
try {
valueBytes = Character.toString(c).getBytes("UTF8");
} catch (IOException ie) {
@@ -1051,7 +1051,7 @@
// using the hex format below. This will be used only
// when the value is not a string type
- byte data [] = value.toByteArray();
+ byte[] data = value.toByteArray();
retval.append('#');
for (int i = 0; i < data.length; i++) {
--- a/jdk/src/java.base/share/classes/sun/security/x509/AlgIdDSA.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/x509/AlgIdDSA.java Wed Jul 05 20:41:12 2017 +0200
@@ -117,7 +117,7 @@
* @param q the DSS/DSA parameter "Q"
* @param g the DSS/DSA parameter "G"
*/
- public AlgIdDSA (byte p [], byte q [], byte g [])
+ public AlgIdDSA (byte[] p, byte[] q, byte[] g)
throws IOException
{
this (new BigInteger (1, p),
--- a/jdk/src/java.base/share/classes/sun/security/x509/AlgorithmId.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/x509/AlgorithmId.java Wed Jul 05 20:41:12 2017 +0200
@@ -648,12 +648,12 @@
/*
* COMMON PUBLIC KEY TYPES
*/
- private static final int DH_data[] = { 1, 2, 840, 113549, 1, 3, 1 };
- private static final int DH_PKIX_data[] = { 1, 2, 840, 10046, 2, 1 };
- private static final int DSA_OIW_data[] = { 1, 3, 14, 3, 2, 12 };
- private static final int DSA_PKIX_data[] = { 1, 2, 840, 10040, 4, 1 };
- private static final int RSA_data[] = { 2, 5, 8, 1, 1 };
- private static final int RSAEncryption_data[] =
+ private static final int[] DH_data = { 1, 2, 840, 113549, 1, 3, 1 };
+ private static final int[] DH_PKIX_data = { 1, 2, 840, 10046, 2, 1 };
+ private static final int[] DSA_OIW_data = { 1, 3, 14, 3, 2, 12 };
+ private static final int[] DSA_PKIX_data = { 1, 2, 840, 10040, 4, 1 };
+ private static final int[] RSA_data = { 2, 5, 8, 1, 1 };
+ private static final int[] RSAEncryption_data =
{ 1, 2, 840, 113549, 1, 1, 1 };
public static final ObjectIdentifier DH_oid;
@@ -674,27 +674,27 @@
/*
* COMMON SIGNATURE ALGORITHMS
*/
- private static final int md2WithRSAEncryption_data[] =
+ private static final int[] md2WithRSAEncryption_data =
{ 1, 2, 840, 113549, 1, 1, 2 };
- private static final int md5WithRSAEncryption_data[] =
+ private static final int[] md5WithRSAEncryption_data =
{ 1, 2, 840, 113549, 1, 1, 4 };
- private static final int sha1WithRSAEncryption_data[] =
+ private static final int[] sha1WithRSAEncryption_data =
{ 1, 2, 840, 113549, 1, 1, 5 };
- private static final int sha1WithRSAEncryption_OIW_data[] =
+ private static final int[] sha1WithRSAEncryption_OIW_data =
{ 1, 3, 14, 3, 2, 29 };
- private static final int sha224WithRSAEncryption_data[] =
+ private static final int[] sha224WithRSAEncryption_data =
{ 1, 2, 840, 113549, 1, 1, 14 };
- private static final int sha256WithRSAEncryption_data[] =
+ private static final int[] sha256WithRSAEncryption_data =
{ 1, 2, 840, 113549, 1, 1, 11 };
- private static final int sha384WithRSAEncryption_data[] =
+ private static final int[] sha384WithRSAEncryption_data =
{ 1, 2, 840, 113549, 1, 1, 12 };
- private static final int sha512WithRSAEncryption_data[] =
+ private static final int[] sha512WithRSAEncryption_data =
{ 1, 2, 840, 113549, 1, 1, 13 };
- private static final int shaWithDSA_OIW_data[] =
+ private static final int[] shaWithDSA_OIW_data =
{ 1, 3, 14, 3, 2, 13 };
- private static final int sha1WithDSA_OIW_data[] =
+ private static final int[] sha1WithDSA_OIW_data =
{ 1, 3, 14, 3, 2, 27 };
- private static final int dsaWithSHA1_PKIX_data[] =
+ private static final int[] dsaWithSHA1_PKIX_data =
{ 1, 2, 840, 10040, 4, 3 };
public static final ObjectIdentifier md2WithRSAEncryption_oid;
--- a/jdk/src/java.base/share/classes/sun/security/x509/NetscapeCertTypeExtension.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/x509/NetscapeCertTypeExtension.java Wed Jul 05 20:41:12 2017 +0200
@@ -69,7 +69,7 @@
public static final String S_MIME_CA = "s_mime_ca";
public static final String OBJECT_SIGNING_CA = "object_signing_ca";
- private static final int CertType_data[] = { 2, 16, 840, 1, 113730, 1, 1 };
+ private static final int[] CertType_data = { 2, 16, 840, 1, 113730, 1, 1 };
/**
* Object identifier for the Netscape-Cert-Type extension.
--- a/jdk/src/java.base/share/classes/sun/security/x509/OIDMap.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/x509/OIDMap.java Wed Jul 05 20:41:12 2017 +0200
@@ -102,7 +102,7 @@
private static final String OCSPNOCHECK = ROOT + "." +
OCSPNoCheckExtension.NAME;
- private static final int NetscapeCertType_data[] =
+ private static final int[] NetscapeCertType_data =
{ 2, 16, 840, 1, 113730, 1, 1 };
/** Map ObjectIdentifier(oid) -> OIDInfo(info) */
--- a/jdk/src/java.base/share/classes/sun/security/x509/PKIXExtensions.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/x509/PKIXExtensions.java Wed Jul 05 20:41:12 2017 +0200
@@ -49,32 +49,32 @@
*/
public class PKIXExtensions {
// The object identifiers
- private static final int AuthorityKey_data [] = { 2, 5, 29, 35 };
- private static final int SubjectKey_data [] = { 2, 5, 29, 14 };
- private static final int KeyUsage_data [] = { 2, 5, 29, 15 };
- private static final int PrivateKeyUsage_data [] = { 2, 5, 29, 16 };
- private static final int CertificatePolicies_data [] = { 2, 5, 29, 32 };
- private static final int PolicyMappings_data [] = { 2, 5, 29, 33 };
- private static final int SubjectAlternativeName_data [] = { 2, 5, 29, 17 };
- private static final int IssuerAlternativeName_data [] = { 2, 5, 29, 18 };
- private static final int SubjectDirectoryAttributes_data [] = { 2, 5, 29, 9 };
- private static final int BasicConstraints_data [] = { 2, 5, 29, 19 };
- private static final int NameConstraints_data [] = { 2, 5, 29, 30 };
- private static final int PolicyConstraints_data [] = { 2, 5, 29, 36 };
- private static final int CRLDistributionPoints_data [] = { 2, 5, 29, 31 };
- private static final int CRLNumber_data [] = { 2, 5, 29, 20 };
- private static final int IssuingDistributionPoint_data [] = { 2, 5, 29, 28 };
- private static final int DeltaCRLIndicator_data [] = { 2, 5, 29, 27 };
- private static final int ReasonCode_data [] = { 2, 5, 29, 21 };
- private static final int HoldInstructionCode_data [] = { 2, 5, 29, 23 };
- private static final int InvalidityDate_data [] = { 2, 5, 29, 24 };
- private static final int ExtendedKeyUsage_data [] = { 2, 5, 29, 37 };
- private static final int InhibitAnyPolicy_data [] = { 2, 5, 29, 54 };
- private static final int CertificateIssuer_data [] = { 2, 5, 29, 29 };
- private static final int AuthInfoAccess_data [] = { 1, 3, 6, 1, 5, 5, 7, 1, 1};
- private static final int SubjectInfoAccess_data [] = { 1, 3, 6, 1, 5, 5, 7, 1, 11};
- private static final int FreshestCRL_data [] = { 2, 5, 29, 46 };
- private static final int OCSPNoCheck_data [] = { 1, 3, 6, 1, 5, 5, 7,
+ private static final int[] AuthorityKey_data = { 2, 5, 29, 35 };
+ private static final int[] SubjectKey_data = { 2, 5, 29, 14 };
+ private static final int[] KeyUsage_data = { 2, 5, 29, 15 };
+ private static final int[] PrivateKeyUsage_data = { 2, 5, 29, 16 };
+ private static final int[] CertificatePolicies_data = { 2, 5, 29, 32 };
+ private static final int[] PolicyMappings_data = { 2, 5, 29, 33 };
+ private static final int[] SubjectAlternativeName_data = { 2, 5, 29, 17 };
+ private static final int[] IssuerAlternativeName_data = { 2, 5, 29, 18 };
+ private static final int[] SubjectDirectoryAttributes_data = { 2, 5, 29, 9 };
+ private static final int[] BasicConstraints_data = { 2, 5, 29, 19 };
+ private static final int[] NameConstraints_data = { 2, 5, 29, 30 };
+ private static final int[] PolicyConstraints_data = { 2, 5, 29, 36 };
+ private static final int[] CRLDistributionPoints_data = { 2, 5, 29, 31 };
+ private static final int[] CRLNumber_data = { 2, 5, 29, 20 };
+ private static final int[] IssuingDistributionPoint_data = { 2, 5, 29, 28 };
+ private static final int[] DeltaCRLIndicator_data = { 2, 5, 29, 27 };
+ private static final int[] ReasonCode_data = { 2, 5, 29, 21 };
+ private static final int[] HoldInstructionCode_data = { 2, 5, 29, 23 };
+ private static final int[] InvalidityDate_data = { 2, 5, 29, 24 };
+ private static final int[] ExtendedKeyUsage_data = { 2, 5, 29, 37 };
+ private static final int[] InhibitAnyPolicy_data = { 2, 5, 29, 54 };
+ private static final int[] CertificateIssuer_data = { 2, 5, 29, 29 };
+ private static final int[] AuthInfoAccess_data = { 1, 3, 6, 1, 5, 5, 7, 1, 1};
+ private static final int[] SubjectInfoAccess_data = { 1, 3, 6, 1, 5, 5, 7, 1, 11};
+ private static final int[] FreshestCRL_data = { 2, 5, 29, 46 };
+ private static final int[] OCSPNoCheck_data = { 1, 3, 6, 1, 5, 5, 7,
48, 1, 5};
/**
--- a/jdk/src/java.base/share/classes/sun/security/x509/X500Name.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/x509/X500Name.java Wed Jul 05 20:41:12 2017 +0200
@@ -1119,25 +1119,25 @@
* Includes all those specified in RFC 5280 as MUST or SHOULD
* be recognized
*/
- private static final int commonName_data[] = { 2, 5, 4, 3 };
- private static final int SURNAME_DATA[] = { 2, 5, 4, 4 };
- private static final int SERIALNUMBER_DATA[] = { 2, 5, 4, 5 };
- private static final int countryName_data[] = { 2, 5, 4, 6 };
- private static final int localityName_data[] = { 2, 5, 4, 7 };
- private static final int stateName_data[] = { 2, 5, 4, 8 };
- private static final int streetAddress_data[] = { 2, 5, 4, 9 };
- private static final int orgName_data[] = { 2, 5, 4, 10 };
- private static final int orgUnitName_data[] = { 2, 5, 4, 11 };
- private static final int title_data[] = { 2, 5, 4, 12 };
- private static final int GIVENNAME_DATA[] = { 2, 5, 4, 42 };
- private static final int INITIALS_DATA[] = { 2, 5, 4, 43 };
- private static final int GENERATIONQUALIFIER_DATA[] = { 2, 5, 4, 44 };
- private static final int DNQUALIFIER_DATA[] = { 2, 5, 4, 46 };
+ private static final int[] commonName_data = { 2, 5, 4, 3 };
+ private static final int[] SURNAME_DATA = { 2, 5, 4, 4 };
+ private static final int[] SERIALNUMBER_DATA = { 2, 5, 4, 5 };
+ private static final int[] countryName_data = { 2, 5, 4, 6 };
+ private static final int[] localityName_data = { 2, 5, 4, 7 };
+ private static final int[] stateName_data = { 2, 5, 4, 8 };
+ private static final int[] streetAddress_data = { 2, 5, 4, 9 };
+ private static final int[] orgName_data = { 2, 5, 4, 10 };
+ private static final int[] orgUnitName_data = { 2, 5, 4, 11 };
+ private static final int[] title_data = { 2, 5, 4, 12 };
+ private static final int[] GIVENNAME_DATA = { 2, 5, 4, 42 };
+ private static final int[] INITIALS_DATA = { 2, 5, 4, 43 };
+ private static final int[] GENERATIONQUALIFIER_DATA = { 2, 5, 4, 44 };
+ private static final int[] DNQUALIFIER_DATA = { 2, 5, 4, 46 };
- private static final int ipAddress_data[] = { 1, 3, 6, 1, 4, 1, 42, 2, 11, 2, 1 };
- private static final int DOMAIN_COMPONENT_DATA[] =
+ private static final int[] ipAddress_data = { 1, 3, 6, 1, 4, 1, 42, 2, 11, 2, 1 };
+ private static final int[] DOMAIN_COMPONENT_DATA =
{ 0, 9, 2342, 19200300, 100, 1, 25 };
- private static final int userid_data[] =
+ private static final int[] userid_data =
{ 0, 9, 2342, 19200300, 100, 1, 1 };
--- a/jdk/src/java.base/share/classes/sun/security/x509/X509CRLImpl.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/x509/X509CRLImpl.java Wed Jul 05 20:41:12 2017 +0200
@@ -1086,7 +1086,7 @@
throw new CRLException("Invalid DER-encoded CRL data");
signedCRL = val.toByteArray();
- DerValue seq[] = new DerValue[3];
+ DerValue[] seq = new DerValue[3];
seq[0] = val.data.getDerValue();
seq[1] = val.data.getDerValue();
--- a/jdk/src/java.desktop/share/classes/sun/awt/util/IdentityArrayList.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/awt/util/IdentityArrayList.java Wed Jul 05 20:41:12 2017 +0200
@@ -142,7 +142,8 @@
public IdentityArrayList(Collection<? extends E> c) {
elementData = c.toArray();
size = elementData.length;
- // c.toArray might (incorrectly) not return Object[] (see 6260652)
+ // defend against c.toArray (incorrectly) not returning Object[]
+ // (see e.g. https://bugs.openjdk.java.net/browse/JDK-6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
}
--- a/jdk/src/java.security.jgss/share/classes/javax/security/auth/kerberos/ServicePermission.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.security.jgss/share/classes/javax/security/auth/kerberos/ServicePermission.java Wed Jul 05 20:41:12 2017 +0200
@@ -427,7 +427,7 @@
/*
- public static void main(String args[]) throws Exception {
+ public static void main(String[] args) throws Exception {
ServicePermission this_ =
new ServicePermission(args[0], "accept");
ServicePermission that_ =
--- a/jdk/src/java.security.jgss/share/classes/sun/security/jgss/GSSCredentialImpl.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/jgss/GSSCredentialImpl.java Wed Jul 05 20:41:12 2017 +0200
@@ -75,7 +75,7 @@
}
GSSCredentialImpl(GSSManagerImpl gssManager, GSSName name,
- int lifetime, Oid mechs[], int usage)
+ int lifetime, Oid[] mechs, int usage)
throws GSSException {
init(gssManager);
boolean defaultList = false;
--- a/jdk/src/java.security.jgss/share/classes/sun/security/jgss/GSSManagerImpl.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/jgss/GSSManagerImpl.java Wed Jul 05 20:41:12 2017 +0200
@@ -128,7 +128,7 @@
return new GSSNameImpl(this, nameStr, nameType);
}
- public GSSName createName(byte name[], Oid nameType)
+ public GSSName createName(byte[] name, Oid nameType)
throws GSSException {
return new GSSNameImpl(this, name, nameType);
}
@@ -138,7 +138,7 @@
return new GSSNameImpl(this, nameStr, nameType, mech);
}
- public GSSName createName(byte name[], Oid nameType, Oid mech)
+ public GSSName createName(byte[] name, Oid nameType, Oid mech)
throws GSSException {
return new GSSNameImpl(this, name, nameType, mech);
}
@@ -155,7 +155,7 @@
}
public GSSCredential createCredential(GSSName aName,
- int lifetime, Oid mechs[], int usage)
+ int lifetime, Oid[] mechs, int usage)
throws GSSException {
return wrap(new GSSCredentialImpl(this, aName, lifetime, mechs, usage));
}
--- a/jdk/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Context.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Context.java Wed Jul 05 20:41:12 2017 +0200
@@ -159,7 +159,7 @@
/**
* Constructor for Krb5Context to import a previously exported context.
*/
- public Krb5Context(GSSCaller caller, byte [] interProcessToken)
+ public Krb5Context(GSSCaller caller, byte[] interProcessToken)
throws GSSException {
throw new GSSException(GSSException.UNAVAILABLE,
-1, "GSS Import Context not available");
@@ -905,7 +905,7 @@
* and verifyMIC care about the remote sequence number (peerSeqNumber).
*/
- public final byte[] wrap(byte inBuf[], int offset, int len,
+ public final byte[] wrap(byte[] inBuf, int offset, int len,
MessageProp msgProp) throws GSSException {
if (DEBUG) {
System.out.println("Krb5Context.wrap: data=["
@@ -943,7 +943,7 @@
}
}
- public final int wrap(byte inBuf[], int inOffset, int len,
+ public final int wrap(byte[] inBuf, int inOffset, int len,
byte[] outBuf, int outOffset,
MessageProp msgProp) throws GSSException {
@@ -977,7 +977,7 @@
}
}
- public final void wrap(byte inBuf[], int offset, int len,
+ public final void wrap(byte[] inBuf, int offset, int len,
OutputStream os, MessageProp msgProp)
throws GSSException {
@@ -1032,7 +1032,7 @@
wrap(data, 0, data.length, os, msgProp);
}
- public final byte[] unwrap(byte inBuf[], int offset, int len,
+ public final byte[] unwrap(byte[] inBuf, int offset, int len,
MessageProp msgProp)
throws GSSException {
@@ -1069,7 +1069,7 @@
return data;
}
- public final int unwrap(byte inBuf[], int inOffset, int len,
+ public final int unwrap(byte[] inBuf, int inOffset, int len,
byte[] outBuf, int outOffset,
MessageProp msgProp) throws GSSException {
@@ -1141,7 +1141,7 @@
}
}
- public final byte[] getMIC(byte []inMsg, int offset, int len,
+ public final byte[] getMIC(byte[] inMsg, int offset, int len,
MessageProp msgProp)
throws GSSException {
@@ -1166,7 +1166,7 @@
}
}
- private int getMIC(byte []inMsg, int offset, int len,
+ private int getMIC(byte[] inMsg, int offset, int len,
byte[] outBuf, int outOffset,
MessageProp msgProp)
throws GSSException {
@@ -1236,7 +1236,7 @@
getMIC(data, 0, data.length, os, msgProp);
}
- public final void verifyMIC(byte []inTok, int tokOffset, int tokLen,
+ public final void verifyMIC(byte[] inTok, int tokOffset, int tokLen,
byte[] inMsg, int msgOffset, int msgLen,
MessageProp msgProp)
throws GSSException {
@@ -1293,7 +1293,7 @@
* @param os the output token will be written to this stream
* @exception GSSException
*/
- public final byte [] export() throws GSSException {
+ public final byte[] export() throws GSSException {
throw new GSSException(GSSException.UNAVAILABLE, -1,
"GSS Export Context not available");
}
--- a/jdk/src/java.security.jgss/share/classes/sun/security/jgss/spi/GSSContextSpi.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/jgss/spi/GSSContextSpi.java Wed Jul 05 20:41:12 2017 +0200
@@ -265,7 +265,7 @@
/**
* For apps that want simplicity and don't care about buffer copies.
*/
- public byte[] wrap(byte inBuf[], int offset, int len,
+ public byte[] wrap(byte[] inBuf, int offset, int len,
MessageProp msgProp) throws GSSException;
/**
@@ -275,7 +275,7 @@
*
* NOTE: This method is not defined in public class org.ietf.jgss.GSSContext
*
- public int wrap(byte inBuf[], int inOffset, int len,
+ public int wrap(byte[] inBuf, int inOffset, int len,
byte[] outBuf, int outOffset,
MessageProp msgProp) throws GSSException;
@@ -292,7 +292,7 @@
*
* NOTE: This method is not defined in public class org.ietf.jgss.GSSContext
*
- public void wrap(byte inBuf[], int offset, int len,
+ public void wrap(byte[] inBuf, int offset, int len,
OutputStream os, MessageProp msgProp)
throws GSSException;
*/
@@ -314,7 +314,7 @@
/**
* For apps that want simplicity and don't care about buffer copies.
*/
- public byte[] unwrap(byte inBuf[], int offset, int len,
+ public byte[] unwrap(byte[] inBuf, int offset, int len,
MessageProp msgProp) throws GSSException;
/**
@@ -324,7 +324,7 @@
*
* NOTE: This method is not defined in public class org.ietf.jgss.GSSContext
*
- public int unwrap(byte inBuf[], int inOffset, int len,
+ public int unwrap(byte[] inBuf, int inOffset, int len,
byte[] outBuf, int outOffset,
MessageProp msgProp) throws GSSException;
@@ -356,7 +356,7 @@
MessageProp msgProp)
throws GSSException;
- public byte[] getMIC(byte []inMsg, int offset, int len,
+ public byte[] getMIC(byte[] inMsg, int offset, int len,
MessageProp msgProp) throws GSSException;
/**
@@ -372,7 +372,7 @@
public void verifyMIC(InputStream is, InputStream msgStr,
MessageProp mProp) throws GSSException;
- public void verifyMIC(byte []inTok, int tokOffset, int tokLen,
+ public void verifyMIC(byte[] inTok, int tokOffset, int tokLen,
byte[] inMsg, int msgOffset, int msgLen,
MessageProp msgProp) throws GSSException;
--- a/jdk/src/java.security.jgss/share/classes/sun/security/jgss/wrapper/NativeGSSContext.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/jgss/wrapper/NativeGSSContext.java Wed Jul 05 20:41:12 2017 +0200
@@ -372,7 +372,7 @@
}
return cStub.wrap(pContext, data, msgProp);
}
- public void wrap(byte inBuf[], int offset, int len,
+ public void wrap(byte[] inBuf, int offset, int len,
OutputStream os, MessageProp msgProp)
throws GSSException {
try {
--- a/jdk/src/java.security.jgss/share/classes/sun/security/jgss/wrapper/SunNativeProvider.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/jgss/wrapper/SunNativeProvider.java Wed Jul 05 20:41:12 2017 +0200
@@ -78,7 +78,7 @@
if (DEBUG) err.printStackTrace();
return null;
}
- String gssLibs[] = new String[0];
+ String[] gssLibs = new String[0];
String defaultLib = System.getProperty(LIB_PROP);
if (defaultLib == null || defaultLib.trim().equals("")) {
String osname = System.getProperty("os.name");
--- a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/PrincipalName.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/PrincipalName.java Wed Jul 05 20:41:12 2017 +0200
@@ -568,7 +568,7 @@
temp.putInteger(bint);
bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x00), temp);
temp = new DerOutputStream();
- DerValue der[] = new DerValue[nameStrings.length];
+ DerValue[] der = new DerValue[nameStrings.length];
for (int i = 0; i < nameStrings.length; i++) {
der[i] = new KerberosString(nameStrings[i]).toDerValue();
}
--- a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/Authenticator.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/Authenticator.java Wed Jul 05 20:41:12 2017 +0200
@@ -198,7 +198,7 @@
if (authorizationData != null) {
v.addElement(new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0x08), authorizationData.asn1Encode()));
}
- DerValue der[] = new DerValue[v.size()];
+ DerValue[] der = new DerValue[v.size()];
v.copyInto(der);
temp = new DerOutputStream();
temp.putSequence(der);
--- a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/AuthorizationData.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/AuthorizationData.java Wed Jul 05 20:41:12 2017 +0200
@@ -120,7 +120,7 @@
*/
public byte[] asn1Encode() throws Asn1Exception, IOException {
DerOutputStream bytes = new DerOutputStream();
- DerValue der[] = new DerValue[entry.length];
+ DerValue[] der = new DerValue[entry.length];
for (int i = 0; i < entry.length; i++) {
der[i] = new DerValue(entry[i].asn1Encode());
}
--- a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/EncAPRepPart.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/EncAPRepPart.java Wed Jul 05 20:41:12 2017 +0200
@@ -151,7 +151,7 @@
v.addElement(new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT,
true, (byte) 0x03), temp.toByteArray()));
}
- DerValue der[] = new DerValue[v.size()];
+ DerValue[] der = new DerValue[v.size()];
v.copyInto(der);
temp = new DerOutputStream();
temp.putSequence(der);
--- a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/EncKrbCredPart.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/EncKrbCredPart.java Wed Jul 05 20:41:12 2017 +0200
@@ -129,7 +129,7 @@
subDer = der.getData().getDerValue();
if ((subDer.getTag() & (byte) 0x1F) == (byte) 0x00) {
- DerValue derValues[] = subDer.getData().getSequence(1);
+ DerValue[] derValues = subDer.getData().getSequence(1);
ticketInfo = new KrbCredInfo[derValues.length];
for (int i = 0; i < derValues.length; i++) {
ticketInfo[i] = new KrbCredInfo(derValues[i]);
--- a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/HostAddresses.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/HostAddresses.java Wed Jul 05 20:41:12 2017 +0200
@@ -98,8 +98,8 @@
throw new KrbException(Krb5.KRB_ERR_GENERIC, "Bad name");
String host = components[1];
- InetAddress addr[] = InetAddress.getAllByName(host);
- HostAddress hAddrs[] = new HostAddress[addr.length];
+ InetAddress[] addr = InetAddress.getAllByName(host);
+ HostAddress[] hAddrs = new HostAddress[addr.length];
for (int i = 0; i < addr.length; i++) {
hAddrs[i] = new HostAddress(addr[i]);
--- a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/KDCReqBody.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/KDCReqBody.java Wed Jul 05 20:41:12 2017 +0200
@@ -269,7 +269,7 @@
ticketsTemp.write(DerValue.tag_SequenceOf, temp);
v.addElement(new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x0B), ticketsTemp.toByteArray()));
}
- DerValue der[] = new DerValue[v.size()];
+ DerValue[] der = new DerValue[v.size()];
v.copyInto(der);
temp = new DerOutputStream();
temp.putSequence(der);
--- a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/KrbCredInfo.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/KrbCredInfo.java Wed Jul 05 20:41:12 2017 +0200
@@ -172,7 +172,7 @@
}
if (caddr != null)
v.addElement(new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x0A), caddr.asn1Encode()));
- DerValue der[] = new DerValue[v.size()];
+ DerValue[] der = new DerValue[v.size()];
v.copyInto(der);
DerOutputStream out = new DerOutputStream();
out.putSequence(der);
--- a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/NetClient.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/NetClient.java Wed Jul 05 20:41:12 2017 +0200
@@ -200,7 +200,7 @@
@Override
public byte[] receive() throws IOException {
- byte ibuf[] = new byte[bufSize];
+ byte[] ibuf = new byte[bufSize];
dgPacketIn = new DatagramPacket(ibuf, ibuf.length);
try {
dgSocket.receive(dgPacketIn);
--- a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/Ticket.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/Ticket.java Wed Jul 05 20:41:12 2017 +0200
@@ -135,7 +135,7 @@
public byte[] asn1Encode() throws Asn1Exception, IOException {
DerOutputStream bytes = new DerOutputStream();
DerOutputStream temp = new DerOutputStream();
- DerValue der[] = new DerValue[4];
+ DerValue[] der = new DerValue[4];
temp.putInteger(BigInteger.valueOf(tkt_vno));
bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x00), temp);
bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x01), sname.getRealm().asn1Encode());
--- a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/ccache/CCacheInputStream.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/ccache/CCacheInputStream.java Wed Jul 05 20:41:12 2017 +0200
@@ -357,7 +357,7 @@
if (DEBUG) {
System.out.println(">>>DEBUG <CCacheInputStream> key type: " + key.getEType());
}
- long times[] = readTimes();
+ long[] times = readTimes();
KerberosTime authtime = new KerberosTime(times[0]);
KerberosTime starttime =
(times[1]==0) ? null : new KerberosTime(times[1]);
@@ -374,9 +374,9 @@
((renewTill==null)?"null":renewTill.toDate().toString()));
}
boolean skey = readskey();
- boolean flags[] = readFlags();
+ boolean[] flags = readFlags();
TicketFlags tFlags = new TicketFlags(flags);
- HostAddress addr[] = readAddr();
+ HostAddress[] addr = readAddr();
HostAddresses addrs = null;
if (addr != null) {
addrs = new HostAddresses(addr);
--- a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/crc32.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/crc32.java Wed Jul 05 20:41:12 2017 +0200
@@ -112,7 +112,7 @@
* This version is more efficient than the byte-at-a-time version;
* it avoids data copies and reduces per-byte call overhead.
*/
- protected synchronized void engineUpdate(byte input[], int offset,
+ protected synchronized void engineUpdate(byte[] input, int offset,
int len) {
processData(input, offset, len);
}
--- a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/ssl/KerberosPreMasterSecret.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/ssl/KerberosPreMasterSecret.java Wed Jul 05 20:41:12 2017 +0200
@@ -53,8 +53,8 @@
final class KerberosPreMasterSecret {
private ProtocolVersion protocolVersion; // preMaster [0,1]
- private byte preMaster[]; // 48 bytes
- private byte encrypted[];
+ private byte[] preMaster; // 48 bytes
+ private byte[] encrypted;
/**
* Constructor used by client to generate premaster secret.
--- a/jdk/src/java.security.sasl/share/classes/com/sun/security/sasl/ClientFactoryImpl.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.security.sasl/share/classes/com/sun/security/sasl/ClientFactoryImpl.java Wed Jul 05 20:41:12 2017 +0200
@@ -47,13 +47,13 @@
* @author Rosanna Lee
*/
final public class ClientFactoryImpl implements SaslClientFactory {
- private static final String myMechs[] = {
+ private static final String[] myMechs = {
"EXTERNAL",
"CRAM-MD5",
"PLAIN",
};
- private static final int mechPolicies[] = {
+ private static final int[] mechPolicies = {
// %%% RL: Policies should actually depend on the external channel
PolicyUtils.NOPLAINTEXT|PolicyUtils.NOACTIVE|PolicyUtils.NODICTIONARY,
PolicyUtils.NOPLAINTEXT|PolicyUtils.NOANONYMOUS, // CRAM-MD5
--- a/jdk/src/java.security.sasl/share/classes/com/sun/security/sasl/CramMD5Server.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.security.sasl/share/classes/com/sun/security/sasl/CramMD5Server.java Wed Jul 05 20:41:12 2017 +0200
@@ -165,7 +165,7 @@
PasswordCallback pcb =
new PasswordCallback("CRAM-MD5 password: ", false);
cbh.handle(new Callback[]{ncb,pcb});
- char pwChars[] = pcb.getPassword();
+ char[] pwChars = pcb.getPassword();
if (pwChars == null || pwChars.length == 0) {
// user has no password; OK to disclose to server
aborted = true;
@@ -190,7 +190,7 @@
clearPassword();
// Check whether digest is as expected
- byte [] expectedDigest = digest.getBytes("UTF8");
+ byte[] expectedDigest = digest.getBytes("UTF8");
int digestLen = responseData.length - ulen - 1;
if (expectedDigest.length != digestLen) {
aborted = true;
--- a/jdk/src/java.security.sasl/share/classes/com/sun/security/sasl/ServerFactoryImpl.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.security.sasl/share/classes/com/sun/security/sasl/ServerFactoryImpl.java Wed Jul 05 20:41:12 2017 +0200
@@ -41,11 +41,11 @@
* @author Rosanna Lee
*/
final public class ServerFactoryImpl implements SaslServerFactory {
- private static final String myMechs[] = {
+ private static final String[] myMechs = {
"CRAM-MD5", //
};
- private static final int mechPolicies[] = {
+ private static final int[] mechPolicies = {
PolicyUtils.NOPLAINTEXT|PolicyUtils.NOANONYMOUS, // CRAM-MD5
};
--- a/jdk/src/java.security.sasl/share/classes/com/sun/security/sasl/digest/DigestMD5Base.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.security.sasl/share/classes/com/sun/security/sasl/digest/DigestMD5Base.java Wed Jul 05 20:41:12 2017 +0200
@@ -272,7 +272,7 @@
*/
/** This array maps the characters to their 6 bit values */
- private final static char pem_array[] = {
+ private final static char[] pem_array = {
// 0 1 2 3 4 5 6 7
'A','B','C','D','E','F','G','H', // 0
'I','J','K','L','M','N','O','P', // 1
@@ -1068,7 +1068,7 @@
byte[] hMAC_MD5 = m.doFinal();
/* First 10 bytes of HMAC_MD5 digest */
- byte macBuffer[] = new byte[10];
+ byte[] macBuffer = new byte[10];
System.arraycopy(hMAC_MD5, 0, macBuffer, 0, 10);
return macBuffer;
--- a/jdk/src/java.security.sasl/share/classes/com/sun/security/sasl/digest/FactoryImpl.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.security.sasl/share/classes/com/sun/security/sasl/digest/FactoryImpl.java Wed Jul 05 20:41:12 2017 +0200
@@ -44,9 +44,9 @@
public final class FactoryImpl implements SaslClientFactory,
SaslServerFactory{
- private static final String myMechs[] = { "DIGEST-MD5" };
+ private static final String[] myMechs = { "DIGEST-MD5" };
private static final int DIGEST_MD5 = 0;
- private static final int mechPolicies[] = {
+ private static final int[] mechPolicies = {
PolicyUtils.NOPLAINTEXT|PolicyUtils.NOANONYMOUS};
/**
--- a/jdk/src/java.security.sasl/share/classes/com/sun/security/sasl/ntlm/FactoryImpl.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/java.security.sasl/share/classes/com/sun/security/sasl/ntlm/FactoryImpl.java Wed Jul 05 20:41:12 2017 +0200
@@ -43,8 +43,8 @@
public final class FactoryImpl implements SaslClientFactory,
SaslServerFactory{
- private static final String myMechs[] = { "NTLM" };
- private static final int mechPolicies[] = {
+ private static final String[] myMechs = { "NTLM" };
+ private static final int[] mechPolicies = {
PolicyUtils.NOPLAINTEXT|PolicyUtils.NOANONYMOUS
};
--- a/jdk/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/KeyStore.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/KeyStore.java Wed Jul 05 20:41:12 2017 +0200
@@ -66,7 +66,7 @@
class KeyEntry
{
private Key privateKey;
- private X509Certificate certChain[];
+ private X509Certificate[] certChain;
private String alias;
KeyEntry(Key key, X509Certificate[] chain) {
--- a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11Cipher.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11Cipher.java Wed Jul 05 20:41:12 2017 +0200
@@ -175,7 +175,7 @@
this.algorithm = algorithm;
this.mechanism = mechanism;
- String algoParts[] = algorithm.split("/");
+ String[] algoParts = algorithm.split("/");
if (algoParts[0].startsWith("AES")) {
blockSize = 16;
--- a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11KeyStore.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11KeyStore.java Wed Jul 05 20:41:12 2017 +0200
@@ -164,7 +164,7 @@
private X509Certificate cert = null;
// chain
- private X509Certificate chain[] = null;
+ private X509Certificate[] chain = null;
// true if CKA_ID for private key and cert match up
private boolean matched = false;
--- a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_AES_CTR_PARAMS.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/wrapper/CK_AES_CTR_PARAMS.java Wed Jul 05 20:41:12 2017 +0200
@@ -42,7 +42,7 @@
public class CK_AES_CTR_PARAMS {
private final long ulCounterBits;
- private final byte cb[];
+ private final byte[] cb;
public CK_AES_CTR_PARAMS(byte[] cb) {
ulCounterBits = 128;
--- a/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/UcryptoException.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/UcryptoException.java Wed Jul 05 20:41:12 2017 +0200
@@ -40,7 +40,7 @@
private static final long serialVersionUID = -933864511110035746L;
// NOTE: check /usr/include/sys/crypto/common.h for updates
- private static final String ERROR_MSG[] = {
+ private static final String[] ERROR_MSG = {
"CRYPTO_SUCCESS",
"CRYPTO_CANCEL",
"CRYPTO_HOST_MEMORY",
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/NoInterruptUnixTerminal.java Wed Jul 05 20:41:12 2017 +0200
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline;
+
+// Based on Apache Karaf impl
+
+/**
+ * Non-interruptible (via CTRL-C) {@link UnixTerminal}.
+ *
+ * @since 2.0
+ */
+public class NoInterruptUnixTerminal
+ extends UnixTerminal
+{
+ public NoInterruptUnixTerminal() throws Exception {
+ super();
+ }
+
+ @Override
+ public void init() throws Exception {
+ super.init();
+ getSettings().set("intr undef");
+ }
+
+ @Override
+ public void restore() throws Exception {
+ getSettings().set("intr ^C");
+ super.restore();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/Terminal.java Wed Jul 05 20:41:12 2017 +0200
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * Representation of the input terminal for a platform.
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.0
+ */
+public interface Terminal
+{
+ void init() throws Exception;
+
+ void restore() throws Exception;
+
+ void reset() throws Exception;
+
+ boolean isSupported();
+
+ int getWidth();
+
+ int getHeight();
+
+ boolean isAnsiSupported();
+
+ /**
+ * When ANSI is not natively handled, the output will have to be wrapped.
+ */
+ OutputStream wrapOutIfNeeded(OutputStream out);
+
+ /**
+ * When using native support, return the InputStream to use for reading characters
+ * else return the input stream passed as a parameter.
+ *
+ * @since 2.6
+ */
+ InputStream wrapInIfNeeded(InputStream in) throws IOException;
+
+ /**
+ * For terminals that don't wrap when character is written in last column,
+ * only when the next character is written.
+ * These are the ones that have 'am' and 'xn' termcap attributes (xterm and
+ * rxvt flavors falls under that category)
+ */
+ boolean hasWeirdWrap();
+
+ boolean isEchoEnabled();
+
+ void setEchoEnabled(boolean enabled);
+
+ String getOutputEncoding();
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/TerminalFactory.java Wed Jul 05 20:41:12 2017 +0200
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline;
+
+import java.text.MessageFormat;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.Callable;
+
+import jdk.internal.jline.internal.Configuration;
+import jdk.internal.jline.internal.Log;
+import jdk.internal.jline.internal.Preconditions;
+import static jdk.internal.jline.internal.Preconditions.checkNotNull;
+
+/**
+ * Creates terminal instances.
+ *
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.0
+ */
+public class TerminalFactory
+{
+ public static final String JLINE_TERMINAL = "jline.terminal";
+
+ public static final String AUTO = "auto";
+
+ public static final String UNIX = "unix";
+
+ public static final String WIN = "win";
+
+ public static final String WINDOWS = "windows";
+
+ public static final String NONE = "none";
+
+ public static final String OFF = "off";
+
+ public static final String FALSE = "false";
+
+ private static Terminal term = null;
+
+ public static synchronized Terminal create() {
+ if (Log.TRACE) {
+ //noinspection ThrowableInstanceNeverThrown
+ Log.trace(new Throwable("CREATE MARKER"));
+ }
+
+ String type = Configuration.getString(JLINE_TERMINAL, AUTO);
+ if ("dumb".equals(System.getenv("TERM"))) {
+ type = "none";
+ Log.debug("$TERM=dumb; setting type=", type);
+ }
+
+ Log.debug("Creating terminal; type=", type);
+
+ Terminal t;
+ try {
+ String tmp = type.toLowerCase();
+
+ if (tmp.equals(UNIX)) {
+ t = getFlavor(Flavor.UNIX);
+ }
+ else if (tmp.equals(WIN) | tmp.equals(WINDOWS)) {
+ t = getFlavor(Flavor.WINDOWS);
+ }
+ else if (tmp.equals(NONE) || tmp.equals(OFF) || tmp.equals(FALSE)) {
+ t = new UnsupportedTerminal();
+ }
+ else {
+ if (tmp.equals(AUTO)) {
+ String os = Configuration.getOsName();
+ Flavor flavor = Flavor.UNIX;
+ if (os.contains(WINDOWS)) {
+ flavor = Flavor.WINDOWS;
+ }
+ t = getFlavor(flavor);
+ }
+ else {
+ try {
+ t = (Terminal) Thread.currentThread().getContextClassLoader().loadClass(type).newInstance();
+ }
+ catch (Exception e) {
+ throw new IllegalArgumentException(MessageFormat.format("Invalid terminal type: {0}", type), e);
+ }
+ }
+ }
+ }
+ catch (Exception e) {
+ Log.error("Failed to construct terminal; falling back to unsupported", e);
+ t = new UnsupportedTerminal();
+ }
+
+ Log.debug("Created Terminal: ", t);
+
+ try {
+ t.init();
+ }
+ catch (Throwable e) {
+ Log.error("Terminal initialization failed; falling back to unsupported", e);
+ return new UnsupportedTerminal();
+ }
+
+ return t;
+ }
+
+ public static synchronized void reset() {
+ term = null;
+ }
+
+ public static synchronized void resetIf(final Terminal t) {
+ if(t == term) {
+ reset();
+ }
+ }
+
+ public static enum Type
+ {
+ AUTO,
+ WINDOWS,
+ UNIX,
+ NONE
+ }
+
+ public static synchronized void configure(final String type) {
+ checkNotNull(type);
+ System.setProperty(JLINE_TERMINAL, type);
+ }
+
+ public static synchronized void configure(final Type type) {
+ checkNotNull(type);
+ configure(type.name().toLowerCase());
+ }
+
+ //
+ // Flavor Support
+ //
+
+ public static enum Flavor
+ {
+ WINDOWS,
+ UNIX
+ }
+
+ private static final Map<Flavor, Callable<? extends Terminal>> FLAVORS = new HashMap<>();
+
+ static {
+// registerFlavor(Flavor.WINDOWS, AnsiWindowsTerminal.class);
+// registerFlavor(Flavor.UNIX, UnixTerminal.class);
+ registerFlavor(Flavor.WINDOWS, WindowsTerminal :: new);
+ registerFlavor(Flavor.UNIX, UnixTerminal :: new);
+ }
+
+ public static synchronized Terminal get() {
+ if (term == null) {
+ term = create();
+ }
+ return term;
+ }
+
+ public static Terminal getFlavor(final Flavor flavor) throws Exception {
+ return FLAVORS.getOrDefault(flavor, () -> {throw new InternalError();}).call();
+ }
+
+ public static void registerFlavor(final Flavor flavor, final Callable<? extends Terminal> sup) {
+ FLAVORS.put(flavor, sup);
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/TerminalSupport.java Wed Jul 05 20:41:12 2017 +0200
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import jdk.internal.jline.internal.Log;
+import jdk.internal.jline.internal.ShutdownHooks;
+import jdk.internal.jline.internal.ShutdownHooks.Task;
+
+/**
+ * Provides support for {@link Terminal} instances.
+ *
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.0
+ */
+public abstract class TerminalSupport
+ implements Terminal
+{
+ public static final int DEFAULT_WIDTH = 80;
+
+ public static final int DEFAULT_HEIGHT = 24;
+
+ private Task shutdownTask;
+
+ private boolean supported;
+
+ private boolean echoEnabled;
+
+ private boolean ansiSupported;
+
+ protected TerminalSupport(final boolean supported) {
+ this.supported = supported;
+ }
+
+ public void init() throws Exception {
+ if (shutdownTask != null) {
+ ShutdownHooks.remove(shutdownTask);
+ }
+ // Register a task to restore the terminal on shutdown
+ this.shutdownTask = ShutdownHooks.add(new Task()
+ {
+ public void run() throws Exception {
+ restore();
+ }
+ });
+ }
+
+ public void restore() throws Exception {
+ TerminalFactory.resetIf(this);
+ if (shutdownTask != null) {
+ ShutdownHooks.remove(shutdownTask);
+ shutdownTask = null;
+ }
+ }
+
+ public void reset() throws Exception {
+ restore();
+ init();
+ }
+
+ public final boolean isSupported() {
+ return supported;
+ }
+
+ public synchronized boolean isAnsiSupported() {
+ return ansiSupported;
+ }
+
+ protected synchronized void setAnsiSupported(final boolean supported) {
+ this.ansiSupported = supported;
+ Log.debug("Ansi supported: ", supported);
+ }
+
+ /**
+ * Subclass to change behavior if needed.
+ * @return the passed out
+ */
+ public OutputStream wrapOutIfNeeded(OutputStream out) {
+ return out;
+ }
+
+ /**
+ * Defaults to true which was the behaviour before this method was added.
+ */
+ public boolean hasWeirdWrap() {
+ return true;
+ }
+
+ public int getWidth() {
+ return DEFAULT_WIDTH;
+ }
+
+ public int getHeight() {
+ return DEFAULT_HEIGHT;
+ }
+
+ public synchronized boolean isEchoEnabled() {
+ return echoEnabled;
+ }
+
+ public synchronized void setEchoEnabled(final boolean enabled) {
+ this.echoEnabled = enabled;
+ Log.debug("Echo enabled: ", enabled);
+ }
+
+ public InputStream wrapInIfNeeded(InputStream in) throws IOException {
+ return in;
+ }
+
+ public String getOutputEncoding() {
+ // null for unknown
+ return null;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/UnixTerminal.java Wed Jul 05 20:41:12 2017 +0200
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline;
+
+import jdk.internal.jline.internal.Log;
+import jdk.internal.jline.internal.TerminalLineSettings;
+
+/**
+ * Terminal that is used for unix platforms. Terminal initialization
+ * is handled by issuing the <em>stty</em> command against the
+ * <em>/dev/tty</em> file to disable character echoing and enable
+ * character input. All known unix systems (including
+ * Linux and Macintosh OS X) support the <em>stty</em>), so this
+ * implementation should work for an reasonable POSIX system.
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ * @author <a href="mailto:dwkemp@gmail.com">Dale Kemp</a>
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @author <a href="mailto:jbonofre@apache.org">Jean-Baptiste Onofr\u00E9</a>
+ * @since 2.0
+ */
+public class UnixTerminal
+ extends TerminalSupport
+{
+ private final TerminalLineSettings settings = new TerminalLineSettings();
+
+ public UnixTerminal() throws Exception {
+ super(true);
+ }
+
+ protected TerminalLineSettings getSettings() {
+ return settings;
+ }
+
+ /**
+ * Remove line-buffered input by invoking "stty -icanon min 1"
+ * against the current terminal.
+ */
+ @Override
+ public void init() throws Exception {
+ super.init();
+
+ setAnsiSupported(true);
+
+ // Set the console to be character-buffered instead of line-buffered.
+ // Make sure we're distinguishing carriage return from newline.
+ // Allow ctrl-s keypress to be used (as forward search)
+ settings.set("-icanon min 1 -icrnl -inlcr -ixon");
+ settings.set("dsusp undef");
+
+ setEchoEnabled(false);
+ }
+
+ /**
+ * Restore the original terminal configuration, which can be used when
+ * shutting down the console reader. The ConsoleReader cannot be
+ * used after calling this method.
+ */
+ @Override
+ public void restore() throws Exception {
+ settings.restore();
+ super.restore();
+ }
+
+ /**
+ * Returns the value of <tt>stty columns</tt> param.
+ */
+ @Override
+ public int getWidth() {
+ int w = settings.getProperty("columns");
+ return w < 1 ? DEFAULT_WIDTH : w;
+ }
+
+ /**
+ * Returns the value of <tt>stty rows>/tt> param.
+ */
+ @Override
+ public int getHeight() {
+ int h = settings.getProperty("rows");
+ return h < 1 ? DEFAULT_HEIGHT : h;
+ }
+
+ @Override
+ public synchronized void setEchoEnabled(final boolean enabled) {
+ try {
+ if (enabled) {
+ settings.set("echo");
+ }
+ else {
+ settings.set("-echo");
+ }
+ super.setEchoEnabled(enabled);
+ }
+ catch (Exception e) {
+ if (e instanceof InterruptedException) {
+ Thread.currentThread().interrupt();
+ }
+ Log.error("Failed to ", (enabled ? "enable" : "disable"), " echo", e);
+ }
+ }
+
+ public void disableInterruptCharacter()
+ {
+ try {
+ settings.set("intr undef");
+ }
+ catch (Exception e) {
+ if (e instanceof InterruptedException) {
+ Thread.currentThread().interrupt();
+ }
+ Log.error("Failed to disable interrupt character", e);
+ }
+ }
+
+ public void enableInterruptCharacter()
+ {
+ try {
+ settings.set("intr ^C");
+ }
+ catch (Exception e) {
+ if (e instanceof InterruptedException) {
+ Thread.currentThread().interrupt();
+ }
+ Log.error("Failed to enable interrupt character", e);
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/UnsupportedTerminal.java Wed Jul 05 20:41:12 2017 +0200
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline;
+
+/**
+ * An unsupported terminal.
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.0
+ */
+public class UnsupportedTerminal
+ extends TerminalSupport
+{
+ public UnsupportedTerminal() {
+ super(false);
+ setAnsiSupported(false);
+ setEchoEnabled(true);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/WindowsTerminal.java Wed Jul 05 20:41:12 2017 +0200
@@ -0,0 +1,546 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline;
+
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import jdk.internal.jline.internal.Configuration;
+import jdk.internal.jline.internal.Log;
+//import org.fusesource.jansi.internal.WindowsSupport;
+//import org.fusesource.jansi.internal.Kernel32;
+//import static org.fusesource.jansi.internal.Kernel32.*;
+
+import static jdk.internal.jline.WindowsTerminal.ConsoleMode.ENABLE_ECHO_INPUT;
+import static jdk.internal.jline.WindowsTerminal.ConsoleMode.ENABLE_LINE_INPUT;
+import static jdk.internal.jline.WindowsTerminal.ConsoleMode.ENABLE_PROCESSED_INPUT;
+import static jdk.internal.jline.WindowsTerminal.ConsoleMode.ENABLE_WINDOW_INPUT;
+
+/**
+ * Terminal implementation for Microsoft Windows. Terminal initialization in
+ * {@link #init} is accomplished by extracting the
+ * <em>jline_<i>version</i>.dll</em>, saving it to the system temporary
+ * directoy (determined by the setting of the <em>java.io.tmpdir</em> System
+ * property), loading the library, and then calling the Win32 APIs <a
+ * href="http://msdn.microsoft.com/library/default.asp?
+ * url=/library/en-us/dllproc/base/setconsolemode.asp">SetConsoleMode</a> and
+ * <a href="http://msdn.microsoft.com/library/default.asp?
+ * url=/library/en-us/dllproc/base/getconsolemode.asp">GetConsoleMode</a> to
+ * disable character echoing.
+ * <p/>
+ * <p>
+ * By default, the {@link #wrapInIfNeeded(java.io.InputStream)} method will attempt
+ * to test to see if the specified {@link InputStream} is {@link System#in} or a wrapper
+ * around {@link FileDescriptor#in}, and if so, will bypass the character reading to
+ * directly invoke the readc() method in the JNI library. This is so the class
+ * can read special keys (like arrow keys) which are otherwise inaccessible via
+ * the {@link System#in} stream. Using JNI reading can be bypassed by setting
+ * the <code>jline.WindowsTerminal.directConsole</code> system property
+ * to <code>false</code>.
+ * </p>
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.0
+ */
+public class WindowsTerminal
+ extends TerminalSupport
+{
+ public static final String DIRECT_CONSOLE = WindowsTerminal.class.getName() + ".directConsole";
+
+ public static final String ANSI = WindowsTerminal.class.getName() + ".ansi";
+
+ private boolean directConsole;
+
+ private int originalMode;
+
+ public WindowsTerminal() throws Exception {
+ super(true);
+ }
+
+ @Override
+ public void init() throws Exception {
+ super.init();
+
+// setAnsiSupported(Configuration.getBoolean(ANSI, true));
+ setAnsiSupported(false);
+
+ //
+ // FIXME: Need a way to disable direct console and sysin detection muck
+ //
+
+ setDirectConsole(Configuration.getBoolean(DIRECT_CONSOLE, true));
+
+ this.originalMode = getConsoleMode();
+ setConsoleMode(originalMode & ~ENABLE_ECHO_INPUT.code);
+ setEchoEnabled(false);
+ }
+
+ /**
+ * Restore the original terminal configuration, which can be used when
+ * shutting down the console reader. The ConsoleReader cannot be
+ * used after calling this method.
+ */
+ @Override
+ public void restore() throws Exception {
+ // restore the old console mode
+ setConsoleMode(originalMode);
+ super.restore();
+ }
+
+ @Override
+ public int getWidth() {
+ int w = getWindowsTerminalWidth();
+ return w < 1 ? DEFAULT_WIDTH : w;
+ }
+
+ @Override
+ public int getHeight() {
+ int h = getWindowsTerminalHeight();
+ return h < 1 ? DEFAULT_HEIGHT : h;
+ }
+
+ @Override
+ public void setEchoEnabled(final boolean enabled) {
+ // Must set these four modes at the same time to make it work fine.
+ if (enabled) {
+ setConsoleMode(getConsoleMode() |
+ ENABLE_ECHO_INPUT.code |
+ ENABLE_LINE_INPUT.code |
+ ENABLE_PROCESSED_INPUT.code |
+ ENABLE_WINDOW_INPUT.code);
+ }
+ else {
+ setConsoleMode(getConsoleMode() &
+ ~(ENABLE_LINE_INPUT.code |
+ ENABLE_ECHO_INPUT.code |
+ ENABLE_PROCESSED_INPUT.code |
+ ENABLE_WINDOW_INPUT.code));
+ }
+ super.setEchoEnabled(enabled);
+ }
+
+ /**
+ * Whether or not to allow the use of the JNI console interaction.
+ */
+ public void setDirectConsole(final boolean flag) {
+ this.directConsole = flag;
+ Log.debug("Direct console: ", flag);
+ }
+
+ /**
+ * Whether or not to allow the use of the JNI console interaction.
+ */
+ public Boolean getDirectConsole() {
+ return directConsole;
+ }
+
+
+ @Override
+ public InputStream wrapInIfNeeded(InputStream in) throws IOException {
+ if (directConsole && isSystemIn(in)) {
+ return new InputStream() {
+ private byte[] buf = null;
+ int bufIdx = 0;
+
+ @Override
+ public int read() throws IOException {
+ while (buf == null || bufIdx == buf.length) {
+ buf = readConsoleInput();
+ bufIdx = 0;
+ }
+ int c = buf[bufIdx] & 0xFF;
+ bufIdx++;
+ return c;
+ }
+ };
+ } else {
+ return super.wrapInIfNeeded(in);
+ }
+ }
+
+ protected boolean isSystemIn(final InputStream in) throws IOException {
+ if (in == null) {
+ return false;
+ }
+ else if (in == System.in) {
+ return true;
+ }
+ else if (in instanceof FileInputStream && ((FileInputStream) in).getFD() == FileDescriptor.in) {
+ return true;
+ }
+
+ return false;
+ }
+
+ @Override
+ public String getOutputEncoding() {
+ int codepage = getConsoleOutputCodepage();
+ //http://docs.oracle.com/javase/6/docs/technotes/guides/intl/encoding.doc.html
+ String charsetMS = "ms" + codepage;
+ if (java.nio.charset.Charset.isSupported(charsetMS)) {
+ return charsetMS;
+ }
+ String charsetCP = "cp" + codepage;
+ if (java.nio.charset.Charset.isSupported(charsetCP)) {
+ return charsetCP;
+ }
+ Log.debug("can't figure out the Java Charset of this code page (" + codepage + ")...");
+ return super.getOutputEncoding();
+ }
+
+ //
+ // Original code:
+ //
+// private int getConsoleMode() {
+// return WindowsSupport.getConsoleMode();
+// }
+//
+// private void setConsoleMode(int mode) {
+// WindowsSupport.setConsoleMode(mode);
+// }
+//
+// private byte[] readConsoleInput() {
+// // XXX does how many events to read in one call matter?
+// INPUT_RECORD[] events = null;
+// try {
+// events = WindowsSupport.readConsoleInput(1);
+// } catch (IOException e) {
+// Log.debug("read Windows console input error: ", e);
+// }
+// if (events == null) {
+// return new byte[0];
+// }
+// StringBuilder sb = new StringBuilder();
+// for (int i = 0; i < events.length; i++ ) {
+// KEY_EVENT_RECORD keyEvent = events[i].keyEvent;
+// //Log.trace(keyEvent.keyDown? "KEY_DOWN" : "KEY_UP", "key code:", keyEvent.keyCode, "char:", (long)keyEvent.uchar);
+// if (keyEvent.keyDown) {
+// if (keyEvent.uchar > 0) {
+// // support some C1 control sequences: ALT + [@-_] (and [a-z]?) => ESC <ascii>
+// // http://en.wikipedia.org/wiki/C0_and_C1_control_codes#C1_set
+// final int altState = KEY_EVENT_RECORD.LEFT_ALT_PRESSED | KEY_EVENT_RECORD.RIGHT_ALT_PRESSED;
+// // Pressing "Alt Gr" is translated to Alt-Ctrl, hence it has to be checked that Ctrl is _not_ pressed,
+// // otherwise inserting of "Alt Gr" codes on non-US keyboards would yield errors
+// final int ctrlState = KEY_EVENT_RECORD.LEFT_CTRL_PRESSED | KEY_EVENT_RECORD.RIGHT_CTRL_PRESSED;
+// if (((keyEvent.uchar >= '@' && keyEvent.uchar <= '_') || (keyEvent.uchar >= 'a' && keyEvent.uchar <= 'z'))
+// && ((keyEvent.controlKeyState & altState) != 0) && ((keyEvent.controlKeyState & ctrlState) == 0)) {
+// sb.append('\u001B'); // ESC
+// }
+//
+// sb.append(keyEvent.uchar);
+// continue;
+// }
+// // virtual keycodes: http://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx
+// // just add support for basic editing keys (no control state, no numpad keys)
+// String escapeSequence = null;
+// switch (keyEvent.keyCode) {
+// case 0x21: // VK_PRIOR PageUp
+// escapeSequence = "\u001B[5~";
+// break;
+// case 0x22: // VK_NEXT PageDown
+// escapeSequence = "\u001B[6~";
+// break;
+// case 0x23: // VK_END
+// escapeSequence = "\u001B[4~";
+// break;
+// case 0x24: // VK_HOME
+// escapeSequence = "\u001B[1~";
+// break;
+// case 0x25: // VK_LEFT
+// escapeSequence = "\u001B[D";
+// break;
+// case 0x26: // VK_UP
+// escapeSequence = "\u001B[A";
+// break;
+// case 0x27: // VK_RIGHT
+// escapeSequence = "\u001B[C";
+// break;
+// case 0x28: // VK_DOWN
+// escapeSequence = "\u001B[B";
+// break;
+// case 0x2D: // VK_INSERT
+// escapeSequence = "\u001B[2~";
+// break;
+// case 0x2E: // VK_DELETE
+// escapeSequence = "\u001B[3~";
+// break;
+// default:
+// break;
+// }
+// if (escapeSequence != null) {
+// for (int k = 0; k < keyEvent.repeatCount; k++) {
+// sb.append(escapeSequence);
+// }
+// }
+// } else {
+// // key up event
+// // support ALT+NumPad input method
+// if (keyEvent.keyCode == 0x12/*VK_MENU ALT key*/ && keyEvent.uchar > 0) {
+// sb.append(keyEvent.uchar);
+// }
+// }
+// }
+// return sb.toString().getBytes();
+// }
+//
+// private int getConsoleOutputCodepage() {
+// return Kernel32.GetConsoleOutputCP();
+// }
+//
+// private int getWindowsTerminalWidth() {
+// return WindowsSupport.getWindowsTerminalWidth();
+// }
+//
+// private int getWindowsTerminalHeight() {
+// return WindowsSupport.getWindowsTerminalHeight();
+// }
+
+ //
+ // Native Bits
+ //
+ static {
+ System.loadLibrary("le");
+ initIDs();
+ }
+
+ private static native void initIDs();
+
+ private native int getConsoleMode();
+
+ private native void setConsoleMode(int mode);
+
+ private byte[] readConsoleInput() {
+ KEY_EVENT_RECORD keyEvent = readKeyEvent();
+
+ return convertKeys(keyEvent).getBytes();
+ }
+
+ public static String convertKeys(KEY_EVENT_RECORD keyEvent) {
+ if (keyEvent == null) {
+ return "";
+ }
+
+ StringBuilder sb = new StringBuilder();
+
+ if (keyEvent.keyDown) {
+ if (keyEvent.uchar > 0) {
+ // support some C1 control sequences: ALT + [@-_] (and [a-z]?) => ESC <ascii>
+ // http://en.wikipedia.org/wiki/C0_and_C1_control_codes#C1_set
+ final int altState = KEY_EVENT_RECORD.ALT_PRESSED;
+ // Pressing "Alt Gr" is translated to Alt-Ctrl, hence it has to be checked that Ctrl is _not_ pressed,
+ // otherwise inserting of "Alt Gr" codes on non-US keyboards would yield errors
+ final int ctrlState = KEY_EVENT_RECORD.CTRL_PRESSED;
+
+ boolean handled = false;
+
+ if ((keyEvent.controlKeyState & ctrlState) != 0) {
+ switch (keyEvent.keyCode) {
+ case 0x43: //Ctrl-C
+ sb.append("\003");
+ handled = true;
+ break;
+ }
+ }
+
+ if ((keyEvent.controlKeyState & KEY_EVENT_RECORD.SHIFT_PRESSED) != 0) {
+ switch (keyEvent.keyCode) {
+ case 0x09: //Shift-Tab
+ sb.append("\033\133\132");
+ handled = true;
+ break;
+ }
+ }
+
+ if (!handled) {
+ if (((keyEvent.uchar >= '@' && keyEvent.uchar <= '_') || (keyEvent.uchar >= 'a' && keyEvent.uchar <= 'z'))
+ && ((keyEvent.controlKeyState & altState) != 0) && ((keyEvent.controlKeyState & ctrlState) == 0)) {
+ sb.append('\u001B'); // ESC
+ }
+
+ sb.append(keyEvent.uchar);
+ }
+ } else {
+ // virtual keycodes: http://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx
+ // just add support for basic editing keys (no control state, no numpad keys)
+ String escapeSequence = null;
+ switch (keyEvent.keyCode) {
+ case 0x21: // VK_PRIOR PageUp
+ escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[5~", "\u001B[5;%d~");
+ break;
+ case 0x22: // VK_NEXT PageDown
+ escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[6~", "\u001B[6;%d~");
+ break;
+ case 0x23: // VK_END
+ escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[4~", "\u001B[4;%d~");
+ break;
+ case 0x24: // VK_HOME
+ escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[1~", "\u001B[1;%d~");
+ break;
+ case 0x25: // VK_LEFT
+ escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[D", "\u001B[1;%dD");
+ break;
+ case 0x26: // VK_UP
+ escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[A", "\u001B[1;%dA");
+ break;
+ case 0x27: // VK_RIGHT
+ escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[C", "\u001B[1;%dC");
+ break;
+ case 0x28: // VK_DOWN
+ escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[B", "\u001B[1;%dB");
+ break;
+ case 0x2D: // VK_INSERT
+ escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[2~", "\u001B[2;%d~");
+ break;
+ case 0x2E: // VK_DELETE
+ escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[3~", "\u001B[3;%d~");
+ break;
+ default:
+ break;
+ }
+ if (escapeSequence != null) {
+ for (int k = 0; k < keyEvent.repeatCount; k++) {
+ sb.append(escapeSequence);
+ }
+ }
+ }
+ } else {
+ // key up event
+ // support ALT+NumPad input method
+ if (keyEvent.keyCode == 0x12/*VK_MENU ALT key*/ && keyEvent.uchar > 0) {
+ sb.append(keyEvent.uchar);
+ }
+ }
+ return sb.toString();
+ }
+
+ private static String escapeSequence(int controlKeyState, String noControlSequence, String withControlSequence) {
+ int controlNum = 1;
+
+ if ((controlKeyState & KEY_EVENT_RECORD.SHIFT_PRESSED) != 0) {
+ controlNum += 1;
+ }
+
+ if ((controlKeyState & KEY_EVENT_RECORD.ALT_PRESSED) != 0) {
+ controlNum += 2;
+ }
+
+ if ((controlKeyState & KEY_EVENT_RECORD.CTRL_PRESSED) != 0) {
+ controlNum += 4;
+ }
+
+ if (controlNum > 1) {
+ return String.format(withControlSequence, controlNum);
+ } else {
+ return noControlSequence;
+ }
+ }
+
+ private native KEY_EVENT_RECORD readKeyEvent();
+
+ public static class KEY_EVENT_RECORD {
+ public final static int ALT_PRESSED = 0x3;
+ public final static int CTRL_PRESSED = 0xC;
+ public final static int SHIFT_PRESSED = 0x10;
+ public final boolean keyDown;
+ public final char uchar;
+ public final int controlKeyState;
+ public final int keyCode;
+ public final int repeatCount;
+
+ public KEY_EVENT_RECORD(boolean keyDown, char uchar, int controlKeyState, int keyCode, int repeatCount) {
+ this.keyDown = keyDown;
+ this.uchar = uchar;
+ this.controlKeyState = controlKeyState;
+ this.keyCode = keyCode;
+ this.repeatCount = repeatCount;
+ }
+
+ }
+
+ private native int getConsoleOutputCodepage();
+
+ private native int getWindowsTerminalWidth();
+
+ private native int getWindowsTerminalHeight();
+
+ /**
+ * Console mode
+ * <p/>
+ * Constants copied <tt>wincon.h</tt>.
+ */
+ public static enum ConsoleMode
+ {
+ /**
+ * The ReadFile or ReadConsole function returns only when a carriage return
+ * character is read. If this mode is disable, the functions return when one
+ * or more characters are available.
+ */
+ ENABLE_LINE_INPUT(2),
+
+ /**
+ * Characters read by the ReadFile or ReadConsole function are written to
+ * the active screen buffer as they are read. This mode can be used only if
+ * the ENABLE_LINE_INPUT mode is also enabled.
+ */
+ ENABLE_ECHO_INPUT(4),
+
+ /**
+ * CTRL+C is processed by the system and is not placed in the input buffer.
+ * If the input buffer is being read by ReadFile or ReadConsole, other
+ * control keys are processed by the system and are not returned in the
+ * ReadFile or ReadConsole buffer. If the ENABLE_LINE_INPUT mode is also
+ * enabled, backspace, carriage return, and linefeed characters are handled
+ * by the system.
+ */
+ ENABLE_PROCESSED_INPUT(1),
+
+ /**
+ * User interactions that change the size of the console screen buffer are
+ * reported in the console's input buffee. Information about these events
+ * can be read from the input buffer by applications using
+ * theReadConsoleInput function, but not by those using ReadFile
+ * orReadConsole.
+ */
+ ENABLE_WINDOW_INPUT(8),
+
+ /**
+ * If the mouse pointer is within the borders of the console window and the
+ * window has the keyboard focus, mouse events generated by mouse movement
+ * and button presses are placed in the input buffer. These events are
+ * discarded by ReadFile or ReadConsole, even when this mode is enabled.
+ */
+ ENABLE_MOUSE_INPUT(16),
+
+ /**
+ * When enabled, text entered in a console window will be inserted at the
+ * current cursor location and all text following that location will not be
+ * overwritten. When disabled, all following text will be overwritten. An OR
+ * operation must be performed with this flag and the ENABLE_EXTENDED_FLAGS
+ * flag to enable this functionality.
+ */
+ ENABLE_PROCESSED_OUTPUT(1),
+
+ /**
+ * This flag enables the user to use the mouse to select and edit text. To
+ * enable this option, use the OR to combine this flag with
+ * ENABLE_EXTENDED_FLAGS.
+ */
+ ENABLE_WRAP_AT_EOL_OUTPUT(2),;
+
+ public final int code;
+
+ ConsoleMode(final int code) {
+ this.code = code;
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/ConsoleKeys.java Wed Jul 05 20:41:12 2017 +0200
@@ -0,0 +1,399 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.console;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import jdk.internal.jline.internal.Log;
+
+/**
+ * @author St\u00E5le W. Pedersen <stale.pedersen@jboss.org>
+ */
+public class ConsoleKeys {
+
+ private KeyMap keys;
+
+ private Map<String, KeyMap> keyMaps;
+ private Map<String, String> variables = new HashMap<String,String>();
+
+ public ConsoleKeys(String appName, URL inputrcUrl) {
+ keyMaps = KeyMap.keyMaps();
+ loadKeys(appName, inputrcUrl);
+ }
+
+ protected boolean isViEditMode() {
+ return keys.isViKeyMap();
+ }
+
+ protected boolean setKeyMap (String name) {
+ KeyMap map = keyMaps.get(name);
+ if (map == null) {
+ return false;
+ }
+ this.keys = map;
+ return true;
+ }
+
+ protected Map<String, KeyMap> getKeyMaps() {
+ return keyMaps;
+ }
+
+ protected KeyMap getKeys() {
+ return keys;
+ }
+
+ protected void setKeys(KeyMap keys) {
+ this.keys = keys;
+ }
+
+ protected boolean getViEditMode() {
+ return keys.isViKeyMap ();
+ }
+
+ protected void loadKeys(String appName, URL inputrcUrl) {
+ keys = keyMaps.get(KeyMap.EMACS);
+
+ try {
+ InputStream input = inputrcUrl.openStream();
+ try {
+ loadKeys(input, appName);
+ Log.debug("Loaded user configuration: ", inputrcUrl);
+ }
+ finally {
+ try {
+ input.close();
+ } catch (IOException e) {
+ // Ignore
+ }
+ }
+ }
+ catch (IOException e) {
+ if (inputrcUrl.getProtocol().equals("file")) {
+ File file = new File(inputrcUrl.getPath());
+ if (file.exists()) {
+ Log.warn("Unable to read user configuration: ", inputrcUrl, e);
+ }
+ } else {
+ Log.warn("Unable to read user configuration: ", inputrcUrl, e);
+ }
+ }
+ }
+
+ private void loadKeys(InputStream input, String appName) throws IOException {
+ BufferedReader reader = new BufferedReader( new java.io.InputStreamReader( input ) );
+ String line;
+ boolean parsing = true;
+ List<Boolean> ifsStack = new ArrayList<Boolean>();
+ while ( (line = reader.readLine()) != null ) {
+ try {
+ line = line.trim();
+ if (line.length() == 0) {
+ continue;
+ }
+ if (line.charAt(0) == '#') {
+ continue;
+ }
+ int i = 0;
+ if (line.charAt(i) == '$') {
+ String cmd;
+ String args;
+ for (++i; i < line.length() && (line.charAt(i) == ' ' || line.charAt(i) == '\t'); i++);
+ int s = i;
+ for (; i < line.length() && (line.charAt(i) != ' ' && line.charAt(i) != '\t'); i++);
+ cmd = line.substring(s, i);
+ for (; i < line.length() && (line.charAt(i) == ' ' || line.charAt(i) == '\t'); i++);
+ s = i;
+ for (; i < line.length() && (line.charAt(i) != ' ' && line.charAt(i) != '\t'); i++);
+ args = line.substring(s, i);
+ if ("if".equalsIgnoreCase(cmd)) {
+ ifsStack.add( parsing );
+ if (!parsing) {
+ continue;
+ }
+ if (args.startsWith("term=")) {
+ // TODO
+ } else if (args.startsWith("mode=")) {
+ if (args.equalsIgnoreCase("mode=vi")) {
+ parsing = isViEditMode();
+ } else if (args.equals("mode=emacs")) {
+ parsing = !isViEditMode();
+ } else {
+ parsing = false;
+ }
+ } else {
+ parsing = args.equalsIgnoreCase(appName);
+ }
+ } else if ("else".equalsIgnoreCase(cmd)) {
+ if (ifsStack.isEmpty()) {
+ throw new IllegalArgumentException("$else found without matching $if");
+ }
+ boolean invert = true;
+ for (boolean b : ifsStack) {
+ if (!b) {
+ invert = false;
+ break;
+ }
+ }
+ if (invert) {
+ parsing = !parsing;
+ }
+ } else if ("endif".equalsIgnoreCase(cmd)) {
+ if (ifsStack.isEmpty()) {
+ throw new IllegalArgumentException("endif found without matching $if");
+ }
+ parsing = ifsStack.remove( ifsStack.size() - 1 );
+ } else if ("include".equalsIgnoreCase(cmd)) {
+ // TODO
+ }
+ continue;
+ }
+ if (!parsing) {
+ continue;
+ }
+ boolean equivalency;
+ String keySeq = "";
+ if (line.charAt(i++) == '"') {
+ boolean esc = false;
+ for (;; i++) {
+ if (i >= line.length()) {
+ throw new IllegalArgumentException("Missing closing quote on line '" + line + "'");
+ }
+ if (esc) {
+ esc = false;
+ } else if (line.charAt(i) == '\\') {
+ esc = true;
+ } else if (line.charAt(i) == '"') {
+ break;
+ }
+ }
+ }
+ for (; i < line.length() && line.charAt(i) != ':'
+ && line.charAt(i) != ' ' && line.charAt(i) != '\t'
+ ; i++);
+ keySeq = line.substring(0, i);
+ equivalency = (i + 1 < line.length() && line.charAt(i) == ':' && line.charAt(i + 1) == '=');
+ i++;
+ if (equivalency) {
+ i++;
+ }
+ if (keySeq.equalsIgnoreCase("set")) {
+ String key;
+ String val;
+ for (; i < line.length() && (line.charAt(i) == ' ' || line.charAt(i) == '\t'); i++);
+ int s = i;
+ for (; i < line.length() && (line.charAt(i) != ' ' && line.charAt(i) != '\t'); i++);
+ key = line.substring( s, i );
+ for (; i < line.length() && (line.charAt(i) == ' ' || line.charAt(i) == '\t'); i++);
+ s = i;
+ for (; i < line.length() && (line.charAt(i) != ' ' && line.charAt(i) != '\t'); i++);
+ val = line.substring( s, i );
+ setVar( key, val );
+ } else {
+ for (; i < line.length() && (line.charAt(i) == ' ' || line.charAt(i) == '\t'); i++);
+ int start = i;
+ if (i < line.length() && (line.charAt(i) == '\'' || line.charAt(i) == '\"')) {
+ char delim = line.charAt(i++);
+ boolean esc = false;
+ for (;; i++) {
+ if (i >= line.length()) {
+ break;
+ }
+ if (esc) {
+ esc = false;
+ } else if (line.charAt(i) == '\\') {
+ esc = true;
+ } else if (line.charAt(i) == delim) {
+ break;
+ }
+ }
+ }
+ for (; i < line.length() && line.charAt(i) != ' ' && line.charAt(i) != '\t'; i++);
+ String val = line.substring(Math.min(start, line.length()), Math.min(i, line.length()));
+ if (keySeq.charAt(0) == '"') {
+ keySeq = translateQuoted(keySeq);
+ } else {
+ // Bind key name
+ String keyName = keySeq.lastIndexOf('-') > 0 ? keySeq.substring( keySeq.lastIndexOf('-') + 1 ) : keySeq;
+ char key = getKeyFromName(keyName);
+ keyName = keySeq.toLowerCase();
+ keySeq = "";
+ if (keyName.contains("meta-") || keyName.contains("m-")) {
+ keySeq += "\u001b";
+ }
+ if (keyName.contains("control-") || keyName.contains("c-") || keyName.contains("ctrl-")) {
+ key = (char)(Character.toUpperCase( key ) & 0x1f);
+ }
+ keySeq += key;
+ }
+ if (val.length() > 0 && (val.charAt(0) == '\'' || val.charAt(0) == '\"')) {
+ keys.bind( keySeq, translateQuoted(val) );
+ } else {
+ String operationName = val.replace('-', '_').toUpperCase();
+ try {
+ keys.bind(keySeq, Operation.valueOf(operationName));
+ } catch(IllegalArgumentException e) {
+ Log.info("Unable to bind key for unsupported operation: ", val);
+ }
+ }
+ }
+ } catch (IllegalArgumentException e) {
+ Log.warn("Unable to parse user configuration: ", e);
+ }
+ }
+ }
+
+ private String translateQuoted(String keySeq) {
+ int i;
+ String str = keySeq.substring( 1, keySeq.length() - 1 );
+ keySeq = "";
+ for (i = 0; i < str.length(); i++) {
+ char c = str.charAt(i);
+ if (c == '\\') {
+ boolean ctrl = str.regionMatches(i, "\\C-", 0, 3)|| str.regionMatches(i, "\\M-\\C-", 0, 6);
+ boolean meta = str.regionMatches(i, "\\M-", 0, 3)|| str.regionMatches(i, "\\C-\\M-", 0, 6);
+ i += (meta ? 3 : 0) + (ctrl ? 3 : 0) + (!meta && !ctrl ? 1 : 0);
+ if (i >= str.length()) {
+ break;
+ }
+ c = str.charAt(i);
+ if (meta) {
+ keySeq += "\u001b";
+ }
+ if (ctrl) {
+ c = c == '?' ? 0x7f : (char)(Character.toUpperCase( c ) & 0x1f);
+ }
+ if (!meta && !ctrl) {
+ switch (c) {
+ case 'a': c = 0x07; break;
+ case 'b': c = '\b'; break;
+ case 'd': c = 0x7f; break;
+ case 'e': c = 0x1b; break;
+ case 'f': c = '\f'; break;
+ case 'n': c = '\n'; break;
+ case 'r': c = '\r'; break;
+ case 't': c = '\t'; break;
+ case 'v': c = 0x0b; break;
+ case '\\': c = '\\'; break;
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ c = 0;
+ for (int j = 0; j < 3; j++, i++) {
+ if (i >= str.length()) {
+ break;
+ }
+ int k = Character.digit(str.charAt(i), 8);
+ if (k < 0) {
+ break;
+ }
+ c = (char)(c * 8 + k);
+ }
+ c &= 0xFF;
+ break;
+ case 'x':
+ i++;
+ c = 0;
+ for (int j = 0; j < 2; j++, i++) {
+ if (i >= str.length()) {
+ break;
+ }
+ int k = Character.digit(str.charAt(i), 16);
+ if (k < 0) {
+ break;
+ }
+ c = (char)(c * 16 + k);
+ }
+ c &= 0xFF;
+ break;
+ case 'u':
+ i++;
+ c = 0;
+ for (int j = 0; j < 4; j++, i++) {
+ if (i >= str.length()) {
+ break;
+ }
+ int k = Character.digit(str.charAt(i), 16);
+ if (k < 0) {
+ break;
+ }
+ c = (char)(c * 16 + k);
+ }
+ break;
+ }
+ }
+ keySeq += c;
+ } else {
+ keySeq += c;
+ }
+ }
+ return keySeq;
+ }
+
+ private char getKeyFromName(String name) {
+ if ("DEL".equalsIgnoreCase(name) || "Rubout".equalsIgnoreCase(name)) {
+ return 0x7f;
+ } else if ("ESC".equalsIgnoreCase(name) || "Escape".equalsIgnoreCase(name)) {
+ return '\033';
+ } else if ("LFD".equalsIgnoreCase(name) || "NewLine".equalsIgnoreCase(name)) {
+ return '\n';
+ } else if ("RET".equalsIgnoreCase(name) || "Return".equalsIgnoreCase(name)) {
+ return '\r';
+ } else if ("SPC".equalsIgnoreCase(name) || "Space".equalsIgnoreCase(name)) {
+ return ' ';
+ } else if ("Tab".equalsIgnoreCase(name)) {
+ return '\t';
+ } else {
+ return name.charAt(0);
+ }
+ }
+
+ private void setVar(String key, String val) {
+ if ("keymap".equalsIgnoreCase(key)) {
+ if (keyMaps.containsKey(val)) {
+ keys = keyMaps.get(val);
+ }
+ } else if ("editing-mode".equals(key)) {
+ if ("vi".equalsIgnoreCase(val)) {
+ keys = keyMaps.get(KeyMap.VI_INSERT);
+ } else if ("emacs".equalsIgnoreCase(key)) {
+ keys = keyMaps.get(KeyMap.EMACS);
+ }
+ } else if ("blink-matching-paren".equals(key)) {
+ if ("on".equalsIgnoreCase(val)) {
+ keys.setBlinkMatchingParen(true);
+ } else if ("off".equalsIgnoreCase(val)) {
+ keys.setBlinkMatchingParen(false);
+ }
+ }
+
+ /*
+ * Technically variables should be defined as a functor class
+ * so that validation on the variable value can be done at parse
+ * time. This is a stop-gap.
+ */
+ variables.put(key, val);
+ }
+
+ /**
+ * Retrieves the value of a variable that was set in the .inputrc file
+ * during processing
+ * @param var The variable name
+ * @return The variable value.
+ */
+ public String getVariable(String var) {
+ return variables.get (var);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/ConsoleReader.java Wed Jul 05 20:41:12 2017 +0200
@@ -0,0 +1,4006 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.console;
+
+//import java.awt.*;
+//import java.awt.datatransfer.Clipboard;
+//import java.awt.datatransfer.DataFlavor;
+//import java.awt.datatransfer.Transferable;
+//import java.awt.datatransfer.UnsupportedFlavorException;
+//import java.awt.event.ActionListener;
+//import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+//import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.Writer;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+//import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.ListIterator;
+//import java.util.Map;
+import java.util.ResourceBundle;
+import java.util.Stack;
+import java.util.regex.Pattern;
+
+import jdk.internal.jline.Terminal;
+import jdk.internal.jline.TerminalFactory;
+import jdk.internal.jline.UnixTerminal;
+import jdk.internal.jline.console.completer.CandidateListCompletionHandler;
+import jdk.internal.jline.console.completer.Completer;
+import jdk.internal.jline.console.completer.CompletionHandler;
+import jdk.internal.jline.console.history.History;
+import jdk.internal.jline.console.history.MemoryHistory;
+import jdk.internal.jline.internal.Configuration;
+import jdk.internal.jline.internal.InputStreamReader;
+import jdk.internal.jline.internal.Log;
+import jdk.internal.jline.internal.NonBlockingInputStream;
+import jdk.internal.jline.internal.Nullable;
+import jdk.internal.jline.internal.Urls;
+//import org.fusesource.jansi.AnsiOutputStream;
+
+import static jdk.internal.jline.internal.Preconditions.checkNotNull;
+
+/**
+ * A reader for console applications. It supports custom tab-completion,
+ * saveable command history, and command line editing. On some platforms,
+ * platform-specific commands will need to be issued before the reader will
+ * function properly. See {@link jline.Terminal#init} for convenience
+ * methods for issuing platform-specific setup commands.
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @author <a href="mailto:gnodet@gmail.com">Guillaume Nodet</a>
+ */
+public class ConsoleReader
+{
+ public static final String JLINE_NOBELL = "jline.nobell";
+
+ public static final String JLINE_ESC_TIMEOUT = "jline.esc.timeout";
+
+ public static final String JLINE_INPUTRC = "jline.inputrc";
+
+ public static final String INPUT_RC = ".inputrc";
+
+ public static final String DEFAULT_INPUT_RC = "/etc/inputrc";
+
+ public static final char BACKSPACE = '\b';
+
+ public static final char RESET_LINE = '\r';
+
+ public static final char KEYBOARD_BELL = '\07';
+
+ public static final char NULL_MASK = 0;
+
+ public static final int TAB_WIDTH = 4;
+
+ private static final ResourceBundle
+ resources = ResourceBundle.getBundle(CandidateListCompletionHandler.class.getName());
+
+ private final Terminal terminal;
+
+ private final Writer out;
+
+ private final CursorBuffer buf = new CursorBuffer();
+
+ private String prompt;
+ private int promptLen;
+
+ private boolean expandEvents = true;
+
+ private boolean bellEnabled = !Configuration.getBoolean(JLINE_NOBELL, true);
+
+ private boolean handleUserInterrupt = false;
+
+ private Character mask;
+
+ private Character echoCharacter;
+
+ private StringBuffer searchTerm = null;
+
+ private String previousSearchTerm = "";
+
+ private int searchIndex = -1;
+
+ private int parenBlinkTimeout = 500;
+
+ /*
+ * The reader and the nonBlockingInput go hand-in-hand. The reader wraps
+ * the nonBlockingInput, but we have to retain a handle to it so that
+ * we can shut down its blocking read thread when we go away.
+ */
+ private NonBlockingInputStream in;
+ private long escapeTimeout;
+ private Reader reader;
+
+ /*
+ * TODO: Please read the comments about this in setInput(), but this needs
+ * to be done away with.
+ */
+ private boolean isUnitTestInput;
+
+ /**
+ * Last character searched for with a vi character search
+ */
+ private char charSearchChar = 0; // Character to search for
+ private char charSearchLastInvokeChar = 0; // Most recent invocation key
+ private char charSearchFirstInvokeChar = 0;// First character that invoked
+
+ /**
+ * The vi yank buffer
+ */
+ private String yankBuffer = "";
+
+ private KillRing killRing = new KillRing();
+
+ private String encoding;
+
+ private boolean recording;
+
+ private String macro = "";
+
+ private String appName;
+
+ private URL inputrcUrl;
+
+ private ConsoleKeys consoleKeys;
+
+ private String commentBegin = null;
+
+ private boolean skipLF = false;
+
+ /**
+ * Set to true if the reader should attempt to detect copy-n-paste. The
+ * effect of this that an attempt is made to detect if tab is quickly
+ * followed by another character, then it is assumed that the tab was
+ * a literal tab as part of a copy-and-paste operation and is inserted as
+ * such.
+ */
+ private boolean copyPasteDetection = false;
+
+ /*
+ * Current internal state of the line reader
+ */
+ private State state = State.NORMAL;
+
+ /**
+ * Possible states in which the current readline operation may be in.
+ */
+ private static enum State {
+ /**
+ * The user is just typing away
+ */
+ NORMAL,
+ /**
+ * In the middle of a emacs seach
+ */
+ SEARCH,
+ FORWARD_SEARCH,
+ /**
+ * VI "yank-to" operation ("y" during move mode)
+ */
+ VI_YANK_TO,
+ /**
+ * VI "delete-to" operation ("d" during move mode)
+ */
+ VI_DELETE_TO,
+ /**
+ * VI "change-to" operation ("c" during move mode)
+ */
+ VI_CHANGE_TO
+ }
+
+ public ConsoleReader() throws IOException {
+ this(null, new FileInputStream(FileDescriptor.in), System.out, null);
+ }
+
+ public ConsoleReader(final InputStream in, final OutputStream out) throws IOException {
+ this(null, in, out, null);
+ }
+
+ public ConsoleReader(final InputStream in, final OutputStream out, final Terminal term) throws IOException {
+ this(null, in, out, term);
+ }
+
+ public ConsoleReader(final @Nullable String appName, final InputStream in, final OutputStream out, final @Nullable Terminal term) throws IOException {
+ this(appName, in, out, term, null);
+ }
+
+ public ConsoleReader(final @Nullable String appName, final InputStream in, final OutputStream out, final @Nullable Terminal term, final @Nullable String encoding)
+ throws IOException
+ {
+ this.appName = appName != null ? appName : "JLine";
+ this.encoding = encoding != null ? encoding : Configuration.getEncoding();
+ this.terminal = term != null ? term : TerminalFactory.get();
+ String outEncoding = terminal.getOutputEncoding() != null? terminal.getOutputEncoding() : this.encoding;
+ this.out = new OutputStreamWriter(terminal.wrapOutIfNeeded(out), outEncoding);
+ setInput( in );
+
+ this.inputrcUrl = getInputRc();
+
+ consoleKeys = new ConsoleKeys(this.appName, inputrcUrl);
+ }
+
+ private URL getInputRc() throws IOException {
+ String path = Configuration.getString(JLINE_INPUTRC);
+ if (path == null) {
+ File f = new File(Configuration.getUserHome(), INPUT_RC);
+ if (!f.exists()) {
+ f = new File(DEFAULT_INPUT_RC);
+ }
+ return f.toURI().toURL();
+ } else {
+ return Urls.create(path);
+ }
+ }
+
+ public KeyMap getKeys() {
+ return consoleKeys.getKeys();
+ }
+
+ void setInput(final InputStream in) throws IOException {
+ this.escapeTimeout = Configuration.getLong(JLINE_ESC_TIMEOUT, 100);
+ /*
+ * This is gross and here is how to fix it. In getCurrentPosition()
+ * and getCurrentAnsiRow(), the logic is disabled when running unit
+ * tests and the fact that it is a unit test is determined by knowing
+ * if the original input stream was a ByteArrayInputStream. So, this
+ * is our test to do this. What SHOULD happen is that the unit
+ * tests should pass in a terminal that is appropriately configured
+ * such that whatever behavior they expect to happen (or not happen)
+ * happens (or doesn't).
+ *
+ * So, TODO, get rid of this and fix the unit tests.
+ */
+ this.isUnitTestInput = in instanceof ByteArrayInputStream;
+ boolean nonBlockingEnabled =
+ escapeTimeout > 0L
+ && terminal.isSupported()
+ && in != null;
+
+ /*
+ * If we had a non-blocking thread already going, then shut it down
+ * and start a new one.
+ */
+ if (this.in != null) {
+ this.in.shutdown();
+ }
+
+ final InputStream wrapped = terminal.wrapInIfNeeded( in );
+
+ this.in = new NonBlockingInputStream(wrapped, nonBlockingEnabled);
+ this.reader = new InputStreamReader( this.in, encoding );
+ }
+
+ /**
+ * Shuts the console reader down. This method should be called when you
+ * have completed using the reader as it shuts down and cleans up resources
+ * that would otherwise be "leaked".
+ */
+ public void shutdown() {
+ if (in != null) {
+ in.shutdown();
+ }
+ }
+
+ /**
+ * Shuts down the ConsoleReader if the JVM attempts to clean it up.
+ */
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ shutdown();
+ }
+ finally {
+ super.finalize();
+ }
+ }
+
+ public InputStream getInput() {
+ return in;
+ }
+
+ public Writer getOutput() {
+ return out;
+ }
+
+ public Terminal getTerminal() {
+ return terminal;
+ }
+
+ public CursorBuffer getCursorBuffer() {
+ return buf;
+ }
+
+ public void setExpandEvents(final boolean expand) {
+ this.expandEvents = expand;
+ }
+
+ public boolean getExpandEvents() {
+ return expandEvents;
+ }
+
+ /**
+ * Enables or disables copy and paste detection. The effect of enabling this
+ * this setting is that when a tab is received immediately followed by another
+ * character, the tab will not be treated as a completion, but as a tab literal.
+ * @param onoff true if detection is enabled
+ */
+ public void setCopyPasteDetection(final boolean onoff) {
+ copyPasteDetection = onoff;
+ }
+
+ /**
+ * @return true if copy and paste detection is enabled.
+ */
+ public boolean isCopyPasteDetectionEnabled() {
+ return copyPasteDetection;
+ }
+
+ /**
+ * Set whether the console bell is enabled.
+ *
+ * @param enabled true if enabled; false otherwise
+ * @since 2.7
+ */
+ public void setBellEnabled(boolean enabled) {
+ this.bellEnabled = enabled;
+ }
+
+ /**
+ * Get whether the console bell is enabled
+ *
+ * @return true if enabled; false otherwise
+ * @since 2.7
+ */
+ public boolean getBellEnabled() {
+ return bellEnabled;
+ }
+
+ /**
+ * Set whether user interrupts (ctrl-C) are handled by having JLine
+ * throw {@link UserInterruptException} from {@link #readLine}.
+ * Otherwise, the JVM will handle {@code SIGINT} as normal, which
+ * usually causes it to exit. The default is {@code false}.
+ *
+ * @since 2.10
+ */
+ public void setHandleUserInterrupt(boolean enabled)
+ {
+ this.handleUserInterrupt = enabled;
+ }
+
+ /**
+ * Get whether user interrupt handling is enabled
+ *
+ * @return true if enabled; false otherwise
+ * @since 2.10
+ */
+ public boolean getHandleUserInterrupt()
+ {
+ return handleUserInterrupt;
+ }
+
+ /**
+ * Sets the string that will be used to start a comment when the
+ * insert-comment key is struck.
+ * @param commentBegin The begin comment string.
+ * @since 2.7
+ */
+ public void setCommentBegin(String commentBegin) {
+ this.commentBegin = commentBegin;
+ }
+
+ /**
+ * @return the string that will be used to start a comment when the
+ * insert-comment key is struck.
+ * @since 2.7
+ */
+ public String getCommentBegin() {
+ String str = commentBegin;
+
+ if (str == null) {
+ str = consoleKeys.getVariable("comment-begin");
+ if (str == null) {
+ str = "#";
+ }
+ }
+ return str;
+ }
+
+ public void setPrompt(final String prompt) {
+ this.prompt = prompt;
+ this.promptLen = ((prompt == null) ? 0 : stripAnsi(lastLine(prompt)).length());
+ }
+
+ public String getPrompt() {
+ return prompt;
+ }
+
+ /**
+ * Set the echo character. For example, to have "*" entered when a password is typed:
+ * <p/>
+ * <pre>
+ * myConsoleReader.setEchoCharacter(new Character('*'));
+ * </pre>
+ * <p/>
+ * Setting the character to
+ * <p/>
+ * <pre>
+ * null
+ * </pre>
+ * <p/>
+ * will restore normal character echoing. Setting the character to
+ * <p/>
+ * <pre>
+ * new Character(0)
+ * </pre>
+ * <p/>
+ * will cause nothing to be echoed.
+ *
+ * @param c the character to echo to the console in place of the typed character.
+ */
+ public void setEchoCharacter(final Character c) {
+ this.echoCharacter = c;
+ }
+
+ /**
+ * Returns the echo character.
+ */
+ public Character getEchoCharacter() {
+ return echoCharacter;
+ }
+
+ /**
+ * Erase the current line.
+ *
+ * @return false if we failed (e.g., the buffer was empty)
+ */
+ protected final boolean resetLine() throws IOException {
+ if (buf.cursor == 0) {
+ return false;
+ }
+
+ StringBuilder killed = new StringBuilder();
+
+ while (buf.cursor > 0) {
+ char c = buf.current();
+ if (c == 0) {
+ break;
+ }
+
+ killed.append(c);
+ backspace();
+ }
+
+ String copy = killed.reverse().toString();
+ killRing.addBackwards(copy);
+
+ return true;
+ }
+
+ int getCursorPosition() {
+ // FIXME: does not handle anything but a line with a prompt absolute position
+ return promptLen + buf.cursor;
+ }
+
+ /**
+ * Returns the text after the last '\n'.
+ * prompt is returned if no '\n' characters are present.
+ * null is returned if prompt is null.
+ */
+ private String lastLine(String str) {
+ if (str == null) return "";
+ int last = str.lastIndexOf("\n");
+
+ if (last >= 0) {
+ return str.substring(last + 1, str.length());
+ }
+
+ return str;
+ }
+
+ String stripAnsi(String str) {
+ if (str == null) return "";
+ return ANSI_CODE_PATTERN.matcher(str).replaceAll("");
+// try {
+// ByteArrayOutputStream baos = new ByteArrayOutputStream();
+// AnsiOutputStream aos = new AnsiOutputStream(baos);
+// aos.write(str.getBytes());
+// aos.flush();
+// return baos.toString();
+// } catch (IOException e) {
+// return str;
+// }
+ }
+ //where:
+ private static final Pattern ANSI_CODE_PATTERN = Pattern.compile("\033\\[[^@-~]*[@-~]");
+
+ /**
+ * Move the cursor position to the specified absolute index.
+ */
+ public final boolean setCursorPosition(final int position) throws IOException {
+ if (position == buf.cursor) {
+ return true;
+ }
+
+ return moveCursor(position - buf.cursor) != 0;
+ }
+
+ /**
+ * Set the current buffer's content to the specified {@link String}. The
+ * visual console will be modified to show the current buffer.
+ *
+ * @param buffer the new contents of the buffer.
+ */
+ private void setBuffer(final String buffer) throws IOException {
+ // don't bother modifying it if it is unchanged
+ if (buffer.equals(buf.buffer.toString())) {
+ return;
+ }
+
+ // obtain the difference between the current buffer and the new one
+ int sameIndex = 0;
+
+ for (int i = 0, l1 = buffer.length(), l2 = buf.buffer.length(); (i < l1)
+ && (i < l2); i++) {
+ if (buffer.charAt(i) == buf.buffer.charAt(i)) {
+ sameIndex++;
+ }
+ else {
+ break;
+ }
+ }
+
+ int diff = buf.cursor - sameIndex;
+ if (diff < 0) { // we can't backspace here so try from the end of the buffer
+ moveToEnd();
+ diff = buf.buffer.length() - sameIndex;
+ }
+
+ backspace(diff); // go back for the differences
+ killLine(); // clear to the end of the line
+ buf.buffer.setLength(sameIndex); // the new length
+ putString(buffer.substring(sameIndex)); // append the differences
+ }
+
+ private void setBuffer(final CharSequence buffer) throws IOException {
+ setBuffer(String.valueOf(buffer));
+ }
+
+ private void setBufferKeepPos(final String buffer) throws IOException {
+ int pos = buf.cursor;
+ setBuffer(buffer);
+ setCursorPosition(pos);
+ }
+
+ private void setBufferKeepPos(final CharSequence buffer) throws IOException {
+ setBufferKeepPos(String.valueOf(buffer));
+ }
+
+ /**
+ * Output put the prompt + the current buffer
+ */
+ public final void drawLine() throws IOException {
+ String prompt = getPrompt();
+ if (prompt != null) {
+ print(prompt);
+ }
+
+ print(buf.buffer.toString());
+
+ if (buf.length() != buf.cursor) { // not at end of line
+ back(buf.length() - buf.cursor - 1);
+ }
+ // force drawBuffer to check for weird wrap (after clear screen)
+ drawBuffer();
+ }
+
+ /**
+ * Clear the line and redraw it.
+ */
+ public final void redrawLine() throws IOException {
+ print(RESET_LINE);
+// flush();
+ drawLine();
+ }
+
+ /**
+ * Clear the buffer and add its contents to the history.
+ *
+ * @return the former contents of the buffer.
+ */
+ final String finishBuffer() throws IOException { // FIXME: Package protected because used by tests
+ String str = buf.buffer.toString();
+ String historyLine = str;
+
+ if (expandEvents) {
+ try {
+ str = expandEvents(str);
+ // all post-expansion occurrences of '!' must have been escaped, so re-add escape to each
+ historyLine = str.replace("!", "\\!");
+ // only leading '^' results in expansion, so only re-add escape for that case
+ historyLine = historyLine.replaceAll("^\\^", "\\\\^");
+ } catch(IllegalArgumentException e) {
+ Log.error("Could not expand event", e);
+ beep();
+ buf.clear();
+ str = "";
+ }
+ }
+
+ // we only add it to the history if the buffer is not empty
+ // and if mask is null, since having a mask typically means
+ // the string was a password. We clear the mask after this call
+ if (str.length() > 0) {
+ if (mask == null && isHistoryEnabled()) {
+ history.add(historyLine);
+ }
+ else {
+ mask = null;
+ }
+ }
+
+ history.moveToEnd();
+
+ buf.buffer.setLength(0);
+ buf.cursor = 0;
+
+ return str;
+ }
+
+ /**
+ * Expand event designator such as !!, !#, !3, etc...
+ * See http://www.gnu.org/software/bash/manual/html_node/Event-Designators.html
+ */
+ @SuppressWarnings("fallthrough")
+ protected String expandEvents(String str) throws IOException {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < str.length(); i++) {
+ char c = str.charAt(i);
+ switch (c) {
+ case '\\':
+ // any '\!' should be considered an expansion escape, so skip expansion and strip the escape character
+ // a leading '\^' should be considered an expansion escape, so skip expansion and strip the escape character
+ // otherwise, add the escape
+ if (i + 1 < str.length()) {
+ char nextChar = str.charAt(i+1);
+ if (nextChar == '!' || (nextChar == '^' && i == 0)) {
+ c = nextChar;
+ i++;
+ }
+ }
+ sb.append(c);
+ break;
+ case '!':
+ if (i + 1 < str.length()) {
+ c = str.charAt(++i);
+ boolean neg = false;
+ String rep = null;
+ int i1, idx;
+ switch (c) {
+ case '!':
+ if (history.size() == 0) {
+ throw new IllegalArgumentException("!!: event not found");
+ }
+ rep = history.get(history.index() - 1).toString();
+ break;
+ case '#':
+ sb.append(sb.toString());
+ break;
+ case '?':
+ i1 = str.indexOf('?', i + 1);
+ if (i1 < 0) {
+ i1 = str.length();
+ }
+ String sc = str.substring(i + 1, i1);
+ i = i1;
+ idx = searchBackwards(sc);
+ if (idx < 0) {
+ throw new IllegalArgumentException("!?" + sc + ": event not found");
+ } else {
+ rep = history.get(idx).toString();
+ }
+ break;
+ case '$':
+ if (history.size() == 0) {
+ throw new IllegalArgumentException("!$: event not found");
+ }
+ String previous = history.get(history.index() - 1).toString().trim();
+ int lastSpace = previous.lastIndexOf(' ');
+ if(lastSpace != -1) {
+ rep = previous.substring(lastSpace+1);
+ } else {
+ rep = previous;
+ }
+ break;
+ case ' ':
+ case '\t':
+ sb.append('!');
+ sb.append(c);
+ break;
+ case '-':
+ neg = true;
+ i++;
+ // fall through
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ i1 = i;
+ for (; i < str.length(); i++) {
+ c = str.charAt(i);
+ if (c < '0' || c > '9') {
+ break;
+ }
+ }
+ idx = 0;
+ try {
+ idx = Integer.parseInt(str.substring(i1, i));
+ } catch (NumberFormatException e) {
+ throw new IllegalArgumentException((neg ? "!-" : "!") + str.substring(i1, i) + ": event not found");
+ }
+ if (neg) {
+ if (idx > 0 && idx <= history.size()) {
+ rep = (history.get(history.index() - idx)).toString();
+ } else {
+ throw new IllegalArgumentException((neg ? "!-" : "!") + str.substring(i1, i) + ": event not found");
+ }
+ } else {
+ if (idx > history.index() - history.size() && idx <= history.index()) {
+ rep = (history.get(idx - 1)).toString();
+ } else {
+ throw new IllegalArgumentException((neg ? "!-" : "!") + str.substring(i1, i) + ": event not found");
+ }
+ }
+ break;
+ default:
+ String ss = str.substring(i);
+ i = str.length();
+ idx = searchBackwards(ss, history.index(), true);
+ if (idx < 0) {
+ throw new IllegalArgumentException("!" + ss + ": event not found");
+ } else {
+ rep = history.get(idx).toString();
+ }
+ break;
+ }
+ if (rep != null) {
+ sb.append(rep);
+ }
+ } else {
+ sb.append(c);
+ }
+ break;
+ case '^':
+ if (i == 0) {
+ int i1 = str.indexOf('^', i + 1);
+ int i2 = str.indexOf('^', i1 + 1);
+ if (i2 < 0) {
+ i2 = str.length();
+ }
+ if (i1 > 0 && i2 > 0) {
+ String s1 = str.substring(i + 1, i1);
+ String s2 = str.substring(i1 + 1, i2);
+ String s = history.get(history.index() - 1).toString().replace(s1, s2);
+ sb.append(s);
+ i = i2 + 1;
+ break;
+ }
+ }
+ sb.append(c);
+ break;
+ default:
+ sb.append(c);
+ break;
+ }
+ }
+ String result = sb.toString();
+ if (!str.equals(result)) {
+ print(result);
+ println();
+ flush();
+ }
+ return result;
+
+ }
+
+ /**
+ * Write out the specified string to the buffer and the output stream.
+ */
+ public final void putString(final CharSequence str) throws IOException {
+ buf.write(str);
+ if (mask == null) {
+ // no masking
+ print(str);
+ } else if (mask == NULL_MASK) {
+ // don't print anything
+ } else {
+ print(mask, str.length());
+ }
+ drawBuffer();
+ }
+
+ /**
+ * Redraw the rest of the buffer from the cursor onwards. This is necessary
+ * for inserting text into the buffer.
+ *
+ * @param clear the number of characters to clear after the end of the buffer
+ */
+ private void drawBuffer(final int clear) throws IOException {
+ // debug ("drawBuffer: " + clear);
+ if (buf.cursor == buf.length() && clear == 0) {
+ } else {
+ char[] chars = buf.buffer.substring(buf.cursor).toCharArray();
+ if (mask != null) {
+ Arrays.fill(chars, mask);
+ }
+ if (terminal.hasWeirdWrap()) {
+ // need to determine if wrapping will occur:
+ int width = terminal.getWidth();
+ int pos = getCursorPosition();
+ for (int i = 0; i < chars.length; i++) {
+ print(chars[i]);
+ if ((pos + i + 1) % width == 0) {
+ print(32); // move cursor to next line by printing dummy space
+ print(13); // CR / not newline.
+ }
+ }
+ } else {
+ print(chars);
+ }
+ clearAhead(clear, chars.length);
+ if (terminal.isAnsiSupported()) {
+ if (chars.length > 0) {
+ back(chars.length);
+ }
+ } else {
+ back(chars.length);
+ }
+ }
+ if (terminal.hasWeirdWrap()) {
+ int width = terminal.getWidth();
+ // best guess on whether the cursor is in that weird location...
+ // Need to do this without calling ansi cursor location methods
+ // otherwise it breaks paste of wrapped lines in xterm.
+ if (getCursorPosition() > 0 && (getCursorPosition() % width == 0)
+ && buf.cursor == buf.length() && clear == 0) {
+ // the following workaround is reverse-engineered from looking
+ // at what bash sent to the terminal in the same situation
+ print(32); // move cursor to next line by printing dummy space
+ print(13); // CR / not newline.
+ }
+ }
+ }
+
+ /**
+ * Redraw the rest of the buffer from the cursor onwards. This is necessary
+ * for inserting text into the buffer.
+ */
+ private void drawBuffer() throws IOException {
+ drawBuffer(0);
+ }
+
+ /**
+ * Clear ahead the specified number of characters without moving the cursor.
+ *
+ * @param num the number of characters to clear
+ * @param delta the difference between the internal cursor and the screen
+ * cursor - if > 0, assume some stuff was printed and weird wrap has to be
+ * checked
+ */
+ private void clearAhead(final int num, int delta) throws IOException {
+ if (num == 0) {
+ return;
+ }
+
+ if (terminal.isAnsiSupported()) {
+ int width = terminal.getWidth();
+ int screenCursorCol = getCursorPosition() + delta;
+ // clear current line
+ printAnsiSequence("K");
+ // if cursor+num wraps, then we need to clear the line(s) below too
+ int curCol = screenCursorCol % width;
+ int endCol = (screenCursorCol + num - 1) % width;
+ int lines = num / width;
+ if (endCol < curCol) lines++;
+ for (int i = 0; i < lines; i++) {
+ printAnsiSequence("B");
+ printAnsiSequence("2K");
+ }
+ for (int i = 0; i < lines; i++) {
+ printAnsiSequence("A");
+ }
+ return;
+ }
+
+ // print blank extra characters
+ print(' ', num);
+
+ // we need to flush here so a "clever" console doesn't just ignore the redundancy
+ // of a space followed by a backspace.
+// flush();
+
+ // reset the visual cursor
+ back(num);
+
+// flush();
+ }
+
+ /**
+ * Move the visual cursor backwards without modifying the buffer cursor.
+ */
+ protected void back(final int num) throws IOException {
+ if (num == 0) return;
+ if (terminal.isAnsiSupported()) {
+ int width = getTerminal().getWidth();
+ int cursor = getCursorPosition();
+ int realCursor = cursor + num;
+ int realCol = realCursor % width;
+ int newCol = cursor % width;
+ int moveup = num / width;
+ int delta = realCol - newCol;
+ if (delta < 0) moveup++;
+ if (moveup > 0) {
+ printAnsiSequence(moveup + "A");
+ }
+ printAnsiSequence((1 + newCol) + "G");
+ return;
+ }
+ print(BACKSPACE, num);
+// flush();
+ }
+
+ /**
+ * Flush the console output stream. This is important for printout out single characters (like a backspace or
+ * keyboard) that we want the console to handle immediately.
+ */
+ public void flush() throws IOException {
+ out.flush();
+ }
+
+ private int backspaceAll() throws IOException {
+ return backspace(Integer.MAX_VALUE);
+ }
+
+ /**
+ * Issue <em>num</em> backspaces.
+ *
+ * @return the number of characters backed up
+ */
+ private int backspace(final int num) throws IOException {
+ if (buf.cursor == 0) {
+ return 0;
+ }
+
+ int count = 0;
+
+ int termwidth = getTerminal().getWidth();
+ int lines = getCursorPosition() / termwidth;
+ count = moveCursor(-1 * num) * -1;
+ buf.buffer.delete(buf.cursor, buf.cursor + count);
+ if (getCursorPosition() / termwidth != lines) {
+ if (terminal.isAnsiSupported()) {
+ // debug("doing backspace redraw: " + getCursorPosition() + " on " + termwidth + ": " + lines);
+ printAnsiSequence("K");
+ // if cursor+num wraps, then we need to clear the line(s) below too
+ // last char printed is one pos less than cursor so we subtract
+ // one
+/*
+ // TODO: fixme (does not work - test with reverse search with wrapping line and CTRL-E)
+ int endCol = (getCursorPosition() + num - 1) % termwidth;
+ int curCol = getCursorPosition() % termwidth;
+ if (endCol < curCol) lines++;
+ for (int i = 1; i < lines; i++) {
+ printAnsiSequence("B");
+ printAnsiSequence("2K");
+ }
+ for (int i = 1; i < lines; i++) {
+ printAnsiSequence("A");
+ }
+ return count;
+*/
+ }
+ }
+ drawBuffer(count);
+
+ return count;
+ }
+
+ /**
+ * Issue a backspace.
+ *
+ * @return true if successful
+ */
+ public boolean backspace() throws IOException {
+ return backspace(1) == 1;
+ }
+
+ protected boolean moveToEnd() throws IOException {
+ if (buf.cursor == buf.length()) {
+ return true;
+ }
+ return moveCursor(buf.length() - buf.cursor) > 0;
+ }
+
+ /**
+ * Delete the character at the current position and redraw the remainder of the buffer.
+ */
+ private boolean deleteCurrentCharacter() throws IOException {
+ if (buf.length() == 0 || buf.cursor == buf.length()) {
+ return false;
+ }
+
+ buf.buffer.deleteCharAt(buf.cursor);
+ drawBuffer(1);
+ return true;
+ }
+
+ /**
+ * This method is calling while doing a delete-to ("d"), change-to ("c"),
+ * or yank-to ("y") and it filters out only those movement operations
+ * that are allowable during those operations. Any operation that isn't
+ * allow drops you back into movement mode.
+ *
+ * @param op The incoming operation to remap
+ * @return The remaped operation
+ */
+ private Operation viDeleteChangeYankToRemap (Operation op) {
+ switch (op) {
+ case VI_EOF_MAYBE:
+ case ABORT:
+ case BACKWARD_CHAR:
+ case FORWARD_CHAR:
+ case END_OF_LINE:
+ case VI_MATCH:
+ case VI_BEGNNING_OF_LINE_OR_ARG_DIGIT:
+ case VI_ARG_DIGIT:
+ case VI_PREV_WORD:
+ case VI_END_WORD:
+ case VI_CHAR_SEARCH:
+ case VI_NEXT_WORD:
+ case VI_FIRST_PRINT:
+ case VI_GOTO_MARK:
+ case VI_COLUMN:
+ case VI_DELETE_TO:
+ case VI_YANK_TO:
+ case VI_CHANGE_TO:
+ return op;
+
+ default:
+ return Operation.VI_MOVEMENT_MODE;
+ }
+ }
+
+ /**
+ * Deletes the previous character from the cursor position
+ * @param count number of times to do it.
+ * @return true if it was done.
+ * @throws IOException
+ */
+ private boolean viRubout(int count) throws IOException {
+ boolean ok = true;
+ for (int i = 0; ok && i < count; i++) {
+ ok = backspace();
+ }
+ return ok;
+ }
+
+ /**
+ * Deletes the character you are sitting on and sucks the rest of
+ * the line in from the right.
+ * @param count Number of times to perform the operation.
+ * @return true if its works, false if it didn't
+ * @throws IOException
+ */
+ private boolean viDelete(int count) throws IOException {
+ boolean ok = true;
+ for (int i = 0; ok && i < count; i++) {
+ ok = deleteCurrentCharacter();
+ }
+ return ok;
+ }
+
+ /**
+ * Switches the case of the current character from upper to lower
+ * or lower to upper as necessary and advances the cursor one
+ * position to the right.
+ * @param count The number of times to repeat
+ * @return true if it completed successfully, false if not all
+ * case changes could be completed.
+ * @throws IOException
+ */
+ private boolean viChangeCase(int count) throws IOException {
+ boolean ok = true;
+ for (int i = 0; ok && i < count; i++) {
+
+ ok = buf.cursor < buf.buffer.length ();
+ if (ok) {
+ char ch = buf.buffer.charAt(buf.cursor);
+ if (Character.isUpperCase(ch)) {
+ ch = Character.toLowerCase(ch);
+ }
+ else if (Character.isLowerCase(ch)) {
+ ch = Character.toUpperCase(ch);
+ }
+ buf.buffer.setCharAt(buf.cursor, ch);
+ drawBuffer(1);
+ moveCursor(1);
+ }
+ }
+ return ok;
+ }
+
+ /**
+ * Implements the vi change character command (in move-mode "r"
+ * followed by the character to change to).
+ * @param count Number of times to perform the action
+ * @param c The character to change to
+ * @return Whether or not there were problems encountered
+ * @throws IOException
+ */
+ private boolean viChangeChar(int count, int c) throws IOException {
+ // EOF, ESC, or CTRL-C aborts.
+ if (c < 0 || c == '\033' || c == '\003') {
+ return true;
+ }
+
+ boolean ok = true;
+ for (int i = 0; ok && i < count; i++) {
+ ok = buf.cursor < buf.buffer.length ();
+ if (ok) {
+ buf.buffer.setCharAt(buf.cursor, (char) c);
+ drawBuffer(1);
+ if (i < (count-1)) {
+ moveCursor(1);
+ }
+ }
+ }
+ return ok;
+ }
+
+ /**
+ * This is a close facsimile of the actual vi previous word logic. In
+ * actual vi words are determined by boundaries of identity characterse.
+ * This logic is a bit more simple and simply looks at white space or
+ * digits or characters. It should be revised at some point.
+ *
+ * @param count number of iterations
+ * @return true if the move was successful, false otherwise
+ * @throws IOException
+ */
+ private boolean viPreviousWord(int count) throws IOException {
+ boolean ok = true;
+ if (buf.cursor == 0) {
+ return false;
+ }
+
+ int pos = buf.cursor - 1;
+ for (int i = 0; pos > 0 && i < count; i++) {
+ // If we are on white space, then move back.
+ while (pos > 0 && isWhitespace(buf.buffer.charAt(pos))) {
+ --pos;
+ }
+
+ while (pos > 0 && !isDelimiter(buf.buffer.charAt(pos-1))) {
+ --pos;
+ }
+
+ if (pos > 0 && i < (count-1)) {
+ --pos;
+ }
+ }
+ setCursorPosition(pos);
+ return ok;
+ }
+
+ /**
+ * Performs the vi "delete-to" action, deleting characters between a given
+ * span of the input line.
+ * @param startPos The start position
+ * @param endPos The end position.
+ * @param isChange If true, then the delete is part of a change operationg
+ * (e.g. "c$" is change-to-end-of line, so we first must delete to end
+ * of line to start the change
+ * @return true if it succeeded, false otherwise
+ * @throws IOException
+ */
+ private boolean viDeleteTo(int startPos, int endPos, boolean isChange) throws IOException {
+ if (startPos == endPos) {
+ return true;
+ }
+
+ if (endPos < startPos) {
+ int tmp = endPos;
+ endPos = startPos;
+ startPos = tmp;
+ }
+
+ setCursorPosition(startPos);
+ buf.cursor = startPos;
+ buf.buffer.delete(startPos, endPos);
+ drawBuffer(endPos - startPos);
+
+ // If we are doing a delete operation (e.g. "d$") then don't leave the
+ // cursor dangling off the end. In reality the "isChange" flag is silly
+ // what is really happening is that if we are in "move-mode" then the
+ // cursor can't be moved off the end of the line, but in "edit-mode" it
+ // is ok, but I have no easy way of knowing which mode we are in.
+ if (! isChange && startPos > 0 && startPos == buf.length()) {
+ moveCursor(-1);
+ }
+ return true;
+ }
+
+ /**
+ * Implement the "vi" yank-to operation. This operation allows you
+ * to yank the contents of the current line based upon a move operation,
+ * for exaple "yw" yanks the current word, "3yw" yanks 3 words, etc.
+ *
+ * @param startPos The starting position from which to yank
+ * @param endPos The ending position to which to yank
+ * @return true if the yank succeeded
+ * @throws IOException
+ */
+ private boolean viYankTo(int startPos, int endPos) throws IOException {
+ int cursorPos = startPos;
+
+ if (endPos < startPos) {
+ int tmp = endPos;
+ endPos = startPos;
+ startPos = tmp;
+ }
+
+ if (startPos == endPos) {
+ yankBuffer = "";
+ return true;
+ }
+
+ yankBuffer = buf.buffer.substring(startPos, endPos);
+
+ /*
+ * It was a movement command that moved the cursor to find the
+ * end position, so put the cursor back where it started.
+ */
+ setCursorPosition(cursorPos);
+ return true;
+ }
+
+ /**
+ * Pasts the yank buffer to the right of the current cursor position
+ * and moves the cursor to the end of the pasted region.
+ *
+ * @param count Number of times to perform the operation.
+ * @return true if it worked, false otherwise
+ * @throws IOException
+ */
+ private boolean viPut(int count) throws IOException {
+ if (yankBuffer.length () == 0) {
+ return true;
+ }
+ if (buf.cursor < buf.buffer.length ()) {
+ moveCursor(1);
+ }
+ for (int i = 0; i < count; i++) {
+ putString(yankBuffer);
+ }
+ moveCursor(-1);
+ return true;
+ }
+
+ /**
+ * Searches forward of the current position for a character and moves
+ * the cursor onto it.
+ * @param count Number of times to repeat the process.
+ * @param ch The character to search for
+ * @return true if the char was found, false otherwise
+ * @throws IOException
+ */
+ private boolean viCharSearch(int count, int invokeChar, int ch) throws IOException {
+ if (ch < 0 || invokeChar < 0) {
+ return false;
+ }
+
+ char searchChar = (char)ch;
+ boolean isForward;
+ boolean stopBefore;
+
+ /*
+ * The character stuff turns out to be hairy. Here is how it works:
+ * f - search forward for ch
+ * F - search backward for ch
+ * t - search forward for ch, but stop just before the match
+ * T - search backward for ch, but stop just after the match
+ * ; - After [fFtT;], repeat the last search, after ',' reverse it
+ * , - After [fFtT;], reverse the last search, after ',' repeat it
+ */
+ if (invokeChar == ';' || invokeChar == ',') {
+ // No recent search done? Then bail
+ if (charSearchChar == 0) {
+ return false;
+ }
+
+ // Reverse direction if switching between ',' and ';'
+ if (charSearchLastInvokeChar == ';' || charSearchLastInvokeChar == ',') {
+ if (charSearchLastInvokeChar != invokeChar) {
+ charSearchFirstInvokeChar = switchCase(charSearchFirstInvokeChar);
+ }
+ }
+ else {
+ if (invokeChar == ',') {
+ charSearchFirstInvokeChar = switchCase(charSearchFirstInvokeChar);
+ }
+ }
+
+ searchChar = charSearchChar;
+ }
+ else {
+ charSearchChar = searchChar;
+ charSearchFirstInvokeChar = (char) invokeChar;
+ }
+
+ charSearchLastInvokeChar = (char)invokeChar;
+
+ isForward = Character.isLowerCase(charSearchFirstInvokeChar);
+ stopBefore = (Character.toLowerCase(charSearchFirstInvokeChar) == 't');
+
+ boolean ok = false;
+
+ if (isForward) {
+ while (count-- > 0) {
+ int pos = buf.cursor + 1;
+ while (pos < buf.buffer.length()) {
+ if (buf.buffer.charAt(pos) == searchChar) {
+ setCursorPosition(pos);
+ ok = true;
+ break;
+ }
+ ++pos;
+ }
+ }
+
+ if (ok) {
+ if (stopBefore)
+ moveCursor(-1);
+
+ /*
+ * When in yank-to, move-to, del-to state we actually want to
+ * go to the character after the one we landed on to make sure
+ * that the character we ended up on is included in the
+ * operation
+ */
+ if (isInViMoveOperationState()) {
+ moveCursor(1);
+ }
+ }
+ }
+ else {
+ while (count-- > 0) {
+ int pos = buf.cursor - 1;
+ while (pos >= 0) {
+ if (buf.buffer.charAt(pos) == searchChar) {
+ setCursorPosition(pos);
+ ok = true;
+ break;
+ }
+ --pos;
+ }
+ }
+
+ if (ok && stopBefore)
+ moveCursor(1);
+ }
+
+ return ok;
+ }
+
+ private char switchCase(char ch) {
+ if (Character.isUpperCase(ch)) {
+ return Character.toLowerCase(ch);
+ }
+ return Character.toUpperCase(ch);
+ }
+
+ /**
+ * @return true if line reader is in the middle of doing a change-to
+ * delete-to or yank-to.
+ */
+ private final boolean isInViMoveOperationState() {
+ return state == State.VI_CHANGE_TO
+ || state == State.VI_DELETE_TO
+ || state == State.VI_YANK_TO;
+ }
+
+ /**
+ * This is a close facsimile of the actual vi next word logic.
+ * As with viPreviousWord() this probably needs to be improved
+ * at some point.
+ *
+ * @param count number of iterations
+ * @return true if the move was successful, false otherwise
+ * @throws IOException
+ */
+ private boolean viNextWord(int count) throws IOException {
+ int pos = buf.cursor;
+ int end = buf.buffer.length();
+
+ for (int i = 0; pos < end && i < count; i++) {
+ // Skip over letter/digits
+ while (pos < end && !isDelimiter(buf.buffer.charAt(pos))) {
+ ++pos;
+ }
+
+ /*
+ * Don't you love special cases? During delete-to and yank-to
+ * operations the word movement is normal. However, during a
+ * change-to, the trailing spaces behind the last word are
+ * left in tact.
+ */
+ if (i < (count-1) || !(state == State.VI_CHANGE_TO)) {
+ while (pos < end && isDelimiter(buf.buffer.charAt(pos))) {
+ ++pos;
+ }
+ }
+ }
+
+ setCursorPosition(pos);
+ return true;
+ }
+
+ /**
+ * Implements a close facsimile of the vi end-of-word movement.
+ * If the character is on white space, it takes you to the end
+ * of the next word. If it is on the last character of a word
+ * it takes you to the next of the next word. Any other character
+ * of a word, takes you to the end of the current word.
+ *
+ * @param count Number of times to repeat the action
+ * @return true if it worked.
+ * @throws IOException
+ */
+ private boolean viEndWord(int count) throws IOException {
+ int pos = buf.cursor;
+ int end = buf.buffer.length();
+
+ for (int i = 0; pos < end && i < count; i++) {
+ if (pos < (end-1)
+ && !isDelimiter(buf.buffer.charAt(pos))
+ && isDelimiter(buf.buffer.charAt (pos+1))) {
+ ++pos;
+ }
+
+ // If we are on white space, then move back.
+ while (pos < end && isDelimiter(buf.buffer.charAt(pos))) {
+ ++pos;
+ }
+
+ while (pos < (end-1) && !isDelimiter(buf.buffer.charAt(pos+1))) {
+ ++pos;
+ }
+ }
+ setCursorPosition(pos);
+ return true;
+ }
+
+ private boolean previousWord() throws IOException {
+ while (isDelimiter(buf.current()) && (moveCursor(-1) != 0)) {
+ // nothing
+ }
+
+ while (!isDelimiter(buf.current()) && (moveCursor(-1) != 0)) {
+ // nothing
+ }
+
+ return true;
+ }
+
+ private boolean nextWord() throws IOException {
+ while (isDelimiter(buf.nextChar()) && (moveCursor(1) != 0)) {
+ // nothing
+ }
+
+ while (!isDelimiter(buf.nextChar()) && (moveCursor(1) != 0)) {
+ // nothing
+ }
+
+ return true;
+ }
+
+ /**
+ * Deletes to the beginning of the word that the cursor is sitting on.
+ * If the cursor is on white-space, it deletes that and to the beginning
+ * of the word before it. If the user is not on a word or whitespace
+ * it deletes up to the end of the previous word.
+ *
+ * @param count Number of times to perform the operation
+ * @return true if it worked, false if you tried to delete too many words
+ * @throws IOException
+ */
+ private boolean unixWordRubout(int count) throws IOException {
+ boolean success = true;
+ StringBuilder killed = new StringBuilder();
+
+ for (; count > 0; --count) {
+ if (buf.cursor == 0) {
+ success = false;
+ break;
+ }
+
+ while (isWhitespace(buf.current())) {
+ char c = buf.current();
+ if (c == 0) {
+ break;
+ }
+
+ killed.append(c);
+ backspace();
+ }
+
+ while (!isWhitespace(buf.current())) {
+ char c = buf.current();
+ if (c == 0) {
+ break;
+ }
+
+ killed.append(c);
+ backspace();
+ }
+ }
+
+ String copy = killed.reverse().toString();
+ killRing.addBackwards(copy);
+
+ return success;
+ }
+
+ private String insertComment(boolean isViMode) throws IOException {
+ String comment = this.getCommentBegin ();
+ setCursorPosition(0);
+ putString(comment);
+ if (isViMode) {
+ consoleKeys.setKeyMap(KeyMap.VI_INSERT);
+ }
+ return accept();
+ }
+
+ /**
+ * Similar to putString() but allows the string to be repeated a specific
+ * number of times, allowing easy support of vi digit arguments to a given
+ * command. The string is placed as the current cursor position.
+ *
+ * @param count The count of times to insert the string.
+ * @param str The string to insert
+ * @return true if the operation is a success, false otherwise
+ * @throws IOException
+ */
+ private boolean insert(int count, final CharSequence str) throws IOException {
+ for (int i = 0; i < count; i++) {
+ buf.write(str);
+ if (mask == null) {
+ // no masking
+ print(str);
+ } else if (mask == NULL_MASK) {
+ // don't print anything
+ } else {
+ print(mask, str.length());
+ }
+ }
+ drawBuffer();
+ return true;
+ }
+
+ /**
+ * Implements vi search ("/" or "?").
+ * @throws IOException
+ */
+ @SuppressWarnings("fallthrough")
+ private int viSearch(char searchChar) throws IOException {
+ boolean isForward = (searchChar == '/');
+
+ /*
+ * This is a little gross, I'm sure there is a more appropriate way
+ * of saving and restoring state.
+ */
+ CursorBuffer origBuffer = buf.copy();
+
+ // Clear the contents of the current line and
+ setCursorPosition (0);
+ killLine();
+
+ // Our new "prompt" is the character that got us into search mode.
+ putString(Character.toString(searchChar));
+ flush();
+
+ boolean isAborted = false;
+ boolean isComplete = false;
+
+ /*
+ * Readline doesn't seem to do any special character map handling
+ * here, so I think we are safe.
+ */
+ int ch = -1;
+ while (!isAborted && !isComplete && (ch = readCharacter()) != -1) {
+ switch (ch) {
+ case '\033': // ESC
+ /*
+ * The ESC behavior doesn't appear to be readline behavior,
+ * but it is a little tweak of my own. I like it.
+ */
+ isAborted = true;
+ break;
+ case '\010': // Backspace
+ case '\177': // Delete
+ backspace();
+ /*
+ * Backspacing through the "prompt" aborts the search.
+ */
+ if (buf.cursor == 0) {
+ isAborted = true;
+ }
+ break;
+ case '\012': // NL
+ case '\015': // CR
+ isComplete = true;
+ break;
+ default:
+ putString(Character.toString((char) ch));
+ }
+
+ flush();
+ }
+
+ // If we aborted, then put ourself at the end of the original buffer.
+ if (ch == -1 || isAborted) {
+ setCursorPosition(0);
+ killLine();
+ putString(origBuffer.buffer);
+ setCursorPosition(origBuffer.cursor);
+ return -1;
+ }
+
+ /*
+ * The first character of the buffer was the search character itself
+ * so we discard it.
+ */
+ String searchTerm = buf.buffer.substring(1);
+ int idx = -1;
+
+ /*
+ * The semantics of the history thing is gross when you want to
+ * explicitly iterate over entries (without an iterator) as size()
+ * returns the actual number of entries in the list but get()
+ * doesn't work the way you think.
+ */
+ int end = history.index();
+ int start = (end <= history.size()) ? 0 : end - history.size();
+
+ if (isForward) {
+ for (int i = start; i < end; i++) {
+ if (history.get(i).toString().contains(searchTerm)) {
+ idx = i;
+ break;
+ }
+ }
+ }
+ else {
+ for (int i = end-1; i >= start; i--) {
+ if (history.get(i).toString().contains(searchTerm)) {
+ idx = i;
+ break;
+ }
+ }
+ }
+
+ /*
+ * No match? Then restore what we were working on, but make sure
+ * the cursor is at the beginning of the line.
+ */
+ if (idx == -1) {
+ setCursorPosition(0);
+ killLine();
+ putString(origBuffer.buffer);
+ setCursorPosition(0);
+ return -1;
+ }
+
+ /*
+ * Show the match.
+ */
+ setCursorPosition(0);
+ killLine();
+ putString(history.get(idx));
+ setCursorPosition(0);
+ flush();
+
+ /*
+ * While searching really only the "n" and "N" keys are interpreted
+ * as movement, any other key is treated as if you are editing the
+ * line with it, so we return it back up to the caller for interpretation.
+ */
+ isComplete = false;
+ while (!isComplete && (ch = readCharacter()) != -1) {
+ boolean forward = isForward;
+ switch (ch) {
+ case 'p': case 'P':
+ forward = !isForward;
+ // Fallthru
+ case 'n': case 'N':
+ boolean isMatch = false;
+ if (forward) {
+ for (int i = idx+1; !isMatch && i < end; i++) {
+ if (history.get(i).toString().contains(searchTerm)) {
+ idx = i;
+ isMatch = true;
+ }
+ }
+ }
+ else {
+ for (int i = idx - 1; !isMatch && i >= start; i--) {
+ if (history.get(i).toString().contains(searchTerm)) {
+ idx = i;
+ isMatch = true;
+ }
+ }
+ }
+ if (isMatch) {
+ setCursorPosition(0);
+ killLine();
+ putString(history.get(idx));
+ setCursorPosition(0);
+ }
+ break;
+ default:
+ isComplete = true;
+ }
+ flush();
+ }
+
+ /*
+ * Complete?
+ */
+ return ch;
+ }
+
+ public void setParenBlinkTimeout(int timeout) {
+ parenBlinkTimeout = timeout;
+ }
+
+ private void insertClose(String s) throws IOException {
+ putString(s);
+ int closePosition = buf.cursor;
+
+ moveCursor(-1);
+ viMatch();
+
+
+ if (in.isNonBlockingEnabled()) {
+ in.peek(parenBlinkTimeout);
+ }
+
+ setCursorPosition(closePosition);
+ }
+
+ /**
+ * Implements vi style bracket matching ("%" command). The matching
+ * bracket for the current bracket type that you are sitting on is matched.
+ * The logic works like so:
+ * @return true if it worked, false if the cursor was not on a bracket
+ * character or if there was no matching bracket.
+ * @throws IOException
+ */
+ private boolean viMatch() throws IOException {
+ int pos = buf.cursor;
+
+ if (pos == buf.length()) {
+ return false;
+ }
+
+ int type = getBracketType(buf.buffer.charAt (pos));
+ int move = (type < 0) ? -1 : 1;
+ int count = 1;
+
+ if (type == 0)
+ return false;
+
+ while (count > 0) {
+ pos += move;
+
+ // Fell off the start or end.
+ if (pos < 0 || pos >= buf.buffer.length ()) {
+ return false;
+ }
+
+ int curType = getBracketType(buf.buffer.charAt (pos));
+ if (curType == type) {
+ ++count;
+ }
+ else if (curType == -type) {
+ --count;
+ }
+ }
+
+ /*
+ * Slight adjustment for delete-to, yank-to, change-to to ensure
+ * that the matching paren is consumed
+ */
+ if (move > 0 && isInViMoveOperationState())
+ ++pos;
+
+ setCursorPosition(pos);
+ return true;
+ }
+
+ /**
+ * Given a character determines what type of bracket it is (paren,
+ * square, curly, or none).
+ * @param ch The character to check
+ * @return 1 is square, 2 curly, 3 parent, or zero for none. The value
+ * will be negated if it is the closing form of the bracket.
+ */
+ private int getBracketType (char ch) {
+ switch (ch) {
+ case '[': return 1;
+ case ']': return -1;
+ case '{': return 2;
+ case '}': return -2;
+ case '(': return 3;
+ case ')': return -3;
+ default:
+ return 0;
+ }
+ }
+
+ private boolean deletePreviousWord() throws IOException {
+ StringBuilder killed = new StringBuilder();
+ char c;
+
+ while (isDelimiter((c = buf.current()))) {
+ if (c == 0) {
+ break;
+ }
+
+ killed.append(c);
+ backspace();
+ }
+
+ while (!isDelimiter((c = buf.current()))) {
+ if (c == 0) {
+ break;
+ }
+
+ killed.append(c);
+ backspace();
+ }
+
+ String copy = killed.reverse().toString();
+ killRing.addBackwards(copy);
+ return true;
+ }
+
+ private boolean deleteNextWord() throws IOException {
+ StringBuilder killed = new StringBuilder();
+ char c;
+
+ while (isDelimiter((c = buf.nextChar()))) {
+ if (c == 0) {
+ break;
+ }
+ killed.append(c);
+ delete();
+ }
+
+ while (!isDelimiter((c = buf.nextChar()))) {
+ if (c == 0) {
+ break;
+ }
+ killed.append(c);
+ delete();
+ }
+
+ String copy = killed.toString();
+ killRing.add(copy);
+
+ return true;
+ }
+
+ private boolean capitalizeWord() throws IOException {
+ boolean first = true;
+ int i = 1;
+ char c;
+ while (buf.cursor + i - 1< buf.length() && !isDelimiter((c = buf.buffer.charAt(buf.cursor + i - 1)))) {
+ buf.buffer.setCharAt(buf.cursor + i - 1, first ? Character.toUpperCase(c) : Character.toLowerCase(c));
+ first = false;
+ i++;
+ }
+ drawBuffer();
+ moveCursor(i - 1);
+ return true;
+ }
+
+ private boolean upCaseWord() throws IOException {
+ int i = 1;
+ char c;
+ while (buf.cursor + i - 1 < buf.length() && !isDelimiter((c = buf.buffer.charAt(buf.cursor + i - 1)))) {
+ buf.buffer.setCharAt(buf.cursor + i - 1, Character.toUpperCase(c));
+ i++;
+ }
+ drawBuffer();
+ moveCursor(i - 1);
+ return true;
+ }
+
+ private boolean downCaseWord() throws IOException {
+ int i = 1;
+ char c;
+ while (buf.cursor + i - 1 < buf.length() && !isDelimiter((c = buf.buffer.charAt(buf.cursor + i - 1)))) {
+ buf.buffer.setCharAt(buf.cursor + i - 1, Character.toLowerCase(c));
+ i++;
+ }
+ drawBuffer();
+ moveCursor(i - 1);
+ return true;
+ }
+
+ /**
+ * Performs character transpose. The character prior to the cursor and the
+ * character under the cursor are swapped and the cursor is advanced one
+ * character unless you are already at the end of the line.
+ *
+ * @param count The number of times to perform the transpose
+ * @return true if the operation succeeded, false otherwise (e.g. transpose
+ * cannot happen at the beginning of the line).
+ * @throws IOException
+ */
+ private boolean transposeChars(int count) throws IOException {
+ for (; count > 0; --count) {
+ if (buf.cursor == 0 || buf.cursor == buf.buffer.length()) {
+ return false;
+ }
+
+ int first = buf.cursor-1;
+ int second = buf.cursor;
+
+ char tmp = buf.buffer.charAt (first);
+ buf.buffer.setCharAt(first, buf.buffer.charAt(second));
+ buf.buffer.setCharAt(second, tmp);
+
+ // This could be done more efficiently by only re-drawing at the end.
+ moveInternal(-1);
+ drawBuffer();
+ moveInternal(2);
+ }
+
+ return true;
+ }
+
+ public boolean isKeyMap(String name) {
+ // Current keymap.
+ KeyMap map = consoleKeys.getKeys();
+ KeyMap mapByName = consoleKeys.getKeyMaps().get(name);
+
+ if (mapByName == null)
+ return false;
+
+ /*
+ * This may not be safe to do, but there doesn't appear to be a
+ * clean way to find this information out.
+ */
+ return map == mapByName;
+ }
+
+
+ /**
+ * The equivalent of hitting <RET>. The line is considered
+ * complete and is returned.
+ *
+ * @return The completed line of text.
+ * @throws IOException
+ */
+ public String accept() throws IOException {
+ moveToEnd();
+ println(); // output newline
+ flush();
+ return finishBuffer();
+ }
+
+ private void abort() throws IOException {
+ beep();
+ buf.clear();
+ println();
+ redrawLine();
+ }
+
+ /**
+ * Move the cursor <i>where</i> characters.
+ *
+ * @param num If less than 0, move abs(<i>where</i>) to the left, otherwise move <i>where</i> to the right.
+ * @return The number of spaces we moved
+ */
+ public int moveCursor(final int num) throws IOException {
+ int where = num;
+
+ if ((buf.cursor == 0) && (where <= 0)) {
+ return 0;
+ }
+
+ if ((buf.cursor == buf.buffer.length()) && (where >= 0)) {
+ return 0;
+ }
+
+ if ((buf.cursor + where) < 0) {
+ where = -buf.cursor;
+ }
+ else if ((buf.cursor + where) > buf.buffer.length()) {
+ where = buf.buffer.length() - buf.cursor;
+ }
+
+ moveInternal(where);
+
+ return where;
+ }
+
+ /**
+ * Move the cursor <i>where</i> characters, without checking the current buffer.
+ *
+ * @param where the number of characters to move to the right or left.
+ */
+ private void moveInternal(final int where) throws IOException {
+ // debug ("move cursor " + where + " ("
+ // + buf.cursor + " => " + (buf.cursor + where) + ")");
+ buf.cursor += where;
+
+ if (terminal.isAnsiSupported()) {
+ if (where < 0) {
+ back(Math.abs(where));
+ } else {
+ int width = getTerminal().getWidth();
+ int cursor = getCursorPosition();
+ int oldLine = (cursor - where) / width;
+ int newLine = cursor / width;
+ if (newLine > oldLine) {
+ printAnsiSequence((newLine - oldLine) + "B");
+ }
+ printAnsiSequence(1 +(cursor % width) + "G");
+ }
+// flush();
+ return;
+ }
+
+ char c;
+
+ if (where < 0) {
+ int len = 0;
+ for (int i = buf.cursor; i < buf.cursor - where; i++) {
+ if (buf.buffer.charAt(i) == '\t') {
+ len += TAB_WIDTH;
+ }
+ else {
+ len++;
+ }
+ }
+
+ char chars[] = new char[len];
+ Arrays.fill(chars, BACKSPACE);
+ out.write(chars);
+
+ return;
+ }
+ else if (buf.cursor == 0) {
+ return;
+ }
+ else if (mask != null) {
+ c = mask;
+ }
+ else {
+ print(buf.buffer.substring(buf.cursor - where, buf.cursor).toCharArray());
+ return;
+ }
+
+ // null character mask: don't output anything
+ if (mask == NULL_MASK) {
+ return;
+ }
+
+ print(c, Math.abs(where));
+ }
+
+ // FIXME: replace() is not used
+
+ public final boolean replace(final int num, final String replacement) {
+ buf.buffer.replace(buf.cursor - num, buf.cursor, replacement);
+ try {
+ moveCursor(-num);
+ drawBuffer(Math.max(0, num - replacement.length()));
+ moveCursor(replacement.length());
+ }
+ catch (IOException e) {
+ e.printStackTrace();
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Read a character from the console.
+ *
+ * @return the character, or -1 if an EOF is received.
+ */
+ public final int readCharacter() throws IOException {
+ int c = reader.read();
+ if (c >= 0) {
+ Log.trace("Keystroke: ", c);
+ // clear any echo characters
+ if (terminal.isSupported()) {
+ clearEcho(c);
+ }
+ }
+ return c;
+ }
+
+ /**
+ * Clear the echoed characters for the specified character code.
+ */
+ private int clearEcho(final int c) throws IOException {
+ // if the terminal is not echoing, then ignore
+ if (!terminal.isEchoEnabled()) {
+ return 0;
+ }
+
+ // otherwise, clear
+ int num = countEchoCharacters(c);
+ back(num);
+ drawBuffer(num);
+
+ return num;
+ }
+
+ private int countEchoCharacters(final int c) {
+ // tabs as special: we need to determine the number of spaces
+ // to cancel based on what out current cursor position is
+ if (c == 9) {
+ int tabStop = 8; // will this ever be different?
+ int position = getCursorPosition();
+
+ return tabStop - (position % tabStop);
+ }
+
+ return getPrintableCharacters(c).length();
+ }
+
+ /**
+ * Return the number of characters that will be printed when the specified
+ * character is echoed to the screen
+ *
+ * Adapted from cat by Torbjorn Granlund, as repeated in stty by David MacKenzie.
+ */
+ private StringBuilder getPrintableCharacters(final int ch) {
+ StringBuilder sbuff = new StringBuilder();
+
+ if (ch >= 32) {
+ if (ch < 127) {
+ sbuff.append(ch);
+ }
+ else if (ch == 127) {
+ sbuff.append('^');
+ sbuff.append('?');
+ }
+ else {
+ sbuff.append('M');
+ sbuff.append('-');
+
+ if (ch >= (128 + 32)) {
+ if (ch < (128 + 127)) {
+ sbuff.append((char) (ch - 128));
+ }
+ else {
+ sbuff.append('^');
+ sbuff.append('?');
+ }
+ }
+ else {
+ sbuff.append('^');
+ sbuff.append((char) (ch - 128 + 64));
+ }
+ }
+ }
+ else {
+ sbuff.append('^');
+ sbuff.append((char) (ch + 64));
+ }
+
+ return sbuff;
+ }
+
+ public final int readCharacter(final char... allowed) throws IOException {
+ // if we restrict to a limited set and the current character is not in the set, then try again.
+ char c;
+
+ Arrays.sort(allowed); // always need to sort before binarySearch
+
+ while (Arrays.binarySearch(allowed, c = (char) readCharacter()) < 0) {
+ // nothing
+ }
+
+ return c;
+ }
+
+ //
+ // Key Bindings
+ //
+
+ public static final String JLINE_COMPLETION_THRESHOLD = "jline.completion.threshold";
+
+ //
+ // Line Reading
+ //
+
+ /**
+ * Read the next line and return the contents of the buffer.
+ */
+ public String readLine() throws IOException {
+ return readLine((String) null);
+ }
+
+ /**
+ * Read the next line with the specified character mask. If null, then
+ * characters will be echoed. If 0, then no characters will be echoed.
+ */
+ public String readLine(final Character mask) throws IOException {
+ return readLine(null, mask);
+ }
+
+ public String readLine(final String prompt) throws IOException {
+ return readLine(prompt, null);
+ }
+
+ /**
+ * Sets the current keymap by name. Supported keymaps are "emacs",
+ * "vi-insert", "vi-move".
+ * @param name The name of the keymap to switch to
+ * @return true if the keymap was set, or false if the keymap is
+ * not recognized.
+ */
+ public boolean setKeyMap(String name) {
+ return consoleKeys.setKeyMap(name);
+ }
+
+ /**
+ * Returns the name of the current key mapping.
+ * @return the name of the key mapping. This will be the canonical name
+ * of the current mode of the key map and may not reflect the name that
+ * was used with {@link #setKeyMap(String)}.
+ */
+ public String getKeyMap() {
+ return consoleKeys.getKeys().getName();
+ }
+
+ /**
+ * Read a line from the <i>in</i> {@link InputStream}, and return the line
+ * (without any trailing newlines).
+ *
+ * @param prompt The prompt to issue to the console, may be null.
+ * @return A line that is read from the terminal, or null if there was null input (e.g., <i>CTRL-D</i>
+ * was pressed).
+ */
+ public String readLine(String prompt, final Character mask) throws IOException {
+ // prompt may be null
+ // mask may be null
+
+ /*
+ * This is the accumulator for VI-mode repeat count. That is, while in
+ * move mode, if you type 30x it will delete 30 characters. This is
+ * where the "30" is accumulated until the command is struck.
+ */
+ int repeatCount = 0;
+
+ // FIXME: This blows, each call to readLine will reset the console's state which doesn't seem very nice.
+ this.mask = mask;
+ if (prompt != null) {
+ setPrompt(prompt);
+ }
+ else {
+ prompt = getPrompt();
+ }
+
+ try {
+ if (!terminal.isSupported()) {
+ beforeReadLine(prompt, mask);
+ }
+
+ if (prompt != null && prompt.length() > 0) {
+ out.write(prompt);
+ out.flush();
+ }
+
+ // if the terminal is unsupported, just use plain-java reading
+ if (!terminal.isSupported()) {
+ return readLineSimple();
+ }
+
+ if (handleUserInterrupt && (terminal instanceof UnixTerminal)) {
+ ((UnixTerminal) terminal).disableInterruptCharacter();
+ }
+
+ String originalPrompt = this.prompt;
+
+ state = State.NORMAL;
+
+ boolean success = true;
+
+ StringBuilder sb = new StringBuilder();
+ Stack<Character> pushBackChar = new Stack<Character>();
+ while (true) {
+ int c = pushBackChar.isEmpty() ? readCharacter() : pushBackChar.pop ();
+ if (c == -1) {
+ return null;
+ }
+ sb.appendCodePoint(c);
+
+ if (recording) {
+ macro += new String(new int[]{c}, 0, 1);
+ }
+
+ Object o = getKeys().getBound( sb );
+ /*
+ * The kill ring keeps record of whether or not the
+ * previous command was a yank or a kill. We reset
+ * that state here if needed.
+ */
+ if (!recording && !(o instanceof KeyMap)) {
+ if (o != Operation.YANK_POP && o != Operation.YANK) {
+ killRing.resetLastYank();
+ }
+ if (o != Operation.KILL_LINE && o != Operation.KILL_WHOLE_LINE
+ && o != Operation.BACKWARD_KILL_WORD && o != Operation.KILL_WORD
+ && o != Operation.UNIX_LINE_DISCARD && o != Operation.UNIX_WORD_RUBOUT) {
+ killRing.resetLastKill();
+ }
+ }
+
+ if (o == Operation.DO_LOWERCASE_VERSION) {
+ sb.setLength( sb.length() - 1);
+ sb.append( Character.toLowerCase( (char) c ));
+ o = getKeys().getBound( sb );
+ }
+
+ /*
+ * A KeyMap indicates that the key that was struck has a
+ * number of keys that can follow it as indicated in the
+ * map. This is used primarily for Emacs style ESC-META-x
+ * lookups. Since more keys must follow, go back to waiting
+ * for the next key.
+ */
+ if ( o instanceof KeyMap ) {
+ /*
+ * The ESC key (#27) is special in that it is ambiguous until
+ * you know what is coming next. The ESC could be a literal
+ * escape, like the user entering vi-move mode, or it could
+ * be part of a terminal control sequence. The following
+ * logic attempts to disambiguate things in the same
+ * fashion as regular vi or readline.
+ *
+ * When ESC is encountered and there is no other pending
+ * character in the pushback queue, then attempt to peek
+ * into the input stream (if the feature is enabled) for
+ * 150ms. If nothing else is coming, then assume it is
+ * not a terminal control sequence, but a raw escape.
+ */
+ if (c == 27
+ && pushBackChar.isEmpty()
+ && in.isNonBlockingEnabled()
+ && in.peek(escapeTimeout) == -2) {
+ o = ((KeyMap) o).getAnotherKey();
+ if (o == null || o instanceof KeyMap) {
+ continue;
+ }
+ sb.setLength(0);
+ }
+ else {
+ continue;
+ }
+ }
+
+ /*
+ * If we didn't find a binding for the key and there is
+ * more than one character accumulated then start checking
+ * the largest span of characters from the beginning to
+ * see if there is a binding for them.
+ *
+ * For example if our buffer has ESC,CTRL-M,C the getBound()
+ * called previously indicated that there is no binding for
+ * this sequence, so this then checks ESC,CTRL-M, and failing
+ * that, just ESC. Each keystroke that is pealed off the end
+ * during these tests is stuffed onto the pushback buffer so
+ * they won't be lost.
+ *
+ * If there is no binding found, then we go back to waiting for
+ * input.
+ */
+ while ( o == null && sb.length() > 0 ) {
+ c = sb.charAt( sb.length() - 1 );
+ sb.setLength( sb.length() - 1 );
+ Object o2 = getKeys().getBound( sb );
+ if ( o2 instanceof KeyMap ) {
+ o = ((KeyMap) o2).getAnotherKey();
+ if ( o == null ) {
+ continue;
+ } else {
+ pushBackChar.push( (char) c );
+ }
+ }
+ }
+
+ if ( o == null ) {
+ continue;
+ }
+ Log.trace("Binding: ", o);
+
+
+ // Handle macros
+ if (o instanceof String) {
+ String macro = (String) o;
+ for (int i = 0; i < macro.length(); i++) {
+ pushBackChar.push(macro.charAt(macro.length() - 1 - i));
+ }
+ sb.setLength( 0 );
+ continue;
+ }
+
+ // Handle custom callbacks
+ //original code:
+// if (o instanceof ActionListener) {
+// ((ActionListener) o).actionPerformed(null);
+// sb.setLength( 0 );
+// continue;
+// }
+ //using reflection to avoid dependency on java.desktop:
+ try {
+ Class<?> actionListener =
+ Class.forName("java.awt.event.ActionListener", false, ClassLoader.getSystemClassLoader());
+ Class<?> actionEvent =
+ Class.forName("java.awt.event.ActionEvent", false, ClassLoader.getSystemClassLoader());
+ if (actionListener.isAssignableFrom(o.getClass())) {
+ Method actionPerformed =
+ actionListener.getMethod("actionPerformed", actionEvent);
+ try {
+ actionPerformed.invoke(o, (Object) null);
+ } catch (InvocationTargetException ex ) {
+ Log.error("Exception while running registered action", ex);
+ }
+ sb.setLength( 0 );
+ continue;
+ }
+ } catch (ReflectiveOperationException ex) {
+ //ignore
+ }
+
+ // Search mode.
+ //
+ // Note that we have to do this first, because if there is a command
+ // not linked to a search command, we leave the search mode and fall
+ // through to the normal state.
+ if (state == State.SEARCH || state == State.FORWARD_SEARCH) {
+ int cursorDest = -1;
+ switch ( ((Operation) o )) {
+ case ABORT:
+ state = State.NORMAL;
+ buf.clear();
+ buf.buffer.append(searchTerm);
+ break;
+
+ case REVERSE_SEARCH_HISTORY:
+ state = State.SEARCH;
+ if (searchTerm.length() == 0) {
+ searchTerm.append(previousSearchTerm);
+ }
+
+ if (searchIndex > 0) {
+ searchIndex = searchBackwards(searchTerm.toString(), searchIndex);
+ }
+ break;
+
+ case FORWARD_SEARCH_HISTORY:
+ state = State.FORWARD_SEARCH;
+ if (searchTerm.length() == 0) {
+ searchTerm.append(previousSearchTerm);
+ }
+
+ if (searchIndex > -1 && searchIndex < history.size() - 1) {
+ searchIndex = searchForwards(searchTerm.toString(), searchIndex);
+ }
+ break;
+
+ case BACKWARD_DELETE_CHAR:
+ if (searchTerm.length() > 0) {
+ searchTerm.deleteCharAt(searchTerm.length() - 1);
+ if (state == State.SEARCH) {
+ searchIndex = searchBackwards(searchTerm.toString());
+ } else {
+ searchIndex = searchForwards(searchTerm.toString());
+ }
+ }
+ break;
+
+ case SELF_INSERT:
+ searchTerm.appendCodePoint(c);
+ if (state == State.SEARCH) {
+ searchIndex = searchBackwards(searchTerm.toString());
+ } else {
+ searchIndex = searchForwards(searchTerm.toString());
+ }
+ break;
+
+ default:
+ // Set buffer and cursor position to the found string.
+ if (searchIndex != -1) {
+ history.moveTo(searchIndex);
+ // set cursor position to the found string
+ cursorDest = history.current().toString().indexOf(searchTerm.toString());
+ }
+ state = State.NORMAL;
+ break;
+ }
+
+ // if we're still in search mode, print the search status
+ if (state == State.SEARCH || state == State.FORWARD_SEARCH) {
+ if (searchTerm.length() == 0) {
+ if (state == State.SEARCH) {
+ printSearchStatus("", "");
+ } else {
+ printForwardSearchStatus("", "");
+ }
+ searchIndex = -1;
+ } else {
+ if (searchIndex == -1) {
+ beep();
+ printSearchStatus(searchTerm.toString(), "");
+ } else if (state == State.SEARCH) {
+ printSearchStatus(searchTerm.toString(), history.get(searchIndex).toString());
+ } else {
+ printForwardSearchStatus(searchTerm.toString(), history.get(searchIndex).toString());
+ }
+ }
+ }
+ // otherwise, restore the line
+ else {
+ restoreLine(originalPrompt, cursorDest);
+ }
+ }
+ if (state != State.SEARCH && state != State.FORWARD_SEARCH) {
+ /*
+ * If this is still false at the end of the switch, then
+ * we reset our repeatCount to 0.
+ */
+ boolean isArgDigit = false;
+
+ /*
+ * Every command that can be repeated a specified number
+ * of times, needs to know how many times to repeat, so
+ * we figure that out here.
+ */
+ int count = (repeatCount == 0) ? 1 : repeatCount;
+
+ /*
+ * Default success to true. You only need to explicitly
+ * set it if something goes wrong.
+ */
+ success = true;
+
+ if (o instanceof Operation) {
+ Operation op = (Operation)o;
+ /*
+ * Current location of the cursor (prior to the operation).
+ * These are used by vi *-to operation (e.g. delete-to)
+ * so we know where we came from.
+ */
+ int cursorStart = buf.cursor;
+ State origState = state;
+
+ /*
+ * If we are on a "vi" movement based operation, then we
+ * need to restrict the sets of inputs pretty heavily.
+ */
+ if (state == State.VI_CHANGE_TO
+ || state == State.VI_YANK_TO
+ || state == State.VI_DELETE_TO) {
+
+ op = viDeleteChangeYankToRemap(op);
+ }
+
+ switch ( op ) {
+ case COMPLETE: // tab
+ // There is an annoyance with tab completion in that
+ // sometimes the user is actually pasting input in that
+ // has physical tabs in it. This attempts to look at how
+ // quickly a character follows the tab, if the character
+ // follows *immediately*, we assume it is a tab literal.
+ boolean isTabLiteral = false;
+ if (copyPasteDetection
+ && c == 9
+ && (!pushBackChar.isEmpty()
+ || (in.isNonBlockingEnabled() && in.peek(escapeTimeout) != -2))) {
+ isTabLiteral = true;
+ }
+
+ if (! isTabLiteral) {
+ success = complete();
+ }
+ else {
+ putString(sb);
+ }
+ break;
+
+ case POSSIBLE_COMPLETIONS:
+ printCompletionCandidates();
+ break;
+
+ case BEGINNING_OF_LINE:
+ success = setCursorPosition(0);
+ break;
+
+ case YANK:
+ success = yank();
+ break;
+
+ case YANK_POP:
+ success = yankPop();
+ break;
+
+ case KILL_LINE: // CTRL-K
+ success = killLine();
+ break;
+
+ case KILL_WHOLE_LINE:
+ success = setCursorPosition(0) && killLine();
+ break;
+
+ case CLEAR_SCREEN: // CTRL-L
+ success = clearScreen();
+ redrawLine();
+ break;
+
+ case OVERWRITE_MODE:
+ buf.setOverTyping(!buf.isOverTyping());
+ break;
+
+ case SELF_INSERT:
+ putString(sb);
+ break;
+
+ case ACCEPT_LINE:
+ return accept();
+
+ case ABORT:
+ if (searchTerm == null) {
+ abort();
+ }
+ break;
+
+ case INTERRUPT:
+ if (handleUserInterrupt) {
+ println();
+ flush();
+ String partialLine = buf.buffer.toString();
+ buf.clear();
+ history.moveToEnd();
+ throw new UserInterruptException(partialLine);
+ }
+ break;
+
+ /*
+ * VI_MOVE_ACCEPT_LINE is the result of an ENTER
+ * while in move mode. This is the same as a normal
+ * ACCEPT_LINE, except that we need to enter
+ * insert mode as well.
+ */
+ case VI_MOVE_ACCEPT_LINE:
+ consoleKeys.setKeyMap(KeyMap.VI_INSERT);
+ return accept();
+
+ case BACKWARD_WORD:
+ success = previousWord();
+ break;
+
+ case FORWARD_WORD:
+ success = nextWord();
+ break;
+
+ case PREVIOUS_HISTORY:
+ success = moveHistory(false);
+ break;
+
+ /*
+ * According to bash/readline move through history
+ * in "vi" mode will move the cursor to the
+ * start of the line. If there is no previous
+ * history, then the cursor doesn't move.
+ */
+ case VI_PREVIOUS_HISTORY:
+ success = moveHistory(false, count)
+ && setCursorPosition(0);
+ break;
+
+ case NEXT_HISTORY:
+ success = moveHistory(true);
+ break;
+
+ /*
+ * According to bash/readline move through history
+ * in "vi" mode will move the cursor to the
+ * start of the line. If there is no next history,
+ * then the cursor doesn't move.
+ */
+ case VI_NEXT_HISTORY:
+ success = moveHistory(true, count)
+ && setCursorPosition(0);
+ break;
+
+ case BACKWARD_DELETE_CHAR: // backspace
+ success = backspace();
+ break;
+
+ case EXIT_OR_DELETE_CHAR:
+ if (buf.buffer.length() == 0) {
+ return null;
+ }
+ success = deleteCurrentCharacter();
+ break;
+
+ case DELETE_CHAR: // delete
+ success = deleteCurrentCharacter();
+ break;
+
+ case BACKWARD_CHAR:
+ success = moveCursor(-(count)) != 0;
+ break;
+
+ case FORWARD_CHAR:
+ success = moveCursor(count) != 0;
+ break;
+
+ case UNIX_LINE_DISCARD:
+ success = resetLine();
+ break;
+
+ case UNIX_WORD_RUBOUT:
+ success = unixWordRubout(count);
+ break;
+
+ case BACKWARD_KILL_WORD:
+ success = deletePreviousWord();
+ break;
+
+ case KILL_WORD:
+ success = deleteNextWord();
+ break;
+
+ case BEGINNING_OF_HISTORY:
+ success = history.moveToFirst();
+ if (success) {
+ setBuffer(history.current());
+ }
+ break;
+
+ case END_OF_HISTORY:
+ success = history.moveToLast();
+ if (success) {
+ setBuffer(history.current());
+ }
+ break;
+
+ case HISTORY_SEARCH_BACKWARD:
+ searchTerm = new StringBuffer(buf.upToCursor());
+ searchIndex = searchBackwards(searchTerm.toString(), history.index(), true);
+
+ if (searchIndex == -1) {
+ beep();
+ } else {
+ // Maintain cursor position while searching.
+ success = history.moveTo(searchIndex);
+ if (success) {
+ setBufferKeepPos(history.current());
+ }
+ }
+ break;
+
+ case HISTORY_SEARCH_FORWARD:
+ searchTerm = new StringBuffer(buf.upToCursor());
+ int index = history.index() + 1;
+
+ if (index == history.size()) {
+ history.moveToEnd();
+ setBufferKeepPos(searchTerm.toString());
+ } else if (index < history.size()) {
+ searchIndex = searchForwards(searchTerm.toString(), index, true);
+ if (searchIndex == -1) {
+ beep();
+ } else {
+ // Maintain cursor position while searching.
+ success = history.moveTo(searchIndex);
+ if (success) {
+ setBufferKeepPos(history.current());
+ }
+ }
+ }
+ break;
+
+ case REVERSE_SEARCH_HISTORY:
+ if (searchTerm != null) {
+ previousSearchTerm = searchTerm.toString();
+ }
+ searchTerm = new StringBuffer(buf.buffer);
+ state = State.SEARCH;
+ if (searchTerm.length() > 0) {
+ searchIndex = searchBackwards(searchTerm.toString());
+ if (searchIndex == -1) {
+ beep();
+ }
+ printSearchStatus(searchTerm.toString(),
+ searchIndex > -1 ? history.get(searchIndex).toString() : "");
+ } else {
+ searchIndex = -1;
+ printSearchStatus("", "");
+ }
+ break;
+
+ case FORWARD_SEARCH_HISTORY:
+ if (searchTerm != null) {
+ previousSearchTerm = searchTerm.toString();
+ }
+ searchTerm = new StringBuffer(buf.buffer);
+ state = State.FORWARD_SEARCH;
+ if (searchTerm.length() > 0) {
+ searchIndex = searchForwards(searchTerm.toString());
+ if (searchIndex == -1) {
+ beep();
+ }
+ printForwardSearchStatus(searchTerm.toString(),
+ searchIndex > -1 ? history.get(searchIndex).toString() : "");
+ } else {
+ searchIndex = -1;
+ printForwardSearchStatus("", "");
+ }
+ break;
+
+ case CAPITALIZE_WORD:
+ success = capitalizeWord();
+ break;
+
+ case UPCASE_WORD:
+ success = upCaseWord();
+ break;
+
+ case DOWNCASE_WORD:
+ success = downCaseWord();
+ break;
+
+ case END_OF_LINE:
+ success = moveToEnd();
+ break;
+
+ case TAB_INSERT:
+ putString( "\t" );
+ break;
+
+ case RE_READ_INIT_FILE:
+ consoleKeys.loadKeys(appName, inputrcUrl);
+ break;
+
+ case START_KBD_MACRO:
+ recording = true;
+ break;
+
+ case END_KBD_MACRO:
+ recording = false;
+ macro = macro.substring(0, macro.length() - sb.length());
+ break;
+
+ case CALL_LAST_KBD_MACRO:
+ for (int i = 0; i < macro.length(); i++) {
+ pushBackChar.push(macro.charAt(macro.length() - 1 - i));
+ }
+ sb.setLength( 0 );
+ break;
+
+ case VI_EDITING_MODE:
+ consoleKeys.setKeyMap(KeyMap.VI_INSERT);
+ break;
+
+ case VI_MOVEMENT_MODE:
+ /*
+ * If we are re-entering move mode from an
+ * aborted yank-to, delete-to, change-to then
+ * don't move the cursor back. The cursor is
+ * only move on an expclit entry to movement
+ * mode.
+ */
+ if (state == State.NORMAL) {
+ moveCursor(-1);
+ }
+ consoleKeys.setKeyMap(KeyMap.VI_MOVE);
+ break;
+
+ case VI_INSERTION_MODE:
+ consoleKeys.setKeyMap(KeyMap.VI_INSERT);
+ break;
+
+ case VI_APPEND_MODE:
+ moveCursor(1);
+ consoleKeys.setKeyMap(KeyMap.VI_INSERT);
+ break;
+
+ case VI_APPEND_EOL:
+ success = moveToEnd();
+ consoleKeys.setKeyMap(KeyMap.VI_INSERT);
+ break;
+
+ /*
+ * Handler for CTRL-D. Attempts to follow readline
+ * behavior. If the line is empty, then it is an EOF
+ * otherwise it is as if the user hit enter.
+ */
+ case VI_EOF_MAYBE:
+ if (buf.buffer.length() == 0) {
+ return null;
+ }
+ return accept();
+
+ case TRANSPOSE_CHARS:
+ success = transposeChars(count);
+ break;
+
+ case INSERT_COMMENT:
+ return insertComment (false);
+
+ case INSERT_CLOSE_CURLY:
+ insertClose("}");
+ break;
+
+ case INSERT_CLOSE_PAREN:
+ insertClose(")");
+ break;
+
+ case INSERT_CLOSE_SQUARE:
+ insertClose("]");
+ break;
+
+ case VI_INSERT_COMMENT:
+ return insertComment (true);
+
+ case VI_MATCH:
+ success = viMatch ();
+ break;
+
+ case VI_SEARCH:
+ int lastChar = viSearch(sb.charAt (0));
+ if (lastChar != -1) {
+ pushBackChar.push((char)lastChar);
+ }
+ break;
+
+ case VI_ARG_DIGIT:
+ repeatCount = (repeatCount * 10) + sb.charAt(0) - '0';
+ isArgDigit = true;
+ break;
+
+ case VI_BEGNNING_OF_LINE_OR_ARG_DIGIT:
+ if (repeatCount > 0) {
+ repeatCount = (repeatCount * 10) + sb.charAt(0) - '0';
+ isArgDigit = true;
+ }
+ else {
+ success = setCursorPosition(0);
+ }
+ break;
+
+ case VI_FIRST_PRINT:
+ success = setCursorPosition(0) && viNextWord(1);
+ break;
+
+ case VI_PREV_WORD:
+ success = viPreviousWord(count);
+ break;
+
+ case VI_NEXT_WORD:
+ success = viNextWord(count);
+ break;
+
+ case VI_END_WORD:
+ success = viEndWord(count);
+ break;
+
+ case VI_INSERT_BEG:
+ success = setCursorPosition(0);
+ consoleKeys.setKeyMap(KeyMap.VI_INSERT);
+ break;
+
+ case VI_RUBOUT:
+ success = viRubout(count);
+ break;
+
+ case VI_DELETE:
+ success = viDelete(count);
+ break;
+
+ case VI_DELETE_TO:
+ /*
+ * This is a weird special case. In vi
+ * "dd" deletes the current line. So if we
+ * get a delete-to, followed by a delete-to,
+ * we delete the line.
+ */
+ if (state == State.VI_DELETE_TO) {
+ success = setCursorPosition(0) && killLine();
+ state = origState = State.NORMAL;
+ }
+ else {
+ state = State.VI_DELETE_TO;
+ }
+ break;
+
+ case VI_YANK_TO:
+ // Similar to delete-to, a "yy" yanks the whole line.
+ if (state == State.VI_YANK_TO) {
+ yankBuffer = buf.buffer.toString();
+ state = origState = State.NORMAL;
+ }
+ else {
+ state = State.VI_YANK_TO;
+ }
+ break;
+
+ case VI_CHANGE_TO:
+ if (state == State.VI_CHANGE_TO) {
+ success = setCursorPosition(0) && killLine();
+ state = origState = State.NORMAL;
+ consoleKeys.setKeyMap(KeyMap.VI_INSERT);
+ }
+ else {
+ state = State.VI_CHANGE_TO;
+ }
+ break;
+
+ case VI_KILL_WHOLE_LINE:
+ success = setCursorPosition(0) && killLine();
+ consoleKeys.setKeyMap(KeyMap.VI_INSERT);
+ break;
+
+ case VI_PUT:
+ success = viPut(count);
+ break;
+
+ case VI_CHAR_SEARCH: {
+ // ';' and ',' don't need another character. They indicate repeat next or repeat prev.
+ int searchChar = (c != ';' && c != ',')
+ ? (pushBackChar.isEmpty()
+ ? readCharacter()
+ : pushBackChar.pop ())
+ : 0;
+
+ success = viCharSearch(count, c, searchChar);
+ }
+ break;
+
+ case VI_CHANGE_CASE:
+ success = viChangeCase(count);
+ break;
+
+ case VI_CHANGE_CHAR:
+ success = viChangeChar(count,
+ pushBackChar.isEmpty()
+ ? readCharacter()
+ : pushBackChar.pop());
+ break;
+
+ case VI_DELETE_TO_EOL:
+ success = viDeleteTo(buf.cursor, buf.buffer.length(), false);
+ break;
+
+ case VI_CHANGE_TO_EOL:
+ success = viDeleteTo(buf.cursor, buf.buffer.length(), true);
+ consoleKeys.setKeyMap(KeyMap.VI_INSERT);
+ break;
+
+ case EMACS_EDITING_MODE:
+ consoleKeys.setKeyMap(KeyMap.EMACS);
+ break;
+
+ default:
+ break;
+ }
+
+ /*
+ * If we were in a yank-to, delete-to, move-to
+ * when this operation started, then fall back to
+ */
+ if (origState != State.NORMAL) {
+ if (origState == State.VI_DELETE_TO) {
+ success = viDeleteTo(cursorStart, buf.cursor, false);
+ }
+ else if (origState == State.VI_CHANGE_TO) {
+ success = viDeleteTo(cursorStart, buf.cursor, true);
+ consoleKeys.setKeyMap(KeyMap.VI_INSERT);
+ }
+ else if (origState == State.VI_YANK_TO) {
+ success = viYankTo(cursorStart, buf.cursor);
+ }
+ state = State.NORMAL;
+ }
+
+ /*
+ * Another subtly. The check for the NORMAL state is
+ * to ensure that we do not clear out the repeat
+ * count when in delete-to, yank-to, or move-to modes.
+ */
+ if (state == State.NORMAL && !isArgDigit) {
+ /*
+ * If the operation performed wasn't a vi argument
+ * digit, then clear out the current repeatCount;
+ */
+ repeatCount = 0;
+ }
+
+ if (state != State.SEARCH && state != State.FORWARD_SEARCH) {
+ previousSearchTerm = "";
+ searchTerm = null;
+ searchIndex = -1;
+ }
+ }
+ }
+ if (!success) {
+ beep();
+ }
+ sb.setLength( 0 );
+ flush();
+ }
+ }
+ finally {
+ if (!terminal.isSupported()) {
+ afterReadLine();
+ }
+ if (handleUserInterrupt && (terminal instanceof UnixTerminal)) {
+ ((UnixTerminal) terminal).enableInterruptCharacter();
+ }
+ }
+ }
+
+ /**
+ * Read a line for unsupported terminals.
+ */
+ private String readLineSimple() throws IOException {
+ StringBuilder buff = new StringBuilder();
+
+ if (skipLF) {
+ skipLF = false;
+
+ int i = readCharacter();
+
+ if (i == -1 || i == '\r') {
+ return buff.toString();
+ } else if (i == '\n') {
+ // ignore
+ } else {
+ buff.append((char) i);
+ }
+ }
+
+ while (true) {
+ int i = readCharacter();
+
+ if (i == -1 && buff.length() == 0) {
+ return null;
+ }
+
+ if (i == -1 || i == '\n') {
+ return buff.toString();
+ } else if (i == '\r') {
+ skipLF = true;
+ return buff.toString();
+ } else {
+ buff.append((char) i);
+ }
+ }
+ }
+
+ //
+ // Completion
+ //
+
+ private final List<Completer> completers = new LinkedList<Completer>();
+
+ private CompletionHandler completionHandler = new CandidateListCompletionHandler();
+
+ /**
+ * Add the specified {@link jline.console.completer.Completer} to the list of handlers for tab-completion.
+ *
+ * @param completer the {@link jline.console.completer.Completer} to add
+ * @return true if it was successfully added
+ */
+ public boolean addCompleter(final Completer completer) {
+ return completers.add(completer);
+ }
+
+ /**
+ * Remove the specified {@link jline.console.completer.Completer} from the list of handlers for tab-completion.
+ *
+ * @param completer The {@link Completer} to remove
+ * @return True if it was successfully removed
+ */
+ public boolean removeCompleter(final Completer completer) {
+ return completers.remove(completer);
+ }
+
+ /**
+ * Returns an unmodifiable list of all the completers.
+ */
+ public Collection<Completer> getCompleters() {
+ return Collections.unmodifiableList(completers);
+ }
+
+ public void setCompletionHandler(final CompletionHandler handler) {
+ this.completionHandler = checkNotNull(handler);
+ }
+
+ public CompletionHandler getCompletionHandler() {
+ return this.completionHandler;
+ }
+
+ /**
+ * Use the completers to modify the buffer with the appropriate completions.
+ *
+ * @return true if successful
+ */
+ protected boolean complete() throws IOException {
+ // debug ("tab for (" + buf + ")");
+ if (completers.size() == 0) {
+ return false;
+ }
+
+ List<CharSequence> candidates = new LinkedList<CharSequence>();
+ String bufstr = buf.buffer.toString();
+ int cursor = buf.cursor;
+
+ int position = -1;
+
+ for (Completer comp : completers) {
+ if ((position = comp.complete(bufstr, cursor, candidates)) != -1) {
+ break;
+ }
+ }
+
+ return candidates.size() != 0 && getCompletionHandler().complete(this, candidates, position);
+ }
+
+ protected void printCompletionCandidates() throws IOException {
+ // debug ("tab for (" + buf + ")");
+ if (completers.size() == 0) {
+ return;
+ }
+
+ List<CharSequence> candidates = new LinkedList<CharSequence>();
+ String bufstr = buf.buffer.toString();
+ int cursor = buf.cursor;
+
+ for (Completer comp : completers) {
+ if (comp.complete(bufstr, cursor, candidates) != -1) {
+ break;
+ }
+ }
+ CandidateListCompletionHandler.printCandidates(this, candidates);
+ drawLine();
+ }
+
+ /**
+ * The number of tab-completion candidates above which a warning will be
+ * prompted before showing all the candidates.
+ */
+ private int autoprintThreshold = Configuration.getInteger(JLINE_COMPLETION_THRESHOLD, 100); // same default as bash
+
+ /**
+ * @param threshold the number of candidates to print without issuing a warning.
+ */
+ public void setAutoprintThreshold(final int threshold) {
+ this.autoprintThreshold = threshold;
+ }
+
+ /**
+ * @return the number of candidates to print without issuing a warning.
+ */
+ public int getAutoprintThreshold() {
+ return autoprintThreshold;
+ }
+
+ private boolean paginationEnabled;
+
+ /**
+ * Whether to use pagination when the number of rows of candidates exceeds the height of the terminal.
+ */
+ public void setPaginationEnabled(final boolean enabled) {
+ this.paginationEnabled = enabled;
+ }
+
+ /**
+ * Whether to use pagination when the number of rows of candidates exceeds the height of the terminal.
+ */
+ public boolean isPaginationEnabled() {
+ return paginationEnabled;
+ }
+
+ //
+ // History
+ //
+
+ private History history = new MemoryHistory();
+
+ public void setHistory(final History history) {
+ this.history = history;
+ }
+
+ public History getHistory() {
+ return history;
+ }
+
+ private boolean historyEnabled = true;
+
+ /**
+ * Whether or not to add new commands to the history buffer.
+ */
+ public void setHistoryEnabled(final boolean enabled) {
+ this.historyEnabled = enabled;
+ }
+
+ /**
+ * Whether or not to add new commands to the history buffer.
+ */
+ public boolean isHistoryEnabled() {
+ return historyEnabled;
+ }
+
+ /**
+ * Used in "vi" mode for argumented history move, to move a specific
+ * number of history entries forward or back.
+ *
+ * @param next If true, move forward
+ * @param count The number of entries to move
+ * @return true if the move was successful
+ * @throws IOException
+ */
+ private boolean moveHistory(final boolean next, int count) throws IOException {
+ boolean ok = true;
+ for (int i = 0; i < count && (ok = moveHistory(next)); i++) {
+ /* empty */
+ }
+ return ok;
+ }
+
+ /**
+ * Move up or down the history tree.
+ */
+ private boolean moveHistory(final boolean next) throws IOException {
+ if (next && !history.next()) {
+ return false;
+ }
+ else if (!next && !history.previous()) {
+ return false;
+ }
+
+ setBuffer(history.current());
+
+ return true;
+ }
+
+ //
+ // Printing
+ //
+
+ public static final String CR = Configuration.getLineSeparator();
+
+ /**
+ * Output the specified character to the output stream without manipulating the current buffer.
+ */
+ private void print(final int c) throws IOException {
+ if (c == '\t') {
+ char chars[] = new char[TAB_WIDTH];
+ Arrays.fill(chars, ' ');
+ out.write(chars);
+ return;
+ }
+
+ out.write(c);
+ }
+
+ /**
+ * Output the specified characters to the output stream without manipulating the current buffer.
+ */
+ private void print(final char... buff) throws IOException {
+ int len = 0;
+ for (char c : buff) {
+ if (c == '\t') {
+ len += TAB_WIDTH;
+ }
+ else {
+ len++;
+ }
+ }
+
+ char chars[];
+ if (len == buff.length) {
+ chars = buff;
+ }
+ else {
+ chars = new char[len];
+ int pos = 0;
+ for (char c : buff) {
+ if (c == '\t') {
+ Arrays.fill(chars, pos, pos + TAB_WIDTH, ' ');
+ pos += TAB_WIDTH;
+ }
+ else {
+ chars[pos] = c;
+ pos++;
+ }
+ }
+ }
+
+ out.write(chars);
+ }
+
+ private void print(final char c, final int num) throws IOException {
+ if (num == 1) {
+ print(c);
+ }
+ else {
+ char[] chars = new char[num];
+ Arrays.fill(chars, c);
+ print(chars);
+ }
+ }
+
+ /**
+ * Output the specified string to the output stream (but not the buffer).
+ */
+ public final void print(final CharSequence s) throws IOException {
+ print(checkNotNull(s).toString().toCharArray());
+ }
+
+ public final void println(final CharSequence s) throws IOException {
+ print(checkNotNull(s).toString().toCharArray());
+ println();
+ }
+
+ /**
+ * Output a platform-dependant newline.
+ */
+ public final void println() throws IOException {
+ print(CR);
+// flush();
+ }
+
+ //
+ // Actions
+ //
+
+ /**
+ * Issue a delete.
+ *
+ * @return true if successful
+ */
+ public final boolean delete() throws IOException {
+ if (buf.cursor == buf.buffer.length()) {
+ return false;
+ }
+
+ buf.buffer.delete(buf.cursor, buf.cursor + 1);
+ drawBuffer(1);
+
+ return true;
+ }
+
+ /**
+ * Kill the buffer ahead of the current cursor position.
+ *
+ * @return true if successful
+ */
+ public boolean killLine() throws IOException {
+ int cp = buf.cursor;
+ int len = buf.buffer.length();
+
+ if (cp >= len) {
+ return false;
+ }
+
+ int num = len - cp;
+ clearAhead(num, 0);
+
+ char[] killed = new char[num];
+ buf.buffer.getChars(cp, (cp + num), killed, 0);
+ buf.buffer.delete(cp, (cp + num));
+
+ String copy = new String(killed);
+ killRing.add(copy);
+
+ return true;
+ }
+
+ public boolean yank() throws IOException {
+ String yanked = killRing.yank();
+
+ if (yanked == null) {
+ return false;
+ }
+ putString(yanked);
+ return true;
+ }
+
+ public boolean yankPop() throws IOException {
+ if (!killRing.lastYank()) {
+ return false;
+ }
+ String current = killRing.yank();
+ if (current == null) {
+ // This shouldn't happen.
+ return false;
+ }
+ backspace(current.length());
+ String yanked = killRing.yankPop();
+ if (yanked == null) {
+ // This shouldn't happen.
+ return false;
+ }
+
+ putString(yanked);
+ return true;
+ }
+
+ /**
+ * Clear the screen by issuing the ANSI "clear screen" code.
+ */
+ public boolean clearScreen() throws IOException {
+ if (!terminal.isAnsiSupported()) {
+ return false;
+ }
+
+ // send the ANSI code to clear the screen
+ printAnsiSequence("2J");
+
+ // then send the ANSI code to go to position 1,1
+ printAnsiSequence("1;1H");
+
+ return true;
+ }
+
+ /**
+ * Issue an audible keyboard bell.
+ */
+ public void beep() throws IOException {
+ if (bellEnabled) {
+ print(KEYBOARD_BELL);
+ // need to flush so the console actually beeps
+ flush();
+ }
+ }
+
+ //disabled to avoid dependency on java.desktop:
+// /**
+// * Paste the contents of the clipboard into the console buffer
+// *
+// * @return true if clipboard contents pasted
+// */
+// public boolean paste() throws IOException {
+// Clipboard clipboard;
+// try { // May throw ugly exception on system without X
+// clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
+// }
+// catch (Exception e) {
+// return false;
+// }
+//
+// if (clipboard == null) {
+// return false;
+// }
+//
+// Transferable transferable = clipboard.getContents(null);
+//
+// if (transferable == null) {
+// return false;
+// }
+//
+// try {
+// @SuppressWarnings("deprecation")
+// Object content = transferable.getTransferData(DataFlavor.plainTextFlavor);
+//
+// // This fix was suggested in bug #1060649 at
+// // http://sourceforge.net/tracker/index.php?func=detail&aid=1060649&group_id=64033&atid=506056
+// // to get around the deprecated DataFlavor.plainTextFlavor, but it
+// // raises a UnsupportedFlavorException on Mac OS X
+//
+// if (content == null) {
+// try {
+// content = new DataFlavor().getReaderForText(transferable);
+// }
+// catch (Exception e) {
+// // ignore
+// }
+// }
+//
+// if (content == null) {
+// return false;
+// }
+//
+// String value;
+//
+// if (content instanceof Reader) {
+// // TODO: we might want instead connect to the input stream
+// // so we can interpret individual lines
+// value = "";
+// String line;
+//
+// BufferedReader read = new BufferedReader((Reader) content);
+// while ((line = read.readLine()) != null) {
+// if (value.length() > 0) {
+// value += "\n";
+// }
+//
+// value += line;
+// }
+// }
+// else {
+// value = content.toString();
+// }
+//
+// if (value == null) {
+// return true;
+// }
+//
+// putString(value);
+//
+// return true;
+// }
+// catch (UnsupportedFlavorException e) {
+// Log.error("Paste failed: ", e);
+//
+// return false;
+// }
+// }
+
+ //disabled to avoid dependency on java.desktop:
+// //
+// // Triggered Actions
+// //
+//
+// private final Map<Character, ActionListener> triggeredActions = new HashMap<Character, ActionListener>();
+//
+// /**
+// * Adding a triggered Action allows to give another curse of action if a character passed the pre-processing.
+// * <p/>
+// * Say you want to close the application if the user enter q.
+// * addTriggerAction('q', new ActionListener(){ System.exit(0); }); would do the trick.
+// */
+// public void addTriggeredAction(final char c, final ActionListener listener) {
+// triggeredActions.put(c, listener);
+// }
+
+ //
+ // Formatted Output
+ //
+
+ /**
+ * Output the specified {@link Collection} in proper columns.
+ */
+ public void printColumns(final Collection<? extends CharSequence> items) throws IOException {
+ if (items == null || items.isEmpty()) {
+ return;
+ }
+
+ int width = getTerminal().getWidth();
+ int height = getTerminal().getHeight();
+
+ int maxWidth = 0;
+ for (CharSequence item : items) {
+ maxWidth = Math.max(maxWidth, item.length());
+ }
+ maxWidth = maxWidth + 3;
+ Log.debug("Max width: ", maxWidth);
+
+ int showLines;
+ if (isPaginationEnabled()) {
+ showLines = height - 1; // page limit
+ }
+ else {
+ showLines = Integer.MAX_VALUE;
+ }
+
+ StringBuilder buff = new StringBuilder();
+ for (CharSequence item : items) {
+ if ((buff.length() + maxWidth) > width) {
+ println(buff);
+ buff.setLength(0);
+
+ if (--showLines == 0) {
+ // Overflow
+ print(resources.getString("DISPLAY_MORE"));
+ flush();
+ int c = readCharacter();
+ if (c == '\r' || c == '\n') {
+ // one step forward
+ showLines = 1;
+ }
+ else if (c != 'q') {
+ // page forward
+ showLines = height - 1;
+ }
+
+ back(resources.getString("DISPLAY_MORE").length());
+ if (c == 'q') {
+ // cancel
+ break;
+ }
+ }
+ }
+
+ // NOTE: toString() is important here due to AnsiString being retarded
+ buff.append(item.toString());
+ for (int i = 0; i < (maxWidth - item.length()); i++) {
+ buff.append(' ');
+ }
+ }
+
+ if (buff.length() > 0) {
+ println(buff);
+ }
+ }
+
+ //
+ // Non-supported Terminal Support
+ //
+
+ private Thread maskThread;
+
+ private void beforeReadLine(final String prompt, final Character mask) {
+ if (mask != null && maskThread == null) {
+ final String fullPrompt = "\r" + prompt
+ + " "
+ + " "
+ + " "
+ + "\r" + prompt;
+
+ maskThread = new Thread()
+ {
+ public void run() {
+ while (!interrupted()) {
+ try {
+ Writer out = getOutput();
+ out.write(fullPrompt);
+ out.flush();
+ sleep(3);
+ }
+ catch (IOException e) {
+ return;
+ }
+ catch (InterruptedException e) {
+ return;
+ }
+ }
+ }
+ };
+
+ maskThread.setPriority(Thread.MAX_PRIORITY);
+ maskThread.setDaemon(true);
+ maskThread.start();
+ }
+ }
+
+ private void afterReadLine() {
+ if (maskThread != null && maskThread.isAlive()) {
+ maskThread.interrupt();
+ }
+
+ maskThread = null;
+ }
+
+ /**
+ * Erases the current line with the existing prompt, then redraws the line
+ * with the provided prompt and buffer
+ * @param prompt
+ * the new prompt
+ * @param buffer
+ * the buffer to be drawn
+ * @param cursorDest
+ * where you want the cursor set when the line has been drawn.
+ * -1 for end of line.
+ * */
+ public void resetPromptLine(String prompt, String buffer, int cursorDest) throws IOException {
+ // move cursor to end of line
+ moveToEnd();
+
+ // backspace all text, including prompt
+ buf.buffer.append(this.prompt);
+ int promptLength = 0;
+ if (this.prompt != null) {
+ promptLength = this.prompt.length();
+ }
+
+ buf.cursor += promptLength;
+ setPrompt("");
+ backspaceAll();
+
+ setPrompt(prompt);
+ redrawLine();
+ setBuffer(buffer);
+
+ // move cursor to destination (-1 will move to end of line)
+ if (cursorDest < 0) cursorDest = buffer.length();
+ setCursorPosition(cursorDest);
+
+ flush();
+ }
+
+ public void printSearchStatus(String searchTerm, String match) throws IOException {
+ printSearchStatus(searchTerm, match, "(reverse-i-search)`");
+ }
+
+ public void printForwardSearchStatus(String searchTerm, String match) throws IOException {
+ printSearchStatus(searchTerm, match, "(i-search)`");
+ }
+
+ private void printSearchStatus(String searchTerm, String match, String searchLabel) throws IOException {
+ String prompt = searchLabel + searchTerm + "': ";
+ int cursorDest = match.indexOf(searchTerm);
+ resetPromptLine(prompt, match, cursorDest);
+ }
+
+ public void restoreLine(String originalPrompt, int cursorDest) throws IOException {
+ // TODO move cursor to matched string
+ String prompt = lastLine(originalPrompt);
+ String buffer = buf.buffer.toString();
+ resetPromptLine(prompt, buffer, cursorDest);
+ }
+
+ //
+ // History search
+ //
+ /**
+ * Search backward in history from a given position.
+ *
+ * @param searchTerm substring to search for.
+ * @param startIndex the index from which on to search
+ * @return index where this substring has been found, or -1 else.
+ */
+ public int searchBackwards(String searchTerm, int startIndex) {
+ return searchBackwards(searchTerm, startIndex, false);
+ }
+
+ /**
+ * Search backwards in history from the current position.
+ *
+ * @param searchTerm substring to search for.
+ * @return index where the substring has been found, or -1 else.
+ */
+ public int searchBackwards(String searchTerm) {
+ return searchBackwards(searchTerm, history.index());
+ }
+
+
+ public int searchBackwards(String searchTerm, int startIndex, boolean startsWith) {
+ ListIterator<History.Entry> it = history.entries(startIndex);
+ while (it.hasPrevious()) {
+ History.Entry e = it.previous();
+ if (startsWith) {
+ if (e.value().toString().startsWith(searchTerm)) {
+ return e.index();
+ }
+ } else {
+ if (e.value().toString().contains(searchTerm)) {
+ return e.index();
+ }
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Search forward in history from a given position.
+ *
+ * @param searchTerm substring to search for.
+ * @param startIndex the index from which on to search
+ * @return index where this substring has been found, or -1 else.
+ */
+ public int searchForwards(String searchTerm, int startIndex) {
+ return searchForwards(searchTerm, startIndex, false);
+ }
+ /**
+ * Search forwards in history from the current position.
+ *
+ * @param searchTerm substring to search for.
+ * @return index where the substring has been found, or -1 else.
+ */
+ public int searchForwards(String searchTerm) {
+ return searchForwards(searchTerm, history.index());
+ }
+
+ public int searchForwards(String searchTerm, int startIndex, boolean startsWith) {
+ if (startIndex >= history.size()) {
+ startIndex = history.size() - 1;
+ }
+
+ ListIterator<History.Entry> it = history.entries(startIndex);
+
+ if (searchIndex != -1 && it.hasNext()) {
+ it.next();
+ }
+
+ while (it.hasNext()) {
+ History.Entry e = it.next();
+ if (startsWith) {
+ if (e.value().toString().startsWith(searchTerm)) {
+ return e.index();
+ }
+ } else {
+ if (e.value().toString().contains(searchTerm)) {
+ return e.index();
+ }
+ }
+ }
+ return -1;
+ }
+
+ //
+ // Helpers
+ //
+
+ /**
+ * Checks to see if the specified character is a delimiter. We consider a
+ * character a delimiter if it is anything but a letter or digit.
+ *
+ * @param c The character to test
+ * @return True if it is a delimiter
+ */
+ private boolean isDelimiter(final char c) {
+ return !Character.isLetterOrDigit(c);
+ }
+
+ /**
+ * Checks to see if a character is a whitespace character. Currently
+ * this delegates to {@link Character#isWhitespace(char)}, however
+ * eventually it should be hooked up so that the definition of whitespace
+ * can be configured, as readline does.
+ *
+ * @param c The character to check
+ * @return true if the character is a whitespace
+ */
+ private boolean isWhitespace(final char c) {
+ return Character.isWhitespace (c);
+ }
+
+ private void printAnsiSequence(String sequence) throws IOException {
+ print(27);
+ print('[');
+ print(sequence);
+ flush(); // helps with step debugging
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/CursorBuffer.java Wed Jul 05 20:41:12 2017 +0200
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.console;
+
+import static jdk.internal.jline.internal.Preconditions.checkNotNull;
+
+/**
+ * A holder for a {@link StringBuilder} that also contains the current cursor position.
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.0
+ */
+public class CursorBuffer
+{
+ private boolean overTyping = false;
+
+ public int cursor = 0;
+
+ public final StringBuilder buffer = new StringBuilder();
+
+ public CursorBuffer copy () {
+ CursorBuffer that = new CursorBuffer();
+ that.overTyping = this.overTyping;
+ that.cursor = this.cursor;
+ that.buffer.append (this.toString());
+
+ return that;
+ }
+
+ public boolean isOverTyping() {
+ return overTyping;
+ }
+
+ public void setOverTyping(final boolean b) {
+ overTyping = b;
+ }
+
+ public int length() {
+ return buffer.length();
+ }
+
+ public char nextChar() {
+ if (cursor == buffer.length()) {
+ return 0;
+ } else {
+ return buffer.charAt(cursor);
+ }
+ }
+
+ public char current() {
+ if (cursor <= 0) {
+ return 0;
+ }
+
+ return buffer.charAt(cursor - 1);
+ }
+
+ /**
+ * Write the specific character into the buffer, setting the cursor position
+ * ahead one. The text may overwrite or insert based on the current setting
+ * of {@link #isOverTyping}.
+ *
+ * @param c the character to insert
+ */
+ public void write(final char c) {
+ buffer.insert(cursor++, c);
+ if (isOverTyping() && cursor < buffer.length()) {
+ buffer.deleteCharAt(cursor);
+ }
+ }
+
+ /**
+ * Insert the specified chars into the buffer, setting the cursor to the end of the insertion point.
+ */
+ public void write(final CharSequence str) {
+ checkNotNull(str);
+
+ if (buffer.length() == 0) {
+ buffer.append(str);
+ }
+ else {
+ buffer.insert(cursor, str);
+ }
+
+ cursor += str.length();
+
+ if (isOverTyping() && cursor < buffer.length()) {
+ buffer.delete(cursor, (cursor + str.length()));
+ }
+ }
+
+ public boolean clear() {
+ if (buffer.length() == 0) {
+ return false;
+ }
+
+ buffer.delete(0, buffer.length());
+ cursor = 0;
+ return true;
+ }
+
+ public String upToCursor() {
+ if (cursor <= 0) {
+ return "";
+ }
+
+ return buffer.substring(0, cursor);
+ }
+
+ @Override
+ public String toString() {
+ return buffer.toString();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/KeyMap.java Wed Jul 05 20:41:12 2017 +0200
@@ -0,0 +1,578 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.console;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * The KeyMap class contains all bindings from keys to operations.
+ *
+ * @author <a href="mailto:gnodet@gmail.com">Guillaume Nodet</a>
+ * @since 2.6
+ */
+public class KeyMap {
+
+ public static final String VI_MOVE = "vi-move";
+ public static final String VI_INSERT = "vi-insert";
+ public static final String EMACS = "emacs";
+ public static final String EMACS_STANDARD = "emacs-standard";
+ public static final String EMACS_CTLX = "emacs-ctlx";
+ public static final String EMACS_META = "emacs-meta";
+
+ private static final int KEYMAP_LENGTH = 256;
+
+ private static final Object NULL_FUNCTION = new Object();
+
+ private Object[] mapping = new Object[KEYMAP_LENGTH];
+ private Object anotherKey = null;
+ private String name;
+ private boolean isViKeyMap;
+
+ public KeyMap(String name, boolean isViKeyMap) {
+ this(name, new Object[KEYMAP_LENGTH], isViKeyMap);
+ }
+
+ protected KeyMap(String name, Object[] mapping, boolean isViKeyMap) {
+ this.mapping = mapping;
+ this.name = name;
+ this.isViKeyMap = isViKeyMap;
+ }
+
+ public boolean isViKeyMap() {
+ return isViKeyMap;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Object getAnotherKey() {
+ return anotherKey;
+ }
+
+ public void from(KeyMap other) {
+ this.mapping = other.mapping;
+ this.anotherKey = other.anotherKey;
+ }
+
+ public Object getBound( CharSequence keySeq ) {
+ if (keySeq != null && keySeq.length() > 0) {
+ KeyMap map = this;
+ for (int i = 0; i < keySeq.length(); i++) {
+ char c = keySeq.charAt(i);
+ if (c > 255) {
+ return Operation.SELF_INSERT;
+ }
+ if (map.mapping[c] instanceof KeyMap) {
+ if (i == keySeq.length() - 1) {
+ return map.mapping[c];
+ } else {
+ map = (KeyMap) map.mapping[c];
+ }
+ } else {
+ return map.mapping[c];
+ }
+ }
+ }
+ return null;
+ }
+
+ public void bindIfNotBound( CharSequence keySeq, Object function ) {
+
+ bind (this, keySeq, function, true);
+ }
+
+ public void bind( CharSequence keySeq, Object function ) {
+
+ bind (this, keySeq, function, false);
+ }
+
+ private static void bind( KeyMap map, CharSequence keySeq, Object function ) {
+
+ bind (map, keySeq, function, false);
+ }
+
+ private static void bind( KeyMap map, CharSequence keySeq, Object function,
+ boolean onlyIfNotBound ) {
+
+ if (keySeq != null && keySeq.length() > 0) {
+ for (int i = 0; i < keySeq.length(); i++) {
+ char c = keySeq.charAt(i);
+ if (c >= map.mapping.length) {
+ return;
+ }
+ if (i < keySeq.length() - 1) {
+ if (!(map.mapping[c] instanceof KeyMap)) {
+ KeyMap m = new KeyMap("anonymous", false);
+ if (map.mapping[c] != Operation.DO_LOWERCASE_VERSION) {
+ m.anotherKey = map.mapping[c];
+ }
+ map.mapping[c] = m;
+ }
+ map = (KeyMap) map.mapping[c];
+ } else {
+ if (function == null) {
+ function = NULL_FUNCTION;
+ }
+ if (map.mapping[c] instanceof KeyMap) {
+ map.anotherKey = function;
+ } else {
+ Object op = map.mapping[c];
+ if (onlyIfNotBound == false
+ || op == null
+ || op == Operation.DO_LOWERCASE_VERSION
+ || op == Operation.VI_MOVEMENT_MODE ) {
+
+ }
+
+ map.mapping[c] = function;
+ }
+ }
+ }
+ }
+ }
+
+ public void setBlinkMatchingParen(boolean on) {
+ if (on) {
+ bind( "}", Operation.INSERT_CLOSE_CURLY );
+ bind( ")", Operation.INSERT_CLOSE_PAREN );
+ bind( "]", Operation.INSERT_CLOSE_SQUARE );
+ }
+ }
+
+ private static void bindArrowKeys(KeyMap map) {
+
+ // MS-DOS
+ bind( map, "\033[0A", Operation.PREVIOUS_HISTORY );
+ bind( map, "\033[0B", Operation.BACKWARD_CHAR );
+ bind( map, "\033[0C", Operation.FORWARD_CHAR );
+ bind( map, "\033[0D", Operation.NEXT_HISTORY );
+
+ // Windows
+ bind( map, "\340\000", Operation.KILL_WHOLE_LINE );
+ bind( map, "\340\107", Operation.BEGINNING_OF_LINE );
+ bind( map, "\340\110", Operation.PREVIOUS_HISTORY );
+ bind( map, "\340\111", Operation.BEGINNING_OF_HISTORY );
+ bind( map, "\340\113", Operation.BACKWARD_CHAR );
+ bind( map, "\340\115", Operation.FORWARD_CHAR );
+ bind( map, "\340\117", Operation.END_OF_LINE );
+ bind( map, "\340\120", Operation.NEXT_HISTORY );
+ bind( map, "\340\121", Operation.END_OF_HISTORY );
+ bind( map, "\340\122", Operation.OVERWRITE_MODE );
+ bind( map, "\340\123", Operation.DELETE_CHAR );
+
+ bind( map, "\000\107", Operation.BEGINNING_OF_LINE );
+ bind( map, "\000\110", Operation.PREVIOUS_HISTORY );
+ bind( map, "\000\111", Operation.BEGINNING_OF_HISTORY );
+ bind( map, "\000\110", Operation.PREVIOUS_HISTORY );
+ bind( map, "\000\113", Operation.BACKWARD_CHAR );
+ bind( map, "\000\115", Operation.FORWARD_CHAR );
+ bind( map, "\000\117", Operation.END_OF_LINE );
+ bind( map, "\000\120", Operation.NEXT_HISTORY );
+ bind( map, "\000\121", Operation.END_OF_HISTORY );
+ bind( map, "\000\122", Operation.OVERWRITE_MODE );
+ bind( map, "\000\123", Operation.DELETE_CHAR );
+
+ bind( map, "\033[A", Operation.PREVIOUS_HISTORY );
+ bind( map, "\033[B", Operation.NEXT_HISTORY );
+ bind( map, "\033[C", Operation.FORWARD_CHAR );
+ bind( map, "\033[D", Operation.BACKWARD_CHAR );
+ bind( map, "\033[H", Operation.BEGINNING_OF_LINE );
+ bind( map, "\033[F", Operation.END_OF_LINE );
+
+ bind( map, "\033OA", Operation.PREVIOUS_HISTORY );
+ bind( map, "\033OB", Operation.NEXT_HISTORY );
+ bind( map, "\033OC", Operation.FORWARD_CHAR );
+ bind( map, "\033OD", Operation.BACKWARD_CHAR );
+ bind( map, "\033OH", Operation.BEGINNING_OF_LINE );
+ bind( map, "\033OF", Operation.END_OF_LINE );
+
+ bind( map, "\033[1~", Operation.BEGINNING_OF_LINE);
+ bind( map, "\033[4~", Operation.END_OF_LINE);
+ bind( map, "\033[3~", Operation.DELETE_CHAR);
+
+ // MINGW32
+ bind( map, "\0340H", Operation.PREVIOUS_HISTORY );
+ bind( map, "\0340P", Operation.NEXT_HISTORY );
+ bind( map, "\0340M", Operation.FORWARD_CHAR );
+ bind( map, "\0340K", Operation.BACKWARD_CHAR );
+ }
+
+// public boolean isConvertMetaCharsToAscii() {
+// return convertMetaCharsToAscii;
+// }
+
+// public void setConvertMetaCharsToAscii(boolean convertMetaCharsToAscii) {
+// this.convertMetaCharsToAscii = convertMetaCharsToAscii;
+// }
+
+ public static boolean isMeta( char c ) {
+ return c > 0x7f && c <= 0xff;
+ }
+
+ public static char unMeta( char c ) {
+ return (char) (c & 0x7F);
+ }
+
+ public static char meta( char c ) {
+ return (char) (c | 0x80);
+ }
+
+ public static Map<String, KeyMap> keyMaps() {
+ Map<String, KeyMap> keyMaps = new HashMap<String, KeyMap>();
+
+ KeyMap emacs = emacs();
+ bindArrowKeys(emacs);
+ keyMaps.put(EMACS, emacs);
+ keyMaps.put(EMACS_STANDARD, emacs);
+ keyMaps.put(EMACS_CTLX, (KeyMap) emacs.getBound("\u0018"));
+ keyMaps.put(EMACS_META, (KeyMap) emacs.getBound("\u001b"));
+
+ KeyMap viMov = viMovement();
+ bindArrowKeys(viMov);
+ keyMaps.put(VI_MOVE, viMov);
+ keyMaps.put("vi-command", viMov);
+
+ KeyMap viIns = viInsertion();
+ bindArrowKeys(viIns);
+ keyMaps.put(VI_INSERT, viIns);
+ keyMaps.put("vi", viIns);
+
+ return keyMaps;
+ }
+
+ public static KeyMap emacs() {
+ Object[] map = new Object[KEYMAP_LENGTH];
+ Object[] ctrl = new Object[] {
+ // Control keys.
+ Operation.SET_MARK, /* Control-@ */
+ Operation.BEGINNING_OF_LINE, /* Control-A */
+ Operation.BACKWARD_CHAR, /* Control-B */
+ Operation.INTERRUPT, /* Control-C */
+ Operation.EXIT_OR_DELETE_CHAR, /* Control-D */
+ Operation.END_OF_LINE, /* Control-E */
+ Operation.FORWARD_CHAR, /* Control-F */
+ Operation.ABORT, /* Control-G */
+ Operation.BACKWARD_DELETE_CHAR, /* Control-H */
+ Operation.COMPLETE, /* Control-I */
+ Operation.ACCEPT_LINE, /* Control-J */
+ Operation.KILL_LINE, /* Control-K */
+ Operation.CLEAR_SCREEN, /* Control-L */
+ Operation.ACCEPT_LINE, /* Control-M */
+ Operation.NEXT_HISTORY, /* Control-N */
+ null, /* Control-O */
+ Operation.PREVIOUS_HISTORY, /* Control-P */
+ Operation.QUOTED_INSERT, /* Control-Q */
+ Operation.REVERSE_SEARCH_HISTORY, /* Control-R */
+ Operation.FORWARD_SEARCH_HISTORY, /* Control-S */
+ Operation.TRANSPOSE_CHARS, /* Control-T */
+ Operation.UNIX_LINE_DISCARD, /* Control-U */
+ Operation.QUOTED_INSERT, /* Control-V */
+ Operation.UNIX_WORD_RUBOUT, /* Control-W */
+ emacsCtrlX(), /* Control-X */
+ Operation.YANK, /* Control-Y */
+ null, /* Control-Z */
+ emacsMeta(), /* Control-[ */
+ null, /* Control-\ */
+ Operation.CHARACTER_SEARCH, /* Control-] */
+ null, /* Control-^ */
+ Operation.UNDO, /* Control-_ */
+ };
+ System.arraycopy( ctrl, 0, map, 0, ctrl.length );
+ for (int i = 32; i < 256; i++) {
+ map[i] = Operation.SELF_INSERT;
+ }
+ map[DELETE] = Operation.BACKWARD_DELETE_CHAR;
+ return new KeyMap(EMACS, map, false);
+ }
+
+ public static final char CTRL_D = (char) 4;
+ public static final char CTRL_G = (char) 7;
+ public static final char CTRL_H = (char) 8;
+ public static final char CTRL_I = (char) 9;
+ public static final char CTRL_J = (char) 10;
+ public static final char CTRL_M = (char) 13;
+ public static final char CTRL_R = (char) 18;
+ public static final char CTRL_S = (char) 19;
+ public static final char CTRL_U = (char) 21;
+ public static final char CTRL_X = (char) 24;
+ public static final char CTRL_Y = (char) 25;
+ public static final char ESCAPE = (char) 27; /* Ctrl-[ */
+ public static final char CTRL_OB = (char) 27; /* Ctrl-[ */
+ public static final char CTRL_CB = (char) 29; /* Ctrl-] */
+
+ public static final int DELETE = (char) 127;
+
+ public static KeyMap emacsCtrlX() {
+ Object[] map = new Object[KEYMAP_LENGTH];
+ map[CTRL_G] = Operation.ABORT;
+ map[CTRL_R] = Operation.RE_READ_INIT_FILE;
+ map[CTRL_U] = Operation.UNDO;
+ map[CTRL_X] = Operation.EXCHANGE_POINT_AND_MARK;
+ map['('] = Operation.START_KBD_MACRO;
+ map[')'] = Operation.END_KBD_MACRO;
+ for (int i = 'A'; i <= 'Z'; i++) {
+ map[i] = Operation.DO_LOWERCASE_VERSION;
+ }
+ map['e'] = Operation.CALL_LAST_KBD_MACRO;
+ map[DELETE] = Operation.KILL_LINE;
+ return new KeyMap(EMACS_CTLX, map, false);
+ }
+
+ public static KeyMap emacsMeta() {
+ Object[] map = new Object[KEYMAP_LENGTH];
+ map[CTRL_G] = Operation.ABORT;
+ map[CTRL_H] = Operation.BACKWARD_KILL_WORD;
+ map[CTRL_I] = Operation.TAB_INSERT;
+ map[CTRL_J] = Operation.VI_EDITING_MODE;
+ map[CTRL_M] = Operation.VI_EDITING_MODE;
+ map[CTRL_R] = Operation.REVERT_LINE;
+ map[CTRL_Y] = Operation.YANK_NTH_ARG;
+ map[CTRL_OB] = Operation.COMPLETE;
+ map[CTRL_CB] = Operation.CHARACTER_SEARCH_BACKWARD;
+ map[' '] = Operation.SET_MARK;
+ map['#'] = Operation.INSERT_COMMENT;
+ map['&'] = Operation.TILDE_EXPAND;
+ map['*'] = Operation.INSERT_COMPLETIONS;
+ map['-'] = Operation.DIGIT_ARGUMENT;
+ map['.'] = Operation.YANK_LAST_ARG;
+ map['<'] = Operation.BEGINNING_OF_HISTORY;
+ map['='] = Operation.POSSIBLE_COMPLETIONS;
+ map['>'] = Operation.END_OF_HISTORY;
+ map['?'] = Operation.POSSIBLE_COMPLETIONS;
+ for (int i = 'A'; i <= 'Z'; i++) {
+ map[i] = Operation.DO_LOWERCASE_VERSION;
+ }
+ map['\\'] = Operation.DELETE_HORIZONTAL_SPACE;
+ map['_'] = Operation.YANK_LAST_ARG;
+ map['b'] = Operation.BACKWARD_WORD;
+ map['c'] = Operation.CAPITALIZE_WORD;
+ map['d'] = Operation.KILL_WORD;
+ map['f'] = Operation.FORWARD_WORD;
+ map['l'] = Operation.DOWNCASE_WORD;
+ map['p'] = Operation.NON_INCREMENTAL_REVERSE_SEARCH_HISTORY;
+ map['r'] = Operation.REVERT_LINE;
+ map['t'] = Operation.TRANSPOSE_WORDS;
+ map['u'] = Operation.UPCASE_WORD;
+ map['y'] = Operation.YANK_POP;
+ map['~'] = Operation.TILDE_EXPAND;
+ map[DELETE] = Operation.BACKWARD_KILL_WORD;
+ return new KeyMap(EMACS_META, map, false);
+ }
+
+ public static KeyMap viInsertion() {
+ Object[] map = new Object[KEYMAP_LENGTH];
+ Object[] ctrl = new Object[] {
+ // Control keys.
+ null, /* Control-@ */
+ Operation.SELF_INSERT, /* Control-A */
+ Operation.SELF_INSERT, /* Control-B */
+ Operation.SELF_INSERT, /* Control-C */
+ Operation.VI_EOF_MAYBE, /* Control-D */
+ Operation.SELF_INSERT, /* Control-E */
+ Operation.SELF_INSERT, /* Control-F */
+ Operation.SELF_INSERT, /* Control-G */
+ Operation.BACKWARD_DELETE_CHAR, /* Control-H */
+ Operation.COMPLETE, /* Control-I */
+ Operation.ACCEPT_LINE, /* Control-J */
+ Operation.SELF_INSERT, /* Control-K */
+ Operation.SELF_INSERT, /* Control-L */
+ Operation.ACCEPT_LINE, /* Control-M */
+ Operation.MENU_COMPLETE, /* Control-N */
+ Operation.SELF_INSERT, /* Control-O */
+ Operation.MENU_COMPLETE_BACKWARD, /* Control-P */
+ Operation.SELF_INSERT, /* Control-Q */
+ Operation.REVERSE_SEARCH_HISTORY, /* Control-R */
+ Operation.FORWARD_SEARCH_HISTORY, /* Control-S */
+ Operation.TRANSPOSE_CHARS, /* Control-T */
+ Operation.UNIX_LINE_DISCARD, /* Control-U */
+ Operation.QUOTED_INSERT, /* Control-V */
+ Operation.UNIX_WORD_RUBOUT, /* Control-W */
+ Operation.SELF_INSERT, /* Control-X */
+ Operation.YANK, /* Control-Y */
+ Operation.SELF_INSERT, /* Control-Z */
+ Operation.VI_MOVEMENT_MODE, /* Control-[ */
+ Operation.SELF_INSERT, /* Control-\ */
+ Operation.SELF_INSERT, /* Control-] */
+ Operation.SELF_INSERT, /* Control-^ */
+ Operation.UNDO, /* Control-_ */
+ };
+ System.arraycopy( ctrl, 0, map, 0, ctrl.length );
+ for (int i = 32; i < 256; i++) {
+ map[i] = Operation.SELF_INSERT;
+ }
+ map[DELETE] = Operation.BACKWARD_DELETE_CHAR;
+ return new KeyMap(VI_INSERT, map, false);
+ }
+
+ public static KeyMap viMovement() {
+ Object[] map = new Object[KEYMAP_LENGTH];
+ Object[] low = new Object[] {
+ // Control keys.
+ null, /* Control-@ */
+ null, /* Control-A */
+ null, /* Control-B */
+ Operation.INTERRUPT, /* Control-C */
+ /*
+ * ^D is supposed to move down half a screen. In bash
+ * appears to be ignored.
+ */
+ Operation.VI_EOF_MAYBE, /* Control-D */
+ Operation.EMACS_EDITING_MODE, /* Control-E */
+ null, /* Control-F */
+ Operation.ABORT, /* Control-G */
+ Operation.BACKWARD_CHAR, /* Control-H */
+ null, /* Control-I */
+ Operation.VI_MOVE_ACCEPT_LINE, /* Control-J */
+ Operation.KILL_LINE, /* Control-K */
+ Operation.CLEAR_SCREEN, /* Control-L */
+ Operation.VI_MOVE_ACCEPT_LINE, /* Control-M */
+ Operation.VI_NEXT_HISTORY, /* Control-N */
+ null, /* Control-O */
+ Operation.VI_PREVIOUS_HISTORY, /* Control-P */
+ /*
+ * My testing with readline is the ^Q is ignored.
+ * Maybe this should be null?
+ */
+ Operation.QUOTED_INSERT, /* Control-Q */
+
+ /*
+ * TODO - Very broken. While in forward/reverse
+ * history search the VI keyset should go out the
+ * window and we need to enter a very simple keymap.
+ */
+ Operation.REVERSE_SEARCH_HISTORY, /* Control-R */
+ /* TODO */
+ Operation.FORWARD_SEARCH_HISTORY, /* Control-S */
+ Operation.TRANSPOSE_CHARS, /* Control-T */
+ Operation.UNIX_LINE_DISCARD, /* Control-U */
+ /* TODO */
+ Operation.QUOTED_INSERT, /* Control-V */
+ Operation.UNIX_WORD_RUBOUT, /* Control-W */
+ null, /* Control-X */
+ /* TODO */
+ Operation.YANK, /* Control-Y */
+ null, /* Control-Z */
+ emacsMeta(), /* Control-[ */
+ null, /* Control-\ */
+ /* TODO */
+ Operation.CHARACTER_SEARCH, /* Control-] */
+ null, /* Control-^ */
+ /* TODO */
+ Operation.UNDO, /* Control-_ */
+ Operation.FORWARD_CHAR, /* SPACE */
+ null, /* ! */
+ null, /* " */
+ Operation.VI_INSERT_COMMENT, /* # */
+ Operation.END_OF_LINE, /* $ */
+ Operation.VI_MATCH, /* % */
+ Operation.VI_TILDE_EXPAND, /* & */
+ null, /* ' */
+ null, /* ( */
+ null, /* ) */
+ /* TODO */
+ Operation.VI_COMPLETE, /* * */
+ Operation.VI_NEXT_HISTORY, /* + */
+ Operation.VI_CHAR_SEARCH, /* , */
+ Operation.VI_PREVIOUS_HISTORY, /* - */
+ /* TODO */
+ Operation.VI_REDO, /* . */
+ Operation.VI_SEARCH, /* / */
+ Operation.VI_BEGNNING_OF_LINE_OR_ARG_DIGIT, /* 0 */
+ Operation.VI_ARG_DIGIT, /* 1 */
+ Operation.VI_ARG_DIGIT, /* 2 */
+ Operation.VI_ARG_DIGIT, /* 3 */
+ Operation.VI_ARG_DIGIT, /* 4 */
+ Operation.VI_ARG_DIGIT, /* 5 */
+ Operation.VI_ARG_DIGIT, /* 6 */
+ Operation.VI_ARG_DIGIT, /* 7 */
+ Operation.VI_ARG_DIGIT, /* 8 */
+ Operation.VI_ARG_DIGIT, /* 9 */
+ null, /* : */
+ Operation.VI_CHAR_SEARCH, /* ; */
+ null, /* < */
+ Operation.VI_COMPLETE, /* = */
+ null, /* > */
+ Operation.VI_SEARCH, /* ? */
+ null, /* @ */
+ Operation.VI_APPEND_EOL, /* A */
+ Operation.VI_PREV_WORD, /* B */
+ Operation.VI_CHANGE_TO_EOL, /* C */
+ Operation.VI_DELETE_TO_EOL, /* D */
+ Operation.VI_END_WORD, /* E */
+ Operation.VI_CHAR_SEARCH, /* F */
+ /* I need to read up on what this does */
+ Operation.VI_FETCH_HISTORY, /* G */
+ null, /* H */
+ Operation.VI_INSERT_BEG, /* I */
+ null, /* J */
+ null, /* K */
+ null, /* L */
+ null, /* M */
+ Operation.VI_SEARCH_AGAIN, /* N */
+ null, /* O */
+ Operation.VI_PUT, /* P */
+ null, /* Q */
+ /* TODO */
+ Operation.VI_REPLACE, /* R */
+ Operation.VI_KILL_WHOLE_LINE, /* S */
+ Operation.VI_CHAR_SEARCH, /* T */
+ /* TODO */
+ Operation.REVERT_LINE, /* U */
+ null, /* V */
+ Operation.VI_NEXT_WORD, /* W */
+ Operation.VI_RUBOUT, /* X */
+ Operation.VI_YANK_TO, /* Y */
+ null, /* Z */
+ null, /* [ */
+ Operation.VI_COMPLETE, /* \ */
+ null, /* ] */
+ Operation.VI_FIRST_PRINT, /* ^ */
+ Operation.VI_YANK_ARG, /* _ */
+ Operation.VI_GOTO_MARK, /* ` */
+ Operation.VI_APPEND_MODE, /* a */
+ Operation.VI_PREV_WORD, /* b */
+ Operation.VI_CHANGE_TO, /* c */
+ Operation.VI_DELETE_TO, /* d */
+ Operation.VI_END_WORD, /* e */
+ Operation.VI_CHAR_SEARCH, /* f */
+ null, /* g */
+ Operation.BACKWARD_CHAR, /* h */
+ Operation.VI_INSERTION_MODE, /* i */
+ Operation.NEXT_HISTORY, /* j */
+ Operation.PREVIOUS_HISTORY, /* k */
+ Operation.FORWARD_CHAR, /* l */
+ Operation.VI_SET_MARK, /* m */
+ Operation.VI_SEARCH_AGAIN, /* n */
+ null, /* o */
+ Operation.VI_PUT, /* p */
+ null, /* q */
+ Operation.VI_CHANGE_CHAR, /* r */
+ Operation.VI_SUBST, /* s */
+ Operation.VI_CHAR_SEARCH, /* t */
+ Operation.UNDO, /* u */
+ null, /* v */
+ Operation.VI_NEXT_WORD, /* w */
+ Operation.VI_DELETE, /* x */
+ Operation.VI_YANK_TO, /* y */
+ null, /* z */
+ null, /* { */
+ Operation.VI_COLUMN, /* | */
+ null, /* } */
+ Operation.VI_CHANGE_CASE, /* ~ */
+ Operation.VI_DELETE /* DEL */
+ };
+ System.arraycopy( low, 0, map, 0, low.length );
+ for (int i = 128; i < 256; i++) {
+ map[i] = null;
+ }
+ return new KeyMap(VI_MOVE, map, false);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/KillRing.java Wed Jul 05 20:41:12 2017 +0200
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2002-2013, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.console;
+
+/**
+ * The kill ring class keeps killed text in a fixed size ring. In this
+ * class we also keep record of whether or not the last command was a
+ * kill or a yank. Depending on this, the class may behave
+ * different. For instance, two consecutive kill-word commands fill
+ * the same slot such that the next yank will return the two
+ * previously killed words instead that only the last one. Likewise
+ * yank pop requires that the previous command was either a yank or a
+ * yank-pop.
+ */
+public final class KillRing {
+
+ /**
+ * Default size is 60, like in emacs.
+ */
+ private static final int DEFAULT_SIZE = 60;
+
+ private final String[] slots;
+ private int head = 0;
+ private boolean lastKill = false;
+ private boolean lastYank = false;
+
+ /**
+ * Creates a new kill ring of the given size.
+ */
+ public KillRing(int size) {
+ slots = new String[size];
+ }
+
+ /**
+ * Creates a new kill ring of the default size. {@see DEFAULT_SIZE}.
+ */
+ public KillRing() {
+ this(DEFAULT_SIZE);
+ }
+
+ /**
+ * Resets the last-yank state.
+ */
+ public void resetLastYank() {
+ lastYank = false;
+ }
+
+ /**
+ * Resets the last-kill state.
+ */
+ public void resetLastKill() {
+ lastKill = false;
+ }
+
+ /**
+ * Returns {@code true} if the last command was a yank.
+ */
+ public boolean lastYank() {
+ return lastYank;
+ }
+
+ /**
+ * Adds the string to the kill-ring. Also sets lastYank to false
+ * and lastKill to true.
+ */
+ public void add(String str) {
+ lastYank = false;
+
+ if (lastKill) {
+ if (slots[head] != null) {
+ slots[head] += str;
+ return;
+ }
+ }
+
+ lastKill = true;
+ next();
+ slots[head] = str;
+ }
+
+ /**
+ * Adds the string to the kill-ring product of killing
+ * backwards. If the previous command was a kill text one then
+ * adds the text at the beginning of the previous kill to avoid
+ * that two consecutive backwards kills followed by a yank leaves
+ * things reversed.
+ */
+ public void addBackwards(String str) {
+ lastYank = false;
+
+ if (lastKill) {
+ if (slots[head] != null) {
+ slots[head] = str + slots[head];
+ return;
+ }
+ }
+
+ lastKill = true;
+ next();
+ slots[head] = str;
+ }
+
+ /**
+ * Yanks a previously killed text. Returns {@code null} if the
+ * ring is empty.
+ */
+ public String yank() {
+ lastKill = false;
+ lastYank = true;
+ return slots[head];
+ }
+
+ /**
+ * Moves the pointer to the current slot back and returns the text
+ * in that position. If the previous command was not yank returns
+ * null.
+ */
+ public String yankPop() {
+ lastKill = false;
+ if (lastYank) {
+ prev();
+ return slots[head];
+ }
+ return null;
+ }
+
+ /**
+ * Moves the pointer to the current slot forward. If the end of
+ * the slots is reached then points back to the beginning.
+ */
+ private void next() {
+ if (head == 0 && slots[0] == null) {
+ return;
+ }
+ head++;
+ if (head == slots.length) {
+ head = 0;
+ }
+ }
+
+ /**
+ * Moves the pointer to the current slot backwards. If the
+ * beginning of the slots is reached then traverses the slot
+ * backwards until one with not null content is found.
+ */
+ private void prev() {
+ head--;
+ if (head == -1) {
+ int x = (slots.length - 1);
+ for (; x >= 0; x--) {
+ if (slots[x] != null) {
+ break;
+ }
+ }
+ head = x;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/Operation.java Wed Jul 05 20:41:12 2017 +0200
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.console;
+
+/**
+ * List of all operations.
+ *
+ * @author <a href="mailto:gnodet@gmail.com">Guillaume Nodet</a>
+ * @since 2.6
+ */
+public enum Operation {
+
+ ABORT,
+ ACCEPT_LINE,
+ ARROW_KEY_PREFIX,
+ BACKWARD_BYTE,
+ BACKWARD_CHAR,
+ BACKWARD_DELETE_CHAR,
+ BACKWARD_KILL_LINE,
+ BACKWARD_KILL_WORD,
+ BACKWARD_WORD,
+ BEGINNING_OF_HISTORY,
+ BEGINNING_OF_LINE,
+ CALL_LAST_KBD_MACRO,
+ CAPITALIZE_WORD,
+ CHARACTER_SEARCH,
+ CHARACTER_SEARCH_BACKWARD,
+ CLEAR_SCREEN,
+ COMPLETE,
+ COPY_BACKWARD_WORD,
+ COPY_FORWARD_WORD,
+ COPY_REGION_AS_KILL,
+ DELETE_CHAR,
+ DELETE_CHAR_OR_LIST,
+ DELETE_HORIZONTAL_SPACE,
+ DIGIT_ARGUMENT,
+ DO_LOWERCASE_VERSION,
+ DOWNCASE_WORD,
+ DUMP_FUNCTIONS,
+ DUMP_MACROS,
+ DUMP_VARIABLES,
+ EMACS_EDITING_MODE,
+ END_KBD_MACRO,
+ END_OF_HISTORY,
+ END_OF_LINE,
+ EXCHANGE_POINT_AND_MARK,
+ EXIT_OR_DELETE_CHAR,
+ FORWARD_BACKWARD_DELETE_CHAR,
+ FORWARD_BYTE,
+ FORWARD_CHAR,
+ FORWARD_SEARCH_HISTORY,
+ FORWARD_WORD,
+ HISTORY_SEARCH_BACKWARD,
+ HISTORY_SEARCH_FORWARD,
+ INSERT_CLOSE_CURLY,
+ INSERT_CLOSE_PAREN,
+ INSERT_CLOSE_SQUARE,
+ INSERT_COMMENT,
+ INSERT_COMPLETIONS,
+ INTERRUPT,
+ KILL_WHOLE_LINE,
+ KILL_LINE,
+ KILL_REGION,
+ KILL_WORD,
+ MENU_COMPLETE,
+ MENU_COMPLETE_BACKWARD,
+ NEXT_HISTORY,
+ NON_INCREMENTAL_FORWARD_SEARCH_HISTORY,
+ NON_INCREMENTAL_REVERSE_SEARCH_HISTORY,
+ NON_INCREMENTAL_FORWARD_SEARCH_HISTORY_AGAIN,
+ NON_INCREMENTAL_REVERSE_SEARCH_HISTORY_AGAIN,
+ OLD_MENU_COMPLETE,
+ OVERWRITE_MODE,
+ PASTE_FROM_CLIPBOARD,
+ POSSIBLE_COMPLETIONS,
+ PREVIOUS_HISTORY,
+ QUOTED_INSERT,
+ RE_READ_INIT_FILE,
+ REDRAW_CURRENT_LINE,
+ REVERSE_SEARCH_HISTORY,
+ REVERT_LINE,
+ SELF_INSERT,
+ SET_MARK,
+ SKIP_CSI_SEQUENCE,
+ START_KBD_MACRO,
+ TAB_INSERT,
+ TILDE_EXPAND,
+ TRANSPOSE_CHARS,
+ TRANSPOSE_WORDS,
+ TTY_STATUS,
+ UNDO,
+ UNIVERSAL_ARGUMENT,
+ UNIX_FILENAME_RUBOUT,
+ UNIX_LINE_DISCARD,
+ UNIX_WORD_RUBOUT,
+ UPCASE_WORD,
+ YANK,
+ YANK_LAST_ARG,
+ YANK_NTH_ARG,
+ YANK_POP,
+ VI_APPEND_EOL,
+ VI_APPEND_MODE,
+ VI_ARG_DIGIT,
+ VI_BACK_TO_INDENT,
+ VI_BACKWARD_BIGWORD,
+ VI_BACKWARD_WORD,
+ VI_BWORD,
+ VI_CHANGE_CASE,
+ VI_CHANGE_CHAR,
+ VI_CHANGE_TO,
+ VI_CHANGE_TO_EOL,
+ VI_CHAR_SEARCH,
+ VI_COLUMN,
+ VI_COMPLETE,
+ VI_DELETE,
+ VI_DELETE_TO,
+ VI_DELETE_TO_EOL,
+ VI_EDITING_MODE,
+ VI_END_BIGWORD,
+ VI_END_WORD,
+ VI_EOF_MAYBE,
+ VI_EWORD,
+ VI_FWORD,
+ VI_FETCH_HISTORY,
+ VI_FIRST_PRINT,
+ VI_FORWARD_BIGWORD,
+ VI_FORWARD_WORD,
+ VI_GOTO_MARK,
+ VI_INSERT_BEG,
+ VI_INSERTION_MODE,
+ VI_KILL_WHOLE_LINE,
+ VI_MATCH,
+ VI_MOVEMENT_MODE,
+ VI_NEXT_WORD,
+ VI_OVERSTRIKE,
+ VI_OVERSTRIKE_DELETE,
+ VI_PREV_WORD,
+ VI_PUT,
+ VI_REDO,
+ VI_REPLACE,
+ VI_RUBOUT,
+ VI_SEARCH,
+ VI_SEARCH_AGAIN,
+ VI_SET_MARK,
+ VI_SUBST,
+ VI_TILDE_EXPAND,
+ VI_YANK_ARG,
+ VI_YANK_TO,
+ VI_MOVE_ACCEPT_LINE,
+ VI_NEXT_HISTORY,
+ VI_PREVIOUS_HISTORY,
+ VI_INSERT_COMMENT,
+ VI_BEGNNING_OF_LINE_OR_ARG_DIGIT,
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/UserInterruptException.java Wed Jul 05 20:41:12 2017 +0200
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.console;
+
+/**
+ * This exception is thrown by {@link ConsoleReader#readLine} when
+ * user interrupt handling is enabled and the user types the
+ * interrupt character (ctrl-C). The partially entered line is
+ * available via the {@link #getPartialLine()} method.
+ */
+public class UserInterruptException
+ extends RuntimeException
+{
+ private static final long serialVersionUID = 6172232572140736750L;
+
+ private final String partialLine;
+
+ public UserInterruptException(String partialLine)
+ {
+ this.partialLine = partialLine;
+ }
+
+ /**
+ * @return the partially entered line when ctrl-C was pressed
+ */
+ public String getPartialLine()
+ {
+ return partialLine;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/AggregateCompleter.java Wed Jul 05 20:41:12 2017 +0200
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.console.completer;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+
+import static jdk.internal.jline.internal.Preconditions.checkNotNull;
+
+/**
+ * Completer which contains multiple completers and aggregates them together.
+ *
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.3
+ */
+public class AggregateCompleter
+ implements Completer
+{
+ private final List<Completer> completers = new ArrayList<Completer>();
+
+ public AggregateCompleter() {
+ // empty
+ }
+
+ /**
+ * Construct an AggregateCompleter with the given collection of completers.
+ * The completers will be used in the iteration order of the collection.
+ *
+ * @param completers the collection of completers
+ */
+ public AggregateCompleter(final Collection<Completer> completers) {
+ checkNotNull(completers);
+ this.completers.addAll(completers);
+ }
+
+ /**
+ * Construct an AggregateCompleter with the given completers.
+ * The completers will be used in the order given.
+ *
+ * @param completers the completers
+ */
+ public AggregateCompleter(final Completer... completers) {
+ this(Arrays.asList(completers));
+ }
+
+ /**
+ * Retrieve the collection of completers currently being aggregated.
+ *
+ * @return the aggregated completers
+ */
+ public Collection<Completer> getCompleters() {
+ return completers;
+ }
+
+ /**
+ * Perform a completion operation across all aggregated completers.
+ *
+ * @see Completer#complete(String, int, java.util.List)
+ * @return the highest completion return value from all completers
+ */
+ public int complete(final String buffer, final int cursor, final List<CharSequence> candidates) {
+ // buffer could be null
+ checkNotNull(candidates);
+
+ List<Completion> completions = new ArrayList<Completion>(completers.size());
+
+ // Run each completer, saving its completion results
+ int max = -1;
+ for (Completer completer : completers) {
+ Completion completion = new Completion(candidates);
+ completion.complete(completer, buffer, cursor);
+
+ // Compute the max cursor position
+ max = Math.max(max, completion.cursor);
+
+ completions.add(completion);
+ }
+
+ // Append candidates from completions which have the same cursor position as max
+ for (Completion completion : completions) {
+ if (completion.cursor == max) {
+ candidates.addAll(completion.candidates);
+ }
+ }
+
+ return max;
+ }
+
+ /**
+ * @return a string representing the aggregated completers
+ */
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + "{" +
+ "completers=" + completers +
+ '}';
+ }
+
+ private class Completion
+ {
+ public final List<CharSequence> candidates;
+
+ public int cursor;
+
+ public Completion(final List<CharSequence> candidates) {
+ checkNotNull(candidates);
+ this.candidates = new LinkedList<CharSequence>(candidates);
+ }
+
+ public void complete(final Completer completer, final String buffer, final int cursor) {
+ checkNotNull(completer);
+ this.cursor = completer.complete(buffer, cursor, candidates);
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/ArgumentCompleter.java Wed Jul 05 20:41:12 2017 +0200
@@ -0,0 +1,461 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.console.completer;
+
+import jdk.internal.jline.internal.Log;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+
+import static jdk.internal.jline.internal.Preconditions.checkNotNull;
+
+/**
+ * A {@link Completer} implementation that invokes a child completer using the appropriate <i>separator</i> argument.
+ * This can be used instead of the individual completers having to know about argument parsing semantics.
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.3
+ */
+public class ArgumentCompleter
+ implements Completer
+{
+ private final ArgumentDelimiter delimiter;
+
+ private final List<Completer> completers = new ArrayList<Completer>();
+
+ private boolean strict = true;
+
+ /**
+ * Create a new completer with the specified argument delimiter.
+ *
+ * @param delimiter The delimiter for parsing arguments
+ * @param completers The embedded completers
+ */
+ public ArgumentCompleter(final ArgumentDelimiter delimiter, final Collection<Completer> completers) {
+ this.delimiter = checkNotNull(delimiter);
+ checkNotNull(completers);
+ this.completers.addAll(completers);
+ }
+
+ /**
+ * Create a new completer with the specified argument delimiter.
+ *
+ * @param delimiter The delimiter for parsing arguments
+ * @param completers The embedded completers
+ */
+ public ArgumentCompleter(final ArgumentDelimiter delimiter, final Completer... completers) {
+ this(delimiter, Arrays.asList(completers));
+ }
+
+ /**
+ * Create a new completer with the default {@link WhitespaceArgumentDelimiter}.
+ *
+ * @param completers The embedded completers
+ */
+ public ArgumentCompleter(final Completer... completers) {
+ this(new WhitespaceArgumentDelimiter(), completers);
+ }
+
+ /**
+ * Create a new completer with the default {@link WhitespaceArgumentDelimiter}.
+ *
+ * @param completers The embedded completers
+ */
+ public ArgumentCompleter(final List<Completer> completers) {
+ this(new WhitespaceArgumentDelimiter(), completers);
+ }
+
+ /**
+ * If true, a completion at argument index N will only succeed
+ * if all the completions from 0-(N-1) also succeed.
+ */
+ public void setStrict(final boolean strict) {
+ this.strict = strict;
+ }
+
+ /**
+ * Returns whether a completion at argument index N will success
+ * if all the completions from arguments 0-(N-1) also succeed.
+ *
+ * @return True if strict.
+ * @since 2.3
+ */
+ public boolean isStrict() {
+ return this.strict;
+ }
+
+ /**
+ * @since 2.3
+ */
+ public ArgumentDelimiter getDelimiter() {
+ return delimiter;
+ }
+
+ /**
+ * @since 2.3
+ */
+ public List<Completer> getCompleters() {
+ return completers;
+ }
+
+ public int complete(final String buffer, final int cursor, final List<CharSequence> candidates) {
+ // buffer can be null
+ checkNotNull(candidates);
+
+ ArgumentDelimiter delim = getDelimiter();
+ ArgumentList list = delim.delimit(buffer, cursor);
+ int argpos = list.getArgumentPosition();
+ int argIndex = list.getCursorArgumentIndex();
+
+ if (argIndex < 0) {
+ return -1;
+ }
+
+ List<Completer> completers = getCompleters();
+ Completer completer;
+
+ // if we are beyond the end of the completers, just use the last one
+ if (argIndex >= completers.size()) {
+ completer = completers.get(completers.size() - 1);
+ }
+ else {
+ completer = completers.get(argIndex);
+ }
+
+ // ensure that all the previous completers are successful before allowing this completer to pass (only if strict).
+ for (int i = 0; isStrict() && (i < argIndex); i++) {
+ Completer sub = completers.get(i >= completers.size() ? (completers.size() - 1) : i);
+ String[] args = list.getArguments();
+ String arg = (args == null || i >= args.length) ? "" : args[i];
+
+ List<CharSequence> subCandidates = new LinkedList<CharSequence>();
+
+ if (sub.complete(arg, arg.length(), subCandidates) == -1) {
+ return -1;
+ }
+
+ if (subCandidates.size() == 0) {
+ return -1;
+ }
+ }
+
+ int ret = completer.complete(list.getCursorArgument(), argpos, candidates);
+
+ if (ret == -1) {
+ return -1;
+ }
+
+ int pos = ret + list.getBufferPosition() - argpos;
+
+ // Special case: when completing in the middle of a line, and the area under the cursor is a delimiter,
+ // then trim any delimiters from the candidates, since we do not need to have an extra delimiter.
+ //
+ // E.g., if we have a completion for "foo", and we enter "f bar" into the buffer, and move to after the "f"
+ // and hit TAB, we want "foo bar" instead of "foo bar".
+
+ if ((cursor != buffer.length()) && delim.isDelimiter(buffer, cursor)) {
+ for (int i = 0; i < candidates.size(); i++) {
+ CharSequence val = candidates.get(i);
+
+ while (val.length() > 0 && delim.isDelimiter(val, val.length() - 1)) {
+ val = val.subSequence(0, val.length() - 1);
+ }
+
+ candidates.set(i, val);
+ }
+ }
+
+ Log.trace("Completing ", buffer, " (pos=", cursor, ") with: ", candidates, ": offset=", pos);
+
+ return pos;
+ }
+
+ /**
+ * The {@link ArgumentCompleter.ArgumentDelimiter} allows custom breaking up of a {@link String} into individual
+ * arguments in order to dispatch the arguments to the nested {@link Completer}.
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ */
+ public static interface ArgumentDelimiter
+ {
+ /**
+ * Break the specified buffer into individual tokens that can be completed on their own.
+ *
+ * @param buffer The buffer to split
+ * @param pos The current position of the cursor in the buffer
+ * @return The tokens
+ */
+ ArgumentList delimit(CharSequence buffer, int pos);
+
+ /**
+ * Returns true if the specified character is a whitespace parameter.
+ *
+ * @param buffer The complete command buffer
+ * @param pos The index of the character in the buffer
+ * @return True if the character should be a delimiter
+ */
+ boolean isDelimiter(CharSequence buffer, int pos);
+ }
+
+ /**
+ * Abstract implementation of a delimiter that uses the {@link #isDelimiter} method to determine if a particular
+ * character should be used as a delimiter.
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ */
+ public abstract static class AbstractArgumentDelimiter
+ implements ArgumentDelimiter
+ {
+ private char[] quoteChars = {'\'', '"'};
+
+ private char[] escapeChars = {'\\'};
+
+ public void setQuoteChars(final char[] chars) {
+ this.quoteChars = chars;
+ }
+
+ public char[] getQuoteChars() {
+ return this.quoteChars;
+ }
+
+ public void setEscapeChars(final char[] chars) {
+ this.escapeChars = chars;
+ }
+
+ public char[] getEscapeChars() {
+ return this.escapeChars;
+ }
+
+ public ArgumentList delimit(final CharSequence buffer, final int cursor) {
+ List<String> args = new LinkedList<String>();
+ StringBuilder arg = new StringBuilder();
+ int argpos = -1;
+ int bindex = -1;
+ int quoteStart = -1;
+
+ for (int i = 0; (buffer != null) && (i < buffer.length()); i++) {
+ // once we reach the cursor, set the
+ // position of the selected index
+ if (i == cursor) {
+ bindex = args.size();
+ // the position in the current argument is just the
+ // length of the current argument
+ argpos = arg.length();
+ }
+
+ if (quoteStart < 0 && isQuoteChar(buffer, i)) {
+ // Start a quote block
+ quoteStart = i;
+ } else if (quoteStart >= 0) {
+ // In a quote block
+ if (buffer.charAt(quoteStart) == buffer.charAt(i) && !isEscaped(buffer, i)) {
+ // End the block; arg could be empty, but that's fine
+ args.add(arg.toString());
+ arg.setLength(0);
+ quoteStart = -1;
+ } else if (!isEscapeChar(buffer, i)) {
+ // Take the next character
+ arg.append(buffer.charAt(i));
+ }
+ } else {
+ // Not in a quote block
+ if (isDelimiter(buffer, i)) {
+ if (arg.length() > 0) {
+ args.add(arg.toString());
+ arg.setLength(0); // reset the arg
+ }
+ } else if (!isEscapeChar(buffer, i)) {
+ arg.append(buffer.charAt(i));
+ }
+ }
+ }
+
+ if (cursor == buffer.length()) {
+ bindex = args.size();
+ // the position in the current argument is just the
+ // length of the current argument
+ argpos = arg.length();
+ }
+ if (arg.length() > 0) {
+ args.add(arg.toString());
+ }
+
+ return new ArgumentList(args.toArray(new String[args.size()]), bindex, argpos, cursor);
+ }
+
+ /**
+ * Returns true if the specified character is a whitespace parameter. Check to ensure that the character is not
+ * escaped by any of {@link #getQuoteChars}, and is not escaped by ant of the {@link #getEscapeChars}, and
+ * returns true from {@link #isDelimiterChar}.
+ *
+ * @param buffer The complete command buffer
+ * @param pos The index of the character in the buffer
+ * @return True if the character should be a delimiter
+ */
+ public boolean isDelimiter(final CharSequence buffer, final int pos) {
+ return !isQuoted(buffer, pos) && !isEscaped(buffer, pos) && isDelimiterChar(buffer, pos);
+ }
+
+ public boolean isQuoted(final CharSequence buffer, final int pos) {
+ return false;
+ }
+
+ public boolean isQuoteChar(final CharSequence buffer, final int pos) {
+ if (pos < 0) {
+ return false;
+ }
+
+ for (int i = 0; (quoteChars != null) && (i < quoteChars.length); i++) {
+ if (buffer.charAt(pos) == quoteChars[i]) {
+ return !isEscaped(buffer, pos);
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Check if this character is a valid escape char (i.e. one that has not been escaped)
+ *
+ * @param buffer
+ * @param pos
+ * @return
+ */
+ public boolean isEscapeChar(final CharSequence buffer, final int pos) {
+ if (pos < 0) {
+ return false;
+ }
+
+ for (int i = 0; (escapeChars != null) && (i < escapeChars.length); i++) {
+ if (buffer.charAt(pos) == escapeChars[i]) {
+ return !isEscaped(buffer, pos); // escape escape
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Check if a character is escaped (i.e. if the previous character is an escape)
+ *
+ * @param buffer
+ * the buffer to check in
+ * @param pos
+ * the position of the character to check
+ * @return true if the character at the specified position in the given buffer is an escape character and the character immediately preceding it is not an
+ * escape character.
+ */
+ public boolean isEscaped(final CharSequence buffer, final int pos) {
+ if (pos <= 0) {
+ return false;
+ }
+
+ return isEscapeChar(buffer, pos - 1);
+ }
+
+ /**
+ * Returns true if the character at the specified position if a delimiter. This method will only be called if
+ * the character is not enclosed in any of the {@link #getQuoteChars}, and is not escaped by ant of the
+ * {@link #getEscapeChars}. To perform escaping manually, override {@link #isDelimiter} instead.
+ */
+ public abstract boolean isDelimiterChar(CharSequence buffer, int pos);
+ }
+
+ /**
+ * {@link ArgumentCompleter.ArgumentDelimiter} implementation that counts all whitespace (as reported by
+ * {@link Character#isWhitespace}) as being a delimiter.
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ */
+ public static class WhitespaceArgumentDelimiter
+ extends AbstractArgumentDelimiter
+ {
+ /**
+ * The character is a delimiter if it is whitespace, and the
+ * preceding character is not an escape character.
+ */
+ @Override
+ public boolean isDelimiterChar(final CharSequence buffer, final int pos) {
+ return Character.isWhitespace(buffer.charAt(pos));
+ }
+ }
+
+ /**
+ * The result of a delimited buffer.
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ */
+ public static class ArgumentList
+ {
+ private String[] arguments;
+
+ private int cursorArgumentIndex;
+
+ private int argumentPosition;
+
+ private int bufferPosition;
+
+ /**
+ * @param arguments The array of tokens
+ * @param cursorArgumentIndex The token index of the cursor
+ * @param argumentPosition The position of the cursor in the current token
+ * @param bufferPosition The position of the cursor in the whole buffer
+ */
+ public ArgumentList(final String[] arguments, final int cursorArgumentIndex, final int argumentPosition, final int bufferPosition) {
+ this.arguments = checkNotNull(arguments);
+ this.cursorArgumentIndex = cursorArgumentIndex;
+ this.argumentPosition = argumentPosition;
+ this.bufferPosition = bufferPosition;
+ }
+
+ public void setCursorArgumentIndex(final int i) {
+ this.cursorArgumentIndex = i;
+ }
+
+ public int getCursorArgumentIndex() {
+ return this.cursorArgumentIndex;
+ }
+
+ public String getCursorArgument() {
+ if ((cursorArgumentIndex < 0) || (cursorArgumentIndex >= arguments.length)) {
+ return null;
+ }
+
+ return arguments[cursorArgumentIndex];
+ }
+
+ public void setArgumentPosition(final int pos) {
+ this.argumentPosition = pos;
+ }
+
+ public int getArgumentPosition() {
+ return this.argumentPosition;
+ }
+
+ public void setArguments(final String[] arguments) {
+ this.arguments = arguments;
+ }
+
+ public String[] getArguments() {
+ return this.arguments;
+ }
+
+ public void setBufferPosition(final int pos) {
+ this.bufferPosition = pos;
+ }
+
+ public int getBufferPosition() {
+ return this.bufferPosition;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/CandidateListCompletionHandler.java Wed Jul 05 20:41:12 2017 +0200
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.console.completer;
+
+import jdk.internal.jline.console.ConsoleReader;
+import jdk.internal.jline.console.CursorBuffer;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.ResourceBundle;
+import java.util.Set;
+
+/**
+ * A {@link CompletionHandler} that deals with multiple distinct completions
+ * by outputting the complete list of possibilities to the console. This
+ * mimics the behavior of the
+ * <a href="http://www.gnu.org/directory/readline.html">readline</a> library.
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.3
+ */
+public class CandidateListCompletionHandler
+ implements CompletionHandler
+{
+ // TODO: handle quotes and escaped quotes && enable automatic escaping of whitespace
+
+ public boolean complete(final ConsoleReader reader, final List<CharSequence> candidates, final int pos) throws
+ IOException
+ {
+ CursorBuffer buf = reader.getCursorBuffer();
+
+ // if there is only one completion, then fill in the buffer
+ if (candidates.size() == 1) {
+ CharSequence value = candidates.get(0);
+
+ // fail if the only candidate is the same as the current buffer
+ if (value.equals(buf.toString())) {
+ return false;
+ }
+
+ setBuffer(reader, value, pos);
+
+ return true;
+ }
+ else if (candidates.size() > 1) {
+ String value = getUnambiguousCompletions(candidates);
+ setBuffer(reader, value, pos);
+ }
+
+ printCandidates(reader, candidates);
+
+ // redraw the current console buffer
+ reader.drawLine();
+
+ return true;
+ }
+
+ public static void setBuffer(final ConsoleReader reader, final CharSequence value, final int offset) throws
+ IOException
+ {
+ while ((reader.getCursorBuffer().cursor > offset) && reader.backspace()) {
+ // empty
+ }
+
+ reader.putString(value);
+ reader.setCursorPosition(offset + value.length());
+ }
+
+ /**
+ * Print out the candidates. If the size of the candidates is greater than the
+ * {@link ConsoleReader#getAutoprintThreshold}, they prompt with a warning.
+ *
+ * @param candidates the list of candidates to print
+ */
+ public static void printCandidates(final ConsoleReader reader, Collection<CharSequence> candidates) throws
+ IOException
+ {
+ Set<CharSequence> distinct = new HashSet<CharSequence>(candidates);
+
+ if (distinct.size() > reader.getAutoprintThreshold()) {
+ //noinspection StringConcatenation
+ reader.print(Messages.DISPLAY_CANDIDATES.format(candidates.size()));
+ reader.flush();
+
+ int c;
+
+ String noOpt = Messages.DISPLAY_CANDIDATES_NO.format();
+ String yesOpt = Messages.DISPLAY_CANDIDATES_YES.format();
+ char[] allowed = {yesOpt.charAt(0), noOpt.charAt(0)};
+
+ while ((c = reader.readCharacter(allowed)) != -1) {
+ String tmp = new String(new char[]{(char) c});
+
+ if (noOpt.startsWith(tmp)) {
+ reader.println();
+ return;
+ }
+ else if (yesOpt.startsWith(tmp)) {
+ break;
+ }
+ else {
+ reader.beep();
+ }
+ }
+ }
+
+ // copy the values and make them distinct, without otherwise affecting the ordering. Only do it if the sizes differ.
+ if (distinct.size() != candidates.size()) {
+ Collection<CharSequence> copy = new ArrayList<CharSequence>();
+
+ for (CharSequence next : candidates) {
+ if (!copy.contains(next)) {
+ copy.add(next);
+ }
+ }
+
+ candidates = copy;
+ }
+
+ reader.println();
+ reader.printColumns(candidates);
+ }
+
+ /**
+ * Returns a root that matches all the {@link String} elements of the specified {@link List},
+ * or null if there are no commonalities. For example, if the list contains
+ * <i>foobar</i>, <i>foobaz</i>, <i>foobuz</i>, the method will return <i>foob</i>.
+ */
+ private String getUnambiguousCompletions(final List<CharSequence> candidates) {
+ if (candidates == null || candidates.isEmpty()) {
+ return null;
+ }
+
+ // convert to an array for speed
+ String[] strings = candidates.toArray(new String[candidates.size()]);
+
+ String first = strings[0];
+ StringBuilder candidate = new StringBuilder();
+
+ for (int i = 0; i < first.length(); i++) {
+ if (startsWith(first.substring(0, i + 1), strings)) {
+ candidate.append(first.charAt(i));
+ }
+ else {
+ break;
+ }
+ }
+
+ return candidate.toString();
+ }
+
+ /**
+ * @return true is all the elements of <i>candidates</i> start with <i>starts</i>
+ */
+ private boolean startsWith(final String starts, final String[] candidates) {
+ for (String candidate : candidates) {
+ if (!candidate.startsWith(starts)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private static enum Messages
+ {
+ DISPLAY_CANDIDATES,
+ DISPLAY_CANDIDATES_YES,
+ DISPLAY_CANDIDATES_NO,;
+
+ private static final
+ ResourceBundle
+ bundle =
+ ResourceBundle.getBundle(CandidateListCompletionHandler.class.getName(), Locale.getDefault());
+
+ public String format(final Object... args) {
+ if (bundle == null)
+ return "";
+ else
+ return String.format(bundle.getString(name()), args);
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/CandidateListCompletionHandler.properties Wed Jul 05 20:41:12 2017 +0200
@@ -0,0 +1,13 @@
+#
+# Copyright (c) 2002-2012, the original author or authors.
+#
+# This software is distributable under the BSD license. See the terms of the
+# BSD license in the documentation provided with this software.
+#
+# http://www.opensource.org/licenses/bsd-license.php
+#
+
+DISPLAY_CANDIDATES=Display all %d possibilities? (y or n)
+DISPLAY_CANDIDATES_YES=y
+DISPLAY_CANDIDATES_NO=n
+DISPLAY_MORE=--More--
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/Completer.java Wed Jul 05 20:41:12 2017 +0200
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.console.completer;
+
+import java.util.List;
+
+/**
+ * A completer is the mechanism by which tab-completion candidates will be resolved.
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.3
+ */
+public interface Completer
+{
+ //
+ // FIXME: Check if we can use CharSequece for buffer?
+ //
+
+ /**
+ * Populates <i>candidates</i> with a list of possible completions for the <i>buffer</i>.
+ *
+ * The <i>candidates</i> list will not be sorted before being displayed to the user: thus, the
+ * complete method should sort the {@link List} before returning.
+ *
+ * @param buffer The buffer
+ * @param cursor The current position of the cursor in the <i>buffer</i>
+ * @param candidates The {@link List} of candidates to populate
+ * @return The index of the <i>buffer</i> for which the completion will be relative
+ */
+ int complete(String buffer, int cursor, List<CharSequence> candidates);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/CompletionHandler.java Wed Jul 05 20:41:12 2017 +0200
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.console.completer;
+
+import jdk.internal.jline.console.ConsoleReader;
+
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * Handler for dealing with candidates for tab-completion.
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.3
+ */
+public interface CompletionHandler
+{
+ boolean complete(ConsoleReader reader, List<CharSequence> candidates, int position) throws IOException;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/EnumCompleter.java Wed Jul 05 20:41:12 2017 +0200
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.console.completer;
+
+import static jdk.internal.jline.internal.Preconditions.checkNotNull;
+
+/**
+ * {@link Completer} for {@link Enum} names.
+ *
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.3
+ */
+public class EnumCompleter
+ extends StringsCompleter
+{
+ public EnumCompleter(Class<? extends Enum<?>> source) {
+ checkNotNull(source);
+
+ for (Enum<?> n : source.getEnumConstants()) {
+ this.getStrings().add(n.name().toLowerCase());
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/FileNameCompleter.java Wed Jul 05 20:41:12 2017 +0200
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.console.completer;
+
+import jdk.internal.jline.internal.Configuration;
+
+import java.io.File;
+import java.util.List;
+
+import static jdk.internal.jline.internal.Preconditions.checkNotNull;
+
+/**
+ * A file name completer takes the buffer and issues a list of
+ * potential completions.
+ * <p/>
+ * This completer tries to behave as similar as possible to
+ * <i>bash</i>'s file name completion (using GNU readline)
+ * with the following exceptions:
+ * <p/>
+ * <ul>
+ * <li>Candidates that are directories will end with "/"</li>
+ * <li>Wildcard regular expressions are not evaluated or replaced</li>
+ * <li>The "~" character can be used to represent the user's home,
+ * but it cannot complete to other users' homes, since java does
+ * not provide any way of determining that easily</li>
+ * </ul>
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.3
+ */
+public class FileNameCompleter
+ implements Completer
+{
+ // TODO: Handle files with spaces in them
+
+ private static final boolean OS_IS_WINDOWS;
+
+ static {
+ String os = Configuration.getOsName();
+ OS_IS_WINDOWS = os.contains("windows");
+ }
+
+ public int complete(String buffer, final int cursor, final List<CharSequence> candidates) {
+ // buffer can be null
+ checkNotNull(candidates);
+
+ if (buffer == null) {
+ buffer = "";
+ }
+
+ if (OS_IS_WINDOWS) {
+ buffer = buffer.replace('/', '\\');
+ }
+
+ String translated = buffer;
+
+ File homeDir = getUserHome();
+
+ // Special character: ~ maps to the user's home directory
+ if (translated.startsWith("~" + separator())) {
+ translated = homeDir.getPath() + translated.substring(1);
+ }
+ else if (translated.startsWith("~")) {
+ translated = homeDir.getParentFile().getAbsolutePath();
+ }
+ else if (!(new File(translated).isAbsolute())) {
+ String cwd = getUserDir().getAbsolutePath();
+ translated = cwd + separator() + translated;
+ }
+
+ File file = new File(translated);
+ final File dir;
+
+ if (translated.endsWith(separator())) {
+ dir = file;
+ }
+ else {
+ dir = file.getParentFile();
+ }
+
+ File[] entries = dir == null ? new File[0] : dir.listFiles();
+
+ return matchFiles(buffer, translated, entries, candidates);
+ }
+
+ protected String separator() {
+ return File.separator;
+ }
+
+ protected File getUserHome() {
+ return Configuration.getUserHome();
+ }
+
+ protected File getUserDir() {
+ return new File(".");
+ }
+
+ protected int matchFiles(final String buffer, final String translated, final File[] files, final List<CharSequence> candidates) {
+ if (files == null) {
+ return -1;
+ }
+
+ int matches = 0;
+
+ // first pass: just count the matches
+ for (File file : files) {
+ if (file.getAbsolutePath().startsWith(translated)) {
+ matches++;
+ }
+ }
+ for (File file : files) {
+ if (file.getAbsolutePath().startsWith(translated)) {
+ CharSequence name = file.getName() + (matches == 1 && file.isDirectory() ? separator() : " ");
+ candidates.add(render(file, name).toString());
+ }
+ }
+
+ final int index = buffer.lastIndexOf(separator());
+
+ return index + separator().length();
+ }
+
+ protected CharSequence render(final File file, final CharSequence name) {
+ return name;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/NullCompleter.java Wed Jul 05 20:41:12 2017 +0200
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.console.completer;
+
+import java.util.List;
+
+/**
+ * Null completer.
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.3
+ */
+public final class NullCompleter
+ implements Completer
+{
+ public static final NullCompleter INSTANCE = new NullCompleter();
+
+ public int complete(final String buffer, final int cursor, final List<CharSequence> candidates) {
+ return -1;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/StringsCompleter.java Wed Jul 05 20:41:12 2017 +0200
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.console.completer;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import static jdk.internal.jline.internal.Preconditions.checkNotNull;
+
+/**
+ * Completer for a set of strings.
+ *
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.3
+ */
+public class StringsCompleter
+ implements Completer
+{
+ private final SortedSet<String> strings = new TreeSet<String>();
+
+ public StringsCompleter() {
+ // empty
+ }
+
+ public StringsCompleter(final Collection<String> strings) {
+ checkNotNull(strings);
+ getStrings().addAll(strings);
+ }
+
+ public StringsCompleter(final String... strings) {
+ this(Arrays.asList(strings));
+ }
+
+ public Collection<String> getStrings() {
+ return strings;
+ }
+
+ public int complete(final String buffer, final int cursor, final List<CharSequence> candidates) {
+ // buffer could be null
+ checkNotNull(candidates);
+
+ if (buffer == null) {
+ candidates.addAll(strings);
+ }
+ else {
+ for (String match : strings.tailSet(buffer)) {
+ if (!match.startsWith(buffer)) {
+ break;
+ }
+
+ candidates.add(match);
+ }
+ }
+
+ if (candidates.size() == 1) {
+ candidates.set(0, candidates.get(0) + " ");
+ }
+
+ return candidates.isEmpty() ? -1 : 0;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/package-info.java Wed Jul 05 20:41:12 2017 +0200
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+/**
+ * Console completer support.
+ *
+ * @since 2.3
+ */
+package jdk.internal.jline.console.completer;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/history/FileHistory.java Wed Jul 05 20:41:12 2017 +0200
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.console.history;
+
+import java.io.BufferedOutputStream;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.Flushable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.PrintStream;
+import java.io.Reader;
+
+import jdk.internal.jline.internal.Log;
+import static jdk.internal.jline.internal.Preconditions.checkNotNull;
+
+/**
+ * {@link History} using a file for persistent backing.
+ * <p/>
+ * Implementers should install shutdown hook to call {@link FileHistory#flush}
+ * to save history to disk.
+ *
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.0
+ */
+public class FileHistory
+ extends MemoryHistory
+ implements PersistentHistory, Flushable
+{
+ private final File file;
+
+ public FileHistory(final File file) throws IOException {
+ this.file = checkNotNull(file);
+ load(file);
+ }
+
+ public File getFile() {
+ return file;
+ }
+
+ public void load(final File file) throws IOException {
+ checkNotNull(file);
+ if (file.exists()) {
+ Log.trace("Loading history from: ", file);
+ load(new FileReader(file));
+ }
+ }
+
+ public void load(final InputStream input) throws IOException {
+ checkNotNull(input);
+ load(new InputStreamReader(input));
+ }
+
+ public void load(final Reader reader) throws IOException {
+ checkNotNull(reader);
+ BufferedReader input = new BufferedReader(reader);
+
+ String item;
+ while ((item = input.readLine()) != null) {
+ internalAdd(item);
+ }
+ }
+
+ public void flush() throws IOException {
+ Log.trace("Flushing history");
+
+ if (!file.exists()) {
+ File dir = file.getParentFile();
+ if (!dir.exists() && !dir.mkdirs()) {
+ Log.warn("Failed to create directory: ", dir);
+ }
+ if (!file.createNewFile()) {
+ Log.warn("Failed to create file: ", file);
+ }
+ }
+
+ PrintStream out = new PrintStream(new BufferedOutputStream(new FileOutputStream(file)));
+ try {
+ for (Entry entry : this) {
+ out.println(entry.value());
+ }
+ }
+ finally {
+ out.close();
+ }
+ }
+
+ public void purge() throws IOException {
+ Log.trace("Purging history");
+
+ clear();
+
+ if (!file.delete()) {
+ Log.warn("Failed to delete history file: ", file);
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/history/History.java Wed Jul 05 20:41:12 2017 +0200
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.console.history;
+
+import java.util.Iterator;
+import java.util.ListIterator;
+
+/**
+ * Console history.
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.3
+ */
+public interface History
+ extends Iterable<History.Entry>
+{
+ int size();
+
+ boolean isEmpty();
+
+ int index();
+
+ void clear();
+
+ CharSequence get(int index);
+
+ void add(CharSequence line);
+
+ /**
+ * Set the history item at the given index to the given CharSequence.
+ *
+ * @param index the index of the history offset
+ * @param item the new item
+ * @since 2.7
+ */
+ void set(int index, CharSequence item);
+
+ /**
+ * Remove the history element at the given index.
+ *
+ * @param i the index of the element to remove
+ * @return the removed element
+ * @since 2.7
+ */
+ CharSequence remove(int i);
+
+ /**
+ * Remove the first element from history.
+ *
+ * @return the removed element
+ * @since 2.7
+ */
+ CharSequence removeFirst();
+
+ /**
+ * Remove the last element from history
+ *
+ * @return the removed element
+ * @since 2.7
+ */
+ CharSequence removeLast();
+
+ void replace(CharSequence item);
+
+ //
+ // Entries
+ //
+
+ interface Entry
+ {
+ int index();
+
+ CharSequence value();
+ }
+
+ ListIterator<Entry> entries(int index);
+
+ ListIterator<Entry> entries();
+
+ Iterator<Entry> iterator();
+
+ //
+ // Navigation
+ //
+
+ CharSequence current();
+
+ boolean previous();
+
+ boolean next();
+
+ boolean moveToFirst();
+
+ boolean moveToLast();
+
+ boolean moveTo(int index);
+
+ void moveToEnd();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/history/MemoryHistory.java Wed Jul 05 20:41:12 2017 +0200
@@ -0,0 +1,348 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.console.history;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.ListIterator;
+import java.util.NoSuchElementException;
+
+import static jdk.internal.jline.internal.Preconditions.checkNotNull;
+
+/**
+ * Non-persistent {@link History}.
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.3
+ */
+public class MemoryHistory
+ implements History
+{
+ public static final int DEFAULT_MAX_SIZE = 500;
+
+ private final LinkedList<CharSequence> items = new LinkedList<CharSequence>();
+
+ private int maxSize = DEFAULT_MAX_SIZE;
+
+ private boolean ignoreDuplicates = true;
+
+ private boolean autoTrim = false;
+
+ // NOTE: These are all ideas from looking at the Bash man page:
+
+ // TODO: Add ignore space? (lines starting with a space are ignored)
+
+ // TODO: Add ignore patterns?
+
+ // TODO: Add history timestamp?
+
+ // TODO: Add erase dups?
+
+ private int offset = 0;
+
+ private int index = 0;
+
+ public void setMaxSize(final int maxSize) {
+ this.maxSize = maxSize;
+ maybeResize();
+ }
+
+ public int getMaxSize() {
+ return maxSize;
+ }
+
+ public boolean isIgnoreDuplicates() {
+ return ignoreDuplicates;
+ }
+
+ public void setIgnoreDuplicates(final boolean flag) {
+ this.ignoreDuplicates = flag;
+ }
+
+ public boolean isAutoTrim() {
+ return autoTrim;
+ }
+
+ public void setAutoTrim(final boolean flag) {
+ this.autoTrim = flag;
+ }
+
+ public int size() {
+ return items.size();
+ }
+
+ public boolean isEmpty() {
+ return items.isEmpty();
+ }
+
+ public int index() {
+ return offset + index;
+ }
+
+ public void clear() {
+ items.clear();
+ offset = 0;
+ index = 0;
+ }
+
+ public CharSequence get(final int index) {
+ return items.get(index - offset);
+ }
+
+ public void set(int index, CharSequence item) {
+ items.set(index - offset, item);
+ }
+
+ public void add(CharSequence item) {
+ checkNotNull(item);
+
+ if (isAutoTrim()) {
+ item = String.valueOf(item).trim();
+ }
+
+ if (isIgnoreDuplicates()) {
+ if (!items.isEmpty() && item.equals(items.getLast())) {
+ return;
+ }
+ }
+
+ internalAdd(item);
+ }
+
+ public CharSequence remove(int i) {
+ return items.remove(i);
+ }
+
+ public CharSequence removeFirst() {
+ return items.removeFirst();
+ }
+
+ public CharSequence removeLast() {
+ return items.removeLast();
+ }
+
+ protected void internalAdd(CharSequence item) {
+ items.add(item);
+
+ maybeResize();
+ }
+
+ public void replace(final CharSequence item) {
+ items.removeLast();
+ add(item);
+ }
+
+ private void maybeResize() {
+ while (size() > getMaxSize()) {
+ items.removeFirst();
+ offset++;
+ }
+
+ index = size();
+ }
+
+ public ListIterator<Entry> entries(final int index) {
+ return new EntriesIterator(index - offset);
+ }
+
+ public ListIterator<Entry> entries() {
+ return entries(offset);
+ }
+
+ public Iterator<Entry> iterator() {
+ return entries();
+ }
+
+ private static class EntryImpl
+ implements Entry
+ {
+ private final int index;
+
+ private final CharSequence value;
+
+ public EntryImpl(int index, CharSequence value) {
+ this.index = index;
+ this.value = value;
+ }
+
+ public int index() {
+ return index;
+ }
+
+ public CharSequence value() {
+ return value;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("%d: %s", index, value);
+ }
+ }
+
+ private class EntriesIterator
+ implements ListIterator<Entry>
+ {
+ private final ListIterator<CharSequence> source;
+
+ private EntriesIterator(final int index) {
+ source = items.listIterator(index);
+ }
+
+ public Entry next() {
+ if (!source.hasNext()) {
+ throw new NoSuchElementException();
+ }
+ return new EntryImpl(offset + source.nextIndex(), source.next());
+ }
+
+ public Entry previous() {
+ if (!source.hasPrevious()) {
+ throw new NoSuchElementException();
+ }
+ return new EntryImpl(offset + source.previousIndex(), source.previous());
+ }
+
+ public int nextIndex() {
+ return offset + source.nextIndex();
+ }
+
+ public int previousIndex() {
+ return offset + source.previousIndex();
+ }
+
+ public boolean hasNext() {
+ return source.hasNext();
+ }
+
+ public boolean hasPrevious() {
+ return source.hasPrevious();
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+ public void set(final Entry entry) {
+ throw new UnsupportedOperationException();
+ }
+
+ public void add(final Entry entry) {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ //
+ // Navigation
+ //
+
+ /**
+ * This moves the history to the last entry. This entry is one position
+ * before the moveToEnd() position.
+ *
+ * @return Returns false if there were no history entries or the history
+ * index was already at the last entry.
+ */
+ public boolean moveToLast() {
+ int lastEntry = size() - 1;
+ if (lastEntry >= 0 && lastEntry != index) {
+ index = size() - 1;
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Move to the specified index in the history
+ * @param index
+ * @return
+ */
+ public boolean moveTo(int index) {
+ index -= offset;
+ if (index >= 0 && index < size() ) {
+ this.index = index;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Moves the history index to the first entry.
+ *
+ * @return Return false if there are no entries in the history or if the
+ * history is already at the beginning.
+ */
+ public boolean moveToFirst() {
+ if (size() > 0 && index != 0) {
+ index = 0;
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Move to the end of the history buffer. This will be a blank entry, after
+ * all of the other entries.
+ */
+ public void moveToEnd() {
+ index = size();
+ }
+
+ /**
+ * Return the content of the current buffer.
+ */
+ public CharSequence current() {
+ if (index >= size()) {
+ return "";
+ }
+
+ return items.get(index);
+ }
+
+ /**
+ * Move the pointer to the previous element in the buffer.
+ *
+ * @return true if we successfully went to the previous element
+ */
+ public boolean previous() {
+ if (index <= 0) {
+ return false;
+ }
+
+ index--;
+
+ return true;
+ }
+
+ /**
+ * Move the pointer to the next element in the buffer.
+ *
+ * @return true if we successfully went to the next element
+ */
+ public boolean next() {
+ if (index >= size()) {
+ return false;
+ }
+
+ index++;
+
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ for (Entry e : this) {
+ sb.append(e.toString() + "\n");
+ }
+ return sb.toString();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/history/PersistentHistory.java Wed Jul 05 20:41:12 2017 +0200
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.console.history;
+
+import java.io.IOException;
+
+/**
+ * Persistent {@link History}.
+ *
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.3
+ */
+public interface PersistentHistory
+ extends History
+{
+ /**
+ * Flush all items to persistent storage.
+ *
+ * @throws IOException Flush failed
+ */
+ void flush() throws IOException;
+
+ /**
+ * Purge persistent storage and {@link #clear}.
+ *
+ * @throws IOException Purge failed
+ */
+ void purge() throws IOException;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/history/package-info.java Wed Jul 05 20:41:12 2017 +0200
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+/**
+ * Console history support.
+ *
+ * @since 2.0
+ */
+package jdk.internal.jline.console.history;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/internal/ConsoleReaderInputStream.java Wed Jul 05 20:41:12 2017 +0200
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.console.internal;
+
+import jdk.internal.jline.console.ConsoleReader;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.SequenceInputStream;
+import java.util.Enumeration;
+
+// FIXME: Clean up API and move to jline.console.runner package
+
+/**
+ * An {@link InputStream} implementation that wraps a {@link ConsoleReader}.
+ * It is useful for setting up the {@link System#in} for a generic console.
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ * @since 2.7
+ */
+class ConsoleReaderInputStream
+ extends SequenceInputStream
+{
+ private static InputStream systemIn = System.in;
+
+ public static void setIn() throws IOException {
+ setIn(new ConsoleReader());
+ }
+
+ public static void setIn(final ConsoleReader reader) {
+ System.setIn(new ConsoleReaderInputStream(reader));
+ }
+
+ /**
+ * Restore the original {@link System#in} input stream.
+ */
+ public static void restoreIn() {
+ System.setIn(systemIn);
+ }
+
+ public ConsoleReaderInputStream(final ConsoleReader reader) {
+ super(new ConsoleEnumeration(reader));
+ }
+
+ private static class ConsoleEnumeration
+ implements Enumeration<InputStream>
+ {
+ private final ConsoleReader reader;
+ private ConsoleLineInputStream next = null;
+ private ConsoleLineInputStream prev = null;
+
+ public ConsoleEnumeration(final ConsoleReader reader) {
+ this.reader = reader;
+ }
+
+ public InputStream nextElement() {
+ if (next != null) {
+ InputStream n = next;
+ prev = next;
+ next = null;
+
+ return n;
+ }
+
+ return new ConsoleLineInputStream(reader);
+ }
+
+ public boolean hasMoreElements() {
+ // the last line was null
+ if ((prev != null) && (prev.wasNull == true)) {
+ return false;
+ }
+
+ if (next == null) {
+ next = (ConsoleLineInputStream) nextElement();
+ }
+
+ return next != null;
+ }
+ }
+
+ private static class ConsoleLineInputStream
+ extends InputStream
+ {
+ private final ConsoleReader reader;
+ private String line = null;
+ private int index = 0;
+ private boolean eol = false;
+ protected boolean wasNull = false;
+
+ public ConsoleLineInputStream(final ConsoleReader reader) {
+ this.reader = reader;
+ }
+
+ public int read() throws IOException {
+ if (eol) {
+ return -1;
+ }
+
+ if (line == null) {
+ line = reader.readLine();
+ }
+
+ if (line == null) {
+ wasNull = true;
+ return -1;
+ }
+
+ if (index >= line.length()) {
+ eol = true;
+ return '\n'; // lines are ended with a newline
+ }
+
+ return line.charAt(index++);
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/internal/ConsoleRunner.java Wed Jul 05 20:41:12 2017 +0200
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.console.internal;
+
+import jdk.internal.jline.console.ConsoleReader;
+import jdk.internal.jline.console.completer.ArgumentCompleter;
+import jdk.internal.jline.console.completer.Completer;
+import jdk.internal.jline.console.history.FileHistory;
+import jdk.internal.jline.internal.Configuration;
+
+import java.io.File;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.StringTokenizer;
+
+// FIXME: Clean up API and move to jline.console.runner package
+
+/**
+ * A pass-through application that sets the system input stream to a
+ * {@link ConsoleReader} and invokes the specified main method.
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ * @since 2.7
+ */
+public class ConsoleRunner
+{
+ public static final String property = "jline.history";
+
+ // FIXME: This is really ugly... re-write this
+
+ public static void main(final String[] args) throws Exception {
+ List<String> argList = new ArrayList<String>(Arrays.asList(args));
+ if (argList.size() == 0) {
+ usage();
+ return;
+ }
+
+ String historyFileName = System.getProperty(ConsoleRunner.property, null);
+
+ String mainClass = argList.remove(0);
+ ConsoleReader reader = new ConsoleReader();
+
+ if (historyFileName != null) {
+ reader.setHistory(new FileHistory(new File(Configuration.getUserHome(),
+ String.format(".jline-%s.%s.history", mainClass, historyFileName))));
+ }
+ else {
+ reader.setHistory(new FileHistory(new File(Configuration.getUserHome(),
+ String.format(".jline-%s.history", mainClass))));
+ }
+
+ String completors = System.getProperty(ConsoleRunner.class.getName() + ".completers", "");
+ List<Completer> completorList = new ArrayList<Completer>();
+
+ for (StringTokenizer tok = new StringTokenizer(completors, ","); tok.hasMoreTokens();) {
+ Object obj = Class.forName(tok.nextToken()).newInstance();
+ completorList.add((Completer) obj);
+ }
+
+ if (completorList.size() > 0) {
+ reader.addCompleter(new ArgumentCompleter(completorList));
+ }
+
+ ConsoleReaderInputStream.setIn(reader);
+
+ try {
+ Class<?> type = Class.forName(mainClass);
+ Method method = type.getMethod("main", String[].class);
+ method.invoke(null);
+ }
+ finally {
+ // just in case this main method is called from another program
+ ConsoleReaderInputStream.restoreIn();
+ }
+ }
+
+ private static void usage() {
+ System.out.println("Usage: \n java " + "[-Djline.history='name'] "
+ + ConsoleRunner.class.getName()
+ + " <target class name> [args]"
+ + "\n\nThe -Djline.history option will avoid history"
+ + "\nmangling when running ConsoleRunner on the same application."
+ + "\n\nargs will be passed directly to the target class name.");
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/package-info.java Wed Jul 05 20:41:12 2017 +0200
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+/**
+ * Console support.
+ *
+ * @since 2.0
+ */
+package jdk.internal.jline.console;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/Configuration.java Wed Jul 05 20:41:12 2017 +0200
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.internal;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.nio.charset.Charset;
+import java.util.Map;
+import java.util.Properties;
+
+import static jdk.internal.jline.internal.Preconditions.checkNotNull;
+
+/**
+ * Provides access to configuration values.
+ *
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @author <a href="mailto:gnodet@gmail.com">Guillaume Nodet</a>
+ * @since 2.4
+ */
+public class Configuration
+{
+ /**
+ * System property which can point to a file or URL containing configuration properties to load.
+ *
+ * @since 2.7
+ */
+ public static final String JLINE_CONFIGURATION = "jline.configuration";
+
+ /**
+ * Default configuration file name loaded from user's home directory.
+ */
+ public static final String JLINE_RC = ".jline.rc";
+
+ private static volatile Properties properties;
+
+ private static Properties initProperties() {
+ URL url = determineUrl();
+ Properties props = new Properties();
+ try {
+ loadProperties(url, props);
+ }
+ catch (IOException e) {
+ // debug here instead of warn, as this can happen normally if default jline.rc file is missing
+ Log.debug("Unable to read configuration from: ", url, e);
+ }
+ return props;
+ }
+
+ private static void loadProperties(final URL url, final Properties props) throws IOException {
+ Log.debug("Loading properties from: ", url);
+ InputStream input = url.openStream();
+ try {
+ props.load(new BufferedInputStream(input));
+ }
+ finally {
+ try {
+ input.close();
+ }
+ catch (IOException e) {
+ // ignore
+ }
+ }
+
+ if (Log.DEBUG) {
+ Log.debug("Loaded properties:");
+ for (Map.Entry<Object,Object> entry : props.entrySet()) {
+ Log.debug(" ", entry.getKey(), "=", entry.getValue());
+ }
+ }
+ }
+
+ private static URL determineUrl() {
+ // See if user has customized the configuration location via sysprop
+ String tmp = System.getProperty(JLINE_CONFIGURATION);
+ if (tmp != null) {
+ return Urls.create(tmp);
+ }
+ else {
+ // Otherwise try the default
+ File file = new File(getUserHome(), JLINE_RC);
+ return Urls.create(file);
+ }
+ }
+
+ /**
+ * @since 2.7
+ */
+ public static void reset() {
+ Log.debug("Resetting");
+ properties = null;
+
+ // force new properties to load
+ getProperties();
+ }
+
+ /**
+ * @since 2.7
+ */
+ public static Properties getProperties() {
+ // Not sure its worth to guard this with any synchronization, volatile field probably sufficient
+ if (properties == null) {
+ properties = initProperties();
+ }
+ return properties;
+ }
+
+ public static String getString(final String name, final String defaultValue) {
+ checkNotNull(name);
+
+ String value;
+
+ // Check sysprops first, it always wins
+ value = System.getProperty(name);
+
+ if (value == null) {
+ // Next try userprops
+ value = getProperties().getProperty(name);
+
+ if (value == null) {
+ // else use the default
+ value = defaultValue;
+ }
+ }
+
+ return value;
+ }
+
+ public static String getString(final String name) {
+ return getString(name, null);
+ }
+
+ public static boolean getBoolean(final String name, final boolean defaultValue) {
+ String value = getString(name);
+ if (value == null) {
+ return defaultValue;
+ }
+ return value.length() == 0
+ || value.equalsIgnoreCase("1")
+ || value.equalsIgnoreCase("on")
+ || value.equalsIgnoreCase("true");
+ }
+
+ /**
+ * @since 2.6
+ */
+ public static int getInteger(final String name, final int defaultValue) {
+ String str = getString(name);
+ if (str == null) {
+ return defaultValue;
+ }
+ return Integer.parseInt(str);
+ }
+
+ /**
+ * @since 2.6
+ */
+ public static long getLong(final String name, final long defaultValue) {
+ String str = getString(name);
+ if (str == null) {
+ return defaultValue;
+ }
+ return Long.parseLong(str);
+ }
+
+ //
+ // System property helpers
+ //
+
+ /**
+ * @since 2.7
+ */
+ public static String getLineSeparator() {
+ return System.getProperty("line.separator");
+ }
+
+ public static File getUserHome() {
+ return new File(System.getProperty("user.home"));
+ }
+
+ public static String getOsName() {
+ return System.getProperty("os.name").toLowerCase();
+ }
+
+ /**
+ * @since 2.7
+ */
+ public static boolean isWindows() {
+ return getOsName().startsWith("windows");
+ }
+
+ // FIXME: Sort out use of property access of file.encoding in InputStreamReader, consolidate should configuration access here
+
+ public static String getFileEncoding() {
+ return System.getProperty("file.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.
+ *
+ * @return The default encoding to use when none is specified.
+ */
+ public static String getEncoding() {
+ // LC_CTYPE is usually in the form en_US.UTF-8
+ String envEncoding = extractEncodingFromCtype(System.getenv("LC_CTYPE"));
+ if (envEncoding != null) {
+ return envEncoding;
+ }
+ return System.getProperty("input.encoding", Charset.defaultCharset().name());
+ }
+
+ /**
+ * Parses the LC_CTYPE value to extract the encoding according to the POSIX standard, which says that the LC_CTYPE
+ * environment variable may be of the format <code>[language[_territory][.codeset][@modifier]]</code>
+ *
+ * @param ctype The ctype to parse, may be null
+ * @return The encoding, if one was present, otherwise null
+ */
+ static String extractEncodingFromCtype(String ctype) {
+ if (ctype != null && ctype.indexOf('.') > 0) {
+ String encodingAndModifier = ctype.substring(ctype.indexOf('.') + 1);
+ if (encodingAndModifier.indexOf('@') > 0) {
+ return encodingAndModifier.substring(0, encodingAndModifier.indexOf('@'));
+ } else {
+ return encodingAndModifier;
+ }
+ }
+ return null;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/InputStreamReader.java Wed Jul 05 20:41:12 2017 +0200
@@ -0,0 +1,338 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.internal;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.UnsupportedEncodingException;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CoderResult;
+import java.nio.charset.CodingErrorAction;
+import java.nio.charset.MalformedInputException;
+import java.nio.charset.UnmappableCharacterException;
+
+
+/**
+ *
+ * NOTE for JLine: the default InputStreamReader that comes from the JRE
+ * usually read more bytes than needed from the input stream, which
+ * is not usable in a character per character model used in the console.
+ * We thus use the harmony code which only reads the minimal number of bytes,
+ * with a modification to ensure we can read larger characters (UTF-16 has
+ * up to 4 bytes, and UTF-32, rare as it is, may have up to 8).
+ */
+/**
+ * A class for turning a byte stream into a character stream. Data read from the
+ * source input stream is converted into characters by either a default or a
+ * provided character converter. The default encoding is taken from the
+ * "file.encoding" system property. {@code InputStreamReader} contains a buffer
+ * of bytes read from the source stream and converts these into characters as
+ * needed. The buffer size is 8K.
+ *
+ * @see OutputStreamWriter
+ */
+public class InputStreamReader extends Reader {
+ private InputStream in;
+
+ private static final int BUFFER_SIZE = 8192;
+
+ private boolean endOfInput = false;
+
+ String encoding;
+
+ CharsetDecoder decoder;
+
+ ByteBuffer bytes = ByteBuffer.allocate(BUFFER_SIZE);
+
+ /**
+ * Constructs a new {@code InputStreamReader} on the {@link InputStream}
+ * {@code in}. This constructor sets the character converter to the encoding
+ * specified in the "file.encoding" property and falls back to ISO 8859_1
+ * (ISO-Latin-1) if the property doesn't exist.
+ *
+ * @param in
+ * the input stream from which to read characters.
+ */
+ public InputStreamReader(InputStream in) {
+ super(in);
+ this.in = in;
+ // FIXME: This should probably use Configuration.getFileEncoding()
+ encoding = System.getProperty("file.encoding", "ISO8859_1"); //$NON-NLS-1$//$NON-NLS-2$
+ decoder = Charset.forName(encoding).newDecoder().onMalformedInput(
+ CodingErrorAction.REPLACE).onUnmappableCharacter(
+ CodingErrorAction.REPLACE);
+ bytes.limit(0);
+ }
+
+ /**
+ * Constructs a new InputStreamReader on the InputStream {@code in}. The
+ * character converter that is used to decode bytes into characters is
+ * identified by name by {@code enc}. If the encoding cannot be found, an
+ * UnsupportedEncodingException error is thrown.
+ *
+ * @param in
+ * the InputStream from which to read characters.
+ * @param enc
+ * identifies the character converter to use.
+ * @throws NullPointerException
+ * if {@code enc} is {@code null}.
+ * @throws UnsupportedEncodingException
+ * if the encoding specified by {@code enc} cannot be found.
+ */
+ public InputStreamReader(InputStream in, final String enc)
+ throws UnsupportedEncodingException {
+ super(in);
+ if (enc == null) {
+ throw new NullPointerException();
+ }
+ this.in = in;
+ try {
+ decoder = Charset.forName(enc).newDecoder().onMalformedInput(
+ CodingErrorAction.REPLACE).onUnmappableCharacter(
+ CodingErrorAction.REPLACE);
+ } catch (IllegalArgumentException e) {
+ throw (UnsupportedEncodingException)
+ new UnsupportedEncodingException(enc).initCause(e);
+ }
+ bytes.limit(0);
+ }
+
+ /**
+ * Constructs a new InputStreamReader on the InputStream {@code in} and
+ * CharsetDecoder {@code dec}.
+ *
+ * @param in
+ * the source InputStream from which to read characters.
+ * @param dec
+ * the CharsetDecoder used by the character conversion.
+ */
+ public InputStreamReader(InputStream in, CharsetDecoder dec) {
+ super(in);
+ dec.averageCharsPerByte();
+ this.in = in;
+ decoder = dec;
+ bytes.limit(0);
+ }
+
+ /**
+ * Constructs a new InputStreamReader on the InputStream {@code in} and
+ * Charset {@code charset}.
+ *
+ * @param in
+ * the source InputStream from which to read characters.
+ * @param charset
+ * the Charset that defines the character converter
+ */
+ public InputStreamReader(InputStream in, Charset charset) {
+ super(in);
+ this.in = in;
+ decoder = charset.newDecoder().onMalformedInput(
+ CodingErrorAction.REPLACE).onUnmappableCharacter(
+ CodingErrorAction.REPLACE);
+ bytes.limit(0);
+ }
+
+ /**
+ * Closes this reader. This implementation closes the source InputStream and
+ * releases all local storage.
+ *
+ * @throws IOException
+ * if an error occurs attempting to close this reader.
+ */
+ @Override
+ public void close() throws IOException {
+ synchronized (lock) {
+ decoder = null;
+ if (in != null) {
+ in.close();
+ in = null;
+ }
+ }
+ }
+
+ /**
+ * Returns the name of the encoding used to convert bytes into characters.
+ * The value {@code null} is returned if this reader has been closed.
+ *
+ * @return the name of the character converter or {@code null} if this
+ * reader is closed.
+ */
+ public String getEncoding() {
+ if (!isOpen()) {
+ return null;
+ }
+ return encoding;
+ }
+
+ /**
+ * Reads a single character from this reader and returns it as an integer
+ * with the two higher-order bytes set to 0. Returns -1 if the end of the
+ * reader has been reached. The byte value is either obtained from
+ * converting bytes in this reader's buffer or by first filling the buffer
+ * from the source InputStream and then reading from the buffer.
+ *
+ * @return the character read or -1 if the end of the reader has been
+ * reached.
+ * @throws IOException
+ * if this reader is closed or some other I/O error occurs.
+ */
+ @Override
+ public int read() throws IOException {
+ synchronized (lock) {
+ if (!isOpen()) {
+ throw new IOException("InputStreamReader is closed.");
+ }
+
+ char buf[] = new char[4];
+ return read(buf, 0, 4) != -1 ? Character.codePointAt(buf, 0) : -1;
+ }
+ }
+
+ /**
+ * Reads at most {@code length} characters from this reader and stores them
+ * at position {@code offset} in the character array {@code buf}. Returns
+ * the number of characters actually read or -1 if the end of the reader has
+ * been reached. The bytes are either obtained from converting bytes in this
+ * reader's buffer or by first filling the buffer from the source
+ * InputStream and then reading from the buffer.
+ *
+ * @param buf
+ * the array to store the characters read.
+ * @param offset
+ * the initial position in {@code buf} to store the characters
+ * read from this reader.
+ * @param length
+ * the maximum number of characters to read.
+ * @return the number of characters read or -1 if the end of the reader has
+ * been reached.
+ * @throws IndexOutOfBoundsException
+ * if {@code offset < 0} or {@code length < 0}, or if
+ * {@code offset + length} is greater than the length of
+ * {@code buf}.
+ * @throws IOException
+ * if this reader is closed or some other I/O error occurs.
+ */
+ @Override
+ public int read(char[] buf, int offset, int length) throws IOException {
+ synchronized (lock) {
+ if (!isOpen()) {
+ throw new IOException("InputStreamReader is closed.");
+ }
+ if (offset < 0 || offset > buf.length - length || length < 0) {
+ throw new IndexOutOfBoundsException();
+ }
+ if (length == 0) {
+ return 0;
+ }
+
+ CharBuffer out = CharBuffer.wrap(buf, offset, length);
+ CoderResult result = CoderResult.UNDERFLOW;
+
+ // bytes.remaining() indicates number of bytes in buffer
+ // when 1-st time entered, it'll be equal to zero
+ boolean needInput = !bytes.hasRemaining();
+
+ while (out.hasRemaining()) {
+ // fill the buffer if needed
+ if (needInput) {
+ try {
+ if ((in.available() == 0)
+ && (out.position() > offset)) {
+ // we could return the result without blocking read
+ break;
+ }
+ } catch (IOException e) {
+ // available didn't work so just try the read
+ }
+
+ int to_read = bytes.capacity() - bytes.limit();
+ int off = bytes.arrayOffset() + bytes.limit();
+ int was_red = in.read(bytes.array(), off, to_read);
+
+ if (was_red == -1) {
+ endOfInput = true;
+ break;
+ } else if (was_red == 0) {
+ break;
+ }
+ bytes.limit(bytes.limit() + was_red);
+ needInput = false;
+ }
+
+ // decode bytes
+ result = decoder.decode(bytes, out, false);
+
+ if (result.isUnderflow()) {
+ // compact the buffer if no space left
+ if (bytes.limit() == bytes.capacity()) {
+ bytes.compact();
+ bytes.limit(bytes.position());
+ bytes.position(0);
+ }
+ needInput = true;
+ } else {
+ break;
+ }
+ }
+
+ if (result == CoderResult.UNDERFLOW && endOfInput) {
+ result = decoder.decode(bytes, out, true);
+ decoder.flush(out);
+ decoder.reset();
+ }
+ if (result.isMalformed()) {
+ throw new MalformedInputException(result.length());
+ } else if (result.isUnmappable()) {
+ throw new UnmappableCharacterException(result.length());
+ }
+
+ return out.position() - offset == 0 ? -1 : out.position() - offset;
+ }
+ }
+
+ /*
+ * Answer a boolean indicating whether or not this InputStreamReader is
+ * open.
+ */
+ private boolean isOpen() {
+ return in != null;
+ }
+
+ /**
+ * Indicates whether this reader is ready to be read without blocking. If
+ * the result is {@code true}, the next {@code read()} will not block. If
+ * the result is {@code false} then this reader may or may not block when
+ * {@code read()} is called. This implementation returns {@code true} if
+ * there are bytes available in the buffer or the source stream has bytes
+ * available.
+ *
+ * @return {@code true} if the receiver will not block when {@code read()}
+ * is called, {@code false} if unknown or blocking will occur.
+ * @throws IOException
+ * if this reader is closed or some other I/O error occurs.
+ */
+ @Override
+ public boolean ready() throws IOException {
+ synchronized (lock) {
+ if (in == null) {
+ throw new IOException("InputStreamReader is closed.");
+ }
+ try {
+ return bytes.hasRemaining() || in.available() > 0;
+ } catch (IOException e) {
+ return false;
+ }
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/Log.java Wed Jul 05 20:41:12 2017 +0200
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.internal;
+
+import java.io.PrintStream;
+
+import static jdk.internal.jline.internal.Preconditions.checkNotNull;
+
+/**
+ * Internal logger.
+ *
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.0
+ */
+public final class Log
+{
+ ///CLOVER:OFF
+
+ public static enum Level
+ {
+ TRACE,
+ DEBUG,
+ INFO,
+ WARN,
+ ERROR
+ }
+
+ @SuppressWarnings({"StringConcatenation"})
+ public static final boolean TRACE = Boolean.getBoolean(Log.class.getName() + ".trace");
+
+ @SuppressWarnings({"StringConcatenation"})
+ public static final boolean DEBUG = TRACE || Boolean.getBoolean(Log.class.getName() + ".debug");
+
+ private static PrintStream output = System.err;
+
+ public static PrintStream getOutput() {
+ return output;
+ }
+
+ public static void setOutput(final PrintStream out) {
+ output = checkNotNull(out);
+ }
+
+ /**
+ * Helper to support rendering messages.
+ */
+ @TestAccessible
+ static void render(final PrintStream out, final Object message) {
+ if (message.getClass().isArray()) {
+ Object[] array = (Object[]) message;
+
+ out.print("[");
+ for (int i = 0; i < array.length; i++) {
+ out.print(array[i]);
+ if (i + 1 < array.length) {
+ out.print(",");
+ }
+ }
+ out.print("]");
+ }
+ else {
+ out.print(message);
+ }
+ }
+
+ @TestAccessible
+ static void log(final Level level, final Object... messages) {
+ //noinspection SynchronizeOnNonFinalField
+ synchronized (output) {
+ output.format("[%s] ", level);
+
+ for (int i=0; i<messages.length; i++) {
+ // Special handling for the last message if its a throwable, render its stack on the next line
+ if (i + 1 == messages.length && messages[i] instanceof Throwable) {
+ output.println();
+ ((Throwable)messages[i]).printStackTrace(output);
+ }
+ else {
+ render(output, messages[i]);
+ }
+ }
+
+ output.println();
+ output.flush();
+ }
+ }
+
+ public static void trace(final Object... messages) {
+ if (TRACE) {
+ log(Level.TRACE, messages);
+ }
+ }
+
+ public static void debug(final Object... messages) {
+ if (TRACE || DEBUG) {
+ log(Level.DEBUG, messages);
+ }
+ }
+
+ /**
+ * @since 2.7
+ */
+ public static void info(final Object... messages) {
+ log(Level.INFO, messages);
+ }
+
+ public static void warn(final Object... messages) {
+ log(Level.WARN, messages);
+ }
+
+ public static void error(final Object... messages) {
+ log(Level.ERROR, messages);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/NonBlockingInputStream.java Wed Jul 05 20:41:12 2017 +0200
@@ -0,0 +1,314 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.internal;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * This class wraps a regular input stream and allows it to appear as if it
+ * is non-blocking; that is, reads can be performed against it that timeout
+ * if no data is seen for a period of time. This effect is achieved by having
+ * a separate thread perform all non-blocking read requests and then
+ * waiting on the thread to complete.
+ *
+ * <p>VERY IMPORTANT NOTES
+ * <ul>
+ * <li> This class is not thread safe. It expects at most one reader.
+ * <li> The {@link #shutdown()} method must be called in order to shut down
+ * the thread that handles blocking I/O.
+ * </ul>
+ * @since 2.7
+ * @author Scott C. Gray <scottgray1@gmail.com>
+ */
+public class NonBlockingInputStream
+ extends InputStream
+ implements Runnable
+{
+ private InputStream in; // The actual input stream
+ private int ch = -2; // Recently read character
+
+ private boolean threadIsReading = false;
+ private boolean isShutdown = false;
+ private IOException exception = null;
+ private boolean nonBlockingEnabled;
+
+ /**
+ * Creates a <code>NonBlockingInputStream</code> out of a normal blocking
+ * stream. Note that this call also spawn a separate thread to perform the
+ * blocking I/O on behalf of the thread that is using this class. The
+ * {@link #shutdown()} method must be called in order to shut this thread down.
+ * @param in The input stream to wrap
+ * @param isNonBlockingEnabled If true, then the non-blocking methods
+ * {@link #read(long)} and {@link #peek(long)} will be available and,
+ * more importantly, the thread will be started to provide support for the
+ * feature. If false, then this class acts as a clean-passthru for the
+ * underlying I/O stream and provides very little overhead.
+ */
+ public NonBlockingInputStream (InputStream in, boolean isNonBlockingEnabled) {
+ this.in = in;
+ this.nonBlockingEnabled = isNonBlockingEnabled;
+
+ if (isNonBlockingEnabled) {
+ Thread t = new Thread(this);
+ t.setName("NonBlockingInputStreamThread");
+ t.setDaemon(true);
+ t.start();
+ }
+ }
+
+ /**
+ * Shuts down the thread that is handling blocking I/O. Note that if the
+ * thread is currently blocked waiting for I/O it will not actually
+ * shut down until the I/O is received. Shutting down the I/O thread
+ * does not prevent this class from being used, but causes the
+ * non-blocking methods to fail if called and causes {@link #isNonBlockingEnabled()}
+ * to return false.
+ */
+ public synchronized void shutdown() {
+ if (!isShutdown && nonBlockingEnabled) {
+ isShutdown = true;
+ notify();
+ }
+ }
+
+ /**
+ * Non-blocking is considered enabled if the feature is enabled and the
+ * I/O thread has not been shut down.
+ * @return true if non-blocking mode is enabled.
+ */
+ public boolean isNonBlockingEnabled() {
+ return nonBlockingEnabled && !isShutdown;
+ }
+
+ @Override
+ public void close() throws IOException {
+ /*
+ * The underlying input stream is closed first. This means that if the
+ * I/O thread was blocked waiting on input, it will be woken for us.
+ */
+ in.close();
+ shutdown();
+ }
+
+ @Override
+ public int read() throws IOException {
+ if (nonBlockingEnabled)
+ return read(0L, false);
+ return in.read ();
+ }
+
+ /**
+ * Peeks to see if there is a byte waiting in the input stream without
+ * actually consuming the byte.
+ *
+ * @param timeout The amount of time to wait, 0 == forever
+ * @return -1 on eof, -2 if the timeout expired with no available input
+ * or the character that was read (without consuming it).
+ * @throws IOException
+ */
+ public int peek(long timeout) throws IOException {
+ if (!nonBlockingEnabled || isShutdown) {
+ throw new UnsupportedOperationException ("peek() "
+ + "cannot be called as non-blocking operation is disabled");
+ }
+ return read(timeout, true);
+ }
+
+ /**
+ * Attempts to read a character from the input stream for a specific
+ * period of time.
+ * @param timeout The amount of time to wait for the character
+ * @return The character read, -1 if EOF is reached, or -2 if the
+ * read timed out.
+ * @throws IOException
+ */
+ public int read(long timeout) throws IOException {
+ if (!nonBlockingEnabled || isShutdown) {
+ throw new UnsupportedOperationException ("read() with timeout "
+ + "cannot be called as non-blocking operation is disabled");
+ }
+ return read(timeout, false);
+ }
+
+ /**
+ * Attempts to read a character from the input stream for a specific
+ * period of time.
+ * @param timeout The amount of time to wait for the character
+ * @return The character read, -1 if EOF is reached, or -2 if the
+ * read timed out.
+ * @throws IOException
+ */
+ private synchronized int read(long timeout, boolean isPeek) throws IOException {
+ /*
+ * If the thread hit an IOException, we report it.
+ */
+ if (exception != null) {
+ assert ch == -2;
+ IOException toBeThrown = exception;
+ if (!isPeek)
+ exception = null;
+ throw toBeThrown;
+ }
+
+ /*
+ * If there was a pending character from the thread, then
+ * we send it. If the timeout is 0L or the thread was shut down
+ * then do a local read.
+ */
+ if (ch >= -1) {
+ assert exception == null;
+ }
+ else if ((timeout == 0L || isShutdown) && !threadIsReading) {
+ ch = in.read();
+ }
+ else {
+ /*
+ * If the thread isn't reading already, then ask it to do so.
+ */
+ if (!threadIsReading) {
+ threadIsReading = true;
+ notify();
+ }
+
+ boolean isInfinite = (timeout <= 0L);
+
+ /*
+ * So the thread is currently doing the reading for us. So
+ * now we play the waiting game.
+ */
+ while (isInfinite || timeout > 0L) {
+ long start = System.currentTimeMillis ();
+
+ try {
+ wait(timeout);
+ }
+ catch (InterruptedException e) {
+ /* IGNORED */
+ }
+
+ if (exception != null) {
+ assert ch == -2;
+
+ IOException toBeThrown = exception;
+ if (!isPeek)
+ exception = null;
+ throw toBeThrown;
+ }
+
+ if (ch >= -1) {
+ assert exception == null;
+ break;
+ }
+
+ if (!isInfinite) {
+ timeout -= System.currentTimeMillis() - start;
+ }
+ }
+ }
+
+ /*
+ * ch is the character that was just read. Either we set it because
+ * a local read was performed or the read thread set it (or failed to
+ * change it). We will return it's value, but if this was a peek
+ * operation, then we leave it in place.
+ */
+ int ret = ch;
+ if (!isPeek) {
+ ch = -2;
+ }
+ return ret;
+ }
+
+ /**
+ * This version of read() is very specific to jline's purposes, it
+ * will always always return a single byte at a time, rather than filling
+ * the entire buffer.
+ */
+ @Override
+ public int read (byte[] b, int off, int len) throws IOException {
+ if (b == null) {
+ throw new NullPointerException();
+ } else if (off < 0 || len < 0 || len > b.length - off) {
+ throw new IndexOutOfBoundsException();
+ } else if (len == 0) {
+ return 0;
+ }
+
+ int c;
+ if (nonBlockingEnabled)
+ c = this.read(0L);
+ else
+ c = in.read();
+
+ if (c == -1) {
+ return -1;
+ }
+ b[off] = (byte)c;
+ return 1;
+ }
+
+ //@Override
+ public void run () {
+ Log.debug("NonBlockingInputStream start");
+ boolean needToShutdown = false;
+ boolean needToRead = false;
+
+ while (!needToShutdown) {
+
+ /*
+ * Synchronize to grab variables accessed by both this thread
+ * and the accessing thread.
+ */
+ synchronized (this) {
+ needToShutdown = this.isShutdown;
+ needToRead = this.threadIsReading;
+
+ try {
+ /*
+ * Nothing to do? Then wait.
+ */
+ if (!needToShutdown && !needToRead) {
+ wait(0);
+ }
+ }
+ catch (InterruptedException e) {
+ /* IGNORED */
+ }
+ }
+
+ /*
+ * We're not shutting down, but we need to read. This cannot
+ * happen while we are holding the lock (which we aren't now).
+ */
+ if (!needToShutdown && needToRead) {
+ int charRead = -2;
+ IOException failure = null;
+ try {
+ charRead = in.read();
+ }
+ catch (IOException e) {
+ failure = e;
+ }
+
+ /*
+ * Re-grab the lock to update the state.
+ */
+ synchronized (this) {
+ exception = failure;
+ ch = charRead;
+ threadIsReading = false;
+ notify();
+ }
+ }
+ }
+
+ Log.debug("NonBlockingInputStream shutdown");
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/Nullable.java Wed Jul 05 20:41:12 2017 +0200
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.internal;
+
+import java.lang.annotation.*;
+
+/**
+ * Marker for reference which can be a null value.
+ *
+ * @since 2.7
+ */
+@Documented
+@Retention(RetentionPolicy.CLASS)
+@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE})
+public @interface Nullable
+{
+ String value() default "";
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/Preconditions.java Wed Jul 05 20:41:12 2017 +0200
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.internal;
+
+// Some bits lifted from Guava's ( http://code.google.com/p/guava-libraries/ ) Preconditions.
+
+/**
+ * Preconditions.
+ *
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.7
+ */
+public class Preconditions
+{
+ public static <T> T checkNotNull(final T reference) {
+ if (reference == null) {
+ throw new NullPointerException();
+ }
+ return reference;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/ShutdownHooks.java Wed Jul 05 20:41:12 2017 +0200
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.internal;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static jdk.internal.jline.internal.Preconditions.checkNotNull;
+
+/**
+ * Manages the JLine shutdown-hook thread and tasks to execute on shutdown.
+ *
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.7
+ */
+public class ShutdownHooks
+{
+ public static final String JLINE_SHUTDOWNHOOK = "jline.shutdownhook";
+
+ private static final boolean enabled = Configuration.getBoolean(JLINE_SHUTDOWNHOOK, true);
+
+ private static final List<Task> tasks = new ArrayList<Task>();
+
+ private static Thread hook;
+
+ public static synchronized <T extends Task> T add(final T task) {
+ checkNotNull(task);
+
+ // If not enabled ignore
+ if (!enabled) {
+ Log.debug("Shutdown-hook is disabled; not installing: ", task);
+ return task;
+ }
+
+ // Install the hook thread if needed
+ if (hook == null) {
+ hook = addHook(new Thread("JLine Shutdown Hook")
+ {
+ @Override
+ public void run() {
+ runTasks();
+ }
+ });
+ }
+
+ // Track the task
+ Log.debug("Adding shutdown-hook task: ", task);
+ tasks.add(task);
+
+ return task;
+ }
+
+ private static synchronized void runTasks() {
+ Log.debug("Running all shutdown-hook tasks");
+
+ // Iterate through copy of tasks list
+ for (Task task : tasks.toArray(new Task[tasks.size()])) {
+ Log.debug("Running task: ", task);
+ try {
+ task.run();
+ }
+ catch (Throwable e) {
+ Log.warn("Task failed", e);
+ }
+ }
+
+ tasks.clear();
+ }
+
+ private static Thread addHook(final Thread thread) {
+ Log.debug("Registering shutdown-hook: ", thread);
+ try {
+ Runtime.getRuntime().addShutdownHook(thread);
+ }
+ catch (AbstractMethodError e) {
+ // JDK 1.3+ only method. Bummer.
+ Log.debug("Failed to register shutdown-hook", e);
+ }
+ return thread;
+ }
+
+ public static synchronized void remove(final Task task) {
+ checkNotNull(task);
+
+ // ignore if not enabled or hook never installed
+ if (!enabled || hook == null) {
+ return;
+ }
+
+ // Drop the task
+ tasks.remove(task);
+
+ // If there are no more tasks, then remove the hook thread
+ if (tasks.isEmpty()) {
+ removeHook(hook);
+ hook = null;
+ }
+ }
+
+ private static void removeHook(final Thread thread) {
+ Log.debug("Removing shutdown-hook: ", thread);
+
+ try {
+ Runtime.getRuntime().removeShutdownHook(thread);
+ }
+ catch (AbstractMethodError e) {
+ // JDK 1.3+ only method. Bummer.
+ Log.debug("Failed to remove shutdown-hook", e);
+ }
+ catch (IllegalStateException e) {
+ // The VM is shutting down, not a big deal; ignore
+ }
+ }
+
+ /**
+ * Essentially a {@link Runnable} which allows running to throw an exception.
+ */
+ public static interface Task
+ {
+ void run() throws Exception;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/TerminalLineSettings.java Wed Jul 05 20:41:12 2017 +0200
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.internal;
+
+import java.io.ByteArrayOutputStream;
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.text.MessageFormat;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import static jdk.internal.jline.internal.Preconditions.checkNotNull;
+
+/**
+ * Provides access to terminal line settings via <tt>stty</tt>.
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ * @author <a href="mailto:dwkemp@gmail.com">Dale Kemp</a>
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @author <a href="mailto:jbonofre@apache.org">Jean-Baptiste Onofr\u00E9</a>
+ * @since 2.0
+ */
+public final class TerminalLineSettings
+{
+ public static final String JLINE_STTY = "jline.stty";
+
+ public static final String DEFAULT_STTY = "stty";
+
+ public static final String JLINE_SH = "jline.sh";
+
+ public static final String DEFAULT_SH = "sh";
+
+ private String sttyCommand;
+
+ private String shCommand;
+
+ private String config;
+ private String initialConfig;
+
+ private long configLastFetched;
+
+ public TerminalLineSettings() throws IOException, InterruptedException {
+ sttyCommand = Configuration.getString(JLINE_STTY, DEFAULT_STTY);
+ shCommand = Configuration.getString(JLINE_SH, DEFAULT_SH);
+ initialConfig = get("-g").trim();
+ config = get("-a");
+ configLastFetched = System.currentTimeMillis();
+
+ Log.debug("Config: ", config);
+
+ // sanity check
+ if (config.length() == 0) {
+ throw new IOException(MessageFormat.format("Unrecognized stty code: {0}", config));
+ }
+ }
+
+ public String getConfig() {
+ return config;
+ }
+
+ public void restore() throws IOException, InterruptedException {
+ set(initialConfig);
+ }
+
+ public String get(final String args) throws IOException, InterruptedException {
+ return stty(args);
+ }
+
+ public void set(final String args) throws IOException, InterruptedException {
+ stty(args);
+ }
+
+ /**
+ * <p>
+ * Get the value of a stty property, including the management of a cache.
+ * </p>
+ *
+ * @param name the stty property.
+ * @return the stty property value.
+ */
+ public int getProperty(String name) {
+ checkNotNull(name);
+ long currentTime = System.currentTimeMillis();
+ try {
+ // tty properties are cached so we don't have to worry too much about getting term width/height
+ if (config == null || currentTime - configLastFetched > 1000) {
+ config = get("-a");
+ }
+ } catch (Exception e) {
+ if (e instanceof InterruptedException) {
+ Thread.currentThread().interrupt();
+ }
+ Log.debug("Failed to query stty ", name, "\n", e);
+ if (config == null) {
+ return -1;
+ }
+ }
+
+ // always update the last fetched time and try to parse the output
+ if (currentTime - configLastFetched > 1000) {
+ configLastFetched = currentTime;
+ }
+
+ return getProperty(name, config);
+ }
+
+ /**
+ * <p>
+ * Parses a stty output (provided by stty -a) and return the value of a given property.
+ * </p>
+ *
+ * @param name property name.
+ * @param stty string resulting of stty -a execution.
+ * @return value of the given property.
+ */
+ protected static int getProperty(String name, String stty) {
+ // try the first kind of regex
+ Pattern pattern = Pattern.compile(name + "\\s+=\\s+(.*?)[;\\n\\r]");
+ Matcher matcher = pattern.matcher(stty);
+ if (!matcher.find()) {
+ // try a second kind of regex
+ pattern = Pattern.compile(name + "\\s+([^;]*)[;\\n\\r]");
+ matcher = pattern.matcher(stty);
+ if (!matcher.find()) {
+ // try a second try of regex
+ pattern = Pattern.compile("(\\S*)\\s+" + name);
+ matcher = pattern.matcher(stty);
+ if (!matcher.find()) {
+ return -1;
+ }
+ }
+ }
+ return parseControlChar(matcher.group(1));
+ }
+
+ private static int parseControlChar(String str) {
+ // under
+ if ("<undef>".equals(str)) {
+ return -1;
+ }
+ // octal
+ if (str.charAt(0) == '0') {
+ return Integer.parseInt(str, 8);
+ }
+ // decimal
+ if (str.charAt(0) >= '1' && str.charAt(0) <= '9') {
+ return Integer.parseInt(str, 10);
+ }
+ // control char
+ if (str.charAt(0) == '^') {
+ if (str.charAt(1) == '?') {
+ return 127;
+ } else {
+ return str.charAt(1) - 64;
+ }
+ } else if (str.charAt(0) == 'M' && str.charAt(1) == '-') {
+ if (str.charAt(2) == '^') {
+ if (str.charAt(3) == '?') {
+ return 127 + 128;
+ } else {
+ return str.charAt(3) - 64 + 128;
+ }
+ } else {
+ return str.charAt(2) + 128;
+ }
+ } else {
+ return str.charAt(0);
+ }
+ }
+
+ private String stty(final String args) throws IOException, InterruptedException {
+ checkNotNull(args);
+ return exec(String.format("%s %s < /dev/tty", sttyCommand, args));
+ }
+
+ private String exec(final String cmd) throws IOException, InterruptedException {
+ checkNotNull(cmd);
+ return exec(shCommand, "-c", cmd);
+ }
+
+ private String exec(final String... cmd) throws IOException, InterruptedException {
+ checkNotNull(cmd);
+
+ ByteArrayOutputStream bout = new ByteArrayOutputStream();
+
+ Log.trace("Running: ", cmd);
+
+ Process p = Runtime.getRuntime().exec(cmd);
+
+ InputStream in = null;
+ InputStream err = null;
+ OutputStream out = null;
+ try {
+ int c;
+ in = p.getInputStream();
+ while ((c = in.read()) != -1) {
+ bout.write(c);
+ }
+ err = p.getErrorStream();
+ while ((c = err.read()) != -1) {
+ bout.write(c);
+ }
+ out = p.getOutputStream();
+ p.waitFor();
+ }
+ finally {
+ close(in, out, err);
+ }
+
+ String result = bout.toString();
+
+ Log.trace("Result: ", result);
+
+ return result;
+ }
+
+ private static void close(final Closeable... closeables) {
+ for (Closeable c : closeables) {
+ try {
+ c.close();
+ }
+ catch (Exception e) {
+ // Ignore
+ }
+ }
+ }
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/TestAccessible.java Wed Jul 05 20:41:12 2017 +0200
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.internal;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * Marker annotation for members which are exposed for testing access.
+ *
+ * @since 2.7
+ */
+@Retention(RUNTIME)
+@Target({TYPE, CONSTRUCTOR, METHOD, FIELD, PARAMETER})
+@Documented
+public @interface TestAccessible
+{
+ // empty
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/Urls.java Wed Jul 05 20:41:12 2017 +0200
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline.internal;
+
+import java.io.File;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+/**
+ * URL helpers.
+ *
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @author <a href="mailto:gnodet@gmail.com">Guillaume Nodet</a>
+ * @since 2.7
+ */
+public class Urls
+{
+ public static URL create(final String input) {
+ if (input == null) {
+ return null;
+ }
+ try {
+ return new URL(input);
+ }
+ catch (MalformedURLException e) {
+ return create(new File(input));
+ }
+ }
+
+ public static URL create(final File file) {
+ try {
+ return file != null ? file.toURI().toURL() : null;
+ }
+ catch (MalformedURLException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/package-info.java Wed Jul 05 20:41:12 2017 +0200
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+/**
+ * Internal support.
+ *
+ * @since 2.0
+ */
+package jdk.internal.jline.internal;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/package-info.java Wed Jul 05 20:41:12 2017 +0200
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+/**
+ * JLine 2.
+ *
+ * @since 2.0
+ */
+package jdk.internal.jline;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.internal.le/windows/native/lible/WindowsTerminal.cpp Wed Jul 05 20:41:12 2017 +0200
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include "jni.h"
+#include "jni_util.h"
+#include "jvm.h"
+#include "jdk_internal_jline_WindowsTerminal.h"
+
+#include <stdlib.h>
+#include <Wincon.h>
+#include <Winuser.h>
+
+static jclass recordClass;
+static jmethodID recordConstructor;
+
+JNIEXPORT void JNICALL Java_jdk_internal_jline_WindowsTerminal_initIDs
+ (JNIEnv *env, jclass) {
+ jclass cls = env->FindClass("jdk/internal/jline/WindowsTerminal$KEY_EVENT_RECORD");
+ CHECK_NULL(cls);
+ recordClass = (jclass) env->NewGlobalRef(cls);
+ CHECK_NULL(recordClass);
+ recordConstructor = env->GetMethodID(cls, "<init>", "(ZCIII)V");
+ CHECK_NULL(recordConstructor);
+}
+
+JNIEXPORT jint JNICALL Java_jdk_internal_jline_WindowsTerminal_getConsoleMode
+ (JNIEnv *, jobject) {
+ HANDLE hStdIn;
+ if ((hStdIn = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE) {
+ return -1;
+ }
+ DWORD fdwMode;
+ if (! GetConsoleMode(hStdIn, &fdwMode)) {
+ return -1;
+ }
+ return fdwMode;
+}
+
+JNIEXPORT void JNICALL Java_jdk_internal_jline_WindowsTerminal_setConsoleMode
+ (JNIEnv *, jobject, jint mode) {
+ HANDLE hStdIn;
+ if ((hStdIn = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE) {
+ return ;
+ }
+ DWORD fdwMode = mode;
+ SetConsoleMode(hStdIn, fdwMode);
+}
+
+JNIEXPORT jobject JNICALL Java_jdk_internal_jline_WindowsTerminal_readKeyEvent
+ (JNIEnv *env, jobject) {
+ HANDLE hStdIn;
+ if ((hStdIn = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE) {
+ return NULL;
+ }
+ INPUT_RECORD record;
+ DWORD n;
+ while (TRUE) {
+ if (ReadConsoleInput(hStdIn, &record, 1, &n) == 0) {
+ return NULL;
+ }
+ if (record.EventType == KEY_EVENT) {
+ jclass clazz = env->FindClass("jdk/internal/jline/WindowsTerminal$KEY_EVENT_RECORD");
+ jmethodID constr = env->GetMethodID(clazz, "<init>", "(ZCIII)V");
+ return env->NewObject(recordClass,
+ recordConstructor,
+ record.Event.KeyEvent.bKeyDown,
+ record.Event.KeyEvent.uChar.UnicodeChar,
+ record.Event.KeyEvent.dwControlKeyState,
+ record.Event.KeyEvent.wVirtualKeyCode,
+ record.Event.KeyEvent.wRepeatCount);
+ }
+ continue;
+ }
+}
+
+JNIEXPORT jint JNICALL Java_jdk_internal_jline_WindowsTerminal_getConsoleOutputCodepage
+ (JNIEnv *, jobject) {
+ return GetConsoleCP();
+}
+
+JNIEXPORT jint JNICALL Java_jdk_internal_jline_WindowsTerminal_getWindowsTerminalWidth
+ (JNIEnv *, jobject) {
+ HANDLE hStdIn;
+ if ((hStdIn = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE) {
+ return -1;
+ }
+ CONSOLE_SCREEN_BUFFER_INFO info;
+ if (! GetConsoleScreenBufferInfo(hStdIn, &info)) {
+ return -1;
+ }
+ return info.dwSize.X;
+}
+
+JNIEXPORT jint JNICALL Java_jdk_internal_jline_WindowsTerminal_getWindowsTerminalHeight
+ (JNIEnv *, jobject) {
+ HANDLE hStdIn;
+ if ((hStdIn = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE) {
+ return -1;
+ }
+ CONSOLE_SCREEN_BUFFER_INFO info;
+ if (! GetConsoleScreenBufferInfo(hStdIn, &info)) {
+ return -1;
+ }
+ return info.dwSize.Y;
+}
--- a/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/Crypt.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/Crypt.java Wed Jul 05 20:41:12 2017 +0200
@@ -377,7 +377,7 @@
*
*/
- public static void main(String arg[]) {
+ public static void main(String[] arg) {
if (arg.length!=2) {
System.err.println("usage: Crypt password salt");
@@ -386,7 +386,7 @@
Crypt c = new Crypt();
try {
- byte result[] = c.crypt
+ byte[] result = c.crypt
(arg[0].getBytes("ISO-8859-1"), arg[1].getBytes("ISO-8859-1"));
for (int i=0; i<result.length; i++) {
System.out.println(" "+i+" "+(char)result[i]);
--- a/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/JndiLoginModule.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/JndiLoginModule.java Wed Jul 05 20:41:12 2017 +0200
@@ -729,8 +729,8 @@
Crypt c = new Crypt();
try {
- byte oldCrypt[] = encryptedPassword.getBytes("UTF8");
- byte newCrypt[] = c.crypt(password.getBytes("UTF8"),
+ byte[] oldCrypt = encryptedPassword.getBytes("UTF8");
+ byte[] newCrypt = c.crypt(password.getBytes("UTF8"),
oldCrypt);
if (newCrypt.length != oldCrypt.length)
return false;
--- a/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/NTLoginModule.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/NTLoginModule.java Wed Jul 05 20:41:12 2017 +0200
@@ -81,7 +81,7 @@
private NTDomainPrincipal userDomain; // user domain
private NTSidDomainPrincipal domainSID; // domain SID
private NTSidPrimaryGroupPrincipal primaryGroup; // primary group
- private NTSidGroupPrincipal groups[]; // supplementary groups
+ private NTSidGroupPrincipal[] groups; // supplementary groups
private NTNumericCredential iToken; // impersonation token
/**
@@ -194,7 +194,7 @@
if (ntSystem.getGroupIDs() != null &&
ntSystem.getGroupIDs().length > 0) {
- String groupSIDs[] = ntSystem.getGroupIDs();
+ String[] groupSIDs = ntSystem.getGroupIDs();
groups = new NTSidGroupPrincipal[groupSIDs.length];
for (int i = 0; i < groupSIDs.length; i++) {
groups[i] = new NTSidGroupPrincipal(groupSIDs[i]);
--- a/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/NTSystem.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/NTSystem.java Wed Jul 05 20:41:12 2017 +0200
@@ -40,7 +40,7 @@
private String domain;
private String domainSID;
private String userSID;
- private String groupIDs[];
+ private String[] groupIDs;
private String primaryGroupID;
private long impersonationToken;
--- a/jdk/src/jdk.security.jgss/share/classes/com/sun/security/sasl/gsskerb/FactoryImpl.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/src/jdk.security.jgss/share/classes/com/sun/security/sasl/gsskerb/FactoryImpl.java Wed Jul 05 20:41:12 2017 +0200
@@ -38,10 +38,10 @@
* @author Rosanna Lee
*/
public final class FactoryImpl implements SaslClientFactory, SaslServerFactory {
- private static final String myMechs[] = {
+ private static final String[] myMechs = {
"GSSAPI"};
- private static final int mechPolicies[] = {
+ private static final int[] mechPolicies = {
PolicyUtils.NOPLAINTEXT|PolicyUtils.NOANONYMOUS|PolicyUtils.NOACTIVE
};
--- a/jdk/test/TEST.groups Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/test/TEST.groups Wed Jul 05 20:41:12 2017 +0200
@@ -243,6 +243,7 @@
javax/xml \
-javax/xml/crypto \
jdk/asm \
+ jdk/internal/jline \
com/sun/jndi \
com/sun/corba \
lib/testlibrary \
--- a/jdk/test/java/lang/ProcessHandle/InfoTest.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/test/java/lang/ProcessHandle/InfoTest.java Wed Jul 05 20:41:12 2017 +0200
@@ -32,24 +32,24 @@
import java.nio.file.attribute.UserPrincipal;
import java.time.Duration;
import java.time.Instant;
-import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Random;
-import java.util.Scanner;
-import java.util.StringTokenizer;
import java.util.concurrent.TimeUnit;
import jdk.testlibrary.Platform;
+import jdk.testlibrary.Utils;
+
import org.testng.Assert;
import org.testng.annotations.Test;
import org.testng.TestNG;
/*
* @test
+ * @build jdk.testlibrary.*
* @library /lib/testlibrary
* @summary Functions of ProcessHandle.Info
* @author Roger Riggs
@@ -91,16 +91,16 @@
"test runner is included.");
ProcessHandle self = ProcessHandle.current();
- Duration somecpu = Duration.ofMillis(200L);
- Instant end = Instant.now().plus(somecpu);
+ Duration someCPU = Duration.ofMillis(200L);
+ Instant end = Instant.now().plus(someCPU);
while (Instant.now().isBefore(end)) {
// waste the cpu
}
ProcessHandle.Info info = self.info();
System.out.printf(" info: %s%n", info);
Optional<Duration> totalCpu = info.totalCpuDuration();
- if (totalCpu.isPresent() && (totalCpu.get().compareTo(somecpu) < 0)) {
- Assert.fail("reported cputime less than expected: " + somecpu + ", " +
+ if (totalCpu.isPresent() && (totalCpu.get().compareTo(someCPU) < 0)) {
+ Assert.fail("reported cputime less than expected: " + someCPU + ", " +
"actual: " + info.totalCpuDuration());
}
}
@@ -111,17 +111,16 @@
@Test
public static void test2() {
try {
- long cpulooptime = 1 << 8;
+ long cpuLoopTime = 100; // 100 ms
String[] extraArgs = {"pid", "parent", "stdin"};
- Instant beforeStart = Instant.now().truncatedTo(ChronoUnit.SECONDS);
JavaChild p1 = JavaChild.spawnJavaChild((Object[])extraArgs);
Instant afterStart = Instant.now();
try (BufferedReader lines = p1.outputReader()) {
Duration lastCpu = Duration.ofMillis(0L);
- for (int j = 0; j < 20; j++) {
+ for (int j = 0; j < 10; j++) {
- p1.sendAction("cpuloop", cpulooptime);
+ p1.sendAction("cpuloop", cpuLoopTime);
p1.sendAction("cputime", "");
// Read cputime from child
@@ -187,17 +186,21 @@
if (info.totalCpuDuration().isPresent()) {
Duration totalCPU = info.totalCpuDuration().get();
Duration epsilon = Duration.ofMillis(200L);
- Assert.assertTrue(totalCPU.toNanos() > 0L,
- "total cpu time expected > 0ms, actual: " + totalCPU);
- Assert.assertTrue(totalCPU.toNanos() < lastCpu.toNanos() + 10_000_000_000L,
- "total cpu time expected < 10s more than previous iteration, actual: " + totalCPU);
if (childCpuTime != null) {
System.out.printf(" info.totalCPU: %s, childCpuTime: %s, diff: %s%n",
- totalCPU.toNanos(), childCpuTime.toNanos(), childCpuTime.toNanos() - totalCPU.toNanos());
+ totalCPU.toNanos(), childCpuTime.toNanos(),
+ childCpuTime.toNanos() - totalCPU.toNanos());
Assert.assertTrue(checkEpsilon(childCpuTime, totalCPU, epsilon),
childCpuTime + " should be within " +
epsilon + " of " + totalCPU);
}
+ Assert.assertTrue(totalCPU.toNanos() > 0L,
+ "total cpu time expected > 0ms, actual: " + totalCPU);
+ long t = Utils.adjustTimeout(10L); // Adjusted timeout seconds
+ Assert.assertTrue(totalCPU.toNanos() < lastCpu.toNanos() + t * 1_000_000_000L,
+ "total cpu time expected < " + t
+ + " seconds more than previous iteration, actual: "
+ + (totalCPU.toNanos() - lastCpu.toNanos()));
lastCpu = totalCPU;
}
@@ -209,7 +212,7 @@
}
}
}
- p1.waitFor(5, TimeUnit.SECONDS);
+ p1.waitFor(Utils.adjustTimeout(5), TimeUnit.SECONDS);
} catch (IOException | InterruptedException ie) {
ie.printStackTrace(System.out);
Assert.fail("unexpected exception", ie);
@@ -252,7 +255,7 @@
Assert.assertTrue(p.waitFor(15, TimeUnit.SECONDS));
}
} catch (IOException | InterruptedException ex) {
- ex.printStackTrace(System.out);;
+ ex.printStackTrace(System.out);
} finally {
// Destroy any children that still exist
ProcessUtil.destroyProcessTree(ProcessHandle.current());
@@ -274,7 +277,7 @@
if (dur1.isPresent() && dur2.isPresent()) {
Duration total1 = dur1.get();
- Duration total2 = dur2.get(); ;
+ Duration total2 = dur2.get();
System.out.printf(" total1 vs. mbean: %s, getProcessCpuTime: %s, diff: %s%n",
Objects.toString(total1), myCputime1, myCputime1.minus(total1));
System.out.printf(" total2 vs. mbean: %s, getProcessCpuTime: %s, diff: %s%n",
@@ -326,7 +329,7 @@
* @param d1 a Duration - presumed to be shorter
* @param d2 a 2nd Duration - presumed to be greater (or within Epsilon)
* @param epsilon Epsilon the amount of overlap allowed
- * @return
+ * @return true if d2 is greater than d1 or within epsilon, false otherwise
*/
static boolean checkEpsilon(Duration d1, Duration d2, Duration epsilon) {
if (d1.toNanos() <= d2.toNanos()) {
@@ -339,7 +342,7 @@
/**
* Spawn a native process with the provided arguments.
* @param command the executable of native process
- * @args
+ * @param args to start a new process
* @return the Process that was started
* @throws IOException thrown by ProcessBuilder.start
*/
--- a/jdk/test/java/lang/ProcessHandle/JavaChild.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/test/java/lang/ProcessHandle/JavaChild.java Wed Jul 05 20:41:12 2017 +0200
@@ -281,12 +281,12 @@
sendResult(action, Integer.toString(millis));
break;
case "cpuloop":
- long times = Long.valueOf(args[nextArg++]);
- Instant end = Instant.now().plusMillis(times);
- while (Instant.now().isBefore(end)) {
- // burn the cpu til the time is up
+ long cpuMillis = Long.valueOf(args[nextArg++]);
+ long cpuTarget = getCpuTime() + cpuMillis * 1_000_000L;
+ while (getCpuTime() < cpuTarget) {
+ // burn the cpu until the time is up
}
- sendResult(action, times);
+ sendResult(action, cpuMillis);
break;
case "cputime":
sendResult(action, getCpuTime());
--- a/jdk/test/java/lang/ProcessHandle/OnExitTest.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/test/java/lang/ProcessHandle/OnExitTest.java Wed Jul 05 20:41:12 2017 +0200
@@ -27,16 +27,19 @@
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
-import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
+
+import jdk.testlibrary.Utils;
+
import org.testng.annotations.Test;
import org.testng.Assert;
import org.testng.TestNG;
/*
* @test
+ * @build jdk.testlibrary.Utils
* @summary Functions of Process.onExit and ProcessHandle.onExit
* @author Roger Riggs
*/
@@ -88,6 +91,7 @@
*/
@Test
public static void test2() {
+ ProcessHandle procHandle = null;
try {
ConcurrentHashMap<ProcessHandle, ProcessHandle> processes = new ConcurrentHashMap<>();
List<ProcessHandle> children = getChildren(ProcessHandle.current());
@@ -96,7 +100,7 @@
"Expected to start with zero children; " + children);
JavaChild proc = JavaChild.spawnJavaChild("stdin");
- ProcessHandle procHandle = proc.toHandle();
+ procHandle = proc.toHandle();
printf(" spawned: %d%n", proc.getPid());
proc.forEachOutputLine((s) -> {
@@ -114,7 +118,8 @@
// Poll until all 9 child processes exist or the timeout is reached
int expected = 9;
- Instant endTimeout = Instant.now().plusSeconds(10L);
+ long timeout = Utils.adjustTimeout(10L);
+ Instant endTimeout = Instant.now().plusSeconds(timeout);
do {
Thread.sleep(200L);
printf(" subprocess count: %d, waiting for %d%n", processes.size(), expected);
@@ -123,16 +128,17 @@
children = getAllChildren(procHandle);
- ArrayBlockingQueue<ProcessHandle> completions = new ArrayBlockingQueue<>(expected + 1);
+ ConcurrentHashMap<ProcessHandle, CompletableFuture<ProcessHandle>> completions =
+ new ConcurrentHashMap<>();
Instant startTime = Instant.now();
// Create a future for each of the 9 children
processes.forEach( (p, parent) -> {
- p.onExit().whenComplete((ph, ex) -> {
+ CompletableFuture<ProcessHandle> cf = p.onExit().whenComplete((ph, ex) -> {
Duration elapsed = Duration.between(startTime, Instant.now());
- completions.add(ph);
printf("whenComplete: pid: %s, exception: %s, thread: %s, elapsed: %s%n",
ph, ex, Thread.currentThread(), elapsed);
});
+ completions.put(p, cf);
});
// Check that each of the spawned processes is included in the children
@@ -153,20 +159,23 @@
proc.destroy(); // kill off the parent
proc.waitFor();
- // Wait for all the processes to be completed
+ // Wait for all the processes and corresponding onExit CF to be completed
processes.forEach((p, parent) -> {
try {
p.onExit().get();
+ completions.get(p).join();
} catch (InterruptedException | ExecutionException ex) {
// ignore
}
});
- // Verify that all 9 exit handlers were called
- processes.forEach((p, parent) ->
- Assert.assertTrue(completions.contains(p), "Child onExit not called: " + p
- + ", parent: " + parent
- + ": " + p.info()));
+ // Verify that all 9 exit handlers were called with the correct ProcessHandle
+ processes.forEach((p, parent) -> {
+ ProcessHandle value = completions.get(p).getNow(null);
+ Assert.assertEquals(p, value, "onExit.get value expected: " + p
+ + ", actual: " + value
+ + ": " + p.info());
+ });
// Show the status of the original children
children.forEach(p -> printProcess(p, "after onExit:"));
@@ -176,13 +185,12 @@
List<ProcessHandle> children2 = getAllChildren(procHandle);
printf(" children2: %s%n", children2.toString());
Assert.assertEquals(children2.size(), 0, "After onExit, expected no children");
-
- Assert.assertEquals(remaining.size(), 0, "Unaccounted for children");
-
} catch (IOException | InterruptedException ex) {
Assert.fail(ex.getMessage());
} finally {
- destroyProcessTree(ProcessHandle.current());
+ if (procHandle != null) {
+ destroyProcessTree(procHandle);
+ }
}
}
--- a/jdk/test/java/lang/ProcessHandle/TreeTest.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/test/java/lang/ProcessHandle/TreeTest.java Wed Jul 05 20:41:12 2017 +0200
@@ -75,10 +75,12 @@
spawned.add(JavaChild.spawnJavaChild("pid", "stdin"));
}
- List<ProcessHandle> subprocesses = getChildren(self);
- subprocesses.forEach(ProcessUtil::printProcess);
- count = subprocesses.size();
- Assert.assertEquals(count, MAXCHILDREN, "Wrong number of spawned children");
+ // Verify spawned Process is in list of children
+ final List<ProcessHandle> initialChildren = getChildren(self);
+ spawned.stream()
+ .map(Process::toHandle)
+ .filter(p -> !initialChildren.contains(p))
+ .forEach(p -> Assert.fail("Spawned process missing from children: " + p));
// Send exit command to each spawned Process
spawned.forEach(p -> {
@@ -102,20 +104,25 @@
});
// Verify that ProcessHandle.isAlive sees each of them as not alive
- for (ProcessHandle ph : subprocesses) {
+ for (Process p : spawned) {
+ ProcessHandle ph = p.toHandle();
Assert.assertFalse(ph.isAlive(),
"ProcessHandle.isAlive for exited process: " + ph);
}
- // Verify no current children are visible
- count = getChildren(self).size();
- Assert.assertEquals(count, 0, "Children destroyed, should be zero");
+ // Verify spawned processes are not visible as children
+ final List<ProcessHandle> afterChildren = getChildren(self);
+ spawned.stream()
+ .map(Process::toHandle)
+ .filter(p -> afterChildren.contains(p))
+ .forEach(p -> Assert.fail("Spawned process missing from children: " + p));
} catch (IOException ioe) {
Assert.fail("unable to spawn process", ioe);
} finally {
// Cleanup any left over processes
- spawned.stream().map(Process::toHandle)
+ spawned.stream()
+ .map(Process::toHandle)
.filter(ProcessHandle::isAlive)
.forEach(ph -> printDeep(ph, "test1 cleanup: "));
destroyProcessTree(ProcessHandle.current());
@@ -127,7 +134,6 @@
*/
@Test
public static void test2() {
- ProcessHandle p1Handle = null;
try {
ProcessHandle self = ProcessHandle.current();
List<ProcessHandle> initialChildren = getChildren(self);
@@ -138,7 +144,7 @@
}
JavaChild p1 = JavaChild.spawnJavaChild("stdin");
- p1Handle = p1.toHandle();
+ ProcessHandle p1Handle = p1.toHandle();
printf(" p1 pid: %d%n", p1.getPid());
int spawnNew = 3;
@@ -187,9 +193,6 @@
throw new RuntimeException(t);
} finally {
// Cleanup any left over processes
- if (p1Handle.isAlive()) {
- printDeep(p1Handle, "test2 cleanup: ");
- }
destroyProcessTree(ProcessHandle.current());
}
}
@@ -205,7 +208,10 @@
JavaChild p1 = JavaChild.spawnJavaChild("stdin");
ProcessHandle p1Handle = p1.toHandle();
printf(" p1: %s%n", p1.getPid());
- long count = getChildren(self).size();
+
+ List<ProcessHandle> subprocesses = getChildren(self);
+ subprocesses.forEach(ProcessUtil::printProcess);
+ long count = subprocesses.size();
Assert.assertEquals(count, 1, "Wrong number of spawned children");
int newChildren = 3;
@@ -213,7 +219,7 @@
p1.sendAction("spawn", newChildren, "stdin");
// Wait for the new processes and save the list
- List<ProcessHandle> subprocesses = waitForAllChildren(p1Handle, newChildren);
+ subprocesses = waitForAllChildren(p1Handle, newChildren);
printDeep(p1Handle, "allChildren");
Assert.assertEquals(subprocesses.size(), newChildren, "Wrong number of children");
@@ -249,6 +255,9 @@
Assert.fail("Spawn of subprocess failed", ioe);
} catch (InterruptedException inte) {
Assert.fail("InterruptedException", inte);
+ } finally {
+ // Cleanup any left over processes
+ destroyProcessTree(ProcessHandle.current());
}
}
@@ -299,16 +308,15 @@
}
/**
- * A test for scale; launch a large number (39) of subprocesses.
+ * A test for scale; launch a large number (14) of subprocesses.
*/
@Test
public static void test5() {
int factor = 2;
- ProcessHandle p1Handle = null;
Instant start = Instant.now();
try {
JavaChild p1 = JavaChild.spawnJavaChild("stdin");
- p1Handle = p1.toHandle();
+ ProcessHandle p1Handle = p1.toHandle();
printf("Spawning %d x %d x %d processes, pid: %d%n",
factor, factor, factor, p1.getPid());
@@ -325,18 +333,14 @@
int newChildren = factor * (1 + factor * (1 + factor));
List<ProcessHandle> children = ProcessUtil.waitForAllChildren(p1Handle, newChildren);
- Assert.assertEquals(p1.children()
- .filter(ProcessUtil::isNotWindowsConsole)
- .count(), factor, "expected direct children");
- Assert.assertEquals(p1.allChildren()
- .filter(ProcessUtil::isNotWindowsConsole)
- .count(),
- factor * factor * factor + factor * factor + factor,
- "expected all children");
+ Assert.assertEquals(getChildren(p1Handle).size(),
+ factor, "expected direct children");
+ long count = getAllChildren(p1Handle).size();
+ long totalChildren = factor * factor * factor + factor * factor + factor;
+ Assert.assertTrue(count >= totalChildren,
+ "expected at least " + totalChildren + ", actual: " + count);
- List<ProcessHandle> subprocesses = p1.allChildren()
- .filter(ProcessUtil::isNotWindowsConsole)
- .collect(Collectors.toList());
+ List<ProcessHandle> subprocesses = getAllChildren(p1Handle);
printf(" allChildren: %s%n",
subprocesses.stream().map(p -> p.getPid())
.collect(Collectors.toList()));
@@ -347,10 +351,6 @@
Assert.fail("Unexpected Exception", ex);
} finally {
printf("Duration: %s%n", Duration.between(start, Instant.now()));
- // Cleanup any left over processes
- if (p1Handle.isAlive()) {
- printDeep(p1Handle, "test5 cleanup: ");
- }
destroyProcessTree(ProcessHandle.current());
}
}
--- a/jdk/test/java/net/Socks/SocksProxyVersion.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/test/java/net/Socks/SocksProxyVersion.java Wed Jul 05 20:41:12 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 6964547 5001942
+ * @bug 6964547 5001942 8129444
* @run main/othervm SocksProxyVersion
* @summary test socksProxyVersion system property
*/
@@ -32,13 +32,15 @@
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
-import java.io.DataInputStream;
import java.io.IOException;
import java.net.InetAddress;
+import java.net.Proxy;
public class SocksProxyVersion implements Runnable {
final ServerSocket ss;
volatile boolean failed;
+ volatile boolean stopped = false;
+ volatile int expected;
public static void main(String[] args) throws Exception {
if (InetAddress.getLocalHost().isLoopbackAddress()) {
@@ -48,21 +50,26 @@
new SocksProxyVersion();
}
- @SuppressWarnings("try")
public SocksProxyVersion() throws Exception {
ss = new ServerSocket(0);
+ int port = ss.getLocalPort();
+ Thread serverThread = new Thread(this);
+ serverThread.start();
try (ServerSocket socket = ss) {
- runTest();
+ runTest(port);
+ } finally {
+ stopped = true;
+ }
+
+ serverThread.join();
+ if (failed) {
+ throw new RuntimeException("socksProxyVersion not being set correctly");
}
}
- void runTest() throws Exception {
- int port = ss.getLocalPort();
- Thread serverThread = new Thread(this);
- serverThread.start();
-
+ final void runTest(int port) throws Exception {
/*
- * Retreving the IP Address of the machine
+ * Retrieving the IP Address of the machine
* since "localhost" is bypassed as a non-proxy host
*/
String addr = InetAddress.getLocalHost().getHostAddress();
@@ -70,46 +77,54 @@
System.setProperty("socksProxyHost", addr);
System.setProperty("socksProxyPort", Integer.toString(port));
+ Proxy proxy = new Proxy(Proxy.Type.SOCKS,
+ new InetSocketAddress(addr, port));
+
// SOCKS V4
System.setProperty("socksProxyVersion", Integer.toString(4));
- try (Socket s = new Socket()) {
- s.connect(new InetSocketAddress(addr, port));
+ this.expected = 4;
+ check(new Socket(), addr, port);
+ check(new Socket(proxy), addr, port);
+
+ // SOCKS V5
+ System.setProperty("socksProxyVersion", Integer.toString(5));
+ this.expected = 5;
+ check(new Socket(), addr, port);
+ check(new Socket(proxy), addr, port);
+ }
+
+ private void check(Socket socket, String addr, int port)
+ throws IOException
+ {
+ try (Socket s = socket) {
+ socket.connect(new InetSocketAddress(addr, port));
} catch (SocketException e) {
// java.net.SocketException: Malformed reply from SOCKS server
// This exception is OK, since the "server" does not implement
// the socks protocol. It just verifies the version and closes.
}
-
- // SOCKS V5
- System.setProperty("socksProxyVersion", Integer.toString(5));
- try (Socket s = new Socket()) {
- s.connect(new InetSocketAddress(addr, port));
- } catch (SocketException e) { /* OK */ }
-
- serverThread.join();
- if (failed) {
- throw new RuntimeException("socksProxyVersion not being set correctly");
- }
}
+ @Override
public void run() {
+ int count = 0;
try {
- try (Socket s = ss.accept()) {
- int version = (s.getInputStream()).read();
- if (version != 4) {
- System.out.println("Got " + version + ", expected 4");
- failed = true;
+ while (!stopped) {
+ try (Socket s = ss.accept()) {
+ int version = (s.getInputStream()).read();
+ if (version != expected) {
+ System.out.printf("Iteration: %d, Got: %d, expected: %d%n",
+ count, version, expected);
+ failed = true;
+ }
}
- }
- try (Socket s = ss.accept()) {
- int version = (s.getInputStream()).read();
- if (version != 5) {
- System.out.println("Got " + version + ", expected 5");
- failed = true;
- }
+ count++;
}
} catch (IOException e) {
- e.printStackTrace();
+ if (!ss.isClosed()) {
+ e.printStackTrace();
+ }
+ // ignore, server socket was closed
}
}
}
--- a/jdk/test/java/util/Collection/MOAT.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/test/java/util/Collection/MOAT.java Wed Jul 05 20:41:12 2017 +0200
@@ -356,13 +356,7 @@
}
check(c.toArray().length == c.size());
- check(c.toArray().getClass() == Object[].class
- ||
- // !!!!
- // 6260652: (coll) Arrays.asList(x).toArray().getClass()
- // should be Object[].class
- (c.getClass().getName().equals("java.util.Arrays$ArrayList"))
- );
+ check(c.toArray().getClass() == Object[].class);
for (int size : new int[]{0,1,c.size(), c.size()+1}) {
Integer[] a = c.toArray(new Integer[size]);
check((size > c.size()) || a.length == c.size());
--- a/jdk/test/java/util/logging/LoggingDeadlock2.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/test/java/util/logging/LoggingDeadlock2.java Wed Jul 05 20:41:12 2017 +0200
@@ -57,35 +57,59 @@
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.LogManager;
import java.io.File;
+import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
+import java.util.concurrent.TimeUnit;
public class LoggingDeadlock2 {
+ // ask child process to dumpstack after 60secs
+ public static final long DUMP_STACK_FREQUENCY_MS = 60000;
+
+ // A marker that allows to validate the subprocess output.
+ public static final String MARKER = "$";
+
public static void realMain(String arg[]) throws Throwable {
try {
System.out.println(javaChildArgs);
ProcessBuilder pb = new ProcessBuilder(javaChildArgs);
ProcessResults r = run(pb.start());
equal(r.exitValue(), 99);
- equal(r.out(), "");
+
+ // output of subprocess should end with "$"
+ final String out = r.out();
+ final String trailingOutput = out.indexOf(MARKER) > -1
+ ? out.substring(out.indexOf(MARKER)+MARKER.length())
+ : out;
+ equal(trailingOutput, "");
equal(r.err(), "");
+ equal(out.startsWith("JavaChild started"), true);
+ equal(out.endsWith("$"), true);
} catch (Throwable t) { unexpected(t); }
}
public static class JavaChild {
public static void main(String args[]) throws Throwable {
+ System.out.println("JavaChild started");
+
final CyclicBarrier startingGate = new CyclicBarrier(2);
final Throwable[] thrown = new Throwable[1];
// Some random variation, to help tickle races.
final Random rnd = new Random();
+ final long seed = rnd.nextLong();
+ rnd.setSeed(seed);
+ System.out.println("seed=" + seed);
final boolean dojoin = rnd.nextBoolean();
final int JITTER = 1024;
final int iters1 = rnd.nextInt(JITTER);
final int iters2 = JITTER - iters1;
final AtomicInteger counter = new AtomicInteger(0);
+ System.out.println("dojoin=" + dojoin);
+ System.out.println("iters1=" + iters1);
+ System.out.println("iters2=" + iters2);
Thread exiter = new Thread() {
public void run() {
@@ -101,6 +125,12 @@
}};
exiter.start();
+ System.out.println("exiter started");
+
+ // signal end of verbose output
+ System.out.print(MARKER);
+ System.out.flush();
+
startingGate.await();
for (int i = 0; i < iters2; i++)
counter.getAndIncrement();
@@ -124,6 +154,9 @@
private static final String javaExe =
System.getProperty("java.home") +
File.separator + "bin" + File.separator + "java";
+ private static final String jstackExe =
+ System.getProperty("java.home") +
+ File.separator + "bin" + File.separator + "jstack";
private static final String classpath =
System.getProperty("java.class.path");
@@ -182,10 +215,15 @@
public void run() {
try {
Reader r = new InputStreamReader(is);
- char[] buf = new char[4096];
int n;
- while ((n = r.read(buf)) > 0) {
- sb.append(buf,0,n);
+ while ((n = r.read()) > 0) {
+ sb.append((char)n);
+
+ // prints everything immediately to System.out so that we can
+ // see the traces even in the event of a test timeout
+ System.out.write((char)n);
+ System.out.flush();
+
}
} catch (Throwable t) {
throwable = t;
@@ -196,6 +234,56 @@
}
}
+ /**
+ * If the child process deadlocks, then the parent may fail in timeout.
+ * In that case, we won't have any interesting traces, unless we manage
+ * to get a thread dump from the child.
+ * It is unsure whether obtaining a thread dump from a deadlocked child
+ * will work - but maybe we could see something if the timeout is a false
+ * positive (the child has not deadlocked but hasn't managed to fully start
+ * yet, for instance).
+ * The idea here is to periodically try to obtain a thread dump from the
+ * child, every 60sec - which should be always less than the jtreg timeout.
+ */
+ private static class TimeoutThread extends Thread {
+ final long ms;
+ final Process process;
+ TimeoutThread(long ms, Process p) {
+ super("TimeoutThread");
+ setDaemon(true);
+ this.ms = ms;
+ this.process = p;
+ }
+
+ @Override
+ public void run() {
+ long start = System.nanoTime();
+ try {
+ while (true) {
+ sleep(ms);
+ System.err.println("Timeout reached: " + ms);
+ if (process.isAlive()) {
+ long pid = process.getPid();
+ ProcessBuilder jstack = new ProcessBuilder(jstackExe, String.valueOf(pid));
+ System.err.println("Dumping subprocess stack: " + pid);
+ Process p = jstack.inheritIO().start();
+ p.waitFor(ms, TimeUnit.MILLISECONDS);
+ } else {
+ System.err.println("Process is not alive!");
+ break;
+ }
+ }
+ } catch (InterruptedException ex) {
+ System.err.println("Interrupted: " + ex);
+ } catch (IOException io) {
+ System.err.println("Failed to get stack from subprocess");
+ io.printStackTrace();
+ }
+ }
+
+
+ }
+
private static ProcessResults run(Process p) {
Throwable throwable = null;
int exitValue = -1;
@@ -208,10 +296,15 @@
new StreamAccumulator(p.getErrorStream());
try {
+ System.out.println("Waiting for child process to exit");
outAccumulator.start();
errAccumulator.start();
+ // ask subprocess to dump stack every 60 secs.
+ new TimeoutThread(DUMP_STACK_FREQUENCY_MS, p).start();
+
exitValue = p.waitFor();
+ System.out.println("\nChild exited with status: " + exitValue);
outAccumulator.join();
errAccumulator.join();
--- a/jdk/test/javax/net/ssl/DTLS/DTLSOverDatagram.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/test/javax/net/ssl/DTLS/DTLSOverDatagram.java Wed Jul 05 20:41:12 2017 +0200
@@ -46,8 +46,8 @@
* An example to show the way to use SSLEngine in datagram connections.
*/
public class DTLSOverDatagram {
- private static int MAX_HANDSHAKE_LOOPS = 60;
- private static int MAX_APP_READ_LOOPS = 10;
+ private static int MAX_HANDSHAKE_LOOPS = 200;
+ private static int MAX_APP_READ_LOOPS = 60;
/*
* The following is to set up the keystores.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/jdk/internal/jline/KeyConversionTest.java Wed Jul 05 20:41:12 2017 +0200
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 8080679
+ * @summary Verify the conversion from key events to escape sequences works properly.
+ * @requires os.family == "windows"
+ */
+
+import jdk.internal.jline.WindowsTerminal;
+import jdk.internal.jline.WindowsTerminal.KEY_EVENT_RECORD;
+
+public class KeyConversionTest {
+ public static void main(String... args) throws Exception {
+ new KeyConversionTest().run();
+ }
+
+ void run() throws Exception {
+ checkKeyConversion(new KEY_EVENT_RECORD(true, '\0', 256, 37, 1), "\033[D"); //LEFT
+ checkKeyConversion(new KEY_EVENT_RECORD(true, '\0', 264, 37, 1), "\033[1;5D"); //Ctrl-LEFT
+ checkKeyConversion(new KEY_EVENT_RECORD(true, '\0', 258, 37, 1), "\033[1;3D"); //Alt-LEFT
+ checkKeyConversion(new KEY_EVENT_RECORD(true, '\0', 256, 46, 1), "\033[3~"); //delete
+ checkKeyConversion(new KEY_EVENT_RECORD(true, '\0', 264, 46, 1), "\033[3;5~"); //Ctrl-delete
+ checkKeyConversion(new KEY_EVENT_RECORD(true, '\0', 258, 46, 1), "\033[3;3~"); //Alt-delete
+ checkKeyConversion(new KEY_EVENT_RECORD(true, '\0', 272, 46, 1), "\033[3;2~"); //Shift-delete
+ checkKeyConversion(new KEY_EVENT_RECORD(true, '\0', 280, 46, 1), "\033[3;6~"); //Ctrl-Shift-delete
+ checkKeyConversion(new KEY_EVENT_RECORD(true, '\0', 274, 46, 1), "\033[3;4~"); //Alt-Shift-delete
+ checkKeyConversion(new KEY_EVENT_RECORD(true, '\0', 282, 46, 1), "\033[3;8~"); //Ctrl-Alt-Shift-delete
+ }
+
+ void checkKeyConversion(KEY_EVENT_RECORD event, String expected) {
+ String actual = WindowsTerminal.convertKeys(event);
+
+ if (!expected.equals(actual)) {
+ throw new AssertionError("Expected: " + expected + "; actual: " + actual);
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/jdk/internal/jline/console/StripAnsiTest.java Wed Jul 05 20:41:12 2017 +0200
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 8080679
+ * @summary Verify ConsoleReader.stripAnsi strips escape sequences from its input correctly.
+ */
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.lang.reflect.Method;
+import jdk.internal.jline.console.ConsoleReader;
+
+public class StripAnsiTest {
+ public static void main(String... args) throws Exception {
+ new StripAnsiTest().run();
+ }
+
+ void run() throws Exception {
+ ByteArrayInputStream in = new ByteArrayInputStream(new byte[0]);
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ ConsoleReader reader = new ConsoleReader(in, out);
+
+ String withAnsi = "0\033[s1\033[2J2\033[37;4m3";
+ String expected = "0123";
+
+ Method stripAnsi = ConsoleReader.class.getDeclaredMethod("stripAnsi", String.class);
+ stripAnsi.setAccessible(true);
+ String actual = (String) stripAnsi.invoke(reader, withAnsi);
+
+ if (!expected.equals(actual)) {
+ throw new IllegalStateException("Did not correctly strip escape sequences: " + actual);
+ }
+ }
+}
--- a/jdk/test/sun/security/krb5/auto/BadKdc1.java Thu Jul 09 13:49:32 2015 -0700
+++ b/jdk/test/sun/security/krb5/auto/BadKdc1.java Wed Jul 05 20:41:12 2017 +0200
@@ -53,7 +53,7 @@
// k3 off k2 on
"(122212(22){1,2}|1222323232-)", // 1
// k1 on
- "(12(12){1,2}|122232-)" // empty
+ "(12(12){1,2}|122212|122232-)" // empty
);
}
}
--- a/make/CompileJavaModules.gmk Thu Jul 09 13:49:32 2015 -0700
+++ b/make/CompileJavaModules.gmk Wed Jul 05 20:41:12 2017 +0200
@@ -368,6 +368,10 @@
################################################################################
+jdk.internal.le_COPY := .properties
+
+################################################################################
+
jdk.jcmd_COPY := _options
################################################################################
--- a/make/Images.gmk Thu Jul 09 13:49:32 2015 -0700
+++ b/make/Images.gmk Wed Jul 05 20:41:12 2017 +0200
@@ -46,7 +46,7 @@
jdk.naming.dns jdk.naming.rmi jdk.scripting.nashorn jdk.zipfs
# tools
-TOOLS_MODULES += jdk.attach jdk.compiler jdk.dev jdk.javadoc jdk.jcmd jdk.jconsole \
+TOOLS_MODULES += jdk.attach jdk.compiler jdk.dev jdk.internal.le jdk.javadoc jdk.jcmd jdk.jconsole \
jdk.hotspot.agent jdk.hprof.agent jdk.jartool jdk.jdeps jdk.jdi jdk.jdwp.agent \
jdk.policytool jdk.rmic jdk.xml.bind jdk.xml.ws
--- a/modules.xml Thu Jul 09 13:49:32 2015 -0700
+++ b/modules.xml Wed Jul 05 20:41:12 2017 +0200
@@ -1625,6 +1625,26 @@
</export>
</module>
<module>
+ <name>jdk.internal.le</name>
+ <depend>java.base</depend>
+ <export>
+ <name>jdk.internal.jline</name>
+ <to>jdk.scripting.nashorn.shell</to>
+ </export>
+ <export>
+ <name>jdk.internal.jline.console</name>
+ <to>jdk.scripting.nashorn.shell</to>
+ </export>
+ <export>
+ <name>jdk.internal.jline.console.completer</name>
+ <to>jdk.scripting.nashorn.shell</to>
+ </export>
+ <export>
+ <name>jdk.internal.jline.console.history</name>
+ <to>jdk.scripting.nashorn.shell</to>
+ </export>
+ </module>
+ <module>
<name>jdk.jartool</name>
<depend>java.base</depend>
<export>