From 246e4e8daf62df4765c95847c3d5dec4a51a4cbe Mon Sep 17 00:00:00 2001 From: Andreas Rieber Date: Mon, 14 Jan 2013 21:30:13 +0530 Subject: [PATCH] 8006181: nashorn script engine does not run jrunscript's initialization script Reviewed-by: lagergren, jlaskey --- .../jdk/nashorn/api/scripting/Formatter.java | 180 ++++ .../api/scripting/NashornScriptEngine.java | 21 +- .../nashorn/api/scripting/resources/engine.js | 8 +- .../nashorn/api/scripting/resources/init.js | 940 ++++++++++++++++++ 4 files changed, 1139 insertions(+), 10 deletions(-) create mode 100644 nashorn/src/jdk/nashorn/api/scripting/Formatter.java create mode 100644 nashorn/src/jdk/nashorn/api/scripting/resources/init.js diff --git a/nashorn/src/jdk/nashorn/api/scripting/Formatter.java b/nashorn/src/jdk/nashorn/api/scripting/Formatter.java new file mode 100644 index 00000000000..12e7cb18aa0 --- /dev/null +++ b/nashorn/src/jdk/nashorn/api/scripting/Formatter.java @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2013 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 jdk.nashorn.api.scripting; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Formatter is a class to get the type conversion between javascript types and + * java types for the format (sprintf) method working. + * + *

In javascript the type for numbers can be different from the format type + * specifier. For format type '%d', '%o', '%x', '%X' double need to be + * converted to integer. For format type 'e', 'E', 'f', 'g', 'G', 'a', 'A' + * integer needs to be converted to double. + * + *

Format type "%c" and javascript string needs special handling. + * + *

The javascript date objects can be handled if they are type double (the + * related javascript code will convert with Date.getTime() to double). So + * double date types are converted to long. + * + *

Pattern and the logic for parameter position: java.util.Formatter + * + */ +public final class Formatter { + + /** + * Method which converts javascript types to java types for the + * String.format method (jrunscript function sprintf). + * + * @param format a format string + * @param args arguments referenced by the format specifiers in format + * @return a formatted string + */ + public static String format(final String format, final Object[] args) { + Matcher m = FS_PATTERN.matcher(format); + int positionalParameter = 1; + + while (m.find()) { + int index = index(m.group(1)); + boolean previous = isPreviousArgument(m.group(2)); + char conversion = m.group(6).charAt(0); + + // skip over some formats + if (index < 0 || previous + || conversion == 'n' || conversion == '%') { + continue; + } + + // index 0 here means take a positional parameter + if (index == 0) { + index = positionalParameter++; + } + + // out of index, String.format will handle + if (index > args.length) { + continue; + } + + // current argument + Object arg = args[index - 1]; + + // for date we convert double to long + if (m.group(5) != null) { + // convert double to long + if (arg instanceof Double) { + args[index - 1] = ((Double) arg).longValue(); + } + } else { + // we have to convert some types + switch (conversion) { + case 'd': + case 'o': + case 'x': + case 'X': + if (arg instanceof Double) { + // convert double to long + args[index - 1] = ((Double) arg).longValue(); + } else if (arg instanceof String + && ((String) arg).length() > 0) { + // convert string (first character) to int + args[index - 1] = (int) ((String) arg).charAt(0); + } + break; + case 'e': + case 'E': + case 'f': + case 'g': + case 'G': + case 'a': + case 'A': + if (arg instanceof Integer) { + // convert integer to double + args[index - 1] = ((Integer) arg).doubleValue(); + } + break; + case 'c': + if (arg instanceof Double) { + // convert double to integer + args[index - 1] = ((Double) arg).intValue(); + } else if (arg instanceof String + && ((String) arg).length() > 0) { + // get the first character from string + args[index - 1] = (int) ((String) arg).charAt(0); + } + break; + default: + break; + } + } + } + + return String.format(format, args); + } + + /** + * Method to parse the integer of the argument index. + * + * @param s + * @return -1 if parsing failed, 0 if string is null, > 0 integer + */ + private static int index(final String s) { + int index = -1; + + if (s != null) { + try { + index = Integer.parseInt(s.substring(0, s.length() - 1)); + } catch (NumberFormatException e) { } + } else { + index = 0; + } + + return index; + } + + /** + * Method to check if a string contains '<'. This is used to find out if + * previous parameter is used. + * + * @param s + * @return true if '<' is in the string, else false + */ + private static boolean isPreviousArgument(final String s) { + return (s != null && s.indexOf('<') >= 0) ? true : false; + } + + // %[argument_index$][flags][width][.precision][t]conversion + private static final String formatSpecifier = + "%(\\d+\\$)?([-#+ 0,(\\<]*)?(\\d+)?(\\.\\d+)?([tT])?([a-zA-Z%])"; + // compiled format string + private static final Pattern FS_PATTERN; + + static { + FS_PATTERN = Pattern.compile(formatSpecifier); + } +} diff --git a/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java b/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java index 112f4df5b09..27ccb9e4772 100644 --- a/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java +++ b/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java @@ -327,7 +327,11 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C } private void evalEngineScript() throws ScriptException { - final URL url = NashornScriptEngine.class.getResource("resources/engine.js"); + evalSupportScript("resources/engine.js"); + } + + private void evalSupportScript(String script) throws ScriptException { + final URL url = NashornScriptEngine.class.getResource(script); try { final InputStream is = url.openStream(); put(ScriptEngine.FILENAME, url); @@ -435,6 +439,16 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C } setContextVariables(ctxt); + final Object val = ctxt.getAttribute(ScriptEngine.FILENAME); + final String fileName = (val != null) ? val.toString() : ""; + + // NOTE: FIXME: If this is jrunscript's init.js, we want to run the replacement. + // This should go away once we fix jrunscript's copy of init.js. + if ("".equals(fileName)) { + evalSupportScript("resources/init.js"); + return null; + } + Object res = ScriptRuntime.apply(script, global); res = ScriptObjectMirror.wrap(res, global); return (res == UNDEFINED) ? null : res; @@ -486,11 +500,6 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C final Object val = ctxt.getAttribute(ScriptEngine.FILENAME); final String fileName = (val != null) ? val.toString() : ""; - // !!HACK!! do not evaluate "init.js" from jrunscript tool!! - if ("".equals(fileName)) { - return null; - } - final Source source = new Source(fileName, buf); if (globalChanged) { setNashornGlobal(global); diff --git a/nashorn/src/jdk/nashorn/api/scripting/resources/engine.js b/nashorn/src/jdk/nashorn/api/scripting/resources/engine.js index 2aba16fcda0..b71f5243713 100644 --- a/nashorn/src/jdk/nashorn/api/scripting/resources/engine.js +++ b/nashorn/src/jdk/nashorn/api/scripting/resources/engine.js @@ -1,21 +1,21 @@ /* * Copyright (c) 2010, 2013, 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. - * + * * 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. diff --git a/nashorn/src/jdk/nashorn/api/scripting/resources/init.js b/nashorn/src/jdk/nashorn/api/scripting/resources/init.js new file mode 100644 index 00000000000..9a4935f407e --- /dev/null +++ b/nashorn/src/jdk/nashorn/api/scripting/resources/init.js @@ -0,0 +1,940 @@ +/* + * Copyright (c) 2005, 2013, 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. + */ + +/** + * jrunscript JavaScript built-in functions and objects. + */ + +/** + * Creates an object that delegates all method calls on + * it to the 'invoke' method on the given delegate object.
+ * + * Example: + *

+ * 
+ *     var x  = { invoke: function(name, args) { //code...}
+ *     var y = new JSInvoker(x);
+ *     y.func(3, 3); // calls x.invoke('func', args); where args is array of arguments
+ * 
+ * 
+ * @param obj object to be wrapped by JSInvoker + * @constructor + */ +function JSInvoker(obj) { + return new JSAdapter({ + __get__ : function(name) { + return function() { + return obj.invoke(name, arguments); + } + } + }); +} + +/** + * This variable represents OS environment. Environment + * variables can be accessed as fields of this object. For + * example, env.PATH will return PATH value configured. + */ +var env = new JSAdapter({ + __get__ : function (name) { + return java.lang.System.getenv(name); + }, + __has__ : function (name) { + return java.lang.System.getenv().containsKey(name); + }, + __getIds__ : function() { + return java.lang.System.getenv().keySet().toArray(); + }, + __delete__ : function(name) { + println("can't delete env item"); + }, + __put__ : function (name, value) { + println("can't change env item"); + }, + toString: function() { + return java.lang.System.getenv().toString(); + } +}); + +/** + * Creates a convenient script object to deal with java.util.Map instances. + * The result script object's field names are keys of the Map. For example, + * scriptObj.keyName can be used to access value associated with given key.
+ * Example: + *
+ * 
+ *     var x = java.lang.SystemProperties();
+ *     var y = jmap(x);
+ *     println(y['java.class.path']); // prints java.class.path System property
+ *     delete y['java.class.path']; // remove java.class.path System property
+ * 
+ * 
+ * + * @param map java.util.Map instance that will be wrapped + * @constructor + */ +function jmap(map) { + return new JSAdapter({ + __get__ : function(name) { + if (map.containsKey(name)) { + return map.get(name); + } else { + return undefined; + } + }, + __has__ : function(name) { + return map.containsKey(name); + }, + + __delete__ : function (name) { + return map.remove(name); + }, + __put__ : function(name, value) { + map.put(name, value); + }, + __getIds__ : function() { + return map.keySet().toArray(); + }, + toString: function() { + return map.toString(); + } + }); +} + +/** + * Creates a convenient script object to deal with java.util.List instances. + * The result script object behaves like an array. For example, + * scriptObj[index] syntax can be used to access values in the List instance. + * 'length' field gives size of the List.
+ * + * Example: + *
+ * 
+ *    var x = new java.util.ArrayList(4);
+ *    x.add('Java');
+ *    x.add('JavaScript');
+ *    x.add('SQL');
+ *    x.add('XML');
+ *
+ *    var y = jlist(x);
+ *    println(y[2]); // prints third element of list
+ *    println(y.length); // prints size of the list
+ *
+ * @param map java.util.List instance that will be wrapped
+ * @constructor
+ */
+function jlist(list) {
+    function isValid(index) {
+        return typeof(index) == 'number' &&
+            index > -1 && index < list.size();
+    }
+    return new JSAdapter({
+        __get__ :  function(name) {
+            if (isValid(name)) {
+                return list.get(name);
+            } else if (name == 'length') {
+                return list.size();
+            } else {
+                return undefined;
+            }
+        },
+        __has__ : function (name) {
+            return isValid(name) || name == 'length';
+        },
+        __delete__ : function(name) {
+            if (isValid(name)) {
+                list.remove(name);
+            }
+        },
+        __put__ : function(name, value) {
+            if (isValid(name)) {
+                list.set(name, value);
+            }
+        },
+        __getIds__: function() {
+            var res = new Array(list.size());
+            for (var i = 0; i < res.length; i++) {
+                res[i] = i;
+            }
+            return res;
+        },
+        toString: function() {
+            return list.toString();
+        }
+    });
+}
+
+/**
+ * This is java.lang.System properties wrapped by jmap.
+ * For eg. to access java.class.path property, you can use
+ * the syntax sysProps["java.class.path"]
+ */
+var sysProps = jmap(java.lang.System.getProperties());
+
+// stdout, stderr & stdin
+var out = java.lang.System.out;
+var err = java.lang.System.err;
+// can't use 'in' because it is a JavaScript keyword :-(
+var inp = java.lang.System["in"];
+
+var BufferedInputStream = java.io.BufferedInputStream;
+var BufferedOutputStream = java.io.BufferedOutputStream;
+var BufferedReader = java.io.BufferedReader;
+var DataInputStream = java.io.DataInputStream;
+var File = java.io.File;
+var FileInputStream = java.io.FileInputStream;
+var FileOutputStream = java.io.FileOutputStream;
+var InputStream = java.io.InputStream;
+var InputStreamReader = java.io.InputStreamReader;
+var OutputStream = java.io.OutputStream;
+var Reader = java.io.Reader;
+var URL = java.net.URL;
+
+/**
+ * Generic any object to input stream mapper
+ * @param str input file name, URL or InputStream
+ * @return InputStream object
+ * @private
+ */
+function inStream(str) {
+    if (typeof(str) == "string") {
+        // '-' means standard input
+        if (str == '-') {
+            return java.lang.System["in"];
+        }
+        // try file first
+        var file = null;
+        try {
+            file = pathToFile(str);
+        } catch (e) {
+        }
+        if (file && file.exists()) {
+            return new FileInputStream(file);
+        } else {
+            try {
+                // treat the string as URL
+                return new URL(str).openStream();
+            } catch (e) {
+                throw 'file or URL ' + str + ' not found';
+            }
+        }
+    } else {
+        if (str instanceof InputStream) {
+            return str;
+        } else if (str instanceof URL) {
+            return str.openStream();
+        } else if (str instanceof File) {
+            return new FileInputStream(str);
+        }
+    }
+    // everything failed, just give input stream
+    return java.lang.System["in"];
+}
+
+/**
+ * Generic any object to output stream mapper
+ *
+ * @param out output file name or stream
+ * @return OutputStream object
+ * @private
+ */
+function outStream(out) {
+    if (typeof(out) == "string") {
+        if (out == '>') {
+            return java.lang.System.out;
+        } else {
+            // treat it as file
+            return new FileOutputStream(pathToFile(out));
+        }
+    } else {
+        if (out instanceof OutputStream) {
+            return out;
+        } else if (out instanceof File) {
+            return new FileOutputStream(out);
+        }
+    }
+
+    // everything failed, just return System.out
+    return java.lang.System.out;
+}
+
+/**
+ * stream close takes care not to close stdin, out & err.
+ * @private
+ */
+function streamClose(stream) {
+    if (stream) {
+        if (stream != java.lang.System["in"] &&
+            stream != java.lang.System.out &&
+            stream != java.lang.System.err) {
+            try {
+                stream.close();
+            } catch (e) {
+                println(e);
+            }
+        }
+    }
+}
+
+/**
+ * Loads and evaluates JavaScript code from a stream or file or URL
+ * + * Examples: + *
+ * 
+ *    load('test.js'); // load script file 'test.js'
+ *    load('http://java.sun.com/foo.js'); // load from a URL
+ * 
+ * 
+ * + * @param str input from which script is loaded and evaluated + */ +if (typeof(load) == 'undefined') { + var load = function(str) { + var stream = inStream(str); + var bstream = new BufferedInputStream(stream); + var reader = new BufferedReader(new InputStreamReader(bstream)); + var oldFilename = engine.get(engine.FILENAME); + engine.put(engine.FILENAME, str); + try { + engine.eval(reader); + } finally { + engine.put(engine.FILENAME, oldFilename); + streamClose(stream); + } + } +} + +// file system utilities + +/** + * Creates a Java byte[] of given length + * @param len size of the array to create + * @private + */ +function javaByteArray(len) { + return java.lang.reflect.Array.newInstance(java.lang.Byte.TYPE, len); +} + +var curDir = new File('.'); + +/** + * Print present working directory + */ +function pwd() { + println(curDir.getAbsolutePath()); +} + +/** + * Changes present working directory to given directory + * @param target directory to change to. optional, defaults to user's HOME + */ +function cd(target) { + if (target == undefined) { + target = sysProps["user.home"]; + } + if (!(target instanceof File)) { + target = pathToFile(target); + } + if (target.exists() && target.isDirectory()) { + curDir = target; + } else { + println(target + " is not a directory"); + } +} + +/** + * Converts path to java.io.File taking care of shell present working dir + * + * @param pathname file path to be converted + * @private + */ +function pathToFile(pathname) { + var tmp = pathname; + if (!(tmp instanceof File)) { + tmp = new File(tmp); + } + if (!tmp.isAbsolute()) { + return new File(curDir, pathname); + } else { + return tmp; + } +} + +/** + * Copies a file or URL or stream to another file or stream + * + * @param from input file or URL or stream + * @param to output stream or file + */ +function cp(from, to) { + if (from == to) { + println("file " + from + " cannot be copied onto itself!"); + return; + } + var inp = inStream(from); + var out = outStream(to); + var binp = new BufferedInputStream(inp); + var bout = new BufferedOutputStream(out); + var buff = javaByteArray(1024); + var len; + while ((len = binp.read(buff)) > 0 ) + bout.write(buff, 0, len); + + bout.flush(); + streamClose(inp); + streamClose(out); +} + +/** + * Shows the content of a file or URL or any InputStream
+ * Examples: + *
+ * 
+ *    cat('test.txt'); // show test.txt file contents
+ *    cat('http://java.net'); // show the contents from the URL http://java.net
+ * 
+ * 
+ * @param obj input to show + * @param pattern optional. show only the lines matching the pattern + */ +function cat(obj, pattern) { + if (obj instanceof File && obj.isDirectory()) { + ls(obj); + return; + } + + var inp = null; + if (!(obj instanceof Reader)) { + inp = inStream(obj); + obj = new BufferedReader(new InputStreamReader(inp)); + } + var line; + if (pattern) { + var count = 1; + while ((line=obj.readLine()) != null) { + if (line.match(pattern)) { + println(count + "\t: " + line); + } + count++; + } + } else { + while ((line=obj.readLine()) != null) { + println(line); + } + } +} + +/** + * Returns directory part of a filename + * + * @param pathname input path name + * @return directory part of the given file name + */ +function dirname(pathname) { + var dirName = "."; + // Normalize '/' to local file separator before work. + var i = pathname.replace('/', File.separatorChar ).lastIndexOf( + File.separator ); + if ( i != -1 ) + dirName = pathname.substring(0, i); + return dirName; +} + +/** + * Creates a new dir of given name + * + * @param dir name of the new directory + */ +function mkdir(dir) { + dir = pathToFile(dir); + println(dir.mkdir()? "created" : "can not create dir"); +} + +/** + * Creates the directory named by given pathname, including + * any necessary but nonexistent parent directories. + * + * @param dir input path name + */ +function mkdirs(dir) { + dir = pathToFile(dir); + println(dir.mkdirs()? "created" : "can not create dirs"); +} + +/** + * Removes a given file + * + * @param pathname name of the file + */ +function rm(pathname) { + var file = pathToFile(pathname); + if (!file.exists()) { + println("file not found: " + pathname); + return false; + } + // note that delete is a keyword in JavaScript! + println(file["delete"]()? "deleted" : "can not delete"); +} + +/** + * Removes a given directory + * + * @param pathname name of the directory + */ +function rmdir(pathname) { + rm(pathname); +} + +/** + * Synonym for 'rm' + */ +function del(pathname) { + rm(pathname); +} + +/** + * Moves a file to another + * + * @param from original name of the file + * @param to new name for the file + */ +function mv(from, to) { + println(pathToFile(from).renameTo(pathToFile(to))? + "moved" : "can not move"); +} + +/** + * Synonym for 'mv'. + */ +function ren(from, to) { + mv(from, to); +} + +var months = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ]; + +/** + * Helper function called by ls + * @private + */ +function printFile(f) { + var sb = new java.lang.StringBuffer(); + sb.append(f.isDirectory()? "d" : "-"); + sb.append(f.canRead() ? "r": "-" ); + sb.append(f.canWrite() ? "w": "-" ); + sb.append(" "); + + var d = new java.util.Date(f.lastModified()); + var c = new java.util.GregorianCalendar(); + c.setTime(d); + var day = c.get(java.util.Calendar.DAY_OF_MONTH); + sb.append(months[c.get(java.util.Calendar.MONTH)] + + " " + day ); + if (day < 10) { + sb.append(" "); + } + + // to get fixed length 'length' field + var fieldlen = 8; + var len = new java.lang.StringBuffer(); + for(var j=0; j + * + * Examples: + *
+ * 
+ *    find('.')
+ *    find('.', '.*\.class', rm);  // remove all .class files
+ *    find('.', '.*\.java');       // print fullpath of each .java file
+ *    find('.', '.*\.java', cat);  // print all .java files
+ * 
+ * 
+ * + * @param dir directory to search files + * @param pattern to search in the files + * @param callback function to call for matching files + */ +function find(dir, pattern, callback) { + dir = pathToFile(dir); + if (!callback) callback = print; + var files = dir.listFiles(); + for (var f in files) { + var file = files[f]; + if (file.isDirectory()) { + find(file, pattern, callback); + } else { + if (pattern) { + if (file.getName().match(pattern)) { + callback(file); + } + } else { + callback(file); + } + } + } +} + +// process utilities + +/** + * Exec's a child process, waits for completion & returns exit code + * + * @param cmd command to execute in child process + */ +function exec(cmd) { + var process = java.lang.Runtime.getRuntime().exec(cmd); + var inp = new DataInputStream(process.getInputStream()); + var line = null; + while ((line = inp.readLine()) != null) { + println(line); + } + process.waitFor(); + $exit = process.exitValue(); +} + +/** + * Exit the shell program. + * + * @param exitCode integer code returned to OS shell. + * optional, defaults to 0 + */ +function exit(code) { + if (code) { + java.lang.System.exit(code + 0); + } else { + java.lang.System.exit(0); + } +} + +/** + * synonym for exit + */ +function quit(code) { + exit(code); +} + +// XML utilities + +/** + * Converts input to DOM Document object + * + * @param inp file or reader. optional, without this param, + * this function returns a new DOM Document. + * @return returns a DOM Document object + */ +function XMLDocument(inp) { + var factory = javax.xml.parsers.DocumentBuilderFactory.newInstance(); + var builder = factory.newDocumentBuilder(); + if (inp) { + if (typeof(inp) == "string") { + return builder.parse(pathToFile(inp)); + } else { + return builder.parse(inp); + } + } else { + return builder.newDocument(); + } +} + +/** + * Converts arbitrary stream, file, URL to XMLSource + * + * @param inp input stream or file or URL + * @return XMLSource object + */ +function XMLSource(inp) { + if (inp instanceof javax.xml.transform.Source) { + return inp; + } else if (inp instanceof Packages.org.w3c.dom.Document) { + return new javax.xml.transform.dom.DOMSource(inp); + } else { + inp = new BufferedInputStream(inStream(inp)); + return new javax.xml.transform.stream.StreamSource(inp); + } +} + +/** + * Converts arbitrary stream, file to XMLResult + * + * @param inp output stream or file + * @return XMLResult object + */ +function XMLResult(out) { + if (out instanceof javax.xml.transform.Result) { + return out; + } else if (out instanceof Packages.org.w3c.dom.Document) { + return new javax.xml.transform.dom.DOMResult(out); + } else { + out = new BufferedOutputStream(outStream(out)); + return new javax.xml.transform.stream.StreamResult(out); + } +} + +/** + * Perform XSLT transform + * + * @param inp Input XML to transform (URL, File or InputStream) + * @param style XSL Stylesheet to be used (URL, File or InputStream). optional. + * @param out Output XML (File or OutputStream + */ +function XSLTransform(inp, style, out) { + switch (arguments.length) { + case 2: + inp = arguments[0]; + out = arguments[1]; + break; + case 3: + inp = arguments[0]; + style = arguments[1]; + out = arguments[2]; + break; + default: + println("XSL tranform requires 2 or 3 arguments"); + return; + } + + var factory = javax.xml.transform.TransformerFactory.newInstance(); + var transformer; + if (style) { + transformer = factory.newTransformer(XMLSource(style)); + } else { + transformer = factory.newTransformer(); + } + var source = XMLSource(inp); + var result = XMLResult(out); + transformer.transform(source, result); + if (source.getInputStream) { + streamClose(source.getInputStream()); + } + if (result.getOutputStream) { + streamClose(result.getOutputStream()); + } +} + +// miscellaneous utilities + +/** + * Prints which command is selected from PATH + * + * @param cmd name of the command searched from PATH + */ +function which(cmd) { + var st = new java.util.StringTokenizer(env.PATH, File.pathSeparator); + while (st.hasMoreTokens()) { + var file = new File(st.nextToken(), cmd); + if (file.exists()) { + println(file.getAbsolutePath()); + return; + } + } +} + +/** + * Prints IP addresses of given domain name + * + * @param name domain name + */ +function ip(name) { + var addrs = InetAddress.getAllByName(name); + for (var i in addrs) { + println(addrs[i]); + } +} + +/** + * Prints current date in current locale + */ +function date() { + println(new Date().toLocaleString()); +} + +/** + * Echoes the given string arguments + */ +function echo(x) { + for (var i = 0; i < arguments.length; i++) { + println(arguments[i]); + } +} + +/** + * Reads one or more lines from stdin after printing prompt + * + * @param prompt optional, default is '>' + * @param multiline to tell whether to read single line or multiple lines + */ +function read(prompt, multiline) { + if (!prompt) { + prompt = '>'; + } + var inp = java.lang.System["in"]; + var reader = new BufferedReader(new InputStreamReader(inp)); + if (multiline) { + var line = ''; + while (true) { + java.lang.System.err.print(prompt); + java.lang.System.err.flush(); + var tmp = reader.readLine(); + if (tmp == '' || tmp == null) break; + line += tmp + '\n'; + } + return line; + } else { + java.lang.System.err.print(prompt); + java.lang.System.err.flush(); + return reader.readLine(); + } +} + +if (typeof(println) == 'undefined') { + var print = function(str, newline) { + if (typeof(str) == 'undefined') { + str = 'undefined'; + } else if (str == null) { + str = 'null'; + } + + if (!(out instanceof java.io.PrintWriter)) { + out = new java.io.PrintWriter(out); + } + + out.print(String(str)); + if (newline) { + out.print('\n'); + } + out.flush(); + } + + var println = function(str) { + print(str, true); + }; +} + +/** + * This is C-like printf + * + * @param format string to format the rest of the print items + * @param args variadic argument list + */ +function printf(format, args/*, more args*/) { + print(sprintf.apply(this, arguments)); +} + +/** + * This is C-like sprintf + * + * @param format string to format the rest of the print items + * @param args variadic argument list + */ +function sprintf(format, args/*, more args*/) { + var len = arguments.length - 1; + var array = []; + + if (len < 0) { + return ""; + } + + for (var i = 0; i < len; i++) { + if (arguments[i+1] instanceof Date) { + array[i] = arguments[i+1].getTime(); + } else { + array[i] = arguments[i+1]; + } + } + + array = Java.toJavaArray(array); + return Packages.jdk.nashorn.api.scripting.Formatter.format(format, array); +}