--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.scripting/share/classes/com/sun/tools/script/shell/Main.java Wed Dec 03 14:22:58 2014 +0000
@@ -0,0 +1,586 @@
+/*
+ * Copyright (c) 2005, 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 com.sun.tools.script.shell;
+
+import java.io.*;
+import java.net.*;
+import java.text.*;
+import java.util.*;
+import javax.script.*;
+
+/**
+ * This is the main class for Java script shell.
+ */
+public class Main {
+ /**
+ * main entry point to the command line tool
+ * @param args command line argument array
+ */
+ public static void main(String[] args) {
+ // parse command line options
+ String[] scriptArgs = processOptions(args);
+
+ // process each script command
+ for (Command cmd : scripts) {
+ cmd.run(scriptArgs);
+ }
+
+ System.exit(EXIT_SUCCESS);
+ }
+
+ // Each -e or -f or interactive mode is represented
+ // by an instance of Command.
+ private static interface Command {
+ public void run(String[] arguments);
+ }
+
+ /**
+ * Parses and processes command line options.
+ * @param args command line argument array
+ */
+ private static String[] processOptions(String[] args) {
+ // current scripting language selected
+ String currentLanguage = DEFAULT_LANGUAGE;
+ // current script file encoding selected
+ String currentEncoding = null;
+
+ // check for -classpath or -cp first
+ checkClassPath(args);
+
+ // have we seen -e or -f ?
+ boolean seenScript = false;
+ // have we seen -f - already?
+ boolean seenStdin = false;
+ for (int i=0; i < args.length; i++) {
+ String arg = args[i];
+ if (arg.equals("-classpath") ||
+ arg.equals("-cp")) {
+ // handled already, just continue
+ i++;
+ continue;
+ }
+
+ // collect non-option arguments and pass these as script arguments
+ if (!arg.startsWith("-")) {
+ int numScriptArgs;
+ int startScriptArg;
+ if (seenScript) {
+ // if we have seen -e or -f already all non-option arguments
+ // are passed as script arguments
+ numScriptArgs = args.length - i;
+ startScriptArg = i;
+ } else {
+ // if we have not seen -e or -f, first non-option argument
+ // is treated as script file name and rest of the non-option
+ // arguments are passed to script as script arguments
+ numScriptArgs = args.length - i - 1;
+ startScriptArg = i + 1;
+ ScriptEngine se = getScriptEngine(currentLanguage);
+ addFileSource(se, args[i], currentEncoding);
+ }
+ // collect script arguments and return to main
+ String[] result = new String[numScriptArgs];
+ System.arraycopy(args, startScriptArg, result, 0, numScriptArgs);
+ return result;
+ }
+
+ if (arg.startsWith("-D")) {
+ String value = arg.substring(2);
+ int eq = value.indexOf('=');
+ if (eq != -1) {
+ System.setProperty(value.substring(0, eq),
+ value.substring(eq + 1));
+ } else {
+ if (!value.equals("")) {
+ System.setProperty(value, "");
+ } else {
+ // do not allow empty property name
+ usage(EXIT_CMD_NO_PROPNAME);
+ }
+ }
+ continue;
+ } else if (arg.equals("-?") || arg.equals("-help")) {
+ usage(EXIT_SUCCESS);
+ } else if (arg.equals("-e")) {
+ seenScript = true;
+ if (++i == args.length)
+ usage(EXIT_CMD_NO_SCRIPT);
+
+ ScriptEngine se = getScriptEngine(currentLanguage);
+ addStringSource(se, args[i]);
+ continue;
+ } else if (arg.equals("-encoding")) {
+ if (++i == args.length)
+ usage(EXIT_CMD_NO_ENCODING);
+ currentEncoding = args[i];
+ continue;
+ } else if (arg.equals("-f")) {
+ seenScript = true;
+ if (++i == args.length)
+ usage(EXIT_CMD_NO_FILE);
+ ScriptEngine se = getScriptEngine(currentLanguage);
+ if (args[i].equals("-")) {
+ if (seenStdin) {
+ usage(EXIT_MULTIPLE_STDIN);
+ } else {
+ seenStdin = true;
+ }
+ addInteractiveMode(se);
+ } else {
+ addFileSource(se, args[i], currentEncoding);
+ }
+ continue;
+ } else if (arg.equals("-l")) {
+ if (++i == args.length)
+ usage(EXIT_CMD_NO_LANG);
+ currentLanguage = args[i];
+ continue;
+ } else if (arg.equals("-q")) {
+ listScriptEngines();
+ }
+ // some unknown option...
+ usage(EXIT_UNKNOWN_OPTION);
+ }
+
+ if (! seenScript) {
+ ScriptEngine se = getScriptEngine(currentLanguage);
+ addInteractiveMode(se);
+ }
+ return new String[0];
+ }
+
+ /**
+ * Adds interactive mode Command
+ * @param se ScriptEngine to use in interactive mode.
+ */
+ private static void addInteractiveMode(final ScriptEngine se) {
+ scripts.add(new Command() {
+ public void run(String[] args) {
+ setScriptArguments(se, args);
+ processSource(se, "-", null);
+ }
+ });
+ }
+
+ /**
+ * Adds script source file Command
+ * @param se ScriptEngine used to evaluate the script file
+ * @param fileName script file name
+ * @param encoding script file encoding
+ */
+ private static void addFileSource(final ScriptEngine se,
+ final String fileName,
+ final String encoding) {
+ scripts.add(new Command() {
+ public void run(String[] args) {
+ setScriptArguments(se, args);
+ processSource(se, fileName, encoding);
+ }
+ });
+ }
+
+ /**
+ * Adds script string source Command
+ * @param se ScriptEngine to be used to evaluate the script string
+ * @param source Script source string
+ */
+ private static void addStringSource(final ScriptEngine se,
+ final String source) {
+ scripts.add(new Command() {
+ public void run(String[] args) {
+ setScriptArguments(se, args);
+ String oldFile = setScriptFilename(se, "<string>");
+ try {
+ evaluateString(se, source);
+ } finally {
+ setScriptFilename(se, oldFile);
+ }
+ }
+ });
+ }
+
+ /**
+ * Prints list of script engines available and exits.
+ */
+ private static void listScriptEngines() {
+ List<ScriptEngineFactory> factories = engineManager.getEngineFactories();
+ for (ScriptEngineFactory factory: factories) {
+ getError().println(getMessage("engine.info",
+ new Object[] { factory.getLanguageName(),
+ factory.getLanguageVersion(),
+ factory.getEngineName(),
+ factory.getEngineVersion()
+ }));
+ }
+ System.exit(EXIT_SUCCESS);
+ }
+
+ /**
+ * Processes a given source file or standard input.
+ * @param se ScriptEngine to be used to evaluate
+ * @param filename file name, can be null
+ * @param encoding script file encoding, can be null
+ */
+ private static void processSource(ScriptEngine se, String filename,
+ String encoding) {
+ if (filename.equals("-")) {
+ BufferedReader in = new BufferedReader
+ (new InputStreamReader(getIn()));
+ boolean hitEOF = false;
+ String prompt = getPrompt(se);
+ se.put(ScriptEngine.FILENAME, "<STDIN>");
+ while (!hitEOF) {
+ getError().print(prompt);
+ String source = "";
+ try {
+ source = in.readLine();
+ } catch (IOException ioe) {
+ getError().println(ioe.toString());
+ }
+ if (source == null) {
+ hitEOF = true;
+ break;
+ }
+ Object res = evaluateString(se, source, false);
+ if (res != null) {
+ res = res.toString();
+ if (res == null) {
+ res = "null";
+ }
+ getError().println(res);
+ }
+ }
+ } else {
+ FileInputStream fis = null;
+ try {
+ fis = new FileInputStream(filename);
+ } catch (FileNotFoundException fnfe) {
+ getError().println(getMessage("file.not.found",
+ new Object[] { filename }));
+ System.exit(EXIT_FILE_NOT_FOUND);
+ }
+ evaluateStream(se, fis, filename, encoding);
+ }
+ }
+
+ /**
+ * Evaluates given script source
+ * @param se ScriptEngine to evaluate the string
+ * @param script Script source string
+ * @param exitOnError whether to exit the process on script error
+ */
+ private static Object evaluateString(ScriptEngine se,
+ String script, boolean exitOnError) {
+ try {
+ return se.eval(script);
+ } catch (ScriptException sexp) {
+ getError().println(getMessage("string.script.error",
+ new Object[] { sexp.getMessage() }));
+ if (exitOnError)
+ System.exit(EXIT_SCRIPT_ERROR);
+ } catch (Exception exp) {
+ exp.printStackTrace(getError());
+ if (exitOnError)
+ System.exit(EXIT_SCRIPT_ERROR);
+ }
+
+ return null;
+ }
+
+ /**
+ * Evaluate script string source and exit on script error
+ * @param se ScriptEngine to evaluate the string
+ * @param script Script source string
+ */
+ private static void evaluateString(ScriptEngine se, String script) {
+ evaluateString(se, script, true);
+ }
+
+ /**
+ * Evaluates script from given reader
+ * @param se ScriptEngine to evaluate the string
+ * @param reader Reader from which is script is read
+ * @param name file name to report in error.
+ */
+ private static Object evaluateReader(ScriptEngine se,
+ Reader reader, String name) {
+ String oldFilename = setScriptFilename(se, name);
+ try {
+ return se.eval(reader);
+ } catch (ScriptException sexp) {
+ getError().println(getMessage("file.script.error",
+ new Object[] { name, sexp.getMessage() }));
+ System.exit(EXIT_SCRIPT_ERROR);
+ } catch (Exception exp) {
+ exp.printStackTrace(getError());
+ System.exit(EXIT_SCRIPT_ERROR);
+ } finally {
+ setScriptFilename(se, oldFilename);
+ }
+ return null;
+ }
+
+ /**
+ * Evaluates given input stream
+ * @param se ScriptEngine to evaluate the string
+ * @param is InputStream from which script is read
+ * @param name file name to report in error
+ */
+ private static Object evaluateStream(ScriptEngine se,
+ InputStream is, String name,
+ String encoding) {
+ BufferedReader reader = null;
+ if (encoding != null) {
+ try {
+ reader = new BufferedReader(new InputStreamReader(is,
+ encoding));
+ } catch (UnsupportedEncodingException uee) {
+ getError().println(getMessage("encoding.unsupported",
+ new Object[] { encoding }));
+ System.exit(EXIT_NO_ENCODING_FOUND);
+ }
+ } else {
+ reader = new BufferedReader(new InputStreamReader(is));
+ }
+ return evaluateReader(se, reader, name);
+ }
+
+ /**
+ * Prints usage message and exits
+ * @param exitCode process exit code
+ */
+ private static void usage(int exitCode) {
+ getError().println(getMessage("main.usage",
+ new Object[] { PROGRAM_NAME }));
+ System.exit(exitCode);
+ }
+
+ /**
+ * Gets prompt for interactive mode
+ * @return prompt string to use
+ */
+ private static String getPrompt(ScriptEngine se) {
+ List<String> names = se.getFactory().getNames();
+ return names.get(0) + "> ";
+ }
+
+ /**
+ * Get formatted, localized error message
+ */
+ private static String getMessage(String key, Object[] params) {
+ return MessageFormat.format(msgRes.getString(key), params);
+ }
+
+ // input stream from where we will read
+ private static InputStream getIn() {
+ return System.in;
+ }
+
+ // stream to print error messages
+ private static PrintStream getError() {
+ return System.err;
+ }
+
+ // get current script engine
+ private static ScriptEngine getScriptEngine(String lang) {
+ ScriptEngine se = engines.get(lang);
+ if (se == null) {
+ se = engineManager.getEngineByName(lang);
+ if (se == null) {
+ getError().println(getMessage("engine.not.found",
+ new Object[] { lang }));
+ System.exit(EXIT_ENGINE_NOT_FOUND);
+ }
+
+ // initialize the engine
+ initScriptEngine(se);
+ // to avoid re-initialization of engine, store it in a map
+ engines.put(lang, se);
+ }
+ return se;
+ }
+
+ // initialize a given script engine
+ private static void initScriptEngine(ScriptEngine se) {
+ // put engine global variable
+ se.put("engine", se);
+
+ // load init.<ext> file from resource
+ List<String> exts = se.getFactory().getExtensions();
+ InputStream sysIn = null;
+ ClassLoader cl = Thread.currentThread().getContextClassLoader();
+ for (String ext : exts) {
+ sysIn = cl.getResourceAsStream("com/sun/tools/script/shell/init." +
+ ext);
+ if (sysIn != null) break;
+ }
+ if (sysIn != null) {
+ evaluateStream(se, sysIn, "<system-init>", null);
+ }
+ }
+
+ /**
+ * Checks for -classpath, -cp in command line args. Creates a ClassLoader
+ * and sets it as Thread context loader for current thread.
+ *
+ * @param args command line argument array
+ */
+ private static void checkClassPath(String[] args) {
+ String classPath = null;
+ for (int i = 0; i < args.length; i++) {
+ if (args[i].equals("-classpath") ||
+ args[i].equals("-cp")) {
+ if (++i == args.length) {
+ // just -classpath or -cp with no value
+ usage(EXIT_CMD_NO_CLASSPATH);
+ } else {
+ classPath = args[i];
+ }
+ }
+ }
+
+ if (classPath != null) {
+ /* We create a class loader, configure it with specified
+ * classpath values and set the same as context loader.
+ * Note that ScriptEngineManager uses context loader to
+ * load script engines. So, this ensures that user defined
+ * script engines will be loaded. For classes referred
+ * from scripts, Rhino engine uses thread context loader
+ * but this is script engine dependent. We don't have
+ * script engine independent solution anyway. Unless we
+ * know the class loader used by a specific engine, we
+ * can't configure correct loader.
+ */
+ URL[] urls = pathToURLs(classPath);
+ URLClassLoader loader = new URLClassLoader(urls);
+ Thread.currentThread().setContextClassLoader(loader);
+ }
+
+ // now initialize script engine manager. Note that this has to
+ // be done after setting the context loader so that manager
+ // will see script engines from user specified classpath
+ engineManager = new ScriptEngineManager();
+ }
+
+ /**
+ * Utility method for converting a search path string to an array
+ * of directory and JAR file URLs.
+ *
+ * @param path the search path string
+ * @return the resulting array of directory and JAR file URLs
+ */
+ private static URL[] pathToURLs(String path) {
+ String[] components = path.split(File.pathSeparator);
+ URL[] urls = new URL[components.length];
+ int count = 0;
+ while(count < components.length) {
+ URL url = fileToURL(new File(components[count]));
+ if (url != null) {
+ urls[count++] = url;
+ }
+ }
+ if (urls.length != count) {
+ URL[] tmp = new URL[count];
+ System.arraycopy(urls, 0, tmp, 0, count);
+ urls = tmp;
+ }
+ return urls;
+ }
+
+ /**
+ * Returns the directory or JAR file URL corresponding to the specified
+ * local file name.
+ *
+ * @param file the File object
+ * @return the resulting directory or JAR file URL, or null if unknown
+ */
+ private static URL fileToURL(File file) {
+ String name;
+ try {
+ name = file.getCanonicalPath();
+ } catch (IOException e) {
+ name = file.getAbsolutePath();
+ }
+ name = name.replace(File.separatorChar, '/');
+ if (!name.startsWith("/")) {
+ name = "/" + name;
+ }
+ // If the file does not exist, then assume that it's a directory
+ if (!file.isFile()) {
+ name = name + "/";
+ }
+ try {
+ return new URL("file", "", name);
+ } catch (MalformedURLException e) {
+ throw new IllegalArgumentException("file");
+ }
+ }
+
+ private static void setScriptArguments(ScriptEngine se, String[] args) {
+ se.put("arguments", args);
+ se.put(ScriptEngine.ARGV, args);
+ }
+
+ private static String setScriptFilename(ScriptEngine se, String name) {
+ String oldName = (String) se.get(ScriptEngine.FILENAME);
+ se.put(ScriptEngine.FILENAME, name);
+ return oldName;
+ }
+
+ // exit codes
+ private static final int EXIT_SUCCESS = 0;
+ private static final int EXIT_CMD_NO_CLASSPATH = 1;
+ private static final int EXIT_CMD_NO_FILE = 2;
+ private static final int EXIT_CMD_NO_SCRIPT = 3;
+ private static final int EXIT_CMD_NO_LANG = 4;
+ private static final int EXIT_CMD_NO_ENCODING = 5;
+ private static final int EXIT_CMD_NO_PROPNAME = 6;
+ private static final int EXIT_UNKNOWN_OPTION = 7;
+ private static final int EXIT_ENGINE_NOT_FOUND = 8;
+ private static final int EXIT_NO_ENCODING_FOUND = 9;
+ private static final int EXIT_SCRIPT_ERROR = 10;
+ private static final int EXIT_FILE_NOT_FOUND = 11;
+ private static final int EXIT_MULTIPLE_STDIN = 12;
+
+ // default scripting language
+ private static final String DEFAULT_LANGUAGE = "js";
+ // list of scripts to process
+ private static List<Command> scripts;
+ // the script engine manager
+ private static ScriptEngineManager engineManager;
+ // map of engines we loaded
+ private static Map<String, ScriptEngine> engines;
+ // error messages resource
+ private static ResourceBundle msgRes;
+ private static String BUNDLE_NAME = "com.sun.tools.script.shell.messages";
+ private static String PROGRAM_NAME = "jrunscript";
+
+ static {
+ scripts = new ArrayList<Command>();
+ engines = new HashMap<String, ScriptEngine>();
+ msgRes = ResourceBundle.getBundle(BUNDLE_NAME, Locale.getDefault());
+ }
+}