diff --git a/.hgtags b/.hgtags
index d6a20f73fdb..07e1de67af7 100644
--- a/.hgtags
+++ b/.hgtags
@@ -313,3 +313,4 @@ ff3fc75f3214ad7e03595be1b0d0f38d887b6f0e jdk9-b66
5b500c93ce4822d47061cd518ff3f72d9d8cb5b5 jdk9-b68
d69c968463f0ae5d0b45de3fc14fe65171b23948 jdk9-b69
43d0179ee9de3bfffae3417f09e07eb6d8efc963 jdk9-b70
+f66c185284727f6e6ffd27e9c45ed2dd9da0a691 jdk9-b71
diff --git a/.hgtags-top-repo b/.hgtags-top-repo
index 7dbc36fa276..e6f4871454e 100644
--- a/.hgtags-top-repo
+++ b/.hgtags-top-repo
@@ -313,3 +313,4 @@ f546760134eb861fcfecd4ce611b0040b0d25a6a jdk9-b67
70e4272790b6199e9ca89df2758ff9cb58ec4125 jdk9-b68
1bcfd6b8726582cff5a42dbfc75903e36f9dd4fe jdk9-b69
eed77fcd77711fcdba05f18fc22f37d86efb243c jdk9-b70
+c706ef5ea5da00078dc5e4334660315f7d99c15b jdk9-b71
diff --git a/common/autoconf/generated-configure.sh b/common/autoconf/generated-configure.sh
index 446fadaba6a..68446dae10c 100644
--- a/common/autoconf/generated-configure.sh
+++ b/common/autoconf/generated-configure.sh
@@ -4364,7 +4364,7 @@ VS_SDK_PLATFORM_NAME_2013=
#CUSTOM_AUTOCONF_INCLUDE
# Do not change or remove the following line, it is needed for consistency checks:
-DATE_WHEN_GENERATED=1434614912
+DATE_WHEN_GENERATED=1435822080
###############################################################################
#
@@ -42961,7 +42961,7 @@ $as_echo "$as_me: WARNING: X11 is not used, so --with-x is ignored" >&2;}
if test "x$x_libraries" = xNONE; then
if test -f "$SYSROOT/usr/X11R6/lib/libX11.so"; then
x_libraries="$SYSROOT/usr/X11R6/lib"
- elif test "$SYSROOT/usr/lib64/libX11.so" && test "x$OPENJDK_TARGET_CPU_BITS" = x64; then
+ elif test -f "$SYSROOT/usr/lib64/libX11.so" && test "x$OPENJDK_TARGET_CPU_BITS" = x64; then
x_libraries="$SYSROOT/usr/lib64"
elif test -f "$SYSROOT/usr/lib/libX11.so"; then
x_libraries="$SYSROOT/usr/lib"
diff --git a/common/autoconf/libraries.m4 b/common/autoconf/libraries.m4
index 6e963b280de..6b651132851 100644
--- a/common/autoconf/libraries.m4
+++ b/common/autoconf/libraries.m4
@@ -113,7 +113,7 @@ AC_DEFUN_ONCE([LIB_SETUP_X11],
if test "x$x_libraries" = xNONE; then
if test -f "$SYSROOT/usr/X11R6/lib/libX11.so"; then
x_libraries="$SYSROOT/usr/X11R6/lib"
- elif test "$SYSROOT/usr/lib64/libX11.so" && test "x$OPENJDK_TARGET_CPU_BITS" = x64; then
+ elif test -f "$SYSROOT/usr/lib64/libX11.so" && test "x$OPENJDK_TARGET_CPU_BITS" = x64; then
x_libraries="$SYSROOT/usr/lib64"
elif test -f "$SYSROOT/usr/lib/libX11.so"; then
x_libraries="$SYSROOT/usr/lib"
diff --git a/common/bin/compare.sh b/common/bin/compare.sh
index 8c7095296bb..ce527af478d 100644
--- a/common/bin/compare.sh
+++ b/common/bin/compare.sh
@@ -1188,28 +1188,11 @@ if [ "$SKIP_DEFAULT" != "true" ]; then
OTHER_JDK="$OTHER/install/jdk"
OTHER_JRE="$OTHER/install/jre"
echo "Selecting install images for compare"
- elif [ -d "$THIS/deploy/jdk" -o -d "$THIS/deploy/images/jdk" ] \
- && [ -d "$OTHER/deploy/jdk" -o -d "$OTHER/deploy/images/jdk" ]; then
- if [ -d "$THIS/deploy/images/jdk" ]; then
- THIS_JDK="$THIS/deploy/images/jdk"
- THIS_JRE="$THIS/deploy/images/jre"
- else
- THIS_JDK="$THIS/deploy/jdk"
- THIS_JRE="$THIS/deploy/jre"
- fi
- if [ -d "$OTHER/deploy/images/jdk" ]; then
- OTHER_JDK="$OTHER/deploy/images/jdk"
- OTHER_JRE="$OTHER/deploy/images/jre"
- else
- OTHER_JDK="$OTHER/deploy/jdk"
- OTHER_JRE="$OTHER/deploy/jre"
- fi
- echo "Selecting deploy images for compare"
- elif [ -d "$THIS/deploy/images/jdk" ] && [ -d "$OTHER/deploy/jdk" ]; then
- THIS_JDK="$THIS/deploy/jdk"
- THIS_JRE="$THIS/deploy/jre"
- OTHER_JDK="$OTHER/deploy/jdk"
- OTHER_JRE="$OTHER/deploy/jre"
+ elif [ -d "$THIS/images/jdk" ] && [ -d "$OTHER/deploy/images/jdk" ]; then
+ THIS_JDK="$THIS/images/jdk"
+ THIS_JRE="$THIS/images/jre"
+ OTHER_JDK="$OTHER/deploy/images/jdk"
+ OTHER_JRE="$OTHER/deploy/images/jre"
echo "Selecting deploy images for compare"
elif [ -d "$THIS/images/jdk" ] && [ -d "$OTHER/images/jdk" ]; then
THIS_JDK="$THIS/images/jdk"
@@ -1221,30 +1204,28 @@ if [ "$SKIP_DEFAULT" != "true" ]; then
echo "No common images found."
exit 1
fi
+ echo " $THIS_JDK"
+ echo " $OTHER_JDK"
- if [ -d "$THIS/deploy/jdk-bundle" -o -d "$THIS/deploy/images/jdk-bundle" ] \
- && [ -d "$OTHER/deploy/jdk-bundle" -o -d "$OTHER/deploy/images/jdk-bundle" ]; then
+ if [ -d "$THIS/images/jdk-bundle" -o -d "$THIS/deploy/images/jdk-bundle" ] \
+ && [ -d "$OTHER/images/jdk-bundle" -o -d "$OTHER/deploy/images/jdk-bundle" ]; then
if [ -d "$THIS/deploy/images/jdk-bundle" ]; then
THIS_JDK_BUNDLE="$THIS/deploy/images/jdk-bundle"
THIS_JRE_BUNDLE="$THIS/deploy/images/jre-bundle"
else
- THIS_JDK_BUNDLE="$THIS/deploy/jdk-bundle"
- THIS_JRE_BUNDLE="$THIS/deploy/jre-bundle"
+ THIS_JDK_BUNDLE="$THIS/images/jdk-bundle"
+ THIS_JRE_BUNDLE="$THIS/images/jre-bundle"
fi
if [ -d "$OTHER/deploy/images/jdk-bundle" ]; then
OTHER_JDK_BUNDLE="$OTHER/deploy/images/jdk-bundle"
OTHER_JRE_BUNDLE="$OTHER/deploy/images/jre-bundle"
else
- OTHER_JDK_BUNDLE="$OTHER/deploy/jdk-bundle"
- OTHER_JRE_BUNDLE="$OTHER/deploy/jre-bundle"
+ OTHER_JDK_BUNDLE="$OTHER/images/jdk-bundle"
+ OTHER_JRE_BUNDLE="$OTHER/images/jre-bundle"
fi
- echo "Also comparing deploy macosx bundles"
- elif [ -d "$THIS/images/jdk-bundle" ] && [ -d "$OTHER/images/jdk-bundle" ]; then
- THIS_JDK_BUNDLE="$THIS/images/jdk-bundle"
- THIS_JRE_BUNDLE="$THIS/images/jre-bundle"
- OTHER_JDK_BUNDLE="$OTHER/images/jdk-bundle"
- OTHER_JRE_BUNDLE="$OTHER/images/jre-bundle"
echo "Also comparing macosx bundles"
+ echo " $THIS_JDK_BUNDLE"
+ echo " $OTHER_JDK_BUNDLE"
fi
if [ -d "$THIS/deploy/bundles" -o -d "$THIS/deploy/images/bundles" ] \
@@ -1262,19 +1243,21 @@ if [ "$SKIP_DEFAULT" != "true" ]; then
echo "Also comparing deploy javadoc bundles"
fi
- if [ -d "$THIS/deploy/JavaAppletPlugin.plugin" -o -d "$THIS/deploy/images/JavaAppletPlugin.plugin" ] \
- && [ -d "$OTHER/deploy/JavaAppletPlugin.plugin" -o -d "$OTHER/deploy/images/JavaAppletPlugin.plugin" ]; then
- if [ -d "$THIS/deploy/images/bundles" ]; then
+ if [ -d "$THIS/images/JavaAppletPlugin.plugin" ] \
+ && [ -d "$OTHER/images/JavaAppletPlugin.plugin" -o -d "$OTHER/deploy/images/JavaAppletPlugin.plugin" ]; then
+ if [ -d "$THIS/images/JavaAppletPlugin.plugin" ]; then
+ THIS_DEPLOY_APPLET_PLUGIN_DIR="$THIS/images/JavaAppletPlugin.plugin"
+ else
THIS_DEPLOY_APPLET_PLUGIN_DIR="$THIS/deploy/images/JavaAppletPlugin.plugin"
- else
- THIS_DEPLOY_APPLET_PLUGIN_DIR="$THIS/deploy/JavaAppletPlugin.plugin"
fi
- if [ -d "$OTHER/deploy/images/bundles" ]; then
- OTHER_DEPLOY_APPLET_PLUGIN_DIR="$OTHER/deploy/images/JavaAppletPlugin.plugin"
+ if [ -d "$OTHER/images/JavaAppletPlugin.plugin" ]; then
+ OTHER_DEPLOY_APPLET_PLUGIN_DIR="$OTHER/images/JavaAppletPlugin.plugin"
else
- OTHER_DEPLOY_APPLET_PLUGIN_DIR="$OTHER/deploy/JavaAppletPlugin.plugin"
+ OTHER_DEPLOY_APPLET_PLUGIN_DIR="$OTHER/deploy/images/JavaAppletPlugin.plugin"
fi
echo "Also comparing deploy applet image"
+ echo " $THIS_DEPLOY_APPLET_PLUGIN_DIR"
+ echo " $OTHER_DEPLOY_APPLET_PLUGIN_DIR"
fi
if [ -d "$OTHER/images" ]; then
diff --git a/corba/.hgtags b/corba/.hgtags
index a2d2d57f9c1..6f8a78b94cc 100644
--- a/corba/.hgtags
+++ b/corba/.hgtags
@@ -313,3 +313,4 @@ afc1e295c4bf83f9a5dd539c29914edd4a754a3f jdk9-b65
8efad64f40eb8cd4df376c0a5275892eeb396bbd jdk9-b68
de8acedcb5b5870f1dc54cba575aaa5d33897ea2 jdk9-b69
e7cf01990ed366bd493080663259281e91ce223b jdk9-b70
+cd39ed501fb0504554a7f58ac6cf3dd2b64afec0 jdk9-b71
diff --git a/corba/src/java.corba/share/classes/com/sun/corba/se/impl/io/ObjectStreamClass.java b/corba/src/java.corba/share/classes/com/sun/corba/se/impl/io/ObjectStreamClass.java
index 185f40cf012..5e6bba759e3 100644
--- a/corba/src/java.corba/share/classes/com/sun/corba/se/impl/io/ObjectStreamClass.java
+++ b/corba/src/java.corba/share/classes/com/sun/corba/se/impl/io/ObjectStreamClass.java
@@ -65,7 +65,7 @@ import org.omg.CORBA.ValueMember;
import sun.corba.Bridge;
/**
- * A ObjectStreamClass describes a class that can be serialized to a stream
+ * An ObjectStreamClass describes a class that can be serialized to a stream
* or a class that was serialized to a stream. It contains the name
* and the serialVersionUID of the class.
*
@@ -788,9 +788,9 @@ public class ObjectStreamClass implements java.io.Serializable {
/* Compare the base class names of streamName and localName.
*
* @return Return true iff the base class name compare.
- * @parameter streamName Fully qualified class name.
- * @parameter localName Fully qualified class name.
- * @parameter pkgSeparator class names use either '.' or '/'.
+ * @param streamName Fully qualified class name.
+ * @param localName Fully qualified class name.
+ * @param pkgSeparator class names use either '.' or '/'.
*
* Only compare base class name to allow package renaming.
*/
diff --git a/corba/src/java.corba/share/classes/com/sun/corba/se/impl/orbutil/ObjectStreamClass_1_3_1.java b/corba/src/java.corba/share/classes/com/sun/corba/se/impl/orbutil/ObjectStreamClass_1_3_1.java
index 3e06edc2550..5188975ff76 100644
--- a/corba/src/java.corba/share/classes/com/sun/corba/se/impl/orbutil/ObjectStreamClass_1_3_1.java
+++ b/corba/src/java.corba/share/classes/com/sun/corba/se/impl/orbutil/ObjectStreamClass_1_3_1.java
@@ -656,9 +656,9 @@ public class ObjectStreamClass_1_3_1 implements java.io.Serializable {
/* Compare the base class names of streamName and localName.
*
* @return Return true iff the base class name compare.
- * @parameter streamName Fully qualified class name.
- * @parameter localName Fully qualified class name.
- * @parameter pkgSeparator class names use either '.' or '/'.
+ * @param streamName Fully qualified class name.
+ * @param localName Fully qualified class name.
+ * @param pkgSeparator class names use either '.' or '/'.
*
* Only compare base class name to allow package renaming.
*/
diff --git a/corba/src/java.corba/share/classes/org/omg/CORBA/BoundsHelper.java b/corba/src/java.corba/share/classes/org/omg/CORBA/BoundsHelper.java
index 54aae7c1df0..52f2128c51e 100644
--- a/corba/src/java.corba/share/classes/org/omg/CORBA/BoundsHelper.java
+++ b/corba/src/java.corba/share/classes/org/omg/CORBA/BoundsHelper.java
@@ -27,10 +27,10 @@ package org.omg.CORBA;
/**
- * This Helper class is used to facilitate the marshalling of Bounds.
+ * This Helper class is used to facilitate the marshalling of {@code Bounds}.
* For more information on Helper files, see
*
- * "Generated Files: Helper Files".
+ * "Generated Files: Helper Files".
*/
abstract public class BoundsHelper
diff --git a/corba/src/java.corba/share/classes/org/omg/CORBA/ORBPackage/InvalidNameHelper.java b/corba/src/java.corba/share/classes/org/omg/CORBA/ORBPackage/InvalidNameHelper.java
index 044e2b17eb4..150f6374e80 100644
--- a/corba/src/java.corba/share/classes/org/omg/CORBA/ORBPackage/InvalidNameHelper.java
+++ b/corba/src/java.corba/share/classes/org/omg/CORBA/ORBPackage/InvalidNameHelper.java
@@ -28,10 +28,10 @@ package org.omg.CORBA.ORBPackage;
/**
* This Helper class is used to facilitate the marshalling of
- * ORBPackage/InvalidName.
+ * {@code ORBPackage/InvalidName}.
* For more information on Helper files, see
*
- * "Generated Files: Helper Files".
+ * "Generated Files: Helper Files".
*/
abstract public class InvalidNameHelper
diff --git a/corba/src/java.corba/share/classes/org/omg/CORBA/TypeCodePackage/BadKindHelper.java b/corba/src/java.corba/share/classes/org/omg/CORBA/TypeCodePackage/BadKindHelper.java
index 755935698dd..3db1ad89f54 100644
--- a/corba/src/java.corba/share/classes/org/omg/CORBA/TypeCodePackage/BadKindHelper.java
+++ b/corba/src/java.corba/share/classes/org/omg/CORBA/TypeCodePackage/BadKindHelper.java
@@ -28,10 +28,10 @@ package org.omg.CORBA.TypeCodePackage;
/**
* This Helper class is used to facilitate the marshalling of
- * TypeCodePackage/BadKind.
+ * {@code TypeCodePackage/BadKind}.
* For more information on Helper files, see
*
- * "Generated Files: Helper Files".
+ * "Generated Files: Helper Files".
*/
abstract public class BadKindHelper
diff --git a/corba/src/java.corba/share/classes/org/omg/CORBA/TypeCodePackage/BoundsHelper.java b/corba/src/java.corba/share/classes/org/omg/CORBA/TypeCodePackage/BoundsHelper.java
index c234c595b17..1a9aeb71e2b 100644
--- a/corba/src/java.corba/share/classes/org/omg/CORBA/TypeCodePackage/BoundsHelper.java
+++ b/corba/src/java.corba/share/classes/org/omg/CORBA/TypeCodePackage/BoundsHelper.java
@@ -28,10 +28,10 @@ package org.omg.CORBA.TypeCodePackage;
/**
* This Helper class is used to facilitate the marshalling of
- * TypeCodePackage/Bounds.
+ * {@code TypeCodePackage/Bounds}.
* For more information on Helper files, see
*
- * "Generated Files: Helper Files".
+ * "Generated Files: Helper Files".
*/
abstract public class BoundsHelper
diff --git a/hotspot/.hgtags b/hotspot/.hgtags
index fc4a736f8e4..357e1c2da27 100644
--- a/hotspot/.hgtags
+++ b/hotspot/.hgtags
@@ -473,3 +473,4 @@ d47dfabd16d48eb96a451edd1b61194a39ee0eb5 jdk9-b67
11af3990d56c97b40318bc1f20608e86f051a3f7 jdk9-b68
ff0929a59ced0e144201aa05819ae2e47d6f2c61 jdk9-b69
8672e9264db30c21504063932dbc374eabc287a1 jdk9-b70
+07c6b035d68b0c41b1dcd442157b50b41a2551e9 jdk9-b71
diff --git a/hotspot/agent/make/Makefile b/hotspot/agent/make/Makefile
index f120c60fa68..9b5d03abc1e 100644
--- a/hotspot/agent/make/Makefile
+++ b/hotspot/agent/make/Makefile
@@ -58,6 +58,7 @@ sun.jvm.hotspot.debugger.cdbg.basic.x86 \
sun.jvm.hotspot.debugger.dummy \
sun.jvm.hotspot.debugger.linux \
sun.jvm.hotspot.debugger.linux.amd64 \
+sun.jvm.hotspot.debugger.linux.aarch64 \
sun.jvm.hotspot.debugger.linux.ppc64 \
sun.jvm.hotspot.debugger.linux.x86 \
sun.jvm.hotspot.debugger.posix \
@@ -65,6 +66,7 @@ sun.jvm.hotspot.debugger.posix.elf \
sun.jvm.hotspot.debugger.ppc64 \
sun.jvm.hotspot.debugger.proc \
sun.jvm.hotspot.debugger.proc.amd64 \
+sun.jvm.hotspot.debugger.proc.aarch64 \
sun.jvm.hotspot.debugger.proc.ppc64 \
sun.jvm.hotspot.debugger.proc.sparc \
sun.jvm.hotspot.debugger.proc.x86 \
@@ -91,11 +93,13 @@ sun.jvm.hotspot.oops \
sun.jvm.hotspot.prims \
sun.jvm.hotspot.runtime \
sun.jvm.hotspot.runtime.amd64 \
+sun.jvm.hotspot.runtime.aarch64 \
sun.jvm.hotspot.runtime.bsd \
sun.jvm.hotspot.runtime.bsd_amd64 \
sun.jvm.hotspot.runtime.bsd_x86 \
sun.jvm.hotspot.runtime.linux \
sun.jvm.hotspot.runtime.linux_amd64 \
+sun.jvm.hotspot.runtime.linux_aarch64 \
sun.jvm.hotspot.runtime.linux_ppc64 \
sun.jvm.hotspot.runtime.linux_sparc \
sun.jvm.hotspot.runtime.linux_x86 \
@@ -149,16 +153,19 @@ sun/jvm/hotspot/debugger/dummy/*.java \
sun/jvm/hotspot/debugger/linux/*.java \
sun/jvm/hotspot/debugger/linux/ppc64/*.java \
sun/jvm/hotspot/debugger/linux/x86/*.java \
+sun/jvm/hotspot/debugger/linux/aarch64/*.java \
sun/jvm/hotspot/debugger/posix/*.java \
sun/jvm/hotspot/debugger/posix/elf/*.java \
sun/jvm/hotspot/debugger/ppc64/*.java \
sun/jvm/hotspot/debugger/proc/*.java \
sun/jvm/hotspot/debugger/proc/amd64/*.java \
+sun/jvm/hotspot/debugger/proc/aarch64/*.java \
sun/jvm/hotspot/debugger/proc/ppc64/*.java \
sun/jvm/hotspot/debugger/proc/sparc/*.java \
sun/jvm/hotspot/debugger/proc/x86/*.java \
sun/jvm/hotspot/debugger/remote/*.java \
sun/jvm/hotspot/debugger/remote/amd64/*.java \
+sun/jvm/hotspot/debugger/remote/aarch64/*.java \
sun/jvm/hotspot/debugger/remote/ppc64/*.java \
sun/jvm/hotspot/debugger/remote/sparc/*.java \
sun/jvm/hotspot/debugger/remote/x86/*.java \
@@ -178,11 +185,13 @@ sun/jvm/hotspot/opto/*.java \
sun/jvm/hotspot/prims/*.java \
sun/jvm/hotspot/runtime/*.java \
sun/jvm/hotspot/runtime/amd64/*.java \
+sun/jvm/hotspot/runtime/aarch64/*.java \
sun/jvm/hotspot/runtime/bsd/*.java \
sun/jvm/hotspot/runtime/bsd_amd64/*.java \
sun/jvm/hotspot/runtime/bsd_x86/*.java \
sun/jvm/hotspot/runtime/linux/*.java \
sun/jvm/hotspot/runtime/linux_amd64/*.java \
+sun/jvm/hotspot/runtime/linux_aarch64/*.java \
sun/jvm/hotspot/runtime/linux_ppc64/*.java \
sun/jvm/hotspot/runtime/linux_sparc/*.java \
sun/jvm/hotspot/runtime/linux_x86/*.java \
diff --git a/hotspot/agent/src/os/linux/LinuxDebuggerLocal.c b/hotspot/agent/src/os/linux/LinuxDebuggerLocal.c
index eb1ef59c074..6a80036daf8 100644
--- a/hotspot/agent/src/os/linux/LinuxDebuggerLocal.c
+++ b/hotspot/agent/src/os/linux/LinuxDebuggerLocal.c
@@ -53,6 +53,10 @@
#include "sun_jvm_hotspot_debugger_ppc64_PPC64ThreadContext.h"
#endif
+#ifdef aarch64
+#include "sun_jvm_hotspot_debugger_aarch64_AARCH64ThreadContext.h"
+#endif
+
static jfieldID p_ps_prochandle_ID = 0;
static jfieldID threadList_ID = 0;
static jfieldID loadObjectList_ID = 0;
@@ -368,7 +372,7 @@ JNIEXPORT jlongArray JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLo
#define NPRGREG sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext_NPRGREG
#endif
#ifdef aarch64
-#define NPRGREG 32
+#define NPRGREG sun_jvm_hotspot_debugger_aarch64_AARCH64ThreadContext_NPRGREG
#endif
#if defined(sparc) || defined(sparcv9)
#define NPRGREG sun_jvm_hotspot_debugger_sparc_SPARCThreadContext_NPRGREG
@@ -473,6 +477,13 @@ JNIEXPORT jlongArray JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLo
#define REG_INDEX(reg) sun_jvm_hotspot_debugger_aarch64_AARCH64ThreadContext_##reg
+ {
+ int i;
+ for (i = 0; i < 31; i++)
+ regs[i] = gregs.regs[i];
+ regs[REG_INDEX(SP)] = gregs.sp;
+ regs[REG_INDEX(PC)] = gregs.pc;
+ }
#endif /* aarch64 */
#ifdef ppc64
diff --git a/hotspot/agent/src/os/linux/Makefile b/hotspot/agent/src/os/linux/Makefile
index dfbb0b9ebd5..9eeabe661e5 100644
--- a/hotspot/agent/src/os/linux/Makefile
+++ b/hotspot/agent/src/os/linux/Makefile
@@ -53,14 +53,15 @@ $(ARCH)/LinuxDebuggerLocal.o: LinuxDebuggerLocal.c
$(JAVAH) -jni -classpath ../../../build/classes -d $(ARCH) \
sun.jvm.hotspot.debugger.x86.X86ThreadContext \
sun.jvm.hotspot.debugger.sparc.SPARCThreadContext \
- sun.jvm.hotspot.debugger.amd64.AMD64ThreadContext
+ sun.jvm.hotspot.debugger.amd64.AMD64ThreadContext \
+ sun.jvm.hotspot.debugger.aarch64.AARCH64ThreadContext
$(GCC) $(CFLAGS) $< -o $@
$(ARCH)/sadis.o: ../../share/native/sadis.c
$(JAVAH) -jni -classpath ../../../build/classes -d $(ARCH) \
sun.jvm.hotspot.asm.Disassembler
$(GCC) $(CFLAGS) $< -o $@
-
+
$(ARCH)/%.o: %.c
$(GCC) $(CFLAGS) $< -o $@
diff --git a/hotspot/agent/src/os/linux/libproc.h b/hotspot/agent/src/os/linux/libproc.h
index 882169a3cee..0f5423ea5fb 100644
--- a/hotspot/agent/src/os/linux/libproc.h
+++ b/hotspot/agent/src/os/linux/libproc.h
@@ -72,6 +72,7 @@ combination of ptrace and /proc calls.
#define user_regs_struct pt_regs
#endif
#if defined(aarch64)
+#include
#define user_regs_struct user_pt_regs
#endif
diff --git a/hotspot/agent/src/os/linux/proc_service.h b/hotspot/agent/src/os/linux/proc_service.h
index 802e5b0bbb3..81297cc5e82 100644
--- a/hotspot/agent/src/os/linux/proc_service.h
+++ b/hotspot/agent/src/os/linux/proc_service.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 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
@@ -30,7 +30,7 @@
// Linux does not have the proc service library, though it does provide the
// thread_db library which can be used to manipulate threads without having
-// to know the details of LinuxThreads or NPTL
+// to know the details of NPTL
// copied from Solaris "proc_service.h"
typedef enum {
diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/HSDB.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/HSDB.java
index bb5cfe16c82..bac6fb7f548 100644
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/HSDB.java
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/HSDB.java
@@ -983,19 +983,15 @@ public class HSDB implements ObjectHistogramPanel.Listener, SAListener {
curFrame.getFP(),
anno));
} else {
- if (VM.getVM().getCPU().equals("x86") || VM.getVM().getCPU().equals("amd64")) {
- // For C2, which has null frame pointers on x86/amd64
- CodeBlob cb = VM.getVM().getCodeCache().findBlob(curFrame.getPC());
- Address sp = curFrame.getSP();
- if (Assert.ASSERTS_ENABLED) {
- Assert.that(cb.getFrameSize() > 0, "CodeBlob must have non-zero frame size");
- }
- annoPanel.addAnnotation(new Annotation(sp,
- sp.addOffsetTo(cb.getFrameSize()),
- anno));
- } else {
- Assert.that(VM.getVM().getCPU().equals("ia64"), "only ia64 should reach here");
+ // For C2, which has null frame pointers on x86/amd64/aarch64
+ CodeBlob cb = VM.getVM().getCodeCache().findBlob(curFrame.getPC());
+ Address sp = curFrame.getSP();
+ if (Assert.ASSERTS_ENABLED) {
+ Assert.that(cb.getFrameSize() > 0, "CodeBlob must have non-zero frame size");
}
+ annoPanel.addAnnotation(new Annotation(sp,
+ sp.addOffsetTo(cb.getFrameSize()),
+ anno));
}
// Add interpreter frame annotations
diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/aarch64/AARCH64ThreadContext.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/aarch64/AARCH64ThreadContext.java
new file mode 100644
index 00000000000..a884a0461dc
--- /dev/null
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/aarch64/AARCH64ThreadContext.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, Red Hat Inc.
+ * 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.
+ *
+ */
+
+package sun.jvm.hotspot.debugger.aarch64;
+
+import java.lang.annotation.Native;
+
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.debugger.cdbg.*;
+
+/** Specifies the thread context on aarch64 platforms; only a sub-portion
+ * of the context is guaranteed to be present on all operating
+ * systems. */
+
+public abstract class AARCH64ThreadContext implements ThreadContext {
+ // Taken from /usr/include/asm/sigcontext.h on Linux/AARCH64.
+
+ // NOTE: the indices for the various registers must be maintained as
+ // listed across various operating systems. However, only a small
+ // subset of the registers' values are guaranteed to be present (and
+ // must be present for the SA's stack walking to work)
+
+ // One instance of the Native annotation is enough to trigger header generation
+ // for this file.
+ @Native
+ public static final int R0 = 0;
+ public static final int R1 = 1;
+ public static final int R2 = 2;
+ public static final int R3 = 3;
+ public static final int R4 = 4;
+ public static final int R5 = 5;
+ public static final int R6 = 6;
+ public static final int R7 = 7;
+ public static final int R8 = 8;
+ public static final int R9 = 9;
+ public static final int R10 = 10;
+ public static final int R11 = 11;
+ public static final int R12 = 12;
+ public static final int R13 = 13;
+ public static final int R14 = 14;
+ public static final int R15 = 15;
+ public static final int R16 = 16;
+ public static final int R17 = 17;
+ public static final int R18 = 18;
+ public static final int R19 = 19;
+ public static final int R20 = 20;
+ public static final int R21 = 21;
+ public static final int R22 = 22;
+ public static final int R23 = 23;
+ public static final int R24 = 24;
+ public static final int R25 = 25;
+ public static final int R26 = 26;
+ public static final int R27 = 27;
+ public static final int R28 = 28;
+ public static final int FP = 29;
+ public static final int LR = 30;
+ public static final int SP = 31;
+ public static final int PC = 32;
+
+ public static final int NPRGREG = 33;
+
+ private long[] data;
+
+ public AARCH64ThreadContext() {
+ data = new long[NPRGREG];
+ }
+
+ public int getNumRegisters() {
+ return NPRGREG;
+ }
+
+ public String getRegisterName(int index) {
+ switch (index) {
+ case LR: return "lr";
+ case SP: return "sp";
+ case PC: return "pc";
+ default:
+ return "r" + index;
+ }
+ }
+
+ public void setRegister(int index, long value) {
+ data[index] = value;
+ }
+
+ public long getRegister(int index) {
+ return data[index];
+ }
+
+ public CFrame getTopFrame(Debugger dbg) {
+ return null;
+ }
+
+ /** This can't be implemented in this class since we would have to
+ * tie the implementation to, for example, the debugging system */
+ public abstract void setRegisterAsAddress(int index, Address value);
+
+ /** This can't be implemented in this class since we would have to
+ * tie the implementation to, for example, the debugging system */
+ public abstract Address getRegisterAsAddress(int index);
+}
diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxCDebugger.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxCDebugger.java
index 9a02dadc17b..efde22ef761 100644
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxCDebugger.java
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxCDebugger.java
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, Red Hat Inc.
* 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,12 +32,14 @@ import sun.jvm.hotspot.debugger.*;
import sun.jvm.hotspot.debugger.cdbg.*;
import sun.jvm.hotspot.debugger.x86.*;
import sun.jvm.hotspot.debugger.amd64.*;
+import sun.jvm.hotspot.debugger.aarch64.*;
import sun.jvm.hotspot.debugger.sparc.*;
import sun.jvm.hotspot.debugger.ppc64.*;
import sun.jvm.hotspot.debugger.linux.x86.*;
import sun.jvm.hotspot.debugger.linux.amd64.*;
import sun.jvm.hotspot.debugger.linux.sparc.*;
import sun.jvm.hotspot.debugger.linux.ppc64.*;
+import sun.jvm.hotspot.debugger.linux.aarch64.*;
import sun.jvm.hotspot.utilities.*;
class LinuxCDebugger implements CDebugger {
@@ -106,6 +109,13 @@ class LinuxCDebugger implements CDebugger {
Address pc = context.getRegisterAsAddress(PPC64ThreadContext.PC);
if (pc == null) return null;
return new LinuxPPC64CFrame(dbg, sp, pc, LinuxDebuggerLocal.getAddressSize());
+ } else if (cpu.equals("aarch64")) {
+ AARCH64ThreadContext context = (AARCH64ThreadContext) thread.getContext();
+ Address fp = context.getRegisterAsAddress(AARCH64ThreadContext.FP);
+ if (fp == null) return null;
+ Address pc = context.getRegisterAsAddress(AARCH64ThreadContext.PC);
+ if (pc == null) return null;
+ return new LinuxAARCH64CFrame(dbg, fp, pc);
} else {
// Runtime exception thrown by LinuxThreadContextFactory if unknown cpu
ThreadContext context = (ThreadContext) thread.getContext();
diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/aarch64/LinuxAARCH64CFrame.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/aarch64/LinuxAARCH64CFrame.java
new file mode 100644
index 00000000000..28e36759a55
--- /dev/null
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/aarch64/LinuxAARCH64CFrame.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, Red Hat Inc.
+ * 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.
+ *
+ */
+
+package sun.jvm.hotspot.debugger.linux.aarch64;
+
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.debugger.aarch64.*;
+import sun.jvm.hotspot.debugger.linux.*;
+import sun.jvm.hotspot.debugger.cdbg.*;
+import sun.jvm.hotspot.debugger.cdbg.basic.*;
+
+final public class LinuxAARCH64CFrame extends BasicCFrame {
+ public LinuxAARCH64CFrame(LinuxDebugger dbg, Address fp, Address pc) {
+ super(dbg.getCDebugger());
+ this.fp = fp;
+ this.pc = pc;
+ this.dbg = dbg;
+ }
+
+ // override base class impl to avoid ELF parsing
+ public ClosestSymbol closestSymbolToPC() {
+ // try native lookup in debugger.
+ return dbg.lookup(dbg.getAddressValue(pc()));
+ }
+
+ public Address pc() {
+ return pc;
+ }
+
+ public Address localVariableBase() {
+ return fp;
+ }
+
+ public CFrame sender(ThreadProxy thread) {
+ AARCH64ThreadContext context = (AARCH64ThreadContext) thread.getContext();
+ Address rsp = context.getRegisterAsAddress(AARCH64ThreadContext.SP);
+
+ if ((fp == null) || fp.lessThan(rsp)) {
+ return null;
+ }
+
+ // Check alignment of fp
+ if (dbg.getAddressValue(fp) % (2 * ADDRESS_SIZE) != 0) {
+ return null;
+ }
+
+ Address nextFP = fp.getAddressAt(0 * ADDRESS_SIZE);
+ if (nextFP == null || nextFP.lessThanOrEqual(fp)) {
+ return null;
+ }
+ Address nextPC = fp.getAddressAt(1 * ADDRESS_SIZE);
+ if (nextPC == null) {
+ return null;
+ }
+ return new LinuxAARCH64CFrame(dbg, nextFP, nextPC);
+ }
+
+ // package/class internals only
+ private static final int ADDRESS_SIZE = 8;
+ private Address pc;
+ private Address sp;
+ private Address fp;
+ private LinuxDebugger dbg;
+}
diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/aarch64/LinuxAARCH64ThreadContext.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/aarch64/LinuxAARCH64ThreadContext.java
new file mode 100644
index 00000000000..77003168671
--- /dev/null
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/aarch64/LinuxAARCH64ThreadContext.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, Red Hat Inc.
+ * 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.
+ *
+ */
+
+package sun.jvm.hotspot.debugger.linux.aarch64;
+
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.debugger.aarch64.*;
+import sun.jvm.hotspot.debugger.linux.*;
+
+public class LinuxAARCH64ThreadContext extends AARCH64ThreadContext {
+ private LinuxDebugger debugger;
+
+ public LinuxAARCH64ThreadContext(LinuxDebugger debugger) {
+ super();
+ this.debugger = debugger;
+ }
+
+ public void setRegisterAsAddress(int index, Address value) {
+ setRegister(index, debugger.getAddressValue(value));
+ }
+
+ public Address getRegisterAsAddress(int index) {
+ return debugger.newAddress(getRegister(index));
+ }
+}
diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ProcDebuggerLocal.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ProcDebuggerLocal.java
index 67086fb9ac4..74e957d94b8 100644
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ProcDebuggerLocal.java
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ProcDebuggerLocal.java
@@ -31,11 +31,13 @@ import java.lang.reflect.*;
import sun.jvm.hotspot.debugger.*;
import sun.jvm.hotspot.debugger.cdbg.*;
import sun.jvm.hotspot.debugger.proc.amd64.*;
+import sun.jvm.hotspot.debugger.proc.aarch64.*;
import sun.jvm.hotspot.debugger.proc.sparc.*;
import sun.jvm.hotspot.debugger.proc.ppc64.*;
import sun.jvm.hotspot.debugger.proc.x86.*;
import sun.jvm.hotspot.debugger.ppc64.*;
import sun.jvm.hotspot.debugger.amd64.*;
+import sun.jvm.hotspot.debugger.aarch64.*;
import sun.jvm.hotspot.debugger.sparc.*;
import sun.jvm.hotspot.debugger.x86.*;
import sun.jvm.hotspot.utilities.*;
@@ -88,6 +90,10 @@ public class ProcDebuggerLocal extends DebuggerBase implements ProcDebugger {
threadFactory = new ProcAMD64ThreadFactory(this);
pcRegIndex = AMD64ThreadContext.RIP;
fpRegIndex = AMD64ThreadContext.RBP;
+ } else if (cpu.equals("aarch64")) {
+ threadFactory = new ProcAARCH64ThreadFactory(this);
+ pcRegIndex = AARCH64ThreadContext.PC;
+ fpRegIndex = AARCH64ThreadContext.FP;
} else if (cpu.equals("ppc64")) {
threadFactory = new ProcPPC64ThreadFactory(this);
pcRegIndex = PPC64ThreadContext.PC;
diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/aarch64/ProcAARCH64Thread.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/aarch64/ProcAARCH64Thread.java
new file mode 100644
index 00000000000..c6531751d94
--- /dev/null
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/aarch64/ProcAARCH64Thread.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, Red Hat Inc.
+ * 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.
+ *
+ */
+
+package sun.jvm.hotspot.debugger.proc.aarch64;
+
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.debugger.aarch64.*;
+import sun.jvm.hotspot.debugger.proc.*;
+import sun.jvm.hotspot.utilities.*;
+
+public class ProcAARCH64Thread implements ThreadProxy {
+ private ProcDebugger debugger;
+ private int id;
+
+ public ProcAARCH64Thread(ProcDebugger debugger, Address addr) {
+ this.debugger = debugger;
+
+ // FIXME: the size here should be configurable. However, making it
+ // so would produce a dependency on the "types" package from the
+ // debugger package, which is not desired.
+ this.id = (int) addr.getCIntegerAt(0, 4, true);
+ }
+
+ public ProcAARCH64Thread(ProcDebugger debugger, long id) {
+ this.debugger = debugger;
+ this.id = (int) id;
+ }
+
+ public ThreadContext getContext() throws IllegalThreadStateException {
+ ProcAARCH64ThreadContext context = new ProcAARCH64ThreadContext(debugger);
+ long[] regs = debugger.getThreadIntegerRegisterSet(id);
+ if (Assert.ASSERTS_ENABLED) {
+ Assert.that(regs.length == AARCH64ThreadContext.NPRGREG, "size mismatch");
+ }
+ for (int i = 0; i < regs.length; i++) {
+ context.setRegister(i, regs[i]);
+ }
+ return context;
+ }
+
+ public boolean canSetContext() throws DebuggerException {
+ return false;
+ }
+
+ public void setContext(ThreadContext context)
+ throws IllegalThreadStateException, DebuggerException {
+ throw new DebuggerException("Unimplemented");
+ }
+
+ public String toString() {
+ return "t@" + id;
+ }
+
+ public boolean equals(Object obj) {
+ if ((obj == null) || !(obj instanceof ProcAARCH64Thread)) {
+ return false;
+ }
+
+ return (((ProcAARCH64Thread) obj).id == id);
+ }
+
+ public int hashCode() {
+ return id;
+ }
+}
diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/aarch64/ProcAARCH64ThreadContext.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/aarch64/ProcAARCH64ThreadContext.java
new file mode 100644
index 00000000000..9d3cbc53d5d
--- /dev/null
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/aarch64/ProcAARCH64ThreadContext.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, Red Hat Inc.
+ * 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.
+ *
+ */
+
+package sun.jvm.hotspot.debugger.proc.aarch64;
+
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.debugger.aarch64.*;
+import sun.jvm.hotspot.debugger.proc.*;
+
+public class ProcAARCH64ThreadContext extends AARCH64ThreadContext {
+ private ProcDebugger debugger;
+
+ public ProcAARCH64ThreadContext(ProcDebugger debugger) {
+ super();
+ this.debugger = debugger;
+ }
+
+ public void setRegisterAsAddress(int index, Address value) {
+ setRegister(index, debugger.getAddressValue(value));
+ }
+
+ public Address getRegisterAsAddress(int index) {
+ return debugger.newAddress(getRegister(index));
+ }
+}
diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/aarch64/ProcAARCH64ThreadFactory.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/aarch64/ProcAARCH64ThreadFactory.java
new file mode 100644
index 00000000000..392ed8b0b16
--- /dev/null
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/aarch64/ProcAARCH64ThreadFactory.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, Red Hat Inc.
+ * 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.
+ *
+ */
+
+package sun.jvm.hotspot.debugger.proc.aarch64;
+
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.debugger.proc.*;
+
+public class ProcAARCH64ThreadFactory implements ProcThreadFactory {
+ private ProcDebugger debugger;
+
+ public ProcAARCH64ThreadFactory(ProcDebugger debugger) {
+ this.debugger = debugger;
+ }
+
+ public ThreadProxy createThreadWrapper(Address threadIdentifierAddr) {
+ return new ProcAARCH64Thread(debugger, threadIdentifierAddr);
+ }
+
+ public ThreadProxy createThreadWrapper(long id) {
+ return new ProcAARCH64Thread(debugger, id);
+ }
+}
diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/aarch64/RemoteAARCH64Thread.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/aarch64/RemoteAARCH64Thread.java
new file mode 100644
index 00000000000..d7dd1d26838
--- /dev/null
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/aarch64/RemoteAARCH64Thread.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, Red Hat Inc.
+ * 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.
+ *
+ */
+
+package sun.jvm.hotspot.debugger.remote.aarch64;
+
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.debugger.aarch64.*;
+import sun.jvm.hotspot.debugger.remote.*;
+import sun.jvm.hotspot.utilities.*;
+
+public class RemoteAARCH64Thread extends RemoteThread {
+ public RemoteAARCH64Thread(RemoteDebuggerClient debugger, Address addr) {
+ super(debugger, addr);
+ }
+
+ public RemoteAARCH64Thread(RemoteDebuggerClient debugger, long id) {
+ super(debugger, id);
+ }
+
+ public ThreadContext getContext() throws IllegalThreadStateException {
+ RemoteAARCH64ThreadContext context = new RemoteAARCH64ThreadContext(debugger);
+ long[] regs = (addr != null)? debugger.getThreadIntegerRegisterSet(addr) :
+ debugger.getThreadIntegerRegisterSet(id);
+ if (Assert.ASSERTS_ENABLED) {
+ Assert.that(regs.length == AARCH64ThreadContext.NPRGREG, "size of register set must match");
+ }
+ for (int i = 0; i < regs.length; i++) {
+ context.setRegister(i, regs[i]);
+ }
+ return context;
+ }
+}
diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/aarch64/RemoteAARCH64ThreadContext.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/aarch64/RemoteAARCH64ThreadContext.java
new file mode 100644
index 00000000000..6bc42d740aa
--- /dev/null
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/aarch64/RemoteAARCH64ThreadContext.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, Red Hat Inc.
+ * 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.
+ *
+ */
+
+package sun.jvm.hotspot.debugger.remote.aarch64;
+
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.debugger.aarch64.*;
+import sun.jvm.hotspot.debugger.remote.*;
+
+public class RemoteAARCH64ThreadContext extends AARCH64ThreadContext {
+ private RemoteDebuggerClient debugger;
+
+ public RemoteAARCH64ThreadContext(RemoteDebuggerClient debugger) {
+ super();
+ this.debugger = debugger;
+ }
+
+ public void setRegisterAsAddress(int index, Address value) {
+ setRegister(index, debugger.getAddressValue(value));
+ }
+
+ public Address getRegisterAsAddress(int index) {
+ return debugger.newAddress(getRegister(index));
+ }
+}
diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/aarch64/RemoteAARCH64ThreadFactory.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/aarch64/RemoteAARCH64ThreadFactory.java
new file mode 100644
index 00000000000..eeb0e5753cc
--- /dev/null
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/aarch64/RemoteAARCH64ThreadFactory.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, Red Hat Inc.
+ * 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.
+ *
+ */
+
+package sun.jvm.hotspot.debugger.remote.aarch64;
+
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.debugger.remote.*;
+
+public class RemoteAARCH64ThreadFactory implements RemoteThreadFactory {
+ private RemoteDebuggerClient debugger;
+
+ public RemoteAARCH64ThreadFactory(RemoteDebuggerClient debugger) {
+ this.debugger = debugger;
+ }
+
+ public ThreadProxy createThreadWrapper(Address threadIdentifierAddr) {
+ return new RemoteAARCH64Thread(debugger, threadIdentifierAddr);
+ }
+
+ public ThreadProxy createThreadWrapper(long id) {
+ return new RemoteAARCH64Thread(debugger, id);
+ }
+}
diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/shared/Generation.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/shared/Generation.java
index d00bf48ef01..fcefa7386ed 100644
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/shared/Generation.java
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/shared/Generation.java
@@ -49,7 +49,6 @@ import sun.jvm.hotspot.types.*;
public abstract class Generation extends VMObject {
private static long reservedFieldOffset;
private static long virtualSpaceFieldOffset;
- private static CIntegerField levelField;
protected static final int K = 1024;
// Fields for class StatRecord
private static Field statRecordField;
@@ -75,7 +74,6 @@ public abstract class Generation extends VMObject {
reservedFieldOffset = type.getField("_reserved").getOffset();
virtualSpaceFieldOffset = type.getField("_virtual_space").getOffset();
- levelField = type.getCIntegerField("_level");
// StatRecord
statRecordField = type.getField("_stat_record");
type = db.lookupType("Generation::StatRecord");
@@ -130,14 +128,6 @@ public abstract class Generation extends VMObject {
}
}
- public GenerationSpec spec() {
- return ((GenCollectedHeap) VM.getVM().getUniverse().heap()).spec(level());
- }
-
- public int level() {
- return (int) levelField.getValue(addr);
- }
-
public int invocations() {
return getStatRecord().getInvocations();
}
diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/Frame.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/Frame.java
index b7b27b98135..b1ee998dcd2 100644
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/Frame.java
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/Frame.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2012, 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
@@ -357,12 +357,6 @@ public abstract class Frame implements Cloneable {
// FIXME: avoiding implementing this for now if possible
// public void interpreter_frame_set_monitor_end(BasicObjectLock* value);
// public void interpreter_frame_verify_monitor(BasicObjectLock* value) const;
- //
- // Tells whether the current interpreter_frame frame pointer
- // corresponds to the old compiled/deoptimized fp
- // The receiver used to be a top level frame
- // public boolean interpreter_frame_equals_unpacked_fp(intptr_t* fp);
-
//--------------------------------------------------------------------------------
// Method and constant pool cache:
//
diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/Threads.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/Threads.java
index 0714e80d9f9..cdafa826127 100644
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/Threads.java
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/Threads.java
@@ -35,6 +35,7 @@ import sun.jvm.hotspot.runtime.win32_amd64.Win32AMD64JavaThreadPDAccess;
import sun.jvm.hotspot.runtime.win32_x86.Win32X86JavaThreadPDAccess;
import sun.jvm.hotspot.runtime.linux_x86.LinuxX86JavaThreadPDAccess;
import sun.jvm.hotspot.runtime.linux_amd64.LinuxAMD64JavaThreadPDAccess;
+import sun.jvm.hotspot.runtime.linux_aarch64.LinuxAARCH64JavaThreadPDAccess;
import sun.jvm.hotspot.runtime.linux_ppc64.LinuxPPC64JavaThreadPDAccess;
import sun.jvm.hotspot.runtime.linux_sparc.LinuxSPARCJavaThreadPDAccess;
import sun.jvm.hotspot.runtime.bsd_x86.BsdX86JavaThreadPDAccess;
@@ -91,6 +92,8 @@ public class Threads {
access = new LinuxSPARCJavaThreadPDAccess();
} else if (cpu.equals("ppc64")) {
access = new LinuxPPC64JavaThreadPDAccess();
+ } else if (cpu.equals("aarch64")) {
+ access = new LinuxAARCH64JavaThreadPDAccess();
} else {
try {
access = (JavaThreadPDAccess)
diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/aarch64/AARCH64CurrentFrameGuess.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/aarch64/AARCH64CurrentFrameGuess.java
new file mode 100644
index 00000000000..cc71287e3fc
--- /dev/null
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/aarch64/AARCH64CurrentFrameGuess.java
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, Red Hat Inc.
+ * 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.
+ *
+ */
+
+package sun.jvm.hotspot.runtime.aarch64;
+
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.debugger.aarch64.*;
+import sun.jvm.hotspot.code.*;
+import sun.jvm.hotspot.interpreter.*;
+import sun.jvm.hotspot.runtime.*;
+import sun.jvm.hotspot.runtime.aarch64.*;
+
+/**
Should be able to be used on all aarch64 platforms we support
+ (Linux/aarch64) to implement JavaThread's "currentFrameGuess()"
+ functionality. Input is an AARCH64ThreadContext; output is SP, FP,
+ and PC for an AARCH64Frame. Instantiation of the AARCH64Frame is
+ left to the caller, since we may need to subclass AARCH64Frame to
+ support signal handler frames on Unix platforms.
+
+
Algorithm is to walk up the stack within a given range (say,
+ 512K at most) looking for a plausible PC and SP for a Java frame,
+ also considering those coming in from the context. If we find a PC
+ that belongs to the VM (i.e., in generated code like the
+ interpreter or CodeCache) then we try to find an associated FP.
+ We repeat this until we either find a complete frame or run out of
+ stack to look at.
- * To use your own class loader you can set the "bcel.classloader" system property
- * which defaults to "com.sun.org.apache.bcel.internal.util.ClassLoader", e.g., with
- *
- *
- * @author M. Dahm
- * @see ClassLoader
- */
-public class JavaWrapper {
- private java.lang.ClassLoader loader;
-
- private static java.lang.ClassLoader getClassLoader() {
- String s = SecuritySupport.getSystemProperty("bcel.classloader");
-
- if((s == null) || "".equals(s))
- s = "com.sun.org.apache.bcel.internal.util.ClassLoader";
-
- try {
- return (java.lang.ClassLoader)Class.forName(s).newInstance();
- } catch(Exception e) {
- throw new RuntimeException(e.toString());
- }
- }
-
- public JavaWrapper(java.lang.ClassLoader loader) {
- this.loader = loader;
- }
-
- public JavaWrapper() {
- this(getClassLoader());
- }
-
- /** Runs the _main method of the given class with the arguments passed in argv
- *
- * @param class_name the fully qualified class name
- * @param argv the arguments just as you would pass them directly
- */
- public void runMain(String class_name, String[] argv) throws ClassNotFoundException
- {
- Class cl = loader.loadClass(class_name);
- Method method = null;
-
- try {
- method = cl.getMethod("_main", new Class[] { argv.getClass() });
-
- /* Method _main is sane ?
- */
- int m = method.getModifiers();
- Class r = method.getReturnType();
-
- if(!(Modifier.isPublic(m) && Modifier.isStatic(m)) ||
- Modifier.isAbstract(m) || (r != Void.TYPE))
- throw new NoSuchMethodException();
- } catch(NoSuchMethodException no) {
- System.out.println("In class " + class_name +
- ": public static void _main(String[] argv) is not defined");
- return;
- }
-
- try {
- method.invoke(null, new Object[] { argv });
- } catch(Exception ex) {
- ex.printStackTrace();
- }
- }
-
- /** Default _main method used as wrapper, expects the fully qualified class name
- * of the real class as the first argument.
- */
- public static void _main(String[] argv) throws Exception {
- /* Expects class name as first argument, other arguments are by-passed.
- */
- if(argv.length == 0) {
- System.out.println("Missing class name.");
- return;
- }
-
- String class_name = argv[0];
- String[] new_argv = new String[argv.length - 1];
- System.arraycopy(argv, 1, new_argv, 0, new_argv.length);
-
- JavaWrapper wrapper = new JavaWrapper();
- wrapper.runMain(class_name, new_argv);
- }
-}
diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/lib/Extensions.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/lib/Extensions.java
index 23082e87aa4..17ff0567cd6 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/lib/Extensions.java
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/lib/Extensions.java
@@ -22,20 +22,16 @@
*/
package com.sun.org.apache.xalan.internal.lib;
-import java.util.Hashtable;
import java.util.StringTokenizer;
-import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import com.sun.org.apache.xalan.internal.extensions.ExpressionContext;
-import com.sun.org.apache.xalan.internal.xslt.EnvironmentCheck;
import com.sun.org.apache.xpath.internal.NodeSet;
import com.sun.org.apache.xpath.internal.objects.XBoolean;
import com.sun.org.apache.xpath.internal.objects.XNumber;
import com.sun.org.apache.xpath.internal.objects.XObject;
-import com.sun.org.apache.xalan.internal.utils.ObjectFactory;
import org.w3c.dom.Document;
import org.w3c.dom.DocumentFragment;
@@ -275,102 +271,6 @@ public class Extensions
return tokenize(toTokenize, " \t\n\r");
}
- /**
- * Return a Node of basic debugging information from the
- * EnvironmentCheck utility about the Java environment.
- *
- *
Simply calls the {@link com.sun.org.apache.xalan.internal.xslt.EnvironmentCheck}
- * utility to grab info about the Java environment and CLASSPATH,
- * etc., and then returns the resulting Node. Stylesheets can
- * then maniuplate this data or simply xsl:copy-of the Node. Note
- * that we first attempt to load the more advanced
- * org.apache.env.Which utility by reflection; only if that fails
- * to we still use the internal version. Which is available from
- * http://xml.apache.org/commons/.
- *
- *
We throw a WrappedRuntimeException in the unlikely case
- * that reading information from the environment throws us an
- * exception. (Is this really the best thing to do?)
- *
- * @param myContext an ExpressionContext passed in by the
- * extension mechanism. This must be an XPathContext.
- * @return a Node as described above.
- */
- public static Node checkEnvironment(ExpressionContext myContext)
- {
-
- Document factoryDocument = getDocument();
-
- Node resultNode = null;
- try
- {
- // First use reflection to try to load Which, which is a
- // better version of EnvironmentCheck
- resultNode = checkEnvironmentUsingWhich(myContext, factoryDocument);
-
- if (null != resultNode)
- return resultNode;
-
- // If reflection failed, fallback to our internal EnvironmentCheck
- EnvironmentCheck envChecker = new EnvironmentCheck();
- Hashtable h = envChecker.getEnvironmentHash();
- resultNode = factoryDocument.createElement("checkEnvironmentExtension");
- envChecker.appendEnvironmentReport(resultNode, factoryDocument, h);
- envChecker = null;
- }
- catch(Exception e)
- {
- throw new com.sun.org.apache.xml.internal.utils.WrappedRuntimeException(e);
- }
-
- return resultNode;
- }
-
- /**
- * Private worker method to attempt to use org.apache.env.Which.
- *
- * @param myContext an ExpressionContext passed in by the
- * extension mechanism. This must be an XPathContext.
- * @param factoryDocument providing createElement services, etc.
- * @return a Node with environment info; null if any error
- */
- private static Node checkEnvironmentUsingWhich(ExpressionContext myContext,
- Document factoryDocument)
- {
- final String WHICH_CLASSNAME = "org.apache.env.Which";
- final String WHICH_METHODNAME = "which";
- final Class WHICH_METHOD_ARGS[] = { java.util.Hashtable.class,
- java.lang.String.class,
- java.lang.String.class };
- try
- {
- // Use reflection to try to find xml-commons utility 'Which'
- Class clazz = ObjectFactory.findProviderClass(WHICH_CLASSNAME, true);
- if (null == clazz)
- return null;
-
- // Fully qualify names since this is the only method they're used in
- java.lang.reflect.Method method = clazz.getMethod(WHICH_METHODNAME, WHICH_METHOD_ARGS);
- Hashtable report = new Hashtable();
-
- // Call the method with our Hashtable, common options, and ignore return value
- Object[] methodArgs = { report, "XmlCommons;Xalan;Xerces;Crimson;Ant", "" };
- Object returnValue = method.invoke(null, methodArgs);
-
- // Create a parent to hold the report and append hash to it
- Node resultNode = factoryDocument.createElement("checkEnvironmentExtension");
- com.sun.org.apache.xml.internal.utils.Hashtree2Node.appendHashToNode(report, "whichReport",
- resultNode, factoryDocument);
-
- return resultNode;
- }
- catch (Throwable t)
- {
- // Simply return null; no need to report error
- return null;
- }
- }
-
/**
* @return an instance of DOM Document
*/
diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/utils/ObjectFactory.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/utils/ObjectFactory.java
index f030ea4442e..e23c00390b6 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/utils/ObjectFactory.java
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/utils/ObjectFactory.java
@@ -121,22 +121,7 @@ public class ObjectFactory {
public static Object newInstance(String className, boolean doFallback)
throws ConfigurationError
{
- if (System.getSecurityManager()!=null) {
- return newInstance(className, null, doFallback);
- } else {
- return newInstance(className,
- findClassLoader (), doFallback);
- }
- }
-
- /**
- * Create an instance of a class using the specified ClassLoader
- */
- static Object newInstance(String className, ClassLoader cl,
- boolean doFallback)
- throws ConfigurationError
- {
- // assert(className != null);
+ ClassLoader cl = System.getSecurityManager()!=null ? null : findClassLoader();
try{
Class providerClass = findProviderClass(className, cl, doFallback);
Object instance = providerClass.newInstance();
diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/SmartTransformerFactoryImpl.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/SmartTransformerFactoryImpl.java
deleted file mode 100644
index 4637dce2035..00000000000
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/SmartTransformerFactoryImpl.java
+++ /dev/null
@@ -1,455 +0,0 @@
-/*
- * reserved comment block
- * DO NOT REMOVE OR ALTER!
- */
-/*
- * Copyright 2001-2004 The Apache Software Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-/*
- * $Id: SmartTransformerFactoryImpl.java,v 1.2.4.1 2005/09/14 09:57:13 pvedula Exp $
- */
-
-
-package com.sun.org.apache.xalan.internal.xsltc.trax;
-
-import javax.xml.XMLConstants;
-import javax.xml.transform.ErrorListener;
-import javax.xml.transform.Source;
-import javax.xml.transform.Templates;
-import javax.xml.transform.Transformer;
-import javax.xml.transform.TransformerConfigurationException;
-import javax.xml.transform.TransformerException;
-import javax.xml.transform.URIResolver;
-import javax.xml.transform.dom.DOMResult;
-import javax.xml.transform.dom.DOMSource;
-import javax.xml.transform.sax.SAXResult;
-import javax.xml.transform.sax.SAXSource;
-import javax.xml.transform.sax.SAXTransformerFactory;
-import javax.xml.transform.sax.TemplatesHandler;
-import javax.xml.transform.sax.TransformerHandler;
-import javax.xml.transform.stream.StreamResult;
-import javax.xml.transform.stream.StreamSource;
-
-import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
-import com.sun.org.apache.xalan.internal.utils.ObjectFactory;
-import org.xml.sax.XMLFilter;
-
-/**
- * Implementation of a transformer factory that uses an XSLTC
- * transformer factory for the creation of Templates objects
- * and uses the Xalan processor transformer factory for the
- * creation of Transformer objects.
- * @author G. Todd Miller
- */
-public class SmartTransformerFactoryImpl extends SAXTransformerFactory
-{
- /**
- *
Set a feature for this SmartTransformerFactory and Transformers
- * or Templates created by this factory.
- *
- *
- * Feature names are fully qualified {@link java.net.URI}s.
- * Implementations may define their own features.
- * An {@link TransformerConfigurationException} is thrown if this TransformerFactory or the
- * Transformers or Templates it creates cannot support the feature.
- * It is possible for an TransformerFactory to expose a feature value but be unable to change its state.
- *
- *
- *
See {@link javax.xml.transform.TransformerFactory} for full documentation of specific features.
- *
- * @param name Feature name.
- * @param value Is feature state true or false.
- *
- * @throws TransformerConfigurationException if this TransformerFactory
- * or the Transformers or Templates it creates cannot support this feature.
- * @throws NullPointerException If the name parameter is null.
- */
- public void setFeature(String name, boolean value)
- throws TransformerConfigurationException {
-
- // feature name cannot be null
- if (name == null) {
- ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_SET_FEATURE_NULL_NAME);
- throw new NullPointerException(err.toString());
- }
- // secure processing?
- else if (name.equals(XMLConstants.FEATURE_SECURE_PROCESSING)) {
- featureSecureProcessing = value;
- // all done processing feature
- return;
- }
- else {
- // unknown feature
- ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_UNSUPPORTED_FEATURE, name);
- throw new TransformerConfigurationException(err.toString());
- }
- }
-
- /**
- * javax.xml.transform.sax.TransformerFactory implementation.
- * Look up the value of a feature (to see if it is supported).
- * This method must be updated as the various methods and features of this
- * class are implemented.
- *
- * @param name The feature name
- * @return 'true' if feature is supported, 'false' if not
- */
- public boolean getFeature(String name) {
- // All supported features should be listed here
- String[] features = {
- DOMSource.FEATURE,
- DOMResult.FEATURE,
- SAXSource.FEATURE,
- SAXResult.FEATURE,
- StreamSource.FEATURE,
- StreamResult.FEATURE
- };
-
- // feature name cannot be null
- if (name == null) {
- ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_GET_FEATURE_NULL_NAME);
- throw new NullPointerException(err.toString());
- }
-
- // Inefficient, but it really does not matter in a function like this
- for (int i = 0; i < features.length; i++) {
- if (name.equals(features[i]))
- return true;
- }
-
- // secure processing?
- if (name.equals(XMLConstants.FEATURE_SECURE_PROCESSING)) {
- return featureSecureProcessing;
- }
-
- // unknown feature
- return false;
- }
-
- public URIResolver getURIResolver() {
- return _uriresolver;
- }
-
- public void setURIResolver(URIResolver resolver) {
- _uriresolver = resolver;
- }
-
- public Source getAssociatedStylesheet(Source source, String media,
- String title, String charset)
- throws TransformerConfigurationException
- {
- if (_currFactory == null) {
- createXSLTCTransformerFactory();
- }
- return _currFactory.getAssociatedStylesheet(source, media,
- title, charset);
- }
-
- /**
- * Create a Transformer object that copies the input document to the
- * result. Uses the com.sun.org.apache.xalan.internal.processor.TransformerFactory.
- * @return A Transformer object.
- */
- public Transformer newTransformer()
- throws TransformerConfigurationException
- {
- if (_xalanFactory == null) {
- createXalanTransformerFactory();
- }
- if (_errorlistener != null) {
- _xalanFactory.setErrorListener(_errorlistener);
- }
- if (_uriresolver != null) {
- _xalanFactory.setURIResolver(_uriresolver);
- }
- _currFactory = _xalanFactory;
- return _currFactory.newTransformer();
- }
-
- /**
- * Create a Transformer object that from the input stylesheet
- * Uses the com.sun.org.apache.xalan.internal.processor.TransformerFactory.
- * @param source the stylesheet.
- * @return A Transformer object.
- */
- public Transformer newTransformer(Source source) throws
- TransformerConfigurationException
- {
- if (_xalanFactory == null) {
- createXalanTransformerFactory();
- }
- if (_errorlistener != null) {
- _xalanFactory.setErrorListener(_errorlistener);
- }
- if (_uriresolver != null) {
- _xalanFactory.setURIResolver(_uriresolver);
- }
- _currFactory = _xalanFactory;
- return _currFactory.newTransformer(source);
- }
-
- /**
- * Create a Templates object that from the input stylesheet
- * Uses the com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactory.
- * @param source the stylesheet.
- * @return A Templates object.
- */
- public Templates newTemplates(Source source)
- throws TransformerConfigurationException
- {
- if (_xsltcFactory == null) {
- createXSLTCTransformerFactory();
- }
- if (_errorlistener != null) {
- _xsltcFactory.setErrorListener(_errorlistener);
- }
- if (_uriresolver != null) {
- _xsltcFactory.setURIResolver(_uriresolver);
- }
- _currFactory = _xsltcFactory;
- return _currFactory.newTemplates(source);
- }
-
- /**
- * Get a TemplatesHandler object that can process SAX ContentHandler
- * events into a Templates object. Uses the
- * com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactory.
- */
- public TemplatesHandler newTemplatesHandler()
- throws TransformerConfigurationException
- {
- if (_xsltcFactory == null) {
- createXSLTCTransformerFactory();
- }
- if (_errorlistener != null) {
- _xsltcFactory.setErrorListener(_errorlistener);
- }
- if (_uriresolver != null) {
- _xsltcFactory.setURIResolver(_uriresolver);
- }
- return _xsltcFactory.newTemplatesHandler();
- }
-
- /**
- * Get a TransformerHandler object that can process SAX ContentHandler
- * events based on a copy transformer.
- * Uses com.sun.org.apache.xalan.internal.processor.TransformerFactory.
- */
- public TransformerHandler newTransformerHandler()
- throws TransformerConfigurationException
- {
- if (_xalanFactory == null) {
- createXalanTransformerFactory();
- }
- if (_errorlistener != null) {
- _xalanFactory.setErrorListener(_errorlistener);
- }
- if (_uriresolver != null) {
- _xalanFactory.setURIResolver(_uriresolver);
- }
- return _xalanFactory.newTransformerHandler();
- }
-
- /**
- * Get a TransformerHandler object that can process SAX ContentHandler
- * events based on a transformer specified by the stylesheet Source.
- * Uses com.sun.org.apache.xalan.internal.processor.TransformerFactory.
- */
- public TransformerHandler newTransformerHandler(Source src)
- throws TransformerConfigurationException
- {
- if (_xalanFactory == null) {
- createXalanTransformerFactory();
- }
- if (_errorlistener != null) {
- _xalanFactory.setErrorListener(_errorlistener);
- }
- if (_uriresolver != null) {
- _xalanFactory.setURIResolver(_uriresolver);
- }
- return _xalanFactory.newTransformerHandler(src);
- }
-
-
- /**
- * Get a TransformerHandler object that can process SAX ContentHandler
- * events based on a transformer specified by the stylesheet Source.
- * Uses com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactory.
- */
- public TransformerHandler newTransformerHandler(Templates templates)
- throws TransformerConfigurationException
- {
- if (_xsltcFactory == null) {
- createXSLTCTransformerFactory();
- }
- if (_errorlistener != null) {
- _xsltcFactory.setErrorListener(_errorlistener);
- }
- if (_uriresolver != null) {
- _xsltcFactory.setURIResolver(_uriresolver);
- }
- return _xsltcFactory.newTransformerHandler(templates);
- }
-
-
- /**
- * Create an XMLFilter that uses the given source as the
- * transformation instructions. Uses
- * com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactory.
- */
- public XMLFilter newXMLFilter(Source src)
- throws TransformerConfigurationException {
- if (_xsltcFactory == null) {
- createXSLTCTransformerFactory();
- }
- if (_errorlistener != null) {
- _xsltcFactory.setErrorListener(_errorlistener);
- }
- if (_uriresolver != null) {
- _xsltcFactory.setURIResolver(_uriresolver);
- }
- Templates templates = _xsltcFactory.newTemplates(src);
- if (templates == null ) return null;
- return newXMLFilter(templates);
- }
-
- /*
- * Create an XMLFilter that uses the given source as the
- * transformation instructions. Uses
- * com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactory.
- */
- public XMLFilter newXMLFilter(Templates templates)
- throws TransformerConfigurationException {
- try {
- return new com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter(templates);
- }
- catch(TransformerConfigurationException e1) {
- if (_xsltcFactory == null) {
- createXSLTCTransformerFactory();
- }
- ErrorListener errorListener = _xsltcFactory.getErrorListener();
- if(errorListener != null) {
- try {
- errorListener.fatalError(e1);
- return null;
- }
- catch( TransformerException e2) {
- new TransformerConfigurationException(e2);
- }
- }
- throw e1;
- }
- }
-}
diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/dom/CoreDOMImplementationImpl.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/dom/CoreDOMImplementationImpl.java
index 4c5ba830907..360bbb3786f 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/dom/CoreDOMImplementationImpl.java
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/dom/CoreDOMImplementationImpl.java
@@ -371,11 +371,7 @@ public class CoreDOMImplementationImpl
// to restrict the number of validation handlers being
// requested
if(freeValidatorIndex < 0) {
- return (RevalidationHandler) (ObjectFactory
- .newInstance(
- "com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator",
- ObjectFactory.findClassLoader(),
- true));
+ return new com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator();
}
// return first available validator
RevalidationHandler val = validators[freeValidatorIndex];
@@ -384,11 +380,7 @@ public class CoreDOMImplementationImpl
}
else if(schemaType == XMLGrammarDescription.XML_DTD) {
if(freeDTDValidatorIndex < 0) {
- return (RevalidationHandler) (ObjectFactory
- .newInstance(
- "com.sun.org.apache.xerces.internal.impl.dtd.XMLDTDValidator",
- ObjectFactory.findClassLoader(),
- true));
+ return new com.sun.org.apache.xerces.internal.impl.dtd.XMLDTDValidator();
}
// return first available validator
RevalidationHandler val = dtdValidators[freeDTDValidatorIndex];
diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java
index 7d2e50580ba..cb490f3287e 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java
@@ -638,7 +638,7 @@ public class XMLEntityManager implements XMLComponent, XMLEntityResolver {
// set preference for redirection
followRedirects = httpInputSource.getFollowHTTPRedirects();
if (!followRedirects) {
- setInstanceFollowRedirects(urlConnection, followRedirects);
+ urlConnection.setInstanceFollowRedirects(followRedirects);
}
}
@@ -2192,20 +2192,6 @@ public class XMLEntityManager implements XMLComponent, XMLEntityResolver {
} // expandSystemIdStrictOn(String,String):String
- /**
- * Attempt to set whether redirects will be followed for an HttpURLConnection.
- * This may fail on earlier JDKs which do not support setting this preference.
- */
- public static void setInstanceFollowRedirects(HttpURLConnection urlCon, boolean followRedirects) {
- try {
- Method method = HttpURLConnection.class.getMethod("setInstanceFollowRedirects", new Class[] {Boolean.TYPE});
- method.invoke(urlCon, new Object[] {followRedirects ? Boolean.TRUE : Boolean.FALSE});
- }
- // setInstanceFollowRedirects doesn't exist.
- catch (Exception exc) {}
- }
-
-
/**
* Helper method for expandSystemId(String,String,boolean):String
*/
diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/util/DOMUtil.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/util/DOMUtil.java
index 4a00810f106..e684ea66288 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/util/DOMUtil.java
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/util/DOMUtil.java
@@ -845,13 +845,7 @@ public class DOMUtil {
*/
public static DOMException createDOMException(short code, Throwable cause) {
DOMException de = new DOMException(code, cause != null ? cause.getMessage() : null);
- if (cause != null && ThrowableMethods.fgThrowableMethodsAvailable) {
- try {
- ThrowableMethods.fgThrowableInitCauseMethod.invoke(de, new Object [] {cause});
- }
- // Something went wrong. There's not much we can do about it.
- catch (Exception e) {}
- }
+ if (cause != null) de.initCause(cause);
return de;
}
@@ -860,42 +854,8 @@ public class DOMUtil {
*/
public static LSException createLSException(short code, Throwable cause) {
LSException lse = new LSException(code, cause != null ? cause.getMessage() : null);
- if (cause != null && ThrowableMethods.fgThrowableMethodsAvailable) {
- try {
- ThrowableMethods.fgThrowableInitCauseMethod.invoke(lse, new Object [] {cause});
- }
- // Something went wrong. There's not much we can do about it.
- catch (Exception e) {}
- }
+ if (cause != null) lse.initCause(cause);
return lse;
}
- /**
- * Holder of methods from java.lang.Throwable.
- */
- static class ThrowableMethods {
-
- // Method: java.lang.Throwable.initCause(java.lang.Throwable)
- private static java.lang.reflect.Method fgThrowableInitCauseMethod = null;
-
- // Flag indicating whether or not Throwable methods available.
- private static boolean fgThrowableMethodsAvailable = false;
-
- private ThrowableMethods() {}
-
- // Attempt to get methods for java.lang.Throwable on class initialization.
- static {
- try {
- fgThrowableInitCauseMethod = Throwable.class.getMethod("initCause", new Class [] {Throwable.class});
- fgThrowableMethodsAvailable = true;
- }
- // ClassNotFoundException, NoSuchMethodException or SecurityException
- // Whatever the case, we cannot use java.lang.Throwable.initCause(java.lang.Throwable).
- catch (Exception exc) {
- fgThrowableInitCauseMethod = null;
- fgThrowableMethodsAvailable = false;
- }
- }
- }
-
} // class DOMUtil
diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/xinclude/XIncludeTextReader.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/xinclude/XIncludeTextReader.java
index f6673b5d005..1ddc1b185f5 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/xinclude/XIncludeTextReader.java
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/xinclude/XIncludeTextReader.java
@@ -140,7 +140,7 @@ public class XIncludeTextReader {
// set preference for redirection
boolean followRedirects = httpInputSource.getFollowHTTPRedirects();
if (!followRedirects) {
- XMLEntityManager.setInstanceFollowRedirects(urlConnection, followRedirects);
+ urlConnection.setInstanceFollowRedirects(followRedirects);
}
}
diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/dtm/DTMException.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/dtm/DTMException.java
index b5677fc441f..7711ce73f88 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/dtm/DTMException.java
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/dtm/DTMException.java
@@ -323,63 +323,5 @@ public class DTMException extends RuntimeException {
super.printStackTrace(s);
} catch (Throwable e) {}
- boolean isJdk14OrHigher = false;
- try {
- Throwable.class.getMethod("getCause", (Class[]) null);
- isJdk14OrHigher = true;
- } catch (NoSuchMethodException nsme) {
- // do nothing
- }
-
- // The printStackTrace method of the Throwable class in jdk 1.4
- // and higher will include the cause when printing the backtrace.
- // The following code is only required when using jdk 1.3 or lower
- if (!isJdk14OrHigher) {
- Throwable exception = getException();
-
- for (int i = 0; (i < 10) && (null != exception); i++) {
- s.println("---------");
-
- try {
- if (exception instanceof DTMException) {
- String locInfo =
- ((DTMException) exception)
- .getLocationAsString();
-
- if (null != locInfo) {
- s.println(locInfo);
- }
- }
-
- exception.printStackTrace(s);
- } catch (Throwable e) {
- s.println("Could not print stack trace...");
- }
-
- try {
- Method meth =
- ((Object) exception).getClass().getMethod("getException",
- (Class[]) null);
-
- if (null != meth) {
- Throwable prev = exception;
-
- exception = (Throwable) meth.invoke(exception, (Object[]) null);
-
- if (prev == exception) {
- break;
- }
- } else {
- exception = null;
- }
- } catch (InvocationTargetException ite) {
- exception = null;
- } catch (IllegalAccessException iae) {
- exception = null;
- } catch (NoSuchMethodException nsme) {
- exception = null;
- }
- }
- }
}
}
diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/dtm/ref/DTMManagerDefault.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/dtm/ref/DTMManagerDefault.java
index 9f93f802ae5..1eadf3a5950 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/dtm/ref/DTMManagerDefault.java
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/dtm/ref/DTMManagerDefault.java
@@ -348,8 +348,7 @@ public class DTMManagerDefault extends DTMManager
if (haveXercesParser) {
// IncrementalSAXSource_Xerces to avoid threading.
try {
- coParser =(IncrementalSAXSource)
- Class.forName("com.sun.org.apache.xml.internal.dtm.ref.IncrementalSAXSource_Xerces").newInstance();
+ coParser = new com.sun.org.apache.xml.internal.dtm.ref.IncrementalSAXSource_Xerces();
} catch( Exception ex ) {
ex.printStackTrace();
coParser=null;
diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/dtm/ref/IncrementalSAXSource_Xerces.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/dtm/ref/IncrementalSAXSource_Xerces.java
index 29881ebabcc..963ccf02c5a 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/dtm/ref/IncrementalSAXSource_Xerces.java
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/dtm/ref/IncrementalSAXSource_Xerces.java
@@ -87,6 +87,9 @@ public class IncrementalSAXSource_Xerces
{
try
{
+ // This should be cleaned up and the use of reflection
+ // removed - see JDK-8129880
+
// Xerces-2 incremental parsing support (as of Beta 3)
// ContentHandlers still get set on fIncrementalParser (to get
// conversion from XNI events to SAX events), but
diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/readers/SAXCatalogReader.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/readers/SAXCatalogReader.java
index d5d5d2aca27..6cfe327bcd6 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/readers/SAXCatalogReader.java
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/resolver/readers/SAXCatalogReader.java
@@ -233,7 +233,13 @@ public class SAXCatalogReader implements CatalogReader, ContentHandler, Document
}
parser.parse(new InputSource(is), spHandler);
} else {
- Parser parser = (Parser) ReflectUtil.forName(parserClass).newInstance();
+ Class> c = ReflectUtil.forName(parserClass);
+ if (!Parser.class.isAssignableFrom(c)) {
+ throw new ClassCastException(parserClass
+ + " cannot be cast to "
+ + Parser.class.getName());
+ }
+ Parser parser = (Parser) c.newInstance();
parser.setDocumentHandler(this);
if (bResolver != null) {
parser.setEntityResolver(bResolver);
diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serialize/BaseMarkupSerializer.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serialize/BaseMarkupSerializer.java
index 2c9a4988fca..878616905b7 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serialize/BaseMarkupSerializer.java
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serialize/BaseMarkupSerializer.java
@@ -1220,37 +1220,13 @@ public abstract class BaseMarkupSerializer
if ( internal != null && internal.length() > 0 )
_printer.printText( internal );
endDTD();
- }
- // DOM Level 1 -- does implementation have methods?
- catch (NoSuchMethodError nsme) {
- Class docTypeClass = docType.getClass();
-
- String docTypePublicId = null;
- String docTypeSystemId = null;
- try {
- java.lang.reflect.Method getPublicId = docTypeClass.getMethod("getPublicId", (Class[]) null);
- if (getPublicId.getReturnType().equals(String.class)) {
- docTypePublicId = (String)getPublicId.invoke(docType, (Object[]) null);
- }
- }
- catch (Exception e) {
- // ignore
- }
- try {
- java.lang.reflect.Method getSystemId = docTypeClass.getMethod("getSystemId", (Class[]) null);
- if (getSystemId.getReturnType().equals(String.class)) {
- docTypeSystemId = (String)getSystemId.invoke(docType, (Object[]) null);
- }
- }
- catch (Exception e) {
- // ignore
- }
+ } catch (Exception e) {
+ // ignore
_printer.enterDTD();
- _docTypePublicId = docTypePublicId;
- _docTypeSystemId = docTypeSystemId;
+ _docTypePublicId = null;
+ _docTypeSystemId = null;
endDTD();
}
-
serializeDTD(docType.getName());
}
diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serialize/DOMSerializerImpl.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serialize/DOMSerializerImpl.java
index dc9378b39e5..d53d1b6649d 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serialize/DOMSerializerImpl.java
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serialize/DOMSerializerImpl.java
@@ -54,7 +54,6 @@ import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.ProcessingInstruction;
-import org.w3c.dom.Text;
import org.w3c.dom.ls.LSException;
import org.w3c.dom.ls.LSOutput;
import org.w3c.dom.ls.LSSerializer;
@@ -1030,15 +1029,12 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration {
private String _getXmlVersion(Node node) {
Document doc = (node.getNodeType() == Node.DOCUMENT_NODE)
? (Document) node : node.getOwnerDocument();
- if (doc != null && DocumentMethods.fgDocumentMethodsAvailable) {
+ if (doc != null) {
try {
- return (String) DocumentMethods.fgDocumentGetXmlVersionMethod.invoke(doc, (Object[]) null);
+ return doc.getXmlVersion();
} // The VM ran out of memory or there was some other serious problem. Re-throw.
- catch (VirtualMachineError vme) {
+ catch (VirtualMachineError | ThreadDeath vme) {
throw vme;
- } // ThreadDeath should always be re-thrown
- catch (ThreadDeath td) {
- throw td;
} // Ignore all other exceptions and errors
catch (Throwable t) {
}
@@ -1049,15 +1045,12 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration {
private String _getInputEncoding(Node node) {
Document doc = (node.getNodeType() == Node.DOCUMENT_NODE)
? (Document) node : node.getOwnerDocument();
- if (doc != null && DocumentMethods.fgDocumentMethodsAvailable) {
+ if (doc != null) {
try {
- return (String) DocumentMethods.fgDocumentGetInputEncodingMethod.invoke(doc, (Object[]) null);
+ return doc.getInputEncoding();
} // The VM ran out of memory or there was some other serious problem. Re-throw.
- catch (VirtualMachineError vme) {
+ catch (VirtualMachineError | ThreadDeath vme) {
throw vme;
- } // ThreadDeath should always be re-thrown
- catch (ThreadDeath td) {
- throw td;
} // Ignore all other exceptions and errors
catch (Throwable t) {
}
@@ -1068,15 +1061,12 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration {
private String _getXmlEncoding(Node node) {
Document doc = (node.getNodeType() == Node.DOCUMENT_NODE)
? (Document) node : node.getOwnerDocument();
- if (doc != null && DocumentMethods.fgDocumentMethodsAvailable) {
+ if (doc != null) {
try {
- return (String) DocumentMethods.fgDocumentGetXmlEncodingMethod.invoke(doc, (Object[]) null);
+ return doc.getXmlEncoding();
} // The VM ran out of memory or there was some other serious problem. Re-throw.
- catch (VirtualMachineError vme) {
+ catch (VirtualMachineError | ThreadDeath vme) {
throw vme;
- } // ThreadDeath should always be re-thrown
- catch (ThreadDeath td) {
- throw td;
} // Ignore all other exceptions and errors
catch (Throwable t) {
}
@@ -1084,42 +1074,4 @@ public class DOMSerializerImpl implements LSSerializer, DOMConfiguration {
return null;
}
- /**
- * Holder of DOM Level 3 methods from org.w3c.dom.Document.
- */
- static class DocumentMethods {
-
- // Method: org.w3c.dom.Document.getXmlVersion()
- private static java.lang.reflect.Method fgDocumentGetXmlVersionMethod = null;
-
- // Method: org.w3c.dom.Document.getInputEncoding()
- private static java.lang.reflect.Method fgDocumentGetInputEncodingMethod = null;
-
- // Method: org.w3c.dom.Document.getXmlEncoding()
- private static java.lang.reflect.Method fgDocumentGetXmlEncodingMethod = null;
-
- // Flag indicating whether or not Document methods are available.
- private static boolean fgDocumentMethodsAvailable = false;
-
- private DocumentMethods() {
- }
-
- // Attempt to get methods for org.w3c.dom.Document on class initialization.
- static {
- try {
- fgDocumentGetXmlVersionMethod = Document.class.getMethod("getXmlVersion", new Class[]{});
- fgDocumentGetInputEncodingMethod = Document.class.getMethod("getInputEncoding", new Class[]{});
- fgDocumentGetXmlEncodingMethod = Document.class.getMethod("getXmlEncoding", new Class[]{});
- fgDocumentMethodsAvailable = true;
- } // ClassNotFoundException, NoSuchMethodException or SecurityException
- // Whatever the case, we cannot retrieve the methods.
- catch (Exception exc) {
- fgDocumentGetXmlVersionMethod = null;
- fgDocumentGetInputEncodingMethod = null;
- fgDocumentGetXmlEncodingMethod = null;
- fgDocumentMethodsAvailable = false;
- }
- }
- }
-
} //DOMSerializerImpl
diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serialize/EncodingInfo.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serialize/EncodingInfo.java
index 6756daf410b..8b3d1261b00 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serialize/EncodingInfo.java
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serialize/EncodingInfo.java
@@ -26,6 +26,8 @@ import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import com.sun.org.apache.xerces.internal.util.EncodingMap;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetEncoder;
/**
* This class represents an encoding.
@@ -37,9 +39,6 @@ import com.sun.org.apache.xerces.internal.util.EncodingMap;
*/
public class EncodingInfo {
- // An array to hold the argument for a method of Charset, CharsetEncoder or CharToByteConverter.
- private Object [] fArgsForMethod = null;
-
// name of encoding as registered with IANA;
// preferably a MIME name, but aliases are fine too.
String ianaName;
@@ -47,15 +46,7 @@ public class EncodingInfo {
int lastPrintable;
// The CharsetEncoder with which we test unusual characters.
- Object fCharsetEncoder = null;
-
- // The CharToByteConverter with which we test unusual characters.
- Object fCharToByteConverter = null;
-
- // Is the converter null because it can't be instantiated
- // for some reason (perhaps we're running with insufficient authority as
- // an applet?
- boolean fHaveTriedCToB = false;
+ CharsetEncoder fCharsetEncoder = null;
// Is the charset encoder usable or available.
boolean fHaveTriedCharsetEncoder = false;
@@ -118,16 +109,12 @@ public class EncodingInfo {
private boolean isPrintable0(char ch) {
// Attempt to get a CharsetEncoder for this encoding.
- if (fCharsetEncoder == null && CharsetMethods.fgNIOCharsetAvailable && !fHaveTriedCharsetEncoder) {
- if (fArgsForMethod == null) {
- fArgsForMethod = new Object [1];
- }
+ if (fCharsetEncoder == null && !fHaveTriedCharsetEncoder) {
// try and create the CharsetEncoder
try {
- fArgsForMethod[0] = javaName;
- Object charset = CharsetMethods.fgCharsetForNameMethod.invoke(null, fArgsForMethod);
- if (((Boolean) CharsetMethods.fgCharsetCanEncodeMethod.invoke(charset, (Object[]) null)).booleanValue()) {
- fCharsetEncoder = CharsetMethods.fgCharsetNewEncoderMethod.invoke(charset, (Object[]) null);
+ Charset charset = java.nio.charset.Charset.forName(javaName);
+ if (charset.canEncode()) {
+ fCharsetEncoder = charset.newEncoder();
}
// This charset cannot be used for encoding, don't try it again...
else {
@@ -142,8 +129,7 @@ public class EncodingInfo {
// Attempt to use the CharsetEncoder to determine whether the character is printable.
if (fCharsetEncoder != null) {
try {
- fArgsForMethod[0] = new Character(ch);
- return ((Boolean) CharsetMethods.fgCharsetEncoderCanEncodeMethod.invoke(fCharsetEncoder, fArgsForMethod)).booleanValue();
+ return fCharsetEncoder.canEncode(ch);
}
catch (Exception e) {
// obviously can't use this charset encoder; possibly a JDK bug
@@ -152,39 +138,7 @@ public class EncodingInfo {
}
}
- // As a last resort try to use a sun.io.CharToByteConverter to
- // determine whether this character is printable. We will always
- // reach here on JDK 1.3 or below.
- if (fCharToByteConverter == null) {
- if (fHaveTriedCToB || !CharToByteConverterMethods.fgConvertersAvailable) {
- // forget it; nothing we can do...
- return false;
- }
- if (fArgsForMethod == null) {
- fArgsForMethod = new Object [1];
- }
- // try and create the CharToByteConverter
- try {
- fArgsForMethod[0] = javaName;
- fCharToByteConverter = CharToByteConverterMethods.fgGetConverterMethod.invoke(null, fArgsForMethod);
- }
- catch (Exception e) {
- // don't try it again...
- fHaveTriedCToB = true;
- return false;
- }
- }
- try {
- fArgsForMethod[0] = new Character(ch);
- return ((Boolean) CharToByteConverterMethods.fgCanConvertMethod.invoke(fCharToByteConverter, fArgsForMethod)).booleanValue();
- }
- catch (Exception e) {
- // obviously can't use this converter; probably some kind of
- // security restriction
- fCharToByteConverter = null;
- fHaveTriedCToB = false;
- return false;
- }
+ return false;
}
// is this an encoding name recognized by this JDK?
@@ -194,82 +148,4 @@ public class EncodingInfo {
String s = new String(bTest, name);
}
- /**
- * Holder of methods from java.nio.charset.Charset and java.nio.charset.CharsetEncoder.
- */
- static class CharsetMethods {
-
- // Method: java.nio.charset.Charset.forName(java.lang.String)
- private static java.lang.reflect.Method fgCharsetForNameMethod = null;
-
- // Method: java.nio.charset.Charset.canEncode()
- private static java.lang.reflect.Method fgCharsetCanEncodeMethod = null;
-
- // Method: java.nio.charset.Charset.newEncoder()
- private static java.lang.reflect.Method fgCharsetNewEncoderMethod = null;
-
- // Method: java.nio.charset.CharsetEncoder.canEncode(char)
- private static java.lang.reflect.Method fgCharsetEncoderCanEncodeMethod = null;
-
- // Flag indicating whether or not java.nio.charset.* is available.
- private static boolean fgNIOCharsetAvailable = false;
-
- private CharsetMethods() {}
-
- // Attempt to get methods for Charset and CharsetEncoder on class initialization.
- static {
- try {
- Class charsetClass = Class.forName("java.nio.charset.Charset");
- Class charsetEncoderClass = Class.forName("java.nio.charset.CharsetEncoder");
- fgCharsetForNameMethod = charsetClass.getMethod("forName", new Class [] {String.class});
- fgCharsetCanEncodeMethod = charsetClass.getMethod("canEncode", new Class [] {});
- fgCharsetNewEncoderMethod = charsetClass.getMethod("newEncoder", new Class [] {});
- fgCharsetEncoderCanEncodeMethod = charsetEncoderClass.getMethod("canEncode", new Class [] {Character.TYPE});
- fgNIOCharsetAvailable = true;
- }
- // ClassNotFoundException, NoSuchMethodException or SecurityException
- // Whatever the case, we cannot use java.nio.charset.*.
- catch (Exception exc) {
- fgCharsetForNameMethod = null;
- fgCharsetCanEncodeMethod = null;
- fgCharsetEncoderCanEncodeMethod = null;
- fgCharsetNewEncoderMethod = null;
- fgNIOCharsetAvailable = false;
- }
- }
- }
-
- /**
- * Holder of methods from sun.io.CharToByteConverter.
- */
- static class CharToByteConverterMethods {
-
- // Method: sun.io.CharToByteConverter.getConverter(java.lang.String)
- private static java.lang.reflect.Method fgGetConverterMethod = null;
-
- // Method: sun.io.CharToByteConverter.canConvert(char)
- private static java.lang.reflect.Method fgCanConvertMethod = null;
-
- // Flag indicating whether or not sun.io.CharToByteConverter is available.
- private static boolean fgConvertersAvailable = false;
-
- private CharToByteConverterMethods() {}
-
- // Attempt to get methods for char to byte converter on class initialization.
- static {
- try {
- Class clazz = Class.forName("sun.io.CharToByteConverter");
- fgGetConverterMethod = clazz.getMethod("getConverter", new Class [] {String.class});
- fgCanConvertMethod = clazz.getMethod("canConvert", new Class [] {Character.TYPE});
- fgConvertersAvailable = true;
- }
- // ClassNotFoundException, NoSuchMethodException or SecurityException
- // Whatever the case, we cannot use sun.io.CharToByteConverter.
- catch (Exception exc) {
- fgGetConverterMethod = null;
- fgCanConvertMethod = null;
- fgConvertersAvailable = false;
- }
- }
- }
}
diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/compiler/FunctionTable.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/compiler/FunctionTable.java
index 6d5b7ff3394..f216fc91a8b 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/compiler/FunctionTable.java
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/compiler/FunctionTable.java
@@ -378,6 +378,12 @@ public class FunctionTable
int funcIndex;
Object funcIndexObj = getFunctionID(name);
+ if (func != null && !Function.class.isAssignableFrom(func)) {
+ throw new ClassCastException(func.getName()
+ + " cannot be cast to "
+ + Function.class.getName());
+ }
+
if (null != funcIndexObj)
{
funcIndex = ((Integer) funcIndexObj).intValue();
diff --git a/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/writers/XMLDOMWriterImpl.java b/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/writers/XMLDOMWriterImpl.java
index 6ab58d44349..c24e9cfcafe 100644
--- a/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/writers/XMLDOMWriterImpl.java
+++ b/jaxp/src/java.xml/share/classes/com/sun/xml/internal/stream/writers/XMLDOMWriterImpl.java
@@ -64,7 +64,6 @@ public class XMLDOMWriterImpl implements XMLStreamWriter {
private Node currentNode = null;
private Node node = null;
private NamespaceSupport namespaceContext = null;
- private Method mXmlVersion = null;
private boolean [] needContextPop = null;
private StringBuffer stringBuffer = null;
private int resizeValue = 20;
@@ -83,25 +82,11 @@ public class XMLDOMWriterImpl implements XMLStreamWriter {
ownerDoc = node.getOwnerDocument();
currentNode = node;
}
- getDLThreeMethods();
stringBuffer = new StringBuffer();
needContextPop = new boolean[resizeValue];
namespaceContext = new NamespaceSupport();
}
- private void getDLThreeMethods(){
- try{
- mXmlVersion = ownerDoc.getClass().getMethod("setXmlVersion",new Class[] {String.class});
- }catch(NoSuchMethodException mex){
- //log these errors at fine level.
- mXmlVersion = null;
- }catch(SecurityException se){
- //log these errors at fine level.
- mXmlVersion = null;
- }
- }
-
-
/**
* This method has no effect when called.
* @throws javax.xml.stream.XMLStreamException {@inheritDoc}
@@ -557,15 +542,7 @@ public class XMLDOMWriterImpl implements XMLStreamWriter {
* @throws javax.xml.stream.XMLStreamException {@inheritDoc}
*/
public void writeStartDocument() throws XMLStreamException {
- try{
- if(mXmlVersion != null){
- mXmlVersion.invoke(ownerDoc, new Object[] {"1.0"});
- }
- }catch(IllegalAccessException iae){
- throw new XMLStreamException(iae);
- }catch(InvocationTargetException ite){
- throw new XMLStreamException(ite);
- }
+ ownerDoc.setXmlVersion("1.0");
}
/**
@@ -575,15 +552,7 @@ public class XMLDOMWriterImpl implements XMLStreamWriter {
* @throws javax.xml.stream.XMLStreamException {@inheritDoc}
*/
public void writeStartDocument(String version) throws XMLStreamException {
- try{
- if(mXmlVersion != null){
- mXmlVersion.invoke(ownerDoc, new Object[] {version});
- }
- }catch(IllegalAccessException iae){
- throw new XMLStreamException(iae);
- }catch(InvocationTargetException ite){
- throw new XMLStreamException(ite);
- }
+ ownerDoc.setXmlVersion(version);
}
/**
@@ -594,15 +563,7 @@ public class XMLDOMWriterImpl implements XMLStreamWriter {
* @throws javax.xml.stream.XMLStreamException {@inheritDoc}
*/
public void writeStartDocument(String encoding, String version) throws XMLStreamException {
- try{
- if(mXmlVersion != null){
- mXmlVersion.invoke(ownerDoc, new Object[] {version});
- }
- }catch(IllegalAccessException iae){
- throw new XMLStreamException(iae);
- }catch(InvocationTargetException ite){
- throw new XMLStreamException(ite);
- }
+ ownerDoc.setXmlVersion(version);
//TODO: What to do with encoding.-Venu
}
diff --git a/jaxp/src/java.xml/share/classes/javax/xml/transform/TransformerException.java b/jaxp/src/java.xml/share/classes/javax/xml/transform/TransformerException.java
index dfd48246e27..78a058c322d 100644
--- a/jaxp/src/java.xml/share/classes/javax/xml/transform/TransformerException.java
+++ b/jaxp/src/java.xml/share/classes/javax/xml/transform/TransformerException.java
@@ -110,6 +110,12 @@ public class TransformerException extends Exception {
*/
public synchronized Throwable initCause(Throwable cause) {
+ // TransformerException doesn't set its cause (probably
+ // because it predates initCause()) - and we may not want
+ // to change this since Exceptions are serializable...
+ // But this also leads to the broken code in printStackTrace
+ // below...
+
if (this.containedException != null) {
throw new IllegalStateException("Can't overwrite cause");
}
@@ -312,61 +318,57 @@ public class TransformerException extends Exception {
}
try {
- String locInfo = getLocationAsString();
-
- if (null != locInfo) {
- s.println(locInfo);
- }
-
- super.printStackTrace(s);
- } catch (Throwable e) {}
-
- Throwable exception = getException();
-
- for (int i = 0; (i < 10) && (null != exception); i++) {
- s.println("---------");
-
try {
- if (exception instanceof TransformerException) {
- String locInfo =
- ((TransformerException) exception)
- .getLocationAsString();
+ String locInfo = getLocationAsString();
- if (null != locInfo) {
- s.println(locInfo);
- }
+ if (null != locInfo) {
+ s.println(locInfo);
}
- exception.printStackTrace(s);
- } catch (Throwable e) {
- s.println("Could not print stack trace...");
- }
+ super.printStackTrace(s);
+ } catch (Throwable e) {}
- try {
- Method meth =
- ((Object) exception).getClass().getMethod("getException",
- (Class[]) null);
+ Throwable exception = getException();
- if (null != meth) {
- Throwable prev = exception;
+ for (int i = 0; (i < 10) && (null != exception); i++) {
+ s.println("---------");
- exception = (Throwable) meth.invoke(exception, (Object[]) null);
+ try {
+ exception.printStackTrace(s);
+ // if exception is a TransformerException it will print
+ // its contained exception, so we don't need to redo it here,
+ // and we can exit the loop now.
+ if (exception instanceof TransformerException) break;
+ } catch (Throwable e) {
+ s.println("Could not print stack trace...");
+ }
- if (prev == exception) {
- break;
+ try {
+ // Is this still needed?
+ Method meth = exception.getClass().getMethod("getException");
+
+ if (null != meth) {
+ Throwable prev = exception;
+
+ exception = (Throwable) meth.invoke(exception, (Object[]) null);
+
+ if (prev == exception) {
+ break;
+ }
+ } else {
+ exception = null;
}
- } else {
+ } catch (InvocationTargetException ite) {
+ exception = null;
+ } catch (IllegalAccessException iae) {
+ exception = null;
+ } catch (NoSuchMethodException nsme) {
exception = null;
}
- } catch (InvocationTargetException ite) {
- exception = null;
- } catch (IllegalAccessException iae) {
- exception = null;
- } catch (NoSuchMethodException nsme) {
- exception = null;
}
+ } finally {
+ // ensure output is written
+ s.flush();
}
- // insure output is written
- s.flush();
}
}
diff --git a/jaxp/src/java.xml/share/classes/javax/xml/validation/SchemaFactoryFinder.java b/jaxp/src/java.xml/share/classes/javax/xml/validation/SchemaFactoryFinder.java
index 4d384a418a7..b0ae3a4cb40 100644
--- a/jaxp/src/java.xml/share/classes/javax/xml/validation/SchemaFactoryFinder.java
+++ b/jaxp/src/java.xml/share/classes/javax/xml/validation/SchemaFactoryFinder.java
@@ -28,7 +28,6 @@ package javax.xml.validation;
import java.io.File;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
-import java.net.URL;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedAction;
diff --git a/jaxp/src/java.xml/share/classes/javax/xml/validation/SecuritySupport.java b/jaxp/src/java.xml/share/classes/javax/xml/validation/SecuritySupport.java
index 1f1741e83b2..0416527be15 100644
--- a/jaxp/src/java.xml/share/classes/javax/xml/validation/SecuritySupport.java
+++ b/jaxp/src/java.xml/share/classes/javax/xml/validation/SecuritySupport.java
@@ -41,13 +41,10 @@ class SecuritySupport {
ClassLoader getContextClassLoader() {
return
- AccessController.doPrivileged(new PrivilegedAction() {
+ AccessController.doPrivileged(new PrivilegedAction<>() {
@Override
public ClassLoader run() {
- ClassLoader cl = null;
- //try {
- cl = Thread.currentThread().getContextClassLoader();
- //} catch (SecurityException ex) { }
+ ClassLoader cl = Thread.currentThread().getContextClassLoader();
if (cl == null)
cl = ClassLoader.getSystemClassLoader();
return cl;
@@ -56,7 +53,7 @@ class SecuritySupport {
}
String getSystemProperty(final String propName) {
- return AccessController.doPrivileged(new PrivilegedAction() {
+ return AccessController.doPrivileged(new PrivilegedAction<>() {
@Override
public String run() {
return System.getProperty(propName);
@@ -69,7 +66,7 @@ class SecuritySupport {
{
try {
return AccessController.doPrivileged(
- new PrivilegedExceptionAction() {
+ new PrivilegedExceptionAction<>() {
@Override
public FileInputStream run() throws FileNotFoundException {
return new FileInputStream(file);
@@ -82,7 +79,7 @@ class SecuritySupport {
// Used for debugging purposes
String getClassSource(Class> cls) {
- return AccessController.doPrivileged(new PrivilegedAction() {
+ return AccessController.doPrivileged(new PrivilegedAction<>() {
@Override
public String run() {
CodeSource cs = cls.getProtectionDomain().getCodeSource();
@@ -97,7 +94,7 @@ class SecuritySupport {
}
boolean doesFileExist(final File f) {
- return AccessController.doPrivileged(new PrivilegedAction() {
+ return AccessController.doPrivileged(new PrivilegedAction<>() {
@Override
public Boolean run() {
return f.exists();
diff --git a/jaxp/src/java.xml/share/classes/javax/xml/xpath/SecuritySupport.java b/jaxp/src/java.xml/share/classes/javax/xml/xpath/SecuritySupport.java
index 9df3ec2c99a..f7b5cc41d97 100644
--- a/jaxp/src/java.xml/share/classes/javax/xml/xpath/SecuritySupport.java
+++ b/jaxp/src/java.xml/share/classes/javax/xml/xpath/SecuritySupport.java
@@ -40,7 +40,7 @@ class SecuritySupport {
ClassLoader getContextClassLoader() {
- return AccessController.doPrivileged(new PrivilegedAction() {
+ return AccessController.doPrivileged(new PrivilegedAction<>() {
@Override
public ClassLoader run() {
ClassLoader cl = null;
@@ -53,7 +53,7 @@ class SecuritySupport {
}
String getSystemProperty(final String propName) {
- return AccessController.doPrivileged(new PrivilegedAction() {
+ return AccessController.doPrivileged(new PrivilegedAction<>() {
@Override
public String run() {
return System.getProperty(propName);
@@ -66,7 +66,7 @@ class SecuritySupport {
{
try {
return AccessController.doPrivileged(
- new PrivilegedExceptionAction() {
+ new PrivilegedExceptionAction<>() {
@Override
public FileInputStream run() throws FileNotFoundException {
return new FileInputStream(file);
@@ -79,7 +79,7 @@ class SecuritySupport {
// Used for debugging purposes
String getClassSource(Class> cls) {
- return AccessController.doPrivileged(new PrivilegedAction() {
+ return AccessController.doPrivileged(new PrivilegedAction<>() {
@Override
public String run() {
CodeSource cs = cls.getProtectionDomain().getCodeSource();
@@ -94,7 +94,7 @@ class SecuritySupport {
}
boolean doesFileExist(final File f) {
- return AccessController.doPrivileged(new PrivilegedAction() {
+ return AccessController.doPrivileged(new PrivilegedAction<>() {
@Override
public Boolean run() {
return f.exists();
diff --git a/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathFactoryFinder.java b/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathFactoryFinder.java
index 6263959a9a6..dc950cbc896 100644
--- a/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathFactoryFinder.java
+++ b/jaxp/src/java.xml/share/classes/javax/xml/xpath/XPathFactoryFinder.java
@@ -28,7 +28,6 @@ package javax.xml.xpath;
import java.io.File;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
-import java.net.URL;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedAction;
diff --git a/jaxp/src/java.xml/share/classes/org/w3c/dom/bootstrap/DOMImplementationRegistry.java b/jaxp/src/java.xml/share/classes/org/w3c/dom/bootstrap/DOMImplementationRegistry.java
index 48fda761e1e..6099cf3cb32 100644
--- a/jaxp/src/java.xml/share/classes/org/w3c/dom/bootstrap/DOMImplementationRegistry.java
+++ b/jaxp/src/java.xml/share/classes/org/w3c/dom/bootstrap/DOMImplementationRegistry.java
@@ -333,59 +333,36 @@ public final class DOMImplementationRegistry {
}
/**
- * A simple JRE (Java Runtime Environment) 1.1 test
- *
- * @return true if JRE 1.1
- */
- private static boolean isJRE11() {
- try {
- Class c = Class.forName("java.security.AccessController");
- // java.security.AccessController existed since 1.2 so, if no
- // exception was thrown, the DOM application is running in a JRE
- // 1.2 or higher
- return false;
- } catch (Exception ex) {
- // ignore
- }
- return true;
- }
-
- /**
- * This method returns the ContextClassLoader or null if
- * running in a JRE 1.1
+ * This method returns the ContextClassLoader.
*
* @return The Context Classloader
*/
private static ClassLoader getContextClassLoader() {
- return isJRE11()
- ? null
- : (ClassLoader)
- AccessController.doPrivileged(new PrivilegedAction() {
- public Object run() {
- ClassLoader classLoader = null;
- try {
- classLoader =
- Thread.currentThread().getContextClassLoader();
- } catch (SecurityException ex) {
- }
- return classLoader;
+ return AccessController.doPrivileged(new PrivilegedAction<>() {
+ @Override
+ public ClassLoader run() {
+ ClassLoader classLoader = null;
+ try {
+ classLoader =
+ Thread.currentThread().getContextClassLoader();
+ } catch (SecurityException ex) {
}
- });
+ return classLoader;
+ }
+ });
}
/**
* This method returns the system property indicated by the specified name
- * after checking access control privileges. For a JRE 1.1, this check is
- * not done.
+ * after checking access control privileges.
*
* @param name the name of the system property
* @return the system property
*/
private static String getSystemProperty(final String name) {
- return isJRE11()
- ? (String) System.getProperty(name)
- : (String) AccessController.doPrivileged(new PrivilegedAction() {
- public Object run() {
+ return AccessController.doPrivileged(new PrivilegedAction<>() {
+ @Override
+ public String run() {
return System.getProperty(name);
}
});
@@ -394,7 +371,7 @@ public final class DOMImplementationRegistry {
/**
* This method returns an Inputstream for the reading resource
* META_INF/services/org.w3c.dom.DOMImplementationSourceList after checking
- * access control privileges. For a JRE 1.1, this check is not done.
+ * access control privileges.
*
* @param classLoader classLoader
* @param name the resource
@@ -402,28 +379,18 @@ public final class DOMImplementationRegistry {
*/
private static InputStream getResourceAsStream(final ClassLoader classLoader,
final String name) {
- if (isJRE11()) {
- InputStream ris;
- if (classLoader == null) {
- ris = ClassLoader.getSystemResourceAsStream(name);
- } else {
- ris = classLoader.getResourceAsStream(name);
- }
- return ris;
- } else {
- return (InputStream)
- AccessController.doPrivileged(new PrivilegedAction() {
- public Object run() {
- InputStream ris;
- if (classLoader == null) {
- ris =
- ClassLoader.getSystemResourceAsStream(name);
- } else {
- ris = classLoader.getResourceAsStream(name);
- }
- return ris;
- }
- });
- }
+ return AccessController.doPrivileged(new PrivilegedAction<>() {
+ @Override
+ public InputStream run() {
+ InputStream ris;
+ if (classLoader == null) {
+ ris =
+ ClassLoader.getSystemResourceAsStream(name);
+ } else {
+ ris = classLoader.getResourceAsStream(name);
+ }
+ return ris;
+ }
+ });
}
}
diff --git a/jaxws/.hgtags b/jaxws/.hgtags
index 9808e797b01..b27eb94f4d6 100644
--- a/jaxws/.hgtags
+++ b/jaxws/.hgtags
@@ -316,3 +316,4 @@ c9785bc8ade98a16a050d7520b70c68363857e00 jdk9-b67
b5878b03d1b2e105917d959fbfa3c57c22495803 jdk9-b68
f5911c6155c29ac24b6f9068273207e5ebd3a3df jdk9-b69
94084caa27a3c8a09a7510aef596ebd64e97c569 jdk9-b70
+61caeb7061bbf8cc74a767997e5d17cc00712629 jdk9-b71
diff --git a/jaxws/src/java.activation/share/classes/com/sun/activation/registries/MailcapTokenizer.java b/jaxws/src/java.activation/share/classes/com/sun/activation/registries/MailcapTokenizer.java
index 225d7e15a8e..9ece7dc645d 100644
--- a/jaxws/src/java.activation/share/classes/com/sun/activation/registries/MailcapTokenizer.java
+++ b/jaxws/src/java.activation/share/classes/com/sun/activation/registries/MailcapTokenizer.java
@@ -42,7 +42,7 @@ public class MailcapTokenizer {
/**
* Constructor
*
- * @parameter inputString the string to tokenize
+ * @param inputString the string to tokenize
*/
public MailcapTokenizer(String inputString) {
data = inputString;
@@ -73,7 +73,7 @@ public class MailcapTokenizer {
/**
* Retrieve current token.
*
- * @returns The current token value
+ * @return The current token value
*/
public int getCurrentToken() {
return currentToken;
@@ -115,7 +115,7 @@ public class MailcapTokenizer {
/*
* Retrieve current token value.
*
- * @returns A String containing the current token value
+ * @return A String containing the current token value
*/
public String getCurrentTokenValue() {
return currentTokenValue;
@@ -123,7 +123,7 @@ public class MailcapTokenizer {
/*
* Process the next token.
*
- * @returns the next token
+ * @return the next token
*/
public int nextToken() {
if (dataIndex < dataLength) {
diff --git a/jaxws/src/java.xml.bind/share/classes/javax/xml/bind/JAXBContext.java b/jaxws/src/java.xml.bind/share/classes/javax/xml/bind/JAXBContext.java
index 376b6738cb5..c5185236400 100644
--- a/jaxws/src/java.xml.bind/share/classes/javax/xml/bind/JAXBContext.java
+++ b/jaxws/src/java.xml.bind/share/classes/javax/xml/bind/JAXBContext.java
@@ -34,8 +34,7 @@ import java.io.IOException;
import java.io.InputStream;
/**
- *
- * The JAXBContext class provides the client's entry point to the
+ * The {@code JAXBContext} class provides the client's entry point to the
* JAXB API. It provides an abstraction for managing the XML/Java binding
* information necessary to implement the JAXB binding framework operations:
* unmarshal, marshal and validate.
@@ -62,16 +61,16 @@ import java.io.InputStream;
*
* The following JAXB 1.0 requirement is only required for schema to
* java interface/implementation binding. It does not apply to JAXB annotated
- * classes. JAXB Providers must generate a jaxb.properties file in
+ * classes. JAXB Providers must generate a {@code jaxb.properties} file in
* each package containing schema derived classes. The property file must
- * contain a property named javax.xml.bind.context.factory whose
- * value is the name of the class that implements the createContext
+ * contain a property named {@code javax.xml.bind.context.factory} whose
+ * value is the name of the class that implements the {@code createContext}
* APIs.
*
*
* The class supplied by the provider does not have to be assignable to
- * javax.xml.bind.JAXBContext, it simply has to provide a class that
- * implements the createContext APIs.
+ * {@code javax.xml.bind.JAXBContext}, it simply has to provide a class that
+ * implements the {@code createContext} APIs.
*
*
* In addition, the provider must call the
@@ -91,13 +90,13 @@ import java.io.InputStream;
* Additionally, the unmarshal method allows for an unrecognized root element that
* has an xsi:type attribute's value that references a type definition declared in
* the schema to be unmarshalled as the root of an instance document.
- * The JAXBContext object
+ * The {@code JAXBContext} object
* allows the merging of global elements and type definitions across a set of schemas (listed
- * in the contextPath). Since each schema in the schema set can belong
+ * in the {@code contextPath}). Since each schema in the schema set can belong
* to distinct namespaces, the unification of schemas to an unmarshalling
* context should be namespace independent. This means that a client
* application is able to unmarshal XML documents that are instances of
- * any of the schemas listed in the contextPath. For example:
+ * any of the schemas listed in the {@code contextPath}. For example:
*
*
* JAXBContext jc = JAXBContext.newInstance( "com.acme.foo:com.acme.bar" );
@@ -114,12 +113,12 @@ import java.io.InputStream;
* For schema-derived interface/implementation classes and for the
* creation of elements that are not bound to a JAXB-annotated
* class, an application needs to have access and knowledge about each of
- * the schema derived ObjectFactory classes that exist in each of
- * java packages contained in the contextPath. For each schema
+ * the schema derived {@code ObjectFactory} classes that exist in each of
+ * java packages contained in the {@code contextPath}. For each schema
* derived java class, there is a static factory method that produces objects
* of that type. For example,
- * assume that after compiling a schema, you have a package com.acme.foo
- * that contains a schema derived interface named PurchaseOrder. In
+ * assume that after compiling a schema, you have a package {@code com.acme.foo}
+ * that contains a schema derived interface named {@code PurchaseOrder}. In
* order to create objects of that type, the client application would use the
* factory method like this:
*
@@ -133,25 +132,25 @@ import java.io.InputStream;
* it can use the mutator methods to set content on it.
*
*
- * For more information on the generated ObjectFactory classes, see
+ * For more information on the generated {@code ObjectFactory} classes, see
* Section 4.2 Java Package of the specification.
*
*
* The provider must generate a class in each
* package that contains all of the necessary object factory methods for that
* package named ObjectFactory as well as the static
- * newInstance( javaContentInterface ) method
+ * {@code newInstance( javaContentInterface )} method
*
*
Marshalling
*
* The {@link Marshaller} class provides the client application the ability
* to convert a Java content tree back into XML data. There is no difference
* between marshalling a content tree that is created manually using the factory
- * methods and marshalling a content tree that is the result an unmarshal
- * operation. Clients can marshal a java content tree back to XML data
- * to a java.io.OutputStream or a java.io.Writer. The
+ * methods and marshalling a content tree that is the result an {@code unmarshal}
+ * operation. Clients can marshal a java content tree back to XML data
+ * to a {@code java.io.OutputStream} or a {@code java.io.Writer}. The
* marshalling process can alternatively produce SAX2 event streams to a
- * registered ContentHandler or produce a DOM Node object.
+ * registered {@code ContentHandler} or produce a DOM Node object.
* Client applications have control over the output encoding as well as
* whether or not to marshal the XML data as a complete document or
* as a fragment.
@@ -178,7 +177,7 @@ import java.io.InputStream;
* Validation has been changed significantly since JAXB 1.0. The {@link Validator}
* class has been deprecated and made optional. This means that you are advised
* not to use this class and, in fact, it may not even be available depending on
- * your JAXB provider. JAXB 1.0 client applications that rely on Validator
+ * your JAXB provider. JAXB 1.0 client applications that rely on {@code Validator}
* will still work properly when deployed with the JAXB 1.0 runtime system.
*
* In JAXB 2.0, the {@link Unmarshaller} has included convenince methods that expose
@@ -192,8 +191,8 @@ import java.io.InputStream;
* The following JAXB 1.0 restriction only applies to binding schema to
* interfaces/implementation classes.
* Since this binding does not require a common runtime system, a JAXB
- * client application must not attempt to mix runtime objects (JAXBContext,
- * Marshaller, etc. ) from different providers. This does not
+ * client application must not attempt to mix runtime objects ({@code JAXBContext,
+ * Marshaller}, etc. ) from different providers. This does not
* mean that the client application isn't portable, it simply means that a
* client has to use a runtime system provided by the same provider that was
* used to compile the schema.
@@ -201,14 +200,14 @@ import java.io.InputStream;
*
*
Discovery of JAXB implementation
*
- * When one of the newInstance methods is called, a JAXB implementation is discovered
+ * When one of the {@code newInstance} methods is called, a JAXB implementation is discovered
* by the following steps.
*
*
*
*
* For each package/class explicitly passed in to the {@link #newInstance} method, in the order they are specified,
- * jaxb.properties file is looked up in its package, by using the associated classloader —
+ * {@code jaxb.properties} file is looked up in its package, by using the associated classloader —
* this is {@link Class#getClassLoader() the owner class loader} for a {@link Class} argument, and for a package
* the specified {@link ClassLoader}.
*
@@ -269,8 +268,6 @@ import java.io.InputStream;
* {@link javax.xml.bind.JAXBContextFactory#createContext(Class[], java.util.Map)} is invoked
* to create a {@link JAXBContext}.
*
- *
- *
* @apiNote
*
Service discovery method using file /META-INF/services/javax.xml.bind.JAXBContext (described in step 4)
* and leveraging provider's static methods is supported only to allow backwards compatibility, but it is strongly
@@ -294,7 +291,7 @@ public abstract class JAXBContext {
/**
* The name of the property that contains the name of the class capable
- * of creating new JAXBContext objects.
+ * of creating new {@code JAXBContext} objects.
*/
public static final String JAXB_CONTEXT_FACTORY = "javax.xml.bind.JAXBContextFactory";
@@ -303,8 +300,7 @@ public abstract class JAXBContext {
/**
- *
- * Create a new instance of a JAXBContext class.
+ * Create a new instance of a {@code JAXBContext} class.
*
*
* This is a convenience method to invoke the
@@ -312,7 +308,7 @@ public abstract class JAXBContext {
* the context class loader of the current thread.
*
* @throws JAXBException if an error was encountered while creating the
- * JAXBContext such as
+ * {@code JAXBContext} such as
*
*
failure to locate either ObjectFactory.class or jaxb.index in the packages
*
an ambiguity among global elements contained in the contextPath
@@ -328,8 +324,7 @@ public abstract class JAXBContext {
}
/**
- *
- * Create a new instance of a JAXBContext class.
+ * Create a new instance of a {@code JAXBContext} class.
*
*
* The client application must supply a context path which is a list of
@@ -340,7 +335,7 @@ public abstract class JAXBContext {
* ObjectFactory.class generated per package.
* Alternatively than being listed in the context path, programmer
* annotated JAXB mapped classes can be listed in a
- * jaxb.index resource file, format described below.
+ * {@code jaxb.index} resource file, format described below.
* Note that a java package can contain both schema-derived classes and
* user annotated JAXB classes. Additionally, the java package may
* contain JAXB package annotations that must be processed. (see JLS,
@@ -349,7 +344,7 @@ public abstract class JAXBContext {
*
*
* Every package listed on the contextPath must meet one or both of the
- * following conditions otherwise a JAXBException will be thrown:
+ * following conditions otherwise a {@code JAXBException} will be thrown:
*
*
*
it must contain ObjectFactory.class
@@ -367,12 +362,12 @@ public abstract class JAXBContext {
* are reachable, as defined in {@link #newInstance(Class...)}, from the
* listed classes are also registered with JAXBContext.
*
- * Constraints on class name occuring in a jaxb.index file are:
+ * Constraints on class name occuring in a {@code jaxb.index} file are:
*
*
Must not end with ".class".
*
Class names are resolved relative to package containing
- * jaxb.index file. Only classes occuring directly in package
- * containing jaxb.index file are allowed.
+ * {@code jaxb.index} file. Only classes occuring directly in package
+ * containing {@code jaxb.index} file are allowed.
*
Fully qualified class names are not allowed.
* A qualified class name,relative to current package,
* is only allowed to specify a nested or inner class.
@@ -381,21 +376,21 @@ public abstract class JAXBContext {
*
* To maintain compatibility with JAXB 1.0 schema to java
* interface/implementation binding, enabled by schema customization
- * {@literal },
+ * {@code },
* the JAXB provider will ensure that each package on the context path
- * has a jaxb.properties file which contains a value for the
- * javax.xml.bind.context.factory property and that all values
+ * has a {@code jaxb.properties} file which contains a value for the
+ * {@code javax.xml.bind.context.factory} property and that all values
* resolve to the same provider. This requirement does not apply to
* JAXB annotated classes.
*
*
* If there are any global XML element name collisions across the various
- * packages listed on the contextPath, a JAXBException
+ * packages listed on the {@code contextPath}, a {@code JAXBException}
* will be thrown.
*
*
* Mixing generated interface/impl bindings from multiple JAXB Providers
- * in the same context path may result in a JAXBException
+ * in the same context path may result in a {@code JAXBException}
* being thrown.
*
*
@@ -408,9 +403,9 @@ public abstract class JAXBContext {
* This class loader will be used to locate the implementation
* classes.
*
- * @return a new instance of a JAXBContext
+ * @return a new instance of a {@code JAXBContext}
* @throws JAXBException if an error was encountered while creating the
- * JAXBContext such as
+ * {@code JAXBContext} such as
*
*
failure to locate either ObjectFactory.class or jaxb.index in the packages
*
an ambiguity among global elements contained in the contextPath
@@ -424,8 +419,7 @@ public abstract class JAXBContext {
}
/**
- *
- * Create a new instance of a JAXBContext class.
+ * Create a new instance of a {@code JAXBContext} class.
*
*
* This is mostly the same as {@link JAXBContext#newInstance(String, ClassLoader)},
@@ -434,7 +428,7 @@ public abstract class JAXBContext {
*
*
* The interpretation of properties is up to implementations. Implementations should
- * throw JAXBException if it finds properties that it doesn't understand.
+ * throw {@code JAXBException} if it finds properties that it doesn't understand.
*
* @param contextPath list of java package names that contain schema derived classes
* @param classLoader
@@ -443,9 +437,9 @@ public abstract class JAXBContext {
* provider-specific properties. Can be null, which means the same thing as passing
* in an empty map.
*
- * @return a new instance of a JAXBContext
+ * @return a new instance of a {@code JAXBContext}
* @throws JAXBException if an error was encountered while creating the
- * JAXBContext such as
+ * {@code JAXBContext} such as
*
*
failure to locate either ObjectFactory.class or jaxb.index in the packages
*
an ambiguity among global elements contained in the contextPath
@@ -472,8 +466,7 @@ public abstract class JAXBContext {
// TODO: resurrect this once we introduce external annotations
// /**
-// *
-// * Create a new instance of a JAXBContext class.
+// * Create a new instance of a {@code JAXBContext} class.
// *
// *
// * The client application must supply a list of classes that the new
@@ -484,8 +477,8 @@ public abstract class JAXBContext {
// * referenced statically from the specified classes.
// *
// * For example, in the following Java code, if you do
-// * newInstance(Foo.class), the newly created {@link JAXBContext}
-// * will recognize both Foo and Bar, but not Zot:
+// * {@code newInstance(Foo.class)}, the newly created {@link JAXBContext}
+// * will recognize both {@code Foo} and {@code Bar}, but not {@code Zot}:
// *
// * class Foo {
// * Bar b;
@@ -509,11 +502,11 @@ public abstract class JAXBContext {
// * spec-defined classes will be returned.
// *
// * @return
-// * A new instance of a JAXBContext.
+// * A new instance of a {@code JAXBContext}.
// *
// * @throws JAXBException
// * if an error was encountered while creating the
-// * JAXBContext, such as (but not limited to):
+// * {@code JAXBContext}, such as (but not limited to):
// *
// *
No JAXB implementation was discovered
// *
Classes use JAXB annotations incorrectly
@@ -546,8 +539,7 @@ public abstract class JAXBContext {
// }
/**
- *
- * Create a new instance of a JAXBContext class.
+ * Create a new instance of a {@code JAXBContext} class.
*
*
* The client application must supply a list of classes that the new
@@ -556,12 +548,12 @@ public abstract class JAXBContext {
* Not only the new context will recognize all the classes specified,
* but it will also recognize any classes that are directly/indirectly
* referenced statically from the specified classes. Subclasses of
- * referenced classes nor @XmlTransient referenced classes
+ * referenced classes nor {@code @XmlTransient} referenced classes
* are not registered with JAXBContext.
*
* For example, in the following Java code, if you do
- * newInstance(Foo.class), the newly created {@link JAXBContext}
- * will recognize both Foo and Bar, but not Zot or FooBar:
+ * {@code newInstance(Foo.class)}, the newly created {@link JAXBContext}
+ * will recognize both {@code Foo} and {@code Bar}, but not {@code Zot} or {@code FooBar}:
*
* class Foo {
* @XmlTransient FooBar c;
@@ -589,11 +581,11 @@ public abstract class JAXBContext {
* spec-defined classes will be returned.
*
* @return
- * A new instance of a JAXBContext.
+ * A new instance of a {@code JAXBContext}.
*
* @throws JAXBException
* if an error was encountered while creating the
- * JAXBContext, such as (but not limited to):
+ * {@code JAXBContext}, such as (but not limited to):
*
*
No JAXB implementation was discovered
*
Classes use JAXB annotations incorrectly
@@ -615,8 +607,7 @@ public abstract class JAXBContext {
}
/**
- *
- * Create a new instance of a JAXBContext class.
+ * Create a new instance of a {@code JAXBContext} class.
*
*
* An overloading of {@link JAXBContext#newInstance(Class...)}
@@ -624,7 +615,7 @@ public abstract class JAXBContext {
*
*
* The interpretation of properties is up to implementations. Implementations should
- * throw JAXBException if it finds properties that it doesn't understand.
+ * throw {@code JAXBException} if it finds properties that it doesn't understand.
*
* @param classesToBeBound
* list of java classes to be recognized by the new {@link JAXBContext}.
@@ -635,11 +626,11 @@ public abstract class JAXBContext {
* in an empty map.
*
* @return
- * A new instance of a JAXBContext.
+ * A new instance of a {@code JAXBContext}.
*
* @throws JAXBException
* if an error was encountered while creating the
- * JAXBContext, such as (but not limited to):
+ * {@code JAXBContext}, such as (but not limited to):
*
*
No JAXB implementation was discovered
*
Classes use JAXB annotations incorrectly
@@ -672,25 +663,25 @@ public abstract class JAXBContext {
}
/**
- * Create an Unmarshaller object that can be used to convert XML
+ * Create an {@code Unmarshaller} object that can be used to convert XML
* data into a java content tree.
*
- * @return an Unmarshaller object
+ * @return an {@code Unmarshaller} object
*
* @throws JAXBException if an error was encountered while creating the
- * Unmarshaller object
+ * {@code Unmarshaller} object
*/
public abstract Unmarshaller createUnmarshaller() throws JAXBException;
/**
- * Create a Marshaller object that can be used to convert a
+ * Create a {@code Marshaller} object that can be used to convert a
* java content tree into XML data.
*
- * @return a Marshaller object
+ * @return a {@code Marshaller} object
*
* @throws JAXBException if an error was encountered while creating the
- * Marshaller object
+ * {@code Marshaller} object
*/
public abstract Marshaller createMarshaller() throws JAXBException;
@@ -699,27 +690,27 @@ public abstract class JAXBContext {
* {@link Validator} has been made optional and deprecated in JAXB 2.0. Please
* refer to the javadoc for {@link Validator} for more detail.
*
- * Create a Validator object that can be used to validate a
+ * Create a {@code Validator} object that can be used to validate a
* java content tree against its source schema.
*
- * @return a Validator object
+ * @return a {@code Validator} object
*
* @throws JAXBException if an error was encountered while creating the
- * Validator object
+ * {@code Validator} object
* @deprecated since JAXB2.0
*/
public abstract Validator createValidator() throws JAXBException;
/**
- * Creates a Binder object that can be used for
+ * Creates a {@code Binder} object that can be used for
* associative/in-place unmarshalling/marshalling.
*
* @param domType select the DOM API to use by passing in its DOM Node class.
*
- * @return always a new valid Binder object.
+ * @return always a new valid {@code Binder} object.
*
* @throws UnsupportedOperationException
- * if DOM API corresponding to domType is not supported by
+ * if DOM API corresponding to {@code domType} is not supported by
* the implementation.
*
* @since 1.6, JAXB 2.0
@@ -731,9 +722,9 @@ public abstract class JAXBContext {
}
/**
- * Creates a Binder for W3C DOM.
+ * Creates a {@code Binder} for W3C DOM.
*
- * @return always a new valid Binder object.
+ * @return always a new valid {@code Binder} object.
*
* @since 1.6, JAXB 2.0
*/
@@ -742,11 +733,11 @@ public abstract class JAXBContext {
}
/**
- * Creates a JAXBIntrospector object that can be used to
+ * Creates a {@code JAXBIntrospector} object that can be used to
* introspect JAXB objects.
*
* @return
- * always return a non-null valid JAXBIntrospector object.
+ * always return a non-null valid {@code JAXBIntrospector} object.
*
* @throws UnsupportedOperationException
* Calling this method on JAXB 1.0 implementations will throw
diff --git a/jaxws/src/java.xml.bind/share/classes/javax/xml/bind/annotation/package.html b/jaxws/src/java.xml.bind/share/classes/javax/xml/bind/annotation/package.html
index 57f80e44acd..4fc54e34dc4 100644
--- a/jaxws/src/java.xml.bind/share/classes/javax/xml/bind/annotation/package.html
+++ b/jaxws/src/java.xml.bind/share/classes/javax/xml/bind/annotation/package.html
@@ -239,7 +239,7 @@
For a property, a given annotation can be applied to
either read or write property but not both.
-
+
A property name must be different from any other
property name in any of the super classes of the
class being mapped.
@@ -250,8 +250,8 @@
Notations
Namespace prefixes
The following namespace prefixes are used in the XML Schema
- fragments in this package.
-
+ fragments in this package.
+
diff --git a/jdk/.hgtags b/jdk/.hgtags
index dc04435f09f..6a1fe8984b3 100644
--- a/jdk/.hgtags
+++ b/jdk/.hgtags
@@ -313,3 +313,4 @@ ed94f3e7ba6bbfec0772de6d24e39543e13f6d88 jdk9-b65
046fd17bb9a0cdf6681124866df9626d17b0516a jdk9-b68
551323004d0ce2f1d4b0e99552f7e0cdcebc6fca jdk9-b69
a7f731125b7fb0e4b0186172f85a21e2d5139f7e jdk9-b70
+e47d3bfbc61accc3fbd372a674fdce2933b54f31 jdk9-b71
diff --git a/jdk/make/lib/Lib-jdk.internal.le.gmk b/jdk/make/lib/Lib-jdk.internal.le.gmk
new file mode 100644
index 00000000000..5f5cb3b58c5
--- /dev/null
+++ b/jdk/make/lib/Lib-jdk.internal.le.gmk
@@ -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
+
+################################################################################
diff --git a/jdk/make/lib/NioLibraries.gmk b/jdk/make/lib/NioLibraries.gmk
index 91d1df93448..81d6e0f7e67 100644
--- a/jdk/make/lib/NioLibraries.gmk
+++ b/jdk/make/lib/NioLibraries.gmk
@@ -81,7 +81,8 @@ $(eval $(call SetupNativeCompilation,BUILD_LIBNIO, \
LDFLAGS_SUFFIX_windows := jvm.lib ws2_32.lib $(WIN_JAVA_LIB) \
$(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libnet/net.lib \
advapi32.lib, \
- LDFLAGS_SUFFIX_macosx := -ljava -lnet -pthread -framework CoreFoundation, \
+ LDFLAGS_SUFFIX_macosx := -ljava -lnet -pthread \
+ -framework CoreFoundation -framework CoreServices, \
LDFLAGS_SUFFIX :=, \
VERSIONINFO_RESOURCE := $(GLOBAL_VERSION_INFO_RESOURCE), \
RC_FLAGS := $(RC_FLAGS) \
diff --git a/jdk/src/java.base/macosx/classes/sun/nio/fs/MacOSXFileSystemProvider.java b/jdk/src/java.base/macosx/classes/sun/nio/fs/MacOSXFileSystemProvider.java
index bf50e71b1c7..0dcee95bfc3 100644
--- a/jdk/src/java.base/macosx/classes/sun/nio/fs/MacOSXFileSystemProvider.java
+++ b/jdk/src/java.base/macosx/classes/sun/nio/fs/MacOSXFileSystemProvider.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 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
@@ -49,6 +49,8 @@ public class MacOSXFileSystemProvider extends BsdFileSystemProvider {
FileTypeDetector getFileTypeDetector() {
Path userMimeTypes = Paths.get(AccessController.doPrivileged(
new GetPropertyAction("user.home")), ".mime.types");
- return new MimeTypesFileTypeDetector(userMimeTypes);
+
+ return chain(new MimeTypesFileTypeDetector(userMimeTypes),
+ new UTIFileTypeDetector());
}
}
diff --git a/jdk/src/java.base/macosx/classes/sun/nio/fs/UTIFileTypeDetector.java b/jdk/src/java.base/macosx/classes/sun/nio/fs/UTIFileTypeDetector.java
new file mode 100644
index 00000000000..69135b80d9c
--- /dev/null
+++ b/jdk/src/java.base/macosx/classes/sun/nio/fs/UTIFileTypeDetector.java
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ */
+
+package sun.nio.fs;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+/**
+ * File type detector that uses a file extension to look up its MIME type
+ * via the Apple Uniform Type Identifier interfaces.
+ */
+class UTIFileTypeDetector extends AbstractFileTypeDetector {
+ UTIFileTypeDetector() {
+ super();
+ }
+
+ private native String probe0(String fileExtension) throws IOException;
+
+ @Override
+ protected String implProbeContentType(Path path) throws IOException {
+ Path fn = path.getFileName();
+ if (fn == null)
+ return null; // no file name
+
+ String ext = getExtension(fn.toString());
+ if (ext.isEmpty())
+ return null; // no extension
+
+ return probe0(ext);
+ }
+
+ static {
+ AccessController.doPrivileged(new PrivilegedAction<>() {
+ @Override
+ public Void run() {
+ System.loadLibrary("nio");
+ return null;
+ }
+ });
+ }
+}
diff --git a/jdk/src/java.base/macosx/native/libnio/fs/UTIFileTypeDetector.c b/jdk/src/java.base/macosx/native/libnio/fs/UTIFileTypeDetector.c
new file mode 100644
index 00000000000..5e9451e850c
--- /dev/null
+++ b/jdk/src/java.base/macosx/native/libnio/fs/UTIFileTypeDetector.c
@@ -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
+#include
+
+/**
+ * Creates a CF string from the given Java string.
+ * If javaString is NULL, NULL is returned.
+ * If a memory error occurs, and OutOfMemoryError is thrown and
+ * NULL is returned.
+ */
+static CFStringRef toCFString(JNIEnv *env, jstring javaString)
+{
+ if (javaString == NULL) {
+ return NULL;
+ } else {
+ CFStringRef result = NULL;
+ jsize length = (*env)->GetStringLength(env, javaString);
+ const jchar *chars = (*env)->GetStringChars(env, javaString, NULL);
+ if (chars == NULL) {
+ JNU_ThrowOutOfMemoryError(env, "toCFString failed");
+ return NULL;
+ }
+ result = CFStringCreateWithCharacters(NULL, (const UniChar *)chars,
+ length);
+ (*env)->ReleaseStringChars(env, javaString, chars);
+ if (result == NULL) {
+ JNU_ThrowOutOfMemoryError(env, "toCFString failed");
+ return NULL;
+ }
+ return result;
+ }
+}
+
+/**
+ * Creates a Java string from the given CF string.
+ * If cfString is NULL, NULL is returned.
+ * If a memory error occurs, and OutOfMemoryError is thrown and
+ * NULL is returned.
+ */
+static jstring toJavaString(JNIEnv *env, CFStringRef cfString)
+{
+ if (cfString == NULL) {
+ return NULL;
+ } else {
+ jstring javaString = NULL;
+
+ CFIndex length = CFStringGetLength(cfString);
+ const UniChar *constchars = CFStringGetCharactersPtr(cfString);
+ if (constchars) {
+ javaString = (*env)->NewString(env, constchars, length);
+ } else {
+ UniChar *chars = malloc(length * sizeof(UniChar));
+ if (chars == NULL) {
+ JNU_ThrowOutOfMemoryError(env, "toJavaString failed");
+ return NULL;
+ }
+ CFStringGetCharacters(cfString, CFRangeMake(0, length), chars);
+ javaString = (*env)->NewString(env, chars, length);
+ free(chars);
+ }
+ return javaString;
+ }
+}
+
+/**
+ * Returns the content type corresponding to the supplied file extension.
+ * The mapping is determined using Uniform Type Identifiers (UTIs). If
+ * the file extension parameter is NULL, a CFString cannot be created
+ * from the file extension parameter, there is no UTI corresponding to
+ * the file extension, the UTI cannot supply a MIME type for the file
+ * extension, or a Java string cannot be created, then NULL is returned;
+ * otherwise the MIME type string is returned.
+ */
+JNIEXPORT jstring JNICALL
+Java_sun_nio_fs_UTIFileTypeDetector_probe0(JNIEnv* env, jobject ftd,
+ jstring ext)
+{
+ jstring result = NULL;
+
+ CFStringRef extension = toCFString(env, ext);
+ if (extension != NULL) {
+ CFStringRef uti =
+ UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension,
+ extension, NULL);
+ CFRelease(extension);
+
+ if (uti != NULL) {
+ CFStringRef mimeType =
+ UTTypeCopyPreferredTagWithClass(uti, kUTTagClassMIMEType);
+ CFRelease(uti);
+
+ if (mimeType != NULL) {
+ result = toJavaString(env, mimeType);
+ CFRelease(mimeType);
+ }
+ }
+ }
+
+ return result;
+}
diff --git a/jdk/src/java.base/share/classes/com/sun/crypto/provider/GHASH.java b/jdk/src/java.base/share/classes/com/sun/crypto/provider/GHASH.java
index ee747c8e36c..dc42e6bbfd9 100644
--- a/jdk/src/java.base/share/classes/com/sun/crypto/provider/GHASH.java
+++ b/jdk/src/java.base/share/classes/com/sun/crypto/provider/GHASH.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015 Red Hat, Inc.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -62,14 +62,16 @@ final class GHASH {
private static final int AES_BLOCK_SIZE = 16;
- // Multiplies state0, state1 by V0, V1.
- private void blockMult(long V0, long V1) {
+ // Multiplies state[0], state[1] by subkeyH[0], subkeyH[1].
+ private static void blockMult(long[] st, long[] subH) {
long Z0 = 0;
long Z1 = 0;
+ long V0 = subH[0];
+ long V1 = subH[1];
long X;
- // Separate loops for processing state0 and state1.
- X = state0;
+ // Separate loops for processing state[0] and state[1].
+ X = st[0];
for (int i = 0; i < 64; i++) {
// Zi+1 = Zi if bit i of x is 0
long mask = X >> 63;
@@ -89,7 +91,7 @@ final class GHASH {
X <<= 1;
}
- X = state1;
+ X = st[1];
for (int i = 64; i < 127; i++) {
// Zi+1 = Zi if bit i of x is 0
long mask = X >> 63;
@@ -115,15 +117,18 @@ final class GHASH {
Z1 ^= V1 & mask;
// Save result.
- state0 = Z0;
- state1 = Z1;
+ st[0] = Z0;
+ st[1] = Z1;
+
}
+ /* subkeyH and state are stored in long[] for GHASH intrinsic use */
+
// hash subkey H; should not change after the object has been constructed
- private final long subkeyH0, subkeyH1;
+ private final long[] subkeyH;
// buffer for storing hash
- private long state0, state1;
+ private final long[] state;
// variables for save/restore calls
private long stateSave0, stateSave1;
@@ -141,8 +146,10 @@ final class GHASH {
if ((subkeyH == null) || subkeyH.length != AES_BLOCK_SIZE) {
throw new ProviderException("Internal error");
}
- this.subkeyH0 = getLong(subkeyH, 0);
- this.subkeyH1 = getLong(subkeyH, 8);
+ state = new long[2];
+ this.subkeyH = new long[2];
+ this.subkeyH[0] = getLong(subkeyH, 0);
+ this.subkeyH[1] = getLong(subkeyH, 8);
}
/**
@@ -151,33 +158,30 @@ final class GHASH {
* this object for different data w/ the same H.
*/
void reset() {
- state0 = 0;
- state1 = 0;
+ state[0] = 0;
+ state[1] = 0;
}
/**
* Save the current snapshot of this GHASH object.
*/
void save() {
- stateSave0 = state0;
- stateSave1 = state1;
+ stateSave0 = state[0];
+ stateSave1 = state[1];
}
/**
* Restores this object using the saved snapshot.
*/
void restore() {
- state0 = stateSave0;
- state1 = stateSave1;
+ state[0] = stateSave0;
+ state[1] = stateSave1;
}
- private void processBlock(byte[] data, int ofs) {
- if (data.length - ofs < AES_BLOCK_SIZE) {
- throw new RuntimeException("need complete block");
- }
- state0 ^= getLong(data, ofs);
- state1 ^= getLong(data, ofs + 8);
- blockMult(subkeyH0, subkeyH1);
+ private static void processBlock(byte[] data, int ofs, long[] st, long[] subH) {
+ st[0] ^= getLong(data, ofs);
+ st[1] ^= getLong(data, ofs + 8);
+ blockMult(st, subH);
}
void update(byte[] in) {
@@ -185,22 +189,57 @@ final class GHASH {
}
void update(byte[] in, int inOfs, int inLen) {
- if (inLen - inOfs > in.length) {
- throw new RuntimeException("input length out of bound");
+ if (inLen == 0) {
+ return;
+ }
+ ghashRangeCheck(in, inOfs, inLen, state, subkeyH);
+ processBlocks(in, inOfs, inLen/AES_BLOCK_SIZE, state, subkeyH);
+ }
+
+ private static void ghashRangeCheck(byte[] in, int inOfs, int inLen, long[] st, long[] subH) {
+ if (inLen < 0) {
+ throw new RuntimeException("invalid input length: " + inLen);
+ }
+ if (inOfs < 0) {
+ throw new RuntimeException("invalid offset: " + inOfs);
+ }
+ if (inLen > in.length - inOfs) {
+ throw new RuntimeException("input length out of bound: " +
+ inLen + " > " + (in.length - inOfs));
}
if (inLen % AES_BLOCK_SIZE != 0) {
- throw new RuntimeException("input length unsupported");
+ throw new RuntimeException("input length/block size mismatch: " +
+ inLen);
}
- for (int i = inOfs; i < (inOfs + inLen); i += AES_BLOCK_SIZE) {
- processBlock(in, i);
+ // These two checks are for C2 checking
+ if (st.length != 2) {
+ throw new RuntimeException("internal state has invalid length: " +
+ st.length);
+ }
+ if (subH.length != 2) {
+ throw new RuntimeException("internal subkeyH has invalid length: " +
+ subH.length);
+ }
+ }
+ /*
+ * This is an intrinsified method. The method's argument list must match
+ * the hotspot signature. This method and methods called by it, cannot
+ * throw exceptions or allocate arrays as it will breaking intrinsics
+ */
+ private static void processBlocks(byte[] data, int inOfs, int blocks, long[] st, long[] subH) {
+ int offset = inOfs;
+ while (blocks > 0) {
+ processBlock(data, offset, st, subH);
+ blocks--;
+ offset += AES_BLOCK_SIZE;
}
}
byte[] digest() {
byte[] result = new byte[AES_BLOCK_SIZE];
- putLong(result, 0, state0);
- putLong(result, 8, state1);
+ putLong(result, 0, state[0]);
+ putLong(result, 8, state[1]);
reset();
return result;
}
diff --git a/jdk/src/java.base/share/classes/com/sun/java/util/jar/pack/Attribute.java b/jdk/src/java.base/share/classes/com/sun/java/util/jar/pack/Attribute.java
index 19a7a08598e..2a4854a5649 100644
--- a/jdk/src/java.base/share/classes/com/sun/java/util/jar/pack/Attribute.java
+++ b/jdk/src/java.base/share/classes/com/sun/java/util/jar/pack/Attribute.java
@@ -1235,7 +1235,7 @@ class Attribute implements Comparable {
int sofar = 0; // how far have we processed the layout?
for (;;) {
// for each dash, collect everything up to the dash
- result.append(layout.substring(sofar, dash));
+ result.append(layout, sofar, dash);
sofar = dash+1; // skip the dash
// then collect intermediate values
int value0 = parseIntBefore(layout, dash);
@@ -1249,7 +1249,7 @@ class Attribute implements Comparable {
dash = findCaseDash(layout, sofar);
if (dash < 0) break;
}
- result.append(layout.substring(sofar)); // collect the rest
+ result.append(layout, sofar, layout.length()); // collect the rest
return result.toString();
}
static {
diff --git a/jdk/src/java.base/share/classes/java/io/StringWriter.java b/jdk/src/java.base/share/classes/java/io/StringWriter.java
index 63ca2f0e0f2..c62d82f4ea8 100644
--- a/jdk/src/java.base/share/classes/java/io/StringWriter.java
+++ b/jdk/src/java.base/share/classes/java/io/StringWriter.java
@@ -109,7 +109,7 @@ public class StringWriter extends Writer {
* @param len Number of characters to write
*/
public void write(String str, int off, int len) {
- buf.append(str.substring(off, off + len));
+ buf.append(str, off, off + len);
}
/**
diff --git a/jdk/src/java.base/share/classes/java/lang/AbstractStringBuilder.java b/jdk/src/java.base/share/classes/java/lang/AbstractStringBuilder.java
index 93b1093df7b..a9216000731 100644
--- a/jdk/src/java.base/share/classes/java/lang/AbstractStringBuilder.java
+++ b/jdk/src/java.base/share/classes/java/lang/AbstractStringBuilder.java
@@ -515,8 +515,12 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
+ s.length());
int len = end - start;
ensureCapacityInternal(count + len);
- for (int i = start, j = count; i < end; i++, j++)
- value[j] = s.charAt(i);
+ if (s instanceof String) {
+ ((String)s).getChars(start, end, value, count);
+ } else {
+ for (int i = start, j = count; i < end; i++, j++)
+ value[j] = s.charAt(i);
+ }
count += len;
return this;
}
diff --git a/jdk/src/java.base/share/classes/java/net/NetworkInterface.java b/jdk/src/java.base/share/classes/java/net/NetworkInterface.java
index 3376bafdf20..81da1c0cf8f 100644
--- a/jdk/src/java.base/share/classes/java/net/NetworkInterface.java
+++ b/jdk/src/java.base/share/classes/java/net/NetworkInterface.java
@@ -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
@@ -25,10 +25,14 @@
package java.net;
+import java.util.Arrays;
import java.util.Enumeration;
import java.util.NoSuchElementException;
-import sun.security.action.*;
import java.security.AccessController;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
/**
* This class represents a Network Interface made up of a name,
@@ -95,8 +99,8 @@ public final class NetworkInterface {
}
/**
- * Convenience method to return an Enumeration with all or a
- * subset of the InetAddresses bound to this network interface.
+ * Get an Enumeration with all or a subset of the InetAddresses bound to
+ * this network interface.
*
* If there is a security manager, its {@code checkConnect}
* method is called for each InetAddress. Only InetAddresses where
@@ -104,53 +108,56 @@ public final class NetworkInterface {
* will be returned in the Enumeration. However, if the caller has the
* {@link NetPermission}("getNetworkInformation") permission, then all
* InetAddresses are returned.
+ *
* @return an Enumeration object with all or a subset of the InetAddresses
* bound to this network interface
+ * @see #inetAddresses()
*/
public Enumeration getInetAddresses() {
+ return enumerationFromArray(getCheckedInetAddresses());
+ }
- class checkedAddresses implements Enumeration {
+ /**
+ * Get a Stream of all or a subset of the InetAddresses bound to this
+ * network interface.
+ *
+ * If there is a security manager, its {@code checkConnect}
+ * method is called for each InetAddress. Only InetAddresses where
+ * the {@code checkConnect} doesn't throw a SecurityException will be
+ * returned in the Stream. However, if the caller has the
+ * {@link NetPermission}("getNetworkInformation") permission, then all
+ * InetAddresses are returned.
+ *
+ * @return a Stream object with all or a subset of the InetAddresses
+ * bound to this network interface
+ * @since 1.9
+ */
+ public Stream inetAddresses() {
+ return streamFromArray(getCheckedInetAddresses());
+ }
- private int i=0, count=0;
- private InetAddress local_addrs[];
+ private InetAddress[] getCheckedInetAddresses() {
+ InetAddress[] local_addrs = new InetAddress[addrs.length];
+ boolean trusted = true;
- checkedAddresses() {
- local_addrs = new InetAddress[addrs.length];
- boolean trusted = true;
-
- SecurityManager sec = System.getSecurityManager();
- if (sec != null) {
- try {
- sec.checkPermission(new NetPermission("getNetworkInformation"));
- } catch (SecurityException e) {
- trusted = false;
- }
- }
- for (int j=0; j getSubInterfaces() {
- class subIFs implements Enumeration {
-
- private int i=0;
-
- subIFs() {
- }
-
- public NetworkInterface nextElement() {
- if (i < childs.length) {
- return childs[i++];
- } else {
- throw new NoSuchElementException();
- }
- }
-
- public boolean hasMoreElements() {
- return (i < childs.length);
- }
- }
- return new subIFs();
+ return enumerationFromArray(childs);
+ }
+ /**
+ * Get a Stream of all subinterfaces (also known as virtual
+ * interfaces) attached to this network interface.
+ *
+ * @return a Stream object with all of the subinterfaces
+ * of this network interface
+ * @since 1.9
+ */
+ public Stream subInterfaces() {
+ return streamFromArray(childs);
}
/**
@@ -326,43 +326,80 @@ public final class NetworkInterface {
}
/**
- * Returns all the interfaces on this machine. The {@code Enumeration}
- * contains at least one element, possibly representing a loopback
- * interface that only supports communication between entities on
+ * Returns an {@code Enumeration} of all the interfaces on this machine. The
+ * {@code Enumeration} contains at least one element, possibly representing
+ * a loopback interface that only supports communication between entities on
* this machine.
*
- * NOTE: can use getNetworkInterfaces()+getInetAddresses()
- * to obtain all IP addresses for this node
+ * @apiNote this method can be used in combination with
+ * {@link #getInetAddresses()} to obtain all IP addresses for this node
*
* @return an Enumeration of NetworkInterfaces found on this machine
* @exception SocketException if an I/O error occurs.
+ * @see #networkInterfaces()
*/
-
public static Enumeration getNetworkInterfaces()
throws SocketException {
- final NetworkInterface[] netifs = getAll();
+ NetworkInterface[] netifs = getAll();
+ assert netifs != null && netifs.length > 0;
- // specified to return null if no network interfaces
- if (netifs == null)
- return null;
+ return enumerationFromArray(netifs);
+ }
+ /**
+ * Returns a {@code Stream} of all the interfaces on this machine. The
+ * {@code Stream} contains at least one interface, possibly representing a
+ * loopback interface that only supports communication between entities on
+ * this machine.
+ *
+ * @apiNote this method can be used in combination with
+ * {@link #inetAddresses()}} to obtain a stream of all IP addresses for
+ * this node, for example:
+ *
+ *
+ * @return a Stream of NetworkInterfaces found on this machine
+ * @exception SocketException if an I/O error occurs.
+ * @since 1.9
+ */
+ public static Stream networkInterfaces()
+ throws SocketException {
+ NetworkInterface[] netifs = getAll();
+ assert netifs != null && netifs.length > 0;
+
+ return streamFromArray(netifs);
+ }
+
+ private static Enumeration enumerationFromArray(T[] a) {
return new Enumeration<>() {
- private int i = 0;
- public NetworkInterface nextElement() {
- if (netifs != null && i < netifs.length) {
- NetworkInterface netif = netifs[i++];
- return netif;
+ int i = 0;
+
+ @Override
+ public T nextElement() {
+ if (i < a.length) {
+ return a[i++];
} else {
throw new NoSuchElementException();
}
}
+ @Override
public boolean hasMoreElements() {
- return (netifs != null && i < netifs.length);
+ return i < a.length;
}
};
}
+ private static Stream streamFromArray(T[] a) {
+ return StreamSupport.stream(
+ Spliterators.spliterator(
+ a,
+ Spliterator.DISTINCT | Spliterator.IMMUTABLE | Spliterator.NONNULL),
+ false);
+ }
+
private native static NetworkInterface[] getAll()
throws SocketException;
diff --git a/jdk/src/java.base/share/classes/java/net/SocksSocketImpl.java b/jdk/src/java.base/share/classes/java/net/SocksSocketImpl.java
index 573945b9632..f7974d0d705 100644
--- a/jdk/src/java.base/share/classes/java/net/SocksSocketImpl.java
+++ b/jdk/src/java.base/share/classes/java/net/SocksSocketImpl.java
@@ -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.AccessController;
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 @@ class SocksSocketImpl extends PlainSocketImpl implements SocksConsts {
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 @@ class SocksSocketImpl extends PlainSocketImpl implements SocksConsts {
// 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 @@ class SocksSocketImpl extends PlainSocketImpl implements SocksConsts {
// 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 {
diff --git a/jdk/src/java.base/share/classes/java/net/URI.java b/jdk/src/java.base/share/classes/java/net/URI.java
index 89a9d50e52a..2896cf222e6 100644
--- a/jdk/src/java.base/share/classes/java/net/URI.java
+++ b/jdk/src/java.base/share/classes/java/net/URI.java
@@ -2018,7 +2018,7 @@ public final class URI
StringBuilder sb = new StringBuilder(base.length() + cn);
// 5.2 (6a)
if (i >= 0)
- sb.append(base.substring(0, i + 1));
+ sb.append(base, 0, i + 1);
// 5.2 (6b)
sb.append(child);
path = sb.toString();
@@ -2686,7 +2686,7 @@ public final class URI
if (!match(c, lowMask, highMask)) {
if (sb == null) {
sb = new StringBuffer();
- sb.append(s.substring(0, i));
+ sb.append(s, 0, i);
}
appendEscape(sb, (byte)c);
} else {
@@ -2698,7 +2698,7 @@ public final class URI
|| Character.isISOControl(c))) {
if (sb == null) {
sb = new StringBuffer();
- sb.append(s.substring(0, i));
+ sb.append(s, 0, i);
}
appendEncoded(sb, c);
} else {
diff --git a/jdk/src/java.base/share/classes/java/security/PermissionCollection.java b/jdk/src/java.base/share/classes/java/security/PermissionCollection.java
index 3f13b9f93d5..0aa6ce74bc4 100644
--- a/jdk/src/java.base/share/classes/java/security/PermissionCollection.java
+++ b/jdk/src/java.base/share/classes/java/security/PermissionCollection.java
@@ -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
@@ -26,6 +26,8 @@
package java.security;
import java.util.*;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
/**
* Abstract class representing a collection of Permission objects.
@@ -126,9 +128,34 @@ public abstract class PermissionCollection implements java.io.Serializable {
* Returns an enumeration of all the Permission objects in the collection.
*
* @return an enumeration of all the Permissions.
+ * @see #elementsAsStream()
*/
public abstract Enumeration elements();
+ /**
+ * Returns a stream of all the Permission objects in the collection.
+ *
+ *
The collection should not be modified (see {@link #add}) during the
+ * execution of the terminal stream operation. Otherwise, the result of the
+ * terminal stream operation is undefined.
+ *
+ * @implSpec
+ * The default implementation creates a stream whose source is derived from
+ * the enumeration returned from a call to {@link #elements()}.
+ *
+ * @return a stream of all the Permissions.
+ * @since 1.9
+ */
+ public Stream elementsAsStream() {
+ int characteristics = isReadOnly()
+ ? Spliterator.NONNULL | Spliterator.IMMUTABLE
+ : Spliterator.NONNULL;
+ return StreamSupport.stream(
+ Spliterators.spliteratorUnknownSize(
+ elements().asIterator(), characteristics),
+ false);
+ }
+
/**
* Marks this PermissionCollection object as "readonly". After
* a PermissionCollection object
diff --git a/jdk/src/java.base/share/classes/java/text/MergeCollation.java b/jdk/src/java.base/share/classes/java/text/MergeCollation.java
index bd541a58afb..4e5e5a53ae0 100644
--- a/jdk/src/java.base/share/classes/java/text/MergeCollation.java
+++ b/jdk/src/java.base/share/classes/java/text/MergeCollation.java
@@ -329,8 +329,8 @@ final class MergeCollation {
PatternEntry e = patterns.get(i);
if (e.chars.regionMatches(0,entry.chars,0,
e.chars.length())) {
- excessChars.append(entry.chars.substring(e.chars.length(),
- entry.chars.length()));
+ excessChars.append(entry.chars, e.chars.length(),
+ entry.chars.length());
break;
}
}
diff --git a/jdk/src/java.base/share/classes/java/text/MessageFormat.java b/jdk/src/java.base/share/classes/java/text/MessageFormat.java
index 2497a490eb0..5239db0c119 100644
--- a/jdk/src/java.base/share/classes/java/text/MessageFormat.java
+++ b/jdk/src/java.base/share/classes/java/text/MessageFormat.java
@@ -1239,7 +1239,7 @@ public class MessageFormat extends Format {
int lastOffset = 0;
int last = result.length();
for (int i = 0; i <= maxOffset; ++i) {
- result.append(pattern.substring(lastOffset, offsets[i]));
+ result.append(pattern, lastOffset, offsets[i]);
lastOffset = offsets[i];
int argumentNumber = argumentNumbers[i];
if (arguments == null || argumentNumber >= arguments.length) {
@@ -1332,7 +1332,7 @@ public class MessageFormat extends Format {
}
}
}
- result.append(pattern.substring(lastOffset, pattern.length()));
+ result.append(pattern, lastOffset, pattern.length());
if (characterIterators != null && last != result.length()) {
characterIterators.add(createAttributedCharacterIterator(
result.substring(last)));
diff --git a/jdk/src/java.base/share/classes/java/util/Collections.java b/jdk/src/java.base/share/classes/java/util/Collections.java
index ce4ae7d1b97..6ae9a2feb16 100644
--- a/jdk/src/java.base/share/classes/java/util/Collections.java
+++ b/jdk/src/java.base/share/classes/java/util/Collections.java
@@ -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
@@ -4268,6 +4268,7 @@ public class Collections {
public boolean hasMoreElements() { return false; }
public E nextElement() { throw new NoSuchElementException(); }
+ public Iterator asIterator() { return emptyIterator(); }
}
/**
@@ -5199,6 +5200,11 @@ public class Collections {
* interoperability with legacy APIs that require an enumeration
* as input.
*
+ *
The iterator returned from a call to {@link Enumeration#asIterator()}
+ * does not support removal of elements from the specified collection. This
+ * is necessary to avoid unintentionally increasing the capabilities of the
+ * returned enumeration.
+ *
* @param the class of the objects in the collection
* @param c the collection for which an enumeration is to be returned.
* @return an enumeration over the specified collection.
diff --git a/jdk/src/java.base/share/classes/java/util/jar/JarFile.java b/jdk/src/java.base/share/classes/java/util/jar/JarFile.java
index f565bc02361..bc8c24c453e 100644
--- a/jdk/src/java.base/share/classes/java/util/jar/JarFile.java
+++ b/jdk/src/java.base/share/classes/java/util/jar/JarFile.java
@@ -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
@@ -265,6 +265,10 @@ class JarFile extends ZipFile {
public JarEntry nextElement() {
return next();
}
+
+ public Iterator asIterator() {
+ return this;
+ }
}
/**
diff --git a/jdk/src/java.base/share/classes/java/util/zip/ZipFile.java b/jdk/src/java.base/share/classes/java/util/zip/ZipFile.java
index 8669158bbc9..a4aa9b39d70 100644
--- a/jdk/src/java.base/share/classes/java/util/zip/ZipFile.java
+++ b/jdk/src/java.base/share/classes/java/util/zip/ZipFile.java
@@ -526,6 +526,10 @@ class ZipFile implements ZipConstants, Closeable {
return ze;
}
}
+
+ public Iterator asIterator() {
+ return this;
+ }
}
/**
diff --git a/jdk/src/java.base/share/classes/sun/invoke/util/BytecodeName.java b/jdk/src/java.base/share/classes/sun/invoke/util/BytecodeName.java
index fa34d2bbb6f..9bebac8f64b 100644
--- a/jdk/src/java.base/share/classes/sun/invoke/util/BytecodeName.java
+++ b/jdk/src/java.base/share/classes/sun/invoke/util/BytecodeName.java
@@ -511,7 +511,7 @@ public class BytecodeName {
if (s.charAt(0) != ESCAPE_C && i > 0)
sb.append(NULL_ESCAPE);
// append the string so far, which is unremarkable:
- sb.append(s.substring(0, i));
+ sb.append(s, 0, i);
}
// rewrite \ to \-, / to \|, etc.
@@ -544,7 +544,7 @@ public class BytecodeName {
if (sb == null) {
sb = new StringBuilder(s.length());
// append the string so far, which is unremarkable:
- sb.append(s.substring(stringStart, i));
+ sb.append(s, stringStart, i);
}
++i; // skip both characters
c = oc;
diff --git a/jdk/src/java.base/share/classes/sun/net/spi/DefaultProxySelector.java b/jdk/src/java.base/share/classes/sun/net/spi/DefaultProxySelector.java
index 36db753365a..c753f6888ab 100644
--- a/jdk/src/java.base/share/classes/sun/net/spi/DefaultProxySelector.java
+++ b/jdk/src/java.base/share/classes/sun/net/spi/DefaultProxySelector.java
@@ -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 class DefaultProxySelector extends ProxySelector {
}
}
+ public static int socksProxyVersion() {
+ return AccessController.doPrivileged(
+ new PrivilegedAction() {
+ @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 @@ public class DefaultProxySelector extends ProxySelector {
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);
}
diff --git a/jdk/src/java.base/share/classes/sun/net/www/ParseUtil.java b/jdk/src/java.base/share/classes/sun/net/www/ParseUtil.java
index 1c9abf9d1f4..52af2cb6510 100644
--- a/jdk/src/java.base/share/classes/sun/net/www/ParseUtil.java
+++ b/jdk/src/java.base/share/classes/sun/net/www/ParseUtil.java
@@ -451,7 +451,7 @@ public class ParseUtil {
if (!match(c, lowMask, highMask) && !isEscaped(s, i)) {
if (sb == null) {
sb = new StringBuffer();
- sb.append(s.substring(0, i));
+ sb.append(s, 0, i);
}
appendEscape(sb, (byte)c);
} else {
@@ -463,7 +463,7 @@ public class ParseUtil {
|| Character.isISOControl(c))) {
if (sb == null) {
sb = new StringBuffer();
- sb.append(s.substring(0, i));
+ sb.append(s, 0, i);
}
appendEncoded(sb, c);
} else {
diff --git a/jdk/src/java.base/share/classes/sun/nio/fs/AbstractFileTypeDetector.java b/jdk/src/java.base/share/classes/sun/nio/fs/AbstractFileTypeDetector.java
index 0e43486e215..4b4e623275c 100644
--- a/jdk/src/java.base/share/classes/sun/nio/fs/AbstractFileTypeDetector.java
+++ b/jdk/src/java.base/share/classes/sun/nio/fs/AbstractFileTypeDetector.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 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,6 +41,27 @@ public abstract class AbstractFileTypeDetector
super();
}
+ /**
+ * Returns the extension of a file name, specifically the portion of the
+ * parameter string after the first dot. If the parameter is {@code null},
+ * empty, does not contain a dot, or the dot is the last character, then an
+ * empty string is returned, otherwise the characters after the dot are
+ * returned.
+ *
+ * @param name A file name
+ * @return The characters after the first dot or an empty string.
+ */
+ protected final String getExtension(String name) {
+ String ext = "";
+ if (name != null && !name.isEmpty()) {
+ int dot = name.indexOf('.');
+ if ((dot >= 0) && (dot < name.length() - 1)) {
+ ext = name.substring(dot + 1);
+ }
+ }
+ return ext;
+ }
+
/**
* Invokes the appropriate probe method to guess a file's content type,
* and checks that the content type's syntax is valid.
diff --git a/jdk/src/java.base/share/classes/sun/text/normalizer/UnicodeSet.java b/jdk/src/java.base/share/classes/sun/text/normalizer/UnicodeSet.java
index f3ee71aa969..3fcd67466b7 100644
--- a/jdk/src/java.base/share/classes/sun/text/normalizer/UnicodeSet.java
+++ b/jdk/src/java.base/share/classes/sun/text/normalizer/UnicodeSet.java
@@ -1850,7 +1850,7 @@ public class UnicodeSet implements UnicodeMatcher {
syntaxError(chars, "Invalid property pattern");
}
chars.jumpahead(pos.getIndex());
- rebuiltPat.append(patStr.substring(0, pos.getIndex()));
+ rebuiltPat.append(patStr, 0, pos.getIndex());
}
//----------------------------------------------------------------
diff --git a/jdk/src/java.base/share/classes/sun/util/BuddhistCalendar.java b/jdk/src/java.base/share/classes/sun/util/BuddhistCalendar.java
index adb4163fe8e..7c4a843239d 100644
--- a/jdk/src/java.base/share/classes/sun/util/BuddhistCalendar.java
+++ b/jdk/src/java.base/share/classes/sun/util/BuddhistCalendar.java
@@ -242,12 +242,13 @@ public class BuddhistCalendar extends GregorianCalendar {
return s;
}
p += yearField.length();
- StringBuilder sb = new StringBuilder(s.substring(0, p));
+ StringBuilder sb = new StringBuilder(s.length() + 10);
+ sb.append(s, 0, p);
// Skip the year number
while (Character.isDigit(s.charAt(p++)))
;
int year = internalGet(YEAR) + BUDDHIST_YEAR_OFFSET;
- sb.append(year).append(s.substring(p - 1));
+ sb.append(year).append(s, p - 1, s.length());
return sb.toString();
}
diff --git a/jdk/src/java.base/share/native/libjli/java.c b/jdk/src/java.base/share/native/libjli/java.c
index fa4c1c9ca99..64deecadec4 100644
--- a/jdk/src/java.base/share/native/libjli/java.c
+++ b/jdk/src/java.base/share/native/libjli/java.c
@@ -145,7 +145,7 @@ static struct vmdesc *knownVMs = NULL;
static int knownVMsCount = 0;
static int knownVMsLimit = 0;
-static void GrowKnownVMs();
+static void GrowKnownVMs(int minimum);
static int KnownVMIndex(const char* name);
static void FreeKnownVMs();
static jboolean IsWildCardEnabled();
diff --git a/jdk/src/java.base/unix/classes/java/io/UnixFileSystem.java b/jdk/src/java.base/unix/classes/java/io/UnixFileSystem.java
index fb0fef63646..c0ca02dd4ad 100644
--- a/jdk/src/java.base/unix/classes/java/io/UnixFileSystem.java
+++ b/jdk/src/java.base/unix/classes/java/io/UnixFileSystem.java
@@ -65,8 +65,8 @@ class UnixFileSystem extends FileSystem {
int n = len;
while ((n > 0) && (pathname.charAt(n - 1) == '/')) n--;
if (n == 0) return "/";
- StringBuffer sb = new StringBuffer(pathname.length());
- if (off > 0) sb.append(pathname.substring(0, off));
+ StringBuilder sb = new StringBuilder(pathname.length());
+ if (off > 0) sb.append(pathname, 0, off);
char prevChar = 0;
for (int i = off; i < n; i++) {
char c = pathname.charAt(i);
diff --git a/jdk/src/java.base/unix/classes/sun/nio/fs/MimeTypesFileTypeDetector.java b/jdk/src/java.base/unix/classes/sun/nio/fs/MimeTypesFileTypeDetector.java
index b742b3f626f..20e077cbdc3 100644
--- a/jdk/src/java.base/unix/classes/sun/nio/fs/MimeTypesFileTypeDetector.java
+++ b/jdk/src/java.base/unix/classes/sun/nio/fs/MimeTypesFileTypeDetector.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -83,18 +83,6 @@ class MimeTypesFileTypeDetector extends AbstractFileTypeDetector {
return mimeType;
}
- // Get the extension of a file name.
- private static String getExtension(String name) {
- String ext = "";
- if (name != null && !name.isEmpty()) {
- int dot = name.indexOf('.');
- if ((dot >= 0) && (dot < name.length() - 1)) {
- ext = name.substring(dot + 1);
- }
- }
- return ext;
- }
-
/**
* Parse the mime types file, and store the type-extension mappings into
* mimeTypeMap. The mime types file is not loaded until the first probe
diff --git a/jdk/src/java.base/windows/classes/java/io/WinNTFileSystem.java b/jdk/src/java.base/windows/classes/java/io/WinNTFileSystem.java
index caa47f80c08..9ee66bf4169 100644
--- a/jdk/src/java.base/windows/classes/java/io/WinNTFileSystem.java
+++ b/jdk/src/java.base/windows/classes/java/io/WinNTFileSystem.java
@@ -104,7 +104,7 @@ class WinNTFileSystem extends FileSystem {
if (off < 3) off = 0; /* Avoid fencepost cases with UNC pathnames */
int src;
char slash = this.slash;
- StringBuffer sb = new StringBuffer(len);
+ StringBuilder sb = new StringBuilder(len);
if (off == 0) {
/* Complete normalization, including prefix */
@@ -112,7 +112,7 @@ class WinNTFileSystem extends FileSystem {
} else {
/* Partial normalization */
src = off;
- sb.append(path.substring(0, off));
+ sb.append(path, 0, off);
}
/* Remove redundant slashes from the remainder of the path, forcing all
@@ -156,8 +156,7 @@ class WinNTFileSystem extends FileSystem {
}
}
- String rv = sb.toString();
- return rv;
+ return sb.toString();
}
/* A normal Win32 pathname contains no duplicate slashes, except possibly
@@ -172,7 +171,7 @@ class WinNTFileSystem extends FileSystem {
else directory-relative (has form "z:foo")
3 absolute local pathname (begins with "z:\\")
*/
- private int normalizePrefix(String path, int len, StringBuffer sb) {
+ private int normalizePrefix(String path, int len, StringBuilder sb) {
int src = 0;
while ((src < len) && isSlash(path.charAt(src))) src++;
char c;
diff --git a/jdk/src/java.sql/share/classes/java/sql/DriverManager.java b/jdk/src/java.sql/share/classes/java/sql/DriverManager.java
index d5d5d43bfc2..7f74c4c869b 100644
--- a/jdk/src/java.sql/share/classes/java/sql/DriverManager.java
+++ b/jdk/src/java.sql/share/classes/java/sql/DriverManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 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
@@ -25,11 +25,17 @@
package java.sql;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
import java.util.Iterator;
+import java.util.List;
import java.util.ServiceLoader;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.stream.Stream;
+
import sun.reflect.CallerSensitive;
import sun.reflect.Reflection;
@@ -429,29 +435,44 @@ public class DriverManager {
* d.getClass().getName()
*
* @return the list of JDBC Drivers loaded by the caller's class loader
+ * @see #drivers()
*/
@CallerSensitive
- public static java.util.Enumeration getDrivers() {
- java.util.Vector result = new java.util.Vector<>();
-
+ public static Enumeration getDrivers() {
ensureDriversInitialized();
- Class> callerClass = Reflection.getCallerClass();
+ return Collections.enumeration(getDrivers(Reflection.getCallerClass()));
+ }
+ /**
+ * Retrieves a Stream with all of the currently loaded JDBC drivers
+ * to which the current caller has access.
+ *
+ * @return the stream of JDBC Drivers loaded by the caller's class loader
+ * @since 1.9
+ */
+ @CallerSensitive
+ public static Stream drivers() {
+ ensureDriversInitialized();
+
+ return getDrivers(Reflection.getCallerClass()).stream();
+ }
+
+ private static List getDrivers(Class> callerClass) {
+ List result = new ArrayList<>();
// Walk through the loaded registeredDrivers.
for (DriverInfo aDriver : registeredDrivers) {
// If the caller does not have permission to load the driver then
// skip it.
if (isDriverAllowed(aDriver.driver, callerClass)) {
- result.addElement(aDriver.driver);
+ result.add(aDriver.driver);
} else {
println(" skipping: " + aDriver.getClass().getName());
}
}
- return (result.elements());
+ return result;
}
-
/**
* Sets the maximum time in seconds that a driver will wait
* while attempting to connect to a database once the driver has
diff --git a/jdk/src/jdk.crypto.mscapi/windows/native/libsunmscapi/security.cpp b/jdk/src/jdk.crypto.mscapi/windows/native/libsunmscapi/security.cpp
index 83613e8c15b..161c2aed088 100644
--- a/jdk/src/jdk.crypto.mscapi/windows/native/libsunmscapi/security.cpp
+++ b/jdk/src/jdk.crypto.mscapi/windows/native/libsunmscapi/security.cpp
@@ -30,6 +30,7 @@
#include
#include
+#include
#include
#include
#include
@@ -58,11 +59,16 @@ void ThrowException(JNIEnv *env, char *exceptionName, DWORD dwError)
char szMessage[1024];
szMessage[0] = '\0';
- FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError, NULL, szMessage,
- 1024, NULL);
+ DWORD res = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError,
+ NULL, szMessage, sizeof(szMessage), NULL);
+ if (res == 0) {
+ strcpy(szMessage, "Unknown error");
+ }
jclass exceptionClazz = env->FindClass(exceptionName);
- env->ThrowNew(exceptionClazz, szMessage);
+ if (exceptionClazz != NULL) {
+ env->ThrowNew(exceptionClazz, szMessage);
+ }
}
@@ -295,22 +301,42 @@ JNIEXPORT void JNICALL Java_sun_security_mscapi_KeyStore_loadKeysOrCertificateCh
// Determine clazz and method ID to generate certificate
jclass clazzArrayList = env->FindClass("java/util/ArrayList");
+ if (clazzArrayList == NULL) {
+ __leave;
+ }
jmethodID mNewArrayList = env->GetMethodID(clazzArrayList, "", "()V");
+ if (mNewArrayList == NULL) {
+ __leave;
+ }
- jmethodID mGenCert = env->GetMethodID(env->GetObjectClass(obj),
+ jclass clazzOfThis = env->GetObjectClass(obj);
+ if (clazzOfThis == NULL) {
+ __leave;
+ }
+
+ jmethodID mGenCert = env->GetMethodID(clazzOfThis,
"generateCertificate",
"([BLjava/util/Collection;)V");
+ if (mGenCert == NULL) {
+ __leave;
+ }
// Determine method ID to generate certificate chain
- jmethodID mGenCertChain = env->GetMethodID(env->GetObjectClass(obj),
+ jmethodID mGenCertChain = env->GetMethodID(clazzOfThis,
"generateCertificateChain",
"(Ljava/lang/String;Ljava/util/Collection;Ljava/util/Collection;)V");
+ if (mGenCertChain == NULL) {
+ __leave;
+ }
// Determine method ID to generate RSA certificate chain
- jmethodID mGenRSAKeyAndCertChain = env->GetMethodID(env->GetObjectClass(obj),
+ jmethodID mGenRSAKeyAndCertChain = env->GetMethodID(clazzOfThis,
"generateRSAKeyAndCertificateChain",
"(Ljava/lang/String;JJILjava/util/Collection;Ljava/util/Collection;)V");
+ if (mGenRSAKeyAndCertChain == NULL) {
+ __leave;
+ }
// Use CertEnumCertificatesInStore to get the certificates
// from the open store. pCertContext must be reset to
@@ -590,9 +616,6 @@ JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_RSASignature_signHash
}
__finally
{
- if (hCryptProvAlt)
- ::CryptReleaseContext(hCryptProvAlt, 0);
-
if (pSignedHashBuffer)
delete [] pSignedHashBuffer;
@@ -601,6 +624,9 @@ JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_RSASignature_signHash
if (hHash)
::CryptDestroyHash(hHash);
+
+ if (hCryptProvAlt)
+ ::CryptReleaseContext(hCryptProvAlt, 0);
}
return jSignedHash;
@@ -688,9 +714,6 @@ JNIEXPORT jboolean JNICALL Java_sun_security_mscapi_RSASignature_verifySignedHas
__finally
{
- if (hCryptProvAlt)
- ::CryptReleaseContext(hCryptProvAlt, 0);
-
if (pSignedHashBuffer)
delete [] pSignedHashBuffer;
@@ -699,6 +722,9 @@ JNIEXPORT jboolean JNICALL Java_sun_security_mscapi_RSASignature_verifySignedHas
if (hHash)
::CryptDestroyHash(hHash);
+
+ if (hCryptProvAlt)
+ ::CryptReleaseContext(hCryptProvAlt, 0);
}
return result;
@@ -763,9 +789,15 @@ JNIEXPORT jobject JNICALL Java_sun_security_mscapi_RSAKeyPairGenerator_generateR
// Get the method ID for the RSAKeyPair constructor
jclass clazzRSAKeyPair =
env->FindClass("sun/security/mscapi/RSAKeyPair");
+ if (clazzRSAKeyPair == NULL) {
+ __leave;
+ }
jmethodID mNewRSAKeyPair =
env->GetMethodID(clazzRSAKeyPair, "", "(JJI)V");
+ if (mNewRSAKeyPair == NULL) {
+ __leave;
+ }
// Create a new RSA keypair
keypair = env->NewObject(clazzRSAKeyPair, mNewRSAKeyPair,
@@ -1948,9 +1980,15 @@ JNIEXPORT jobject JNICALL Java_sun_security_mscapi_KeyStore_storePrivateKey
// Get the method ID for the RSAPrivateKey constructor
jclass clazzRSAPrivateKey =
env->FindClass("sun/security/mscapi/RSAPrivateKey");
+ if (clazzRSAPrivateKey == NULL) {
+ __leave;
+ }
jmethodID mNewRSAPrivateKey =
env->GetMethodID(clazzRSAPrivateKey, "", "(JJI)V");
+ if (mNewRSAPrivateKey == NULL) {
+ __leave;
+ }
// Create a new RSA private key
privateKey = env->NewObject(clazzRSAPrivateKey, mNewRSAPrivateKey,
@@ -2035,9 +2073,15 @@ JNIEXPORT jobject JNICALL Java_sun_security_mscapi_RSASignature_importPublicKey
// Get the method ID for the RSAPublicKey constructor
jclass clazzRSAPublicKey =
env->FindClass("sun/security/mscapi/RSAPublicKey");
+ if (clazzRSAPublicKey == NULL) {
+ __leave;
+ }
jmethodID mNewRSAPublicKey =
env->GetMethodID(clazzRSAPublicKey, "", "(JJI)V");
+ if (mNewRSAPublicKey == NULL) {
+ __leave;
+ }
// Create a new RSA public key
publicKey = env->NewObject(clazzRSAPublicKey, mNewRSAPublicKey,
diff --git a/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/NoInterruptUnixTerminal.java b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/NoInterruptUnixTerminal.java
new file mode 100644
index 00000000000..7f27a61d511
--- /dev/null
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/NoInterruptUnixTerminal.java
@@ -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();
+ }
+}
diff --git a/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/Terminal.java b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/Terminal.java
new file mode 100644
index 00000000000..18f634e9282
--- /dev/null
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/Terminal.java
@@ -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 Marc Prud'hommeaux
+ * @author Jason Dillon
+ * @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();
+
+}
diff --git a/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/TerminalFactory.java b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/TerminalFactory.java
new file mode 100644
index 00000000000..ec7b91ead94
--- /dev/null
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/TerminalFactory.java
@@ -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 Jason Dillon
+ * @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> 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);
+ }
+
+}
diff --git a/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/TerminalSupport.java b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/TerminalSupport.java
new file mode 100644
index 00000000000..cf15ec4b383
--- /dev/null
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/TerminalSupport.java
@@ -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 Jason Dillon
+ * @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;
+ }
+}
diff --git a/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/UnixTerminal.java b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/UnixTerminal.java
new file mode 100644
index 00000000000..a3699ad6752
--- /dev/null
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/UnixTerminal.java
@@ -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 stty command against the
+ * /dev/tty file to disable character echoing and enable
+ * character input. All known unix systems (including
+ * Linux and Macintosh OS X) support the stty), so this
+ * implementation should work for an reasonable POSIX system.
+ *
+ * @author Marc Prud'hommeaux
+ * @author Dale Kemp
+ * @author Jason Dillon
+ * @author Jean-Baptiste Onofr\u00E9
+ * @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 stty columns param.
+ */
+ @Override
+ public int getWidth() {
+ int w = settings.getProperty("columns");
+ return w < 1 ? DEFAULT_WIDTH : w;
+ }
+
+ /**
+ * Returns the value of 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);
+ }
+ }
+}
diff --git a/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/UnsupportedTerminal.java b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/UnsupportedTerminal.java
new file mode 100644
index 00000000000..0ad67a53bae
--- /dev/null
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/UnsupportedTerminal.java
@@ -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 Marc Prud'hommeaux
+ * @author Jason Dillon
+ * @since 2.0
+ */
+public class UnsupportedTerminal
+ extends TerminalSupport
+{
+ public UnsupportedTerminal() {
+ super(false);
+ setAnsiSupported(false);
+ setEchoEnabled(true);
+ }
+}
diff --git a/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/WindowsTerminal.java b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/WindowsTerminal.java
new file mode 100644
index 00000000000..69691a8554b
--- /dev/null
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/WindowsTerminal.java
@@ -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
+ * jline_version.dll, saving it to the system temporary
+ * directoy (determined by the setting of the java.io.tmpdir System
+ * property), loading the library, and then calling the Win32 APIs SetConsoleMode and
+ * GetConsoleMode to
+ * disable character echoing.
+ *
+ *
+ * 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 jline.WindowsTerminal.directConsole system property
+ * to false.
+ *
+ *
+ * @author Marc Prud'hommeaux
+ * @author Jason Dillon
+ * @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
+// // 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
+ // 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
+ *
+ * Constants copied wincon.h.
+ */
+ 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;
+ }
+ }
+
+}
diff --git a/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/ConsoleKeys.java b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/ConsoleKeys.java
new file mode 100644
index 00000000000..d0759318d92
--- /dev/null
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/ConsoleKeys.java
@@ -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
+ */
+public class ConsoleKeys {
+
+ private KeyMap keys;
+
+ private Map keyMaps;
+ private Map variables = new HashMap();
+
+ 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 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 ifsStack = new ArrayList();
+ 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);
+ }
+}
diff --git a/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/ConsoleReader.java b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/ConsoleReader.java
new file mode 100644
index 00000000000..2c9337d6404
--- /dev/null
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/ConsoleReader.java
@@ -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 Marc Prud'hommeaux
+ * @author Jason Dillon
+ * @author Guillaume Nodet
+ */
+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:
+ *
+ *
+ *
+ * will restore normal character echoing. Setting the character to
+ *
+ *
+ * new Character(0)
+ *
+ *
+ * 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 num 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 where characters.
+ *
+ * @param num If less than 0, move abs(where) to the left, otherwise move where 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 where 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 in {@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., CTRL-D
+ * 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 pushBackChar = new Stack();
+ 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 completers = new LinkedList();
+
+ 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 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 candidates = new LinkedList();
+ 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 candidates = new LinkedList();
+ 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 triggeredActions = new HashMap();
+//
+// /**
+// * Adding a triggered Action allows to give another curse of action if a character passed the pre-processing.
+// *
+// * 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 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 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
+ }
+
+}
diff --git a/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/CursorBuffer.java b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/CursorBuffer.java
new file mode 100644
index 00000000000..2866d6f5ae6
--- /dev/null
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/CursorBuffer.java
@@ -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 Marc Prud'hommeaux
+ * @author Jason Dillon
+ * @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();
+ }
+}
diff --git a/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/KeyMap.java b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/KeyMap.java
new file mode 100644
index 00000000000..d0bca43b97d
--- /dev/null
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/KeyMap.java
@@ -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 Guillaume Nodet
+ * @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 keyMaps() {
+ Map keyMaps = new HashMap();
+
+ 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);
+ }
+}
diff --git a/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/KillRing.java b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/KillRing.java
new file mode 100644
index 00000000000..0d6c6bf39ab
--- /dev/null
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/KillRing.java
@@ -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;
+ }
+ }
+}
diff --git a/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/Operation.java b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/Operation.java
new file mode 100644
index 00000000000..755b657dd6f
--- /dev/null
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/Operation.java
@@ -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 Guillaume Nodet
+ * @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,
+}
diff --git a/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/UserInterruptException.java b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/UserInterruptException.java
new file mode 100644
index 00000000000..81021b9f860
--- /dev/null
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/UserInterruptException.java
@@ -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;
+ }
+}
diff --git a/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/AggregateCompleter.java b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/AggregateCompleter.java
new file mode 100644
index 00000000000..f3ea1964d2c
--- /dev/null
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/AggregateCompleter.java
@@ -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 Jason Dillon
+ * @since 2.3
+ */
+public class AggregateCompleter
+ implements Completer
+{
+ private final List completers = new ArrayList();
+
+ 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 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 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 candidates) {
+ // buffer could be null
+ checkNotNull(candidates);
+
+ List completions = new ArrayList(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 candidates;
+
+ public int cursor;
+
+ public Completion(final List candidates) {
+ checkNotNull(candidates);
+ this.candidates = new LinkedList(candidates);
+ }
+
+ public void complete(final Completer completer, final String buffer, final int cursor) {
+ checkNotNull(completer);
+ this.cursor = completer.complete(buffer, cursor, candidates);
+ }
+ }
+}
diff --git a/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/ArgumentCompleter.java b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/ArgumentCompleter.java
new file mode 100644
index 00000000000..b7ffce465c4
--- /dev/null
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/ArgumentCompleter.java
@@ -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 separator argument.
+ * This can be used instead of the individual completers having to know about argument parsing semantics.
+ *
+ * @author Marc Prud'hommeaux
+ * @author Jason Dillon
+ * @since 2.3
+ */
+public class ArgumentCompleter
+ implements Completer
+{
+ private final ArgumentDelimiter delimiter;
+
+ private final List completers = new ArrayList();
+
+ 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 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 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 getCompleters() {
+ return completers;
+ }
+
+ public int complete(final String buffer, final int cursor, final List 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 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 subCandidates = new LinkedList();
+
+ 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 Marc Prud'hommeaux
+ */
+ 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 Marc Prud'hommeaux
+ */
+ 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 args = new LinkedList();
+ 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 Marc Prud'hommeaux
+ */
+ 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 Marc Prud'hommeaux
+ */
+ 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;
+ }
+ }
+}
diff --git a/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/CandidateListCompletionHandler.java b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/CandidateListCompletionHandler.java
new file mode 100644
index 00000000000..166493d3c98
--- /dev/null
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/CandidateListCompletionHandler.java
@@ -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
+ * readline library.
+ *
+ * @author Marc Prud'hommeaux
+ * @author Jason Dillon
+ * @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 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 candidates) throws
+ IOException
+ {
+ Set distinct = new HashSet(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 copy = new ArrayList();
+
+ 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
+ * foobar, foobaz, foobuz, the method will return foob.
+ */
+ private String getUnambiguousCompletions(final List 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 candidates start with starts
+ */
+ 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);
+ }
+ }
+}
diff --git a/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/CandidateListCompletionHandler.properties b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/CandidateListCompletionHandler.properties
new file mode 100644
index 00000000000..3d7af092633
--- /dev/null
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/CandidateListCompletionHandler.properties
@@ -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--
diff --git a/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/Completer.java b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/Completer.java
new file mode 100644
index 00000000000..3c88ec22ccd
--- /dev/null
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/Completer.java
@@ -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 Marc Prud'hommeaux
+ * @author Jason Dillon
+ * @since 2.3
+ */
+public interface Completer
+{
+ //
+ // FIXME: Check if we can use CharSequece for buffer?
+ //
+
+ /**
+ * Populates candidates with a list of possible completions for the buffer.
+ *
+ * The candidates 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 buffer
+ * @param candidates The {@link List} of candidates to populate
+ * @return The index of the buffer for which the completion will be relative
+ */
+ int complete(String buffer, int cursor, List candidates);
+}
diff --git a/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/CompletionHandler.java b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/CompletionHandler.java
new file mode 100644
index 00000000000..a441fe918b8
--- /dev/null
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/CompletionHandler.java
@@ -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 Marc Prud'hommeaux
+ * @author Jason Dillon
+ * @since 2.3
+ */
+public interface CompletionHandler
+{
+ boolean complete(ConsoleReader reader, List candidates, int position) throws IOException;
+}
diff --git a/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/EnumCompleter.java b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/EnumCompleter.java
new file mode 100644
index 00000000000..78b39d9ba63
--- /dev/null
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/EnumCompleter.java
@@ -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 Jason Dillon
+ * @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());
+ }
+ }
+}
diff --git a/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/FileNameCompleter.java b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/FileNameCompleter.java
new file mode 100644
index 00000000000..110b25680c8
--- /dev/null
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/FileNameCompleter.java
@@ -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.
+ *
+ * This completer tries to behave as similar as possible to
+ * bash's file name completion (using GNU readline)
+ * with the following exceptions:
+ *
+ *
+ *
Candidates that are directories will end with "/"
+ *
Wildcard regular expressions are not evaluated or replaced
+ *
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
+ *
+ *
+ * @author Marc Prud'hommeaux
+ * @author Jason Dillon
+ * @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 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 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;
+ }
+}
diff --git a/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/NullCompleter.java b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/NullCompleter.java
new file mode 100644
index 00000000000..de5c10c048d
--- /dev/null
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/NullCompleter.java
@@ -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 Marc Prud'hommeaux
+ * @author Jason Dillon
+ * @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 candidates) {
+ return -1;
+ }
+}
diff --git a/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/StringsCompleter.java b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/StringsCompleter.java
new file mode 100644
index 00000000000..c77fb5ce995
--- /dev/null
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/StringsCompleter.java
@@ -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 Jason Dillon
+ * @since 2.3
+ */
+public class StringsCompleter
+ implements Completer
+{
+ private final SortedSet strings = new TreeSet();
+
+ public StringsCompleter() {
+ // empty
+ }
+
+ public StringsCompleter(final Collection strings) {
+ checkNotNull(strings);
+ getStrings().addAll(strings);
+ }
+
+ public StringsCompleter(final String... strings) {
+ this(Arrays.asList(strings));
+ }
+
+ public Collection getStrings() {
+ return strings;
+ }
+
+ public int complete(final String buffer, final int cursor, final List 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;
+ }
+}
diff --git a/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/package-info.java b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/package-info.java
new file mode 100644
index 00000000000..410d621a092
--- /dev/null
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/completer/package-info.java
@@ -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;
diff --git a/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/history/FileHistory.java b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/history/FileHistory.java
new file mode 100644
index 00000000000..47344e5da4c
--- /dev/null
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/history/FileHistory.java
@@ -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.
+ *
+ * Implementers should install shutdown hook to call {@link FileHistory#flush}
+ * to save history to disk.
+ *
+ * @author Jason Dillon
+ * @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);
+ }
+ }
+}
diff --git a/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/history/History.java b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/history/History.java
new file mode 100644
index 00000000000..3188b152824
--- /dev/null
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/history/History.java
@@ -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 Marc Prud'hommeaux
+ * @author Jason Dillon
+ * @since 2.3
+ */
+public interface History
+ extends Iterable
+{
+ 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 entries(int index);
+
+ ListIterator entries();
+
+ Iterator iterator();
+
+ //
+ // Navigation
+ //
+
+ CharSequence current();
+
+ boolean previous();
+
+ boolean next();
+
+ boolean moveToFirst();
+
+ boolean moveToLast();
+
+ boolean moveTo(int index);
+
+ void moveToEnd();
+}
diff --git a/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/history/MemoryHistory.java b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/history/MemoryHistory.java
new file mode 100644
index 00000000000..e01584edd71
--- /dev/null
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/history/MemoryHistory.java
@@ -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 Marc Prud'hommeaux
+ * @author Jason Dillon
+ * @since 2.3
+ */
+public class MemoryHistory
+ implements History
+{
+ public static final int DEFAULT_MAX_SIZE = 500;
+
+ private final LinkedList items = new LinkedList();
+
+ 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 entries(final int index) {
+ return new EntriesIterator(index - offset);
+ }
+
+ public ListIterator entries() {
+ return entries(offset);
+ }
+
+ public Iterator 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
+ {
+ private final ListIterator 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();
+ }
+}
diff --git a/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/history/PersistentHistory.java b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/history/PersistentHistory.java
new file mode 100644
index 00000000000..f3e573cfff3
--- /dev/null
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/history/PersistentHistory.java
@@ -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 Jason Dillon
+ * @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;
+}
diff --git a/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/history/package-info.java b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/history/package-info.java
new file mode 100644
index 00000000000..48410fefb09
--- /dev/null
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/history/package-info.java
@@ -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;
diff --git a/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/internal/ConsoleReaderInputStream.java b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/internal/ConsoleReaderInputStream.java
new file mode 100644
index 00000000000..f2b8bdfc129
--- /dev/null
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/internal/ConsoleReaderInputStream.java
@@ -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 Marc Prud'hommeaux
+ * @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
+ {
+ 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++);
+ }
+ }
+}
diff --git a/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/internal/ConsoleRunner.java b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/internal/ConsoleRunner.java
new file mode 100644
index 00000000000..0ac8d4b69b4
--- /dev/null
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/internal/ConsoleRunner.java
@@ -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 Marc Prud'hommeaux
+ * @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 argList = new ArrayList(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 completorList = new ArrayList();
+
+ 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()
+ + " [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.");
+ }
+}
diff --git a/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/package-info.java b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/package-info.java
new file mode 100644
index 00000000000..265518fb258
--- /dev/null
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/package-info.java
@@ -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;
diff --git a/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/Configuration.java b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/Configuration.java
new file mode 100644
index 00000000000..7011cf7764a
--- /dev/null
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/internal/Configuration.java
@@ -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 Jason Dillon
+ * @author Guillaume Nodet
+ * @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