Mon, 04 Feb 2013 14:48:35 -0400
8006191: `cmd` -> exec("cmd") in script mode
Reviewed-by: sundar, lagergren, hannesw
Contributed-by: james.laskey@oracle.com
1.1 --- a/src/jdk/nashorn/api/scripting/NashornScriptEngine.java Mon Feb 04 16:20:05 2013 +0100 1.2 +++ b/src/jdk/nashorn/api/scripting/NashornScriptEngine.java Mon Feb 04 14:48:35 2013 -0400 1.3 @@ -259,7 +259,7 @@ 1.4 @Override 1.5 public ScriptObject run() { 1.6 try { 1.7 - return nashornContext.createGlobal(); 1.8 + return nashornContext.newGlobal(); 1.9 } catch (final RuntimeException e) { 1.10 if (Context.DEBUG) { 1.11 e.printStackTrace(); 1.12 @@ -269,6 +269,8 @@ 1.13 } 1.14 }); 1.15 1.16 + nashornContext.initGlobal(newGlobal); 1.17 + 1.18 // current ScriptContext exposed as "context" 1.19 newGlobal.addOwnProperty("context", Property.NOT_ENUMERABLE, UNDEFINED); 1.20 // current ScriptEngine instance exposed as "engine". We added @SuppressWarnings("LeakingThisInConstructor") as
2.1 --- a/src/jdk/nashorn/internal/objects/Global.java Mon Feb 04 16:20:05 2013 +0100 2.2 +++ b/src/jdk/nashorn/internal/objects/Global.java Mon Feb 04 14:48:35 2013 -0400 2.3 @@ -1450,6 +1450,10 @@ 2.4 value = ScriptFunctionImpl.makeFunction("quit", ScriptingFunctions.QUIT); 2.5 addOwnProperty("quit", Attribute.NOT_ENUMERABLE, value); 2.6 2.7 + final String execName = ScriptingFunctions.EXEC_NAME; 2.8 + value = ScriptFunctionImpl.makeFunction(execName, ScriptingFunctions.EXEC); 2.9 + addOwnProperty(execName, Attribute.NOT_ENUMERABLE, value); 2.10 + 2.11 // Nashorn extension: global.echo (scripting-mode-only) 2.12 // alias for "print" 2.13 value = get("print"); 2.14 @@ -1458,6 +1462,10 @@ 2.15 // Nashorn extension: global.$OPTIONS (scripting-mode-only) 2.16 value = new OptionsObject(this.getContext()); 2.17 addOwnProperty("$OPTIONS", Attribute.NOT_ENUMERABLE, value); 2.18 + 2.19 + // Nashorn extension: global.$ENV (scripting-mode-only) 2.20 + value = ScriptingFunctions.getENVValues(newEmptyInstance(), this.isStrictContext()); 2.21 + addOwnProperty(ScriptingFunctions.ENV_NAME, Attribute.NOT_ENUMERABLE, value); 2.22 } 2.23 2.24 private void initTypedArray() {
3.1 --- a/src/jdk/nashorn/internal/parser/Lexer.java Mon Feb 04 16:20:05 2013 +0100 3.2 +++ b/src/jdk/nashorn/internal/parser/Lexer.java Mon Feb 04 14:48:35 2013 -0400 3.3 @@ -36,9 +36,11 @@ 3.4 import static jdk.nashorn.internal.parser.TokenType.LBRACE; 3.5 import static jdk.nashorn.internal.parser.TokenType.LPAREN; 3.6 import static jdk.nashorn.internal.parser.TokenType.OCTAL; 3.7 +import static jdk.nashorn.internal.parser.TokenType.RBRACE; 3.8 import static jdk.nashorn.internal.parser.TokenType.REGEX; 3.9 import static jdk.nashorn.internal.parser.TokenType.RPAREN; 3.10 import static jdk.nashorn.internal.parser.TokenType.STRING; 3.11 +import static jdk.nashorn.internal.parser.TokenType.EXECSTRING; 3.12 import static jdk.nashorn.internal.parser.TokenType.XML; 3.13 3.14 import jdk.nashorn.internal.runtime.ECMAErrors; 3.15 @@ -367,12 +369,13 @@ 3.16 } 3.17 3.18 /** 3.19 - * Test if char is a string delimiter, e.g. '\' or '"' 3.20 + * Test if char is a string delimiter, e.g. '\' or '"'. Also scans exec 3.21 + * strings ('`') in scripting mode. 3.22 * @param ch a char 3.23 * @return true if string delimiter 3.24 */ 3.25 protected boolean isStringDelimiter(final char ch) { 3.26 - return ch == '\'' || ch == '"'; 3.27 + return ch == '\'' || ch == '"' || (scripting && ch == '`'); 3.28 } 3.29 3.30 /** 3.31 @@ -936,12 +939,29 @@ 3.32 // Record end of string. 3.33 stringState.setLimit(position - 1); 3.34 3.35 - // Only edit double quoted strings. 3.36 - if (scripting && quote == '\"' && !stringState.isEmpty()) { 3.37 - // Edit string. 3.38 - editString(type, stringState); 3.39 + if (scripting && !stringState.isEmpty()) { 3.40 + switch (quote) { 3.41 + case '`': 3.42 + // Mark the beginning of an exec string. 3.43 + add(EXECSTRING, stringState.position, stringState.limit); 3.44 + // Frame edit string with left brace. 3.45 + add(LBRACE, stringState.position, stringState.position); 3.46 + // Process edit string. 3.47 + editString(type, stringState); 3.48 + // Frame edit string with right brace. 3.49 + add(RBRACE, stringState.limit, stringState.limit); 3.50 + break; 3.51 + case '"': 3.52 + // Only edit double quoted strings. 3.53 + editString(type, stringState); 3.54 + break; 3.55 + case '\'': 3.56 + // Add string token without editing. 3.57 + add(type, stringState.position, stringState.limit); 3.58 + break; 3.59 + } 3.60 } else { 3.61 - // Add string token. 3.62 + /// Add string token without editing. 3.63 add(type, stringState.position, stringState.limit); 3.64 } 3.65 }
4.1 --- a/src/jdk/nashorn/internal/parser/Parser.java Mon Feb 04 16:20:05 2013 +0100 4.2 +++ b/src/jdk/nashorn/internal/parser/Parser.java Mon Feb 04 14:48:35 2013 -0400 4.3 @@ -39,6 +39,7 @@ 4.4 import static jdk.nashorn.internal.parser.TokenType.ELSE; 4.5 import static jdk.nashorn.internal.parser.TokenType.EOF; 4.6 import static jdk.nashorn.internal.parser.TokenType.EOL; 4.7 +import static jdk.nashorn.internal.parser.TokenType.EXECSTRING; 4.8 import static jdk.nashorn.internal.parser.TokenType.FINALLY; 4.9 import static jdk.nashorn.internal.parser.TokenType.FUNCTION; 4.10 import static jdk.nashorn.internal.parser.TokenType.IDENT; 4.11 @@ -98,6 +99,7 @@ 4.12 import jdk.nashorn.internal.runtime.Context; 4.13 import jdk.nashorn.internal.runtime.JSErrorType; 4.14 import jdk.nashorn.internal.runtime.ParserException; 4.15 +import jdk.nashorn.internal.runtime.ScriptingFunctions; 4.16 4.17 /** 4.18 * Builds the IR. 4.19 @@ -107,8 +109,12 @@ 4.20 /** Code generator. */ 4.21 private final Compiler compiler; 4.22 4.23 + /** Current context. */ 4.24 private final Context context; 4.25 4.26 + /** Is scripting mode. */ 4.27 + private final boolean scripting; 4.28 + 4.29 /** Top level script being compiled. */ 4.30 private FunctionNode script; 4.31 4.32 @@ -136,6 +142,7 @@ 4.33 4.34 this.compiler = compiler; 4.35 this.context = compiler.getContext(); 4.36 + this.scripting = this.context._scripting; 4.37 } 4.38 4.39 /** 4.40 @@ -146,7 +153,7 @@ 4.41 public FunctionNode parse(final String scriptName) { 4.42 try { 4.43 stream = new TokenStream(); 4.44 - lexer = new Lexer(source, stream, context._scripting && !context._no_syntax_extensions); 4.45 + lexer = new Lexer(source, stream, scripting && !context._no_syntax_extensions); 4.46 4.47 // Set up first token (skips opening EOL.) 4.48 k = -1; 4.49 @@ -1856,6 +1863,8 @@ 4.50 case REGEX: 4.51 case XML: 4.52 return getLiteral(); 4.53 + case EXECSTRING: 4.54 + return execString(primaryToken); 4.55 case FALSE: 4.56 next(); 4.57 return LiteralNode.newInstance(source, primaryToken, finish, false); 4.58 @@ -1893,6 +1902,28 @@ 4.59 return null; 4.60 } 4.61 4.62 + /** 4.63 + * Convert execString to a call to $EXEC. 4.64 + * 4.65 + * @param primaryToken Original string token. 4.66 + * @return callNode to $EXEC. 4.67 + */ 4.68 + Node execString(final long primaryToken) { 4.69 + // Synthesize an ident to call $EXEC. 4.70 + final IdentNode execIdent = new IdentNode(source, primaryToken, finish, ScriptingFunctions.EXEC_NAME); 4.71 + // Skip over EXECSTRING. 4.72 + next(); 4.73 + // Set up argument list for call. 4.74 + final List<Node> arguments = new ArrayList<>(); 4.75 + // Skip beginning of edit string expression. 4.76 + expect(LBRACE); 4.77 + // Add the following expression to arguments. 4.78 + arguments.add(expression()); 4.79 + // Skip ending of edit string expression. 4.80 + expect(RBRACE); 4.81 + 4.82 + return new CallNode(source, primaryToken, finish, execIdent, arguments); 4.83 + } 4.84 4.85 /** 4.86 * ArrayLiteral :
5.1 --- a/src/jdk/nashorn/internal/parser/TokenType.java Mon Feb 04 16:20:05 2013 +0100 5.2 +++ b/src/jdk/nashorn/internal/parser/TokenType.java Mon Feb 04 14:48:35 2013 -0400 5.3 @@ -168,6 +168,7 @@ 5.4 FLOATING (LITERAL, null), 5.5 STRING (LITERAL, null), 5.6 ESCSTRING (LITERAL, null), 5.7 + EXECSTRING (LITERAL, null), 5.8 IDENT (LITERAL, null), 5.9 REGEX (LITERAL, null), 5.10 XML (LITERAL, null),
6.1 --- a/src/jdk/nashorn/internal/runtime/Context.java Mon Feb 04 16:20:05 2013 +0100 6.2 +++ b/src/jdk/nashorn/internal/runtime/Context.java Mon Feb 04 14:48:35 2013 -0400 6.3 @@ -744,16 +744,37 @@ 6.4 } 6.5 6.6 /** 6.7 - * Create global script object 6.8 + * Create and initialize a new global scope object. 6.9 + * 6.10 + * @return the initialized global scope object. 6.11 + */ 6.12 + public ScriptObject createGlobal() { 6.13 + return initGlobal(newGlobal()); 6.14 + } 6.15 + 6.16 + /** 6.17 + * Create a new uninitialized global scope object 6.18 * @return the global script object 6.19 */ 6.20 - public ScriptObject createGlobal() { 6.21 + public ScriptObject newGlobal() { 6.22 final SecurityManager sm = System.getSecurityManager(); 6.23 if (sm != null) { 6.24 sm.checkPermission(new RuntimePermission("createNashornGlobal")); 6.25 } 6.26 6.27 - final ScriptObject global = newGlobal(); 6.28 + return newGlobalTrusted(); 6.29 + } 6.30 + 6.31 + /** 6.32 + * Initialize given global scope object. 6.33 + * 6.34 + * @return the initialized global scope object. 6.35 + */ 6.36 + public ScriptObject initGlobal(final ScriptObject global) { 6.37 + if (! (global instanceof GlobalObject)) { 6.38 + throw new IllegalArgumentException("not a global object!"); 6.39 + } 6.40 + 6.41 // Need only minimal global object, if we are just compiling. 6.42 if (!_compile_only) { 6.43 final ScriptObject oldGlobal = Context.getGlobalTrusted(); 6.44 @@ -929,7 +950,7 @@ 6.45 }); 6.46 } 6.47 6.48 - private ScriptObject newGlobal() { 6.49 + private ScriptObject newGlobalTrusted() { 6.50 try { 6.51 final Class<?> clazz = Class.forName("jdk.nashorn.internal.objects.Global", true, scriptLoader); 6.52 return (ScriptObject) clazz.newInstance();
7.1 --- a/src/jdk/nashorn/internal/runtime/OptionsObject.java Mon Feb 04 16:20:05 2013 +0100 7.2 +++ b/src/jdk/nashorn/internal/runtime/OptionsObject.java Mon Feb 04 14:48:35 2013 -0400 7.3 @@ -40,10 +40,10 @@ 7.4 /** Only compile script, do not run it or generate other ScriptObjects */ 7.5 public final boolean _compile_only; 7.6 7.7 - /** Accumulated callsite flags that will be used when boostrapping script callsites */ 7.8 + /** Accumulated callsite flags that will be used when bootstrapping script callsites */ 7.9 public final int _callsite_flags; 7.10 7.11 - /** Genereate line number table in class files */ 7.12 + /** Generate line number table in class files */ 7.13 public final boolean _debug_lines; 7.14 7.15 /** Package to which generated class files are added */
8.1 --- a/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java Mon Feb 04 16:20:05 2013 +0100 8.2 +++ b/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java Mon Feb 04 14:48:35 2013 -0400 8.3 @@ -32,9 +32,15 @@ 8.4 import java.io.BufferedReader; 8.5 import java.io.File; 8.6 import java.io.IOException; 8.7 +import java.io.InputStream; 8.8 import java.io.InputStreamReader; 8.9 +import java.io.OutputStream; 8.10 import java.lang.invoke.MethodHandle; 8.11 import java.lang.invoke.MethodHandles; 8.12 +import java.util.HashMap; 8.13 +import java.util.Map; 8.14 +import java.util.Set; 8.15 +import java.util.StringTokenizer; 8.16 8.17 /** 8.18 * Global functions supported only in scripting mode. 8.19 @@ -50,6 +56,19 @@ 8.20 /** Handle to implementation of {@link ScriptingFunctions#quit} - Nashorn extension */ 8.21 public static final MethodHandle QUIT = findOwnMH("quit", Object.class, Object.class, Object.class); 8.22 8.23 + /** Handle to implementation of {@link ScriptingFunctions#quit} - Nashorn extension */ 8.24 + public static final MethodHandle EXEC = findOwnMH("exec", Object.class, Object.class, Object.class, Object.class); 8.25 + 8.26 + /** Names of special properties used by $EXEC API. */ 8.27 + public static final String EXEC_NAME = "$EXEC"; 8.28 + private static final String OUT_NAME = "$OUT"; 8.29 + private static final String ERR_NAME = "$ERR"; 8.30 + private static final String EXIT_NAME = "$EXIT"; 8.31 + 8.32 + /** Names of special properties used by $ENV API. */ 8.33 + public static final String ENV_NAME = "$ENV"; 8.34 + private static final String PWD_NAME = "PWD"; 8.35 + 8.36 private ScriptingFunctions() { 8.37 } 8.38 8.39 @@ -108,6 +127,118 @@ 8.40 return UNDEFINED; 8.41 } 8.42 8.43 + /** 8.44 + * Nashorn extension: exec a string in a separate process. 8.45 + * 8.46 + * @param self self reference 8.47 + * @param string string to execute 8.48 + * 8.49 + * @return output string from the request 8.50 + */ 8.51 + public static Object exec(final Object self, final Object string, final Object input) throws IOException, InterruptedException { 8.52 + // Current global is need to fetch additional inputs and for additional results. 8.53 + final ScriptObject global = Context.getGlobal(); 8.54 + 8.55 + // Current ENV property state. 8.56 + final Object env = global.get(ENV_NAME); 8.57 + // Make sure ENV is a valid script object. 8.58 + if (!(env instanceof ScriptObject)) { 8.59 + typeError("env.not.object"); 8.60 + } 8.61 + final ScriptObject envProperties = (ScriptObject)env; 8.62 + 8.63 + // Break exec string into tokens. 8.64 + final StringTokenizer tokenizer = new StringTokenizer(JSType.toString(string)); 8.65 + final String[] cmdArray = new String[tokenizer.countTokens()]; 8.66 + for (int i = 0; tokenizer.hasMoreTokens(); i++) { 8.67 + cmdArray[i] = tokenizer.nextToken(); 8.68 + } 8.69 + 8.70 + // Set up initial process. 8.71 + final ProcessBuilder processBuilder = new ProcessBuilder(cmdArray); 8.72 + 8.73 + // If a working directory is present, use it. 8.74 + final Object pwd = envProperties.get(PWD_NAME); 8.75 + if (pwd != UNDEFINED) { 8.76 + processBuilder.directory(new File(JSType.toString(pwd))); 8.77 + } 8.78 + 8.79 + // Set up ENV variables. 8.80 + final Map<String, String> environment = processBuilder.environment(); 8.81 + environment.clear(); 8.82 + for (Map.Entry<Object, Object> entry : envProperties.entrySet()) { 8.83 + 8.84 + environment.put(JSType.toString(entry.getKey()), JSType.toString(entry.getValue())); 8.85 + } 8.86 + 8.87 + // Start the process. 8.88 + final Process process = processBuilder.start(); 8.89 + 8.90 + // If input is present, pass on to process. 8.91 + try (OutputStream outputStream = process.getOutputStream()) { 8.92 + if (input != UNDEFINED) { 8.93 + outputStream.write(JSType.toString(input).getBytes()); 8.94 + } 8.95 + } 8.96 + 8.97 + // Wait for the process to complete. 8.98 + final int exit = process.waitFor(); 8.99 + 8.100 + // Collect output. 8.101 + String out; 8.102 + try (InputStream inputStream = process.getInputStream()) { 8.103 + final StringBuilder outBuffer = new StringBuilder(); 8.104 + for (int ch; (ch = inputStream.read()) != -1; ) { 8.105 + outBuffer.append((char)ch); 8.106 + } 8.107 + out = outBuffer.toString(); 8.108 + } 8.109 + 8.110 + // Collect errors. 8.111 + String err; 8.112 + try (InputStream errorStream = process.getErrorStream()) { 8.113 + final StringBuilder errBuffer = new StringBuilder(); 8.114 + for (int ch; (ch = errorStream.read()) != -1; ) { 8.115 + errBuffer.append((char)ch); 8.116 + } 8.117 + err = errBuffer.toString(); 8.118 + } 8.119 + 8.120 + // Set globals for secondary results. 8.121 + final boolean isStrict = global.isStrictContext(); 8.122 + global.set(OUT_NAME, out, isStrict); 8.123 + global.set(ERR_NAME, err, isStrict); 8.124 + global.set(EXIT_NAME, exit, isStrict); 8.125 + 8.126 + // Return the result from stdout. 8.127 + return out; 8.128 + } 8.129 + 8.130 + /** 8.131 + * Return an object containing properties mapping to ENV variables. 8.132 + * 8.133 + * @param envProperties object to receive properties 8.134 + * @param isStrict global's strict state 8.135 + * 8.136 + * @return Script object with properties mapping to ENV variables. 8.137 + */ 8.138 + public static ScriptObject getENVValues(final ScriptObject envProperties, final boolean isStrict) { 8.139 + // Retrieve current state of ENV variables. 8.140 + Map<String, String> envVars; 8.141 + try { 8.142 + envVars = System.getenv(); 8.143 + } catch(SecurityException ex) { 8.144 + envVars = new HashMap<>(); 8.145 + } 8.146 + 8.147 + // Map ENV variables. 8.148 + for (Map.Entry<String, String> entry : envVars.entrySet()) { 8.149 + envProperties.set(entry.getKey(), entry.getValue(), isStrict); 8.150 + } 8.151 + 8.152 + return envProperties; 8.153 + } 8.154 + 8.155 private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) { 8.156 return MH.findStatic(MethodHandles.lookup(), ScriptingFunctions.class, name, MH.type(rtype, types)); 8.157 }
9.1 --- a/src/jdk/nashorn/internal/runtime/resources/Messages.properties Mon Feb 04 16:20:05 2013 +0100 9.2 +++ b/src/jdk/nashorn/internal/runtime/resources/Messages.properties Mon Feb 04 14:48:35 2013 -0400 9.3 @@ -121,6 +121,7 @@ 9.4 type.error.no.constructor.matches.args=Can not construct {0} with the passed arguments; they do not match any of its constructor signatures. 9.5 type.error.no.method.matches.args=Can not invoke method {0} with the passed arguments; they do not match any of its method signatures. 9.6 type.error.method.not.constructor=Java method {0} can't be used as a constructor. 9.7 +type.error.env.not.object=$ENV must be an Object. 9.8 range.error.inappropriate.array.length=inappropriate array length: {0} 9.9 range.error.invalid.fraction.digits=fractionDigits argument to {0} must be in [0, 20] 9.10 range.error.invalid.precision=precision argument toPrecision() must be in [1, 21]
10.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 10.2 +++ b/test/script/basic/JDK-8006191.js Mon Feb 04 14:48:35 2013 -0400 10.3 @@ -0,0 +1,65 @@ 10.4 +/* 10.5 + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 10.6 + * 10.7 + * Redistribution and use in source and binary forms, with or without 10.8 + * modification, are permitted provided that the following conditions 10.9 + * are met: 10.10 + * 10.11 + * - Redistributions of source code must retain the above copyright 10.12 + * notice, this list of conditions and the following disclaimer. 10.13 + * 10.14 + * - Redistributions in binary form must reproduce the above copyright 10.15 + * notice, this list of conditions and the following disclaimer in the 10.16 + * documentation and/or other materials provided with the distribution. 10.17 + * 10.18 + * - Neither the name of Oracle nor the names of its 10.19 + * contributors may be used to endorse or promote products derived 10.20 + * from this software without specific prior written permission. 10.21 + * 10.22 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 10.23 + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 10.24 + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 10.25 + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 10.26 + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 10.27 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 10.28 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 10.29 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 10.30 + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 10.31 + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 10.32 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 10.33 + */ 10.34 + 10.35 +/** 10.36 + * JDK-8006191 - `cmd` -> exec("cmd") in script mode 10.37 + * 10.38 + * @test 10.39 + * @option -scripting 10.40 + * @argument ArgumentFromCommandLine 10.41 + * @run 10.42 + */ 10.43 + 10.44 +#!/usr/bin/jjs 10.45 + 10.46 +$ENV.PWD = "."; 10.47 +print($ENV.PWD); 10.48 + 10.49 +var files = `ls`.trim().split("\n"); 10.50 +for (var i in files) { 10.51 + var file = files[i]; 10.52 + if (file.contains("README")) { 10.53 + print(file); 10.54 + } 10.55 +} 10.56 + 10.57 +var result = $EXEC("cat", <<EOD); 10.58 +This is a bunch of stuff 10.59 +that I want written out 10.60 +including ${$ARG[0]} 10.61 +EOD 10.62 +print(result); 10.63 +print($OUT); 10.64 + 10.65 +var arg = "-Q"; 10.66 +`ls ${arg}`; 10.67 +print($ERR); 10.68 +print($EXIT);
11.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 11.2 +++ b/test/script/basic/JDK-8006191.js.EXPECTED Mon Feb 04 14:48:35 2013 -0400 11.3 @@ -0,0 +1,14 @@ 11.4 +. 11.5 +README 11.6 +RELEASE_README 11.7 +THIRD_PARTY_README 11.8 +This is a bunch of stuff 11.9 +that I want written out 11.10 +including ArgumentFromCommandLine 11.11 +This is a bunch of stuff 11.12 +that I want written out 11.13 +including ArgumentFromCommandLine 11.14 +ls: illegal option -- Q 11.15 +usage: ls [-ABCFGHLOPRSTUWabcdefghiklmnopqrstuwx1] [file ...] 11.16 + 11.17 +1