# HG changeset patch # User mhaupt # Date 1433834822 -7200 # Tue Jun 09 09:27:02 2015 +0200 # Node ID a172c639cba24913e7c5e0ba8e0963ec9fbcf814 # Parent d1689c1df3aa7449886f3ebab36b33a0d910a489 8080490: add $EXECV command to Nashorn scripting mode diff --git a/samples/exec.js b/samples/exec.js new file mode 100644 --- /dev/null +++ b/samples/exec.js @@ -0,0 +1,48 @@ +# exec script requires -scripting mode + +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// The $EXEC builtin function can be used to run external commands: +$EXEC("ls") +$EXEC("ls -la") + +// It can also be given a string to use as stdin: +$EXEC("cat", "Hello, world!") + +// Additional arguments can be passed after the stdin argument, as an array of +// strings, or a sequence of varargs: +$EXEC("ls", "" /* no stdin */, "-l", "-a") +$EXEC("ls", "" /* no stdin */, ["-l", "-a"]) + +// Output of running external commands is returned from $EXEC: +print($EXEC("ls")) + diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java --- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java +++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java @@ -2580,15 +2580,18 @@ final int parameterCount = methodType.parameterCount(); final int callCount = callType.parameterCount(); + final int pdiff = callCount - parameterCount + 1; final boolean isCalleeVarArg = parameterCount > 0 && methodType.parameterType(parameterCount - 1).isArray(); - final boolean isCallerVarArg = callerVarArg != null ? callerVarArg.booleanValue() : callCount > 0 && + final boolean isCallerVarArg = callerVarArg != null ? callerVarArg : callCount > 0 && callType.parameterType(callCount - 1).isArray(); - if (isCalleeVarArg) { + // A value of pdiff < 0 means that there are additional normal arguments in the callee that must not be consumed + // by the vararg collector. No vararg collector is required in that case, and no varargs are passed. + if (isCalleeVarArg && pdiff >= 0) { return isCallerVarArg ? methodHandle : - MH.asCollector(methodHandle, Object[].class, callCount - parameterCount + 1); + MH.asCollector(methodHandle, Object[].class, pdiff); } if (isCallerVarArg) { diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptingFunctions.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptingFunctions.java --- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptingFunctions.java +++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptingFunctions.java @@ -41,6 +41,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; +import jdk.nashorn.internal.objects.NativeArray; /** * Global functions supported only in scripting mode. @@ -54,7 +55,7 @@ public static final MethodHandle READFULLY = findOwnMH("readFully", Object.class, Object.class, Object.class); /** Handle to implementation of {@link ScriptingFunctions#exec} - Nashorn extension */ - public static final MethodHandle EXEC = findOwnMH("exec", Object.class, Object.class, Object.class, Object.class); + public static final MethodHandle EXEC = findOwnMH("exec", Object.class, Object.class, Object.class, Object.class, Object[].class); /** EXEC name - special property used by $EXEC API. */ public static final String EXEC_NAME = "$EXEC"; @@ -128,17 +129,30 @@ * @param self self reference * @param string string to execute * @param input input + * @param argv additional arguments, to be appended to {@code string}. Additional arguments can be passed as + * either one JavaScript array, whose elements will be converted to strings; or as a sequence of + * varargs, each of which will be converted to a string. * * @return output string from the request + * * @throws IOException if any stream access fails * @throws InterruptedException if execution is interrupted */ - public static Object exec(final Object self, final Object string, final Object input) throws IOException, InterruptedException { + public static Object exec(final Object self, final Object string, final Object input, final Object... argv) throws IOException, InterruptedException { // Current global is need to fetch additional inputs and for additional results. final ScriptObject global = Context.getGlobal(); + // Assemble command line, process additional arguments. + final List cmdLine = tokenizeString(JSType.toString(string)); + final Object[] additionalArgs = argv.length == 1 && argv[0] instanceof NativeArray ? + ((NativeArray) argv[0]).asObjectArray() : + argv; + for (Object arg : additionalArgs) { + cmdLine.add(JSType.toString(arg)); + } + // Set up initial process. - final ProcessBuilder processBuilder = new ProcessBuilder(tokenizeString(JSType.toString(string))); + final ProcessBuilder processBuilder = new ProcessBuilder(cmdLine); // Current ENV property state. final Object env = global.get(ENV_NAME);