8006191: `cmd` -> exec("cmd") in script mode

Mon, 04 Feb 2013 14:48:35 -0400

author
jlaskey
date
Mon, 04 Feb 2013 14:48:35 -0400
changeset 67
6f58c28c4faa
parent 66
bee7c8a45a04
child 68
5c2ed5d89524

8006191: `cmd` -> exec("cmd") in script mode
Reviewed-by: sundar, lagergren, hannesw
Contributed-by: james.laskey@oracle.com

src/jdk/nashorn/api/scripting/NashornScriptEngine.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/objects/Global.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/parser/Lexer.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/parser/Parser.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/parser/TokenType.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/Context.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/OptionsObject.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/ScriptingFunctions.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/resources/Messages.properties file | annotate | diff | comparison | revisions
test/script/basic/JDK-8006191.js file | annotate | diff | comparison | revisions
test/script/basic/JDK-8006191.js.EXPECTED file | annotate | diff | comparison | revisions
     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

mercurial