aboutsummaryrefslogtreecommitdiffstats
path: root/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell')
-rw-r--r--trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/ConsoleTextArea.java300
-rw-r--r--trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/Environment.java141
-rw-r--r--trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/Global.java1038
-rw-r--r--trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/JSConsole.java225
-rw-r--r--trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/JavaPolicySecurity.java240
-rw-r--r--trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/Main.java638
-rw-r--r--trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/QuitAction.java50
-rw-r--r--trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/SecurityProxy.java48
-rw-r--r--trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/ShellContextFactory.java114
9 files changed, 2794 insertions, 0 deletions
diff --git a/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/ConsoleTextArea.java b/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/ConsoleTextArea.java
new file mode 100644
index 0000000..08cac62
--- /dev/null
+++ b/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/ConsoleTextArea.java
@@ -0,0 +1,300 @@
+/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Rhino JavaScript Debugger code, released
+ * November 21, 2000.
+ *
+ * The Initial Developer of the Original Code is
+ * See Beyond Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Christopher Oliver
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * the GNU General Public License Version 2 or later (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of those above. If
+ * you wish to allow use of your version of this file only under the terms of
+ * the GPL and not to allow others to use your version of this file under the
+ * MPL, indicate your decision by deleting the provisions above and replacing
+ * them with the notice and other provisions required by the GPL. If you do
+ * not delete the provisions above, a recipient may use your version of this
+ * file under either the MPL or the GPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+package org.mozilla.javascript.tools.shell;
+import java.io.*;
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import javax.swing.text.Document;
+import javax.swing.text.Segment;
+
+class ConsoleWrite implements Runnable {
+ private ConsoleTextArea textArea;
+ private String str;
+
+ public ConsoleWrite(ConsoleTextArea textArea, String str) {
+ this.textArea = textArea;
+ this.str = str;
+ }
+
+ public void run() {
+ textArea.write(str);
+ }
+}
+
+class ConsoleWriter extends java.io.OutputStream {
+
+ private ConsoleTextArea textArea;
+ private StringBuffer buffer;
+
+ public ConsoleWriter(ConsoleTextArea textArea) {
+ this.textArea = textArea;
+ buffer = new StringBuffer();
+ }
+
+ public synchronized void write(int ch) {
+ buffer.append((char)ch);
+ if(ch == '\n') {
+ flushBuffer();
+ }
+ }
+
+ public synchronized void write (char[] data, int off, int len) {
+ for(int i = off; i < len; i++) {
+ buffer.append(data[i]);
+ if(data[i] == '\n') {
+ flushBuffer();
+ }
+ }
+ }
+
+ public synchronized void flush() {
+ if (buffer.length() > 0) {
+ flushBuffer();
+ }
+ }
+
+ public void close () {
+ flush();
+ }
+
+ private void flushBuffer() {
+ String str = buffer.toString();
+ buffer.setLength(0);
+ SwingUtilities.invokeLater(new ConsoleWrite(textArea, str));
+ }
+}
+
+public class ConsoleTextArea
+ extends JTextArea implements KeyListener, DocumentListener
+{
+ static final long serialVersionUID = 8557083244830872961L;
+
+ private ConsoleWriter console1;
+ private ConsoleWriter console2;
+ private PrintStream out;
+ private PrintStream err;
+ private PrintWriter inPipe;
+ private PipedInputStream in;
+ private java.util.Vector history;
+ private int historyIndex = -1;
+ private int outputMark = 0;
+
+ public void select(int start, int end) {
+ requestFocus();
+ super.select(start, end);
+ }
+
+ public ConsoleTextArea(String[] argv) {
+ super();
+ history = new java.util.Vector();
+ console1 = new ConsoleWriter(this);
+ console2 = new ConsoleWriter(this);
+ out = new PrintStream(console1);
+ err = new PrintStream(console2);
+ PipedOutputStream outPipe = new PipedOutputStream();
+ inPipe = new PrintWriter(outPipe);
+ in = new PipedInputStream();
+ try {
+ outPipe.connect(in);
+ } catch(IOException exc) {
+ exc.printStackTrace();
+ }
+ getDocument().addDocumentListener(this);
+ addKeyListener(this);
+ setLineWrap(true);
+ setFont(new Font("Monospaced", 0, 12));
+ }
+
+
+ synchronized void returnPressed() {
+ Document doc = getDocument();
+ int len = doc.getLength();
+ Segment segment = new Segment();
+ try {
+ doc.getText(outputMark, len - outputMark, segment);
+ } catch(javax.swing.text.BadLocationException ignored) {
+ ignored.printStackTrace();
+ }
+ if(segment.count > 0) {
+ history.addElement(segment.toString());
+ }
+ historyIndex = history.size();
+ inPipe.write(segment.array, segment.offset, segment.count);
+ append("\n");
+ outputMark = doc.getLength();
+ inPipe.write("\n");
+ inPipe.flush();
+ console1.flush();
+ }
+
+ public void eval(String str) {
+ inPipe.write(str);
+ inPipe.write("\n");
+ inPipe.flush();
+ console1.flush();
+ }
+
+ public void keyPressed(KeyEvent e) {
+ int code = e.getKeyCode();
+ if(code == KeyEvent.VK_BACK_SPACE || code == KeyEvent.VK_LEFT) {
+ if(outputMark == getCaretPosition()) {
+ e.consume();
+ }
+ } else if(code == KeyEvent.VK_HOME) {
+ int caretPos = getCaretPosition();
+ if(caretPos == outputMark) {
+ e.consume();
+ } else if(caretPos > outputMark) {
+ if(!e.isControlDown()) {
+ if(e.isShiftDown()) {
+ moveCaretPosition(outputMark);
+ } else {
+ setCaretPosition(outputMark);
+ }
+ e.consume();
+ }
+ }
+ } else if(code == KeyEvent.VK_ENTER) {
+ returnPressed();
+ e.consume();
+ } else if(code == KeyEvent.VK_UP) {
+ historyIndex--;
+ if(historyIndex >= 0) {
+ if(historyIndex >= history.size()) {
+ historyIndex = history.size() -1;
+ }
+ if(historyIndex >= 0) {
+ String str = (String)history.elementAt(historyIndex);
+ int len = getDocument().getLength();
+ replaceRange(str, outputMark, len);
+ int caretPos = outputMark + str.length();
+ select(caretPos, caretPos);
+ } else {
+ historyIndex++;
+ }
+ } else {
+ historyIndex++;
+ }
+ e.consume();
+ } else if(code == KeyEvent.VK_DOWN) {
+ int caretPos = outputMark;
+ if(history.size() > 0) {
+ historyIndex++;
+ if(historyIndex < 0) {historyIndex = 0;}
+ int len = getDocument().getLength();
+ if(historyIndex < history.size()) {
+ String str = (String)history.elementAt(historyIndex);
+ replaceRange(str, outputMark, len);
+ caretPos = outputMark + str.length();
+ } else {
+ historyIndex = history.size();
+ replaceRange("", outputMark, len);
+ }
+ }
+ select(caretPos, caretPos);
+ e.consume();
+ }
+ }
+
+ public void keyTyped(KeyEvent e) {
+ int keyChar = e.getKeyChar();
+ if(keyChar == 0x8 /* KeyEvent.VK_BACK_SPACE */) {
+ if(outputMark == getCaretPosition()) {
+ e.consume();
+ }
+ } else if(getCaretPosition() < outputMark) {
+ setCaretPosition(outputMark);
+ }
+ }
+
+ public synchronized void keyReleased(KeyEvent e) {
+ }
+
+ public synchronized void write(String str) {
+ insert(str, outputMark);
+ int len = str.length();
+ outputMark += len;
+ select(outputMark, outputMark);
+ }
+
+ public synchronized void insertUpdate(DocumentEvent e) {
+ int len = e.getLength();
+ int off = e.getOffset();
+ if(outputMark > off) {
+ outputMark += len;
+ }
+ }
+
+ public synchronized void removeUpdate(DocumentEvent e) {
+ int len = e.getLength();
+ int off = e.getOffset();
+ if(outputMark > off) {
+ if(outputMark >= off + len) {
+ outputMark -= len;
+ } else {
+ outputMark = off;
+ }
+ }
+ }
+
+ public synchronized void postUpdateUI() {
+ // this attempts to cleanup the damage done by updateComponentTreeUI
+ requestFocus();
+ setCaret(getCaret());
+ select(outputMark, outputMark);
+ }
+
+ public synchronized void changedUpdate(DocumentEvent e) {
+ }
+
+
+ public InputStream getIn() {
+ return in;
+ }
+
+ public PrintStream getOut() {
+ return out;
+ }
+
+ public PrintStream getErr() {
+ return err;
+ }
+
+}
diff --git a/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/Environment.java b/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/Environment.java
new file mode 100644
index 0000000..19904b9
--- /dev/null
+++ b/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/Environment.java
@@ -0,0 +1,141 @@
+/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Rhino code, released
+ * May 6, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1997-1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * the GNU General Public License Version 2 or later (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of those above. If
+ * you wish to allow use of your version of this file only under the terms of
+ * the GPL and not to allow others to use your version of this file under the
+ * MPL, indicate your decision by deleting the provisions above and replacing
+ * them with the notice and other provisions required by the GPL. If you do
+ * not delete the provisions above, a recipient may use your version of this
+ * file under either the MPL or the GPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ Environment.java
+
+ Wraps java.lang.System properties.
+
+ by Patrick C. Beard <beard@netscape.com>
+ */
+
+package org.mozilla.javascript.tools.shell;
+
+import org.mozilla.javascript.Scriptable;
+import org.mozilla.javascript.ScriptRuntime;
+import org.mozilla.javascript.ScriptableObject;
+
+import java.util.Vector;
+import java.util.Enumeration;
+import java.util.Properties;
+
+/**
+ * Environment, intended to be instantiated at global scope, provides
+ * a natural way to access System properties from JavaScript.
+ *
+ * @author Patrick C. Beard
+ */
+public class Environment extends ScriptableObject
+{
+ static final long serialVersionUID = -430727378460177065L;
+
+ private Environment thePrototypeInstance = null;
+
+ public static void defineClass(ScriptableObject scope) {
+ try {
+ ScriptableObject.defineClass(scope, Environment.class);
+ } catch (Exception e) {
+ throw new Error(e.getMessage());
+ }
+ }
+
+ public String getClassName() {
+ return "Environment";
+ }
+
+ public Environment() {
+ if (thePrototypeInstance == null)
+ thePrototypeInstance = this;
+ }
+
+ public Environment(ScriptableObject scope) {
+ setParentScope(scope);
+ Object ctor = ScriptRuntime.getTopLevelProp(scope, "Environment");
+ if (ctor != null && ctor instanceof Scriptable) {
+ Scriptable s = (Scriptable) ctor;
+ setPrototype((Scriptable) s.get("prototype", s));
+ }
+ }
+
+ public boolean has(String name, Scriptable start) {
+ if (this == thePrototypeInstance)
+ return super.has(name, start);
+
+ return (System.getProperty(name) != null);
+ }
+
+ public Object get(String name, Scriptable start) {
+ if (this == thePrototypeInstance)
+ return super.get(name, start);
+
+ String result = System.getProperty(name);
+ if (result != null)
+ return ScriptRuntime.toObject(getParentScope(), result);
+ else
+ return Scriptable.NOT_FOUND;
+ }
+
+ public void put(String name, Scriptable start, Object value) {
+ if (this == thePrototypeInstance)
+ super.put(name, start, value);
+ else
+ System.getProperties().put(name, ScriptRuntime.toString(value));
+ }
+
+ private Object[] collectIds() {
+ Properties props = System.getProperties();
+ Enumeration names = props.propertyNames();
+ Vector keys = new Vector();
+ while (names.hasMoreElements())
+ keys.addElement(names.nextElement());
+ Object[] ids = new Object[keys.size()];
+ keys.copyInto(ids);
+ return ids;
+ }
+
+ public Object[] getIds() {
+ if (this == thePrototypeInstance)
+ return super.getIds();
+ return collectIds();
+ }
+
+ public Object[] getAllIds() {
+ if (this == thePrototypeInstance)
+ return super.getAllIds();
+ return collectIds();
+ }
+}
diff --git a/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/Global.java b/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/Global.java
new file mode 100644
index 0000000..fdb8f4e
--- /dev/null
+++ b/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/Global.java
@@ -0,0 +1,1038 @@
+/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Rhino code, released
+ * May 6, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1997-1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Patrick Beard
+ * Igor Bukanov
+ * Norris Boyd
+ * Rob Ginda
+ * Kurt Westerfeld
+ * Matthias Radestock
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * the GNU General Public License Version 2 or later (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of those above. If
+ * you wish to allow use of your version of this file only under the terms of
+ * the GPL and not to allow others to use your version of this file under the
+ * MPL, indicate your decision by deleting the provisions above and replacing
+ * them with the notice and other provisions required by the GPL. If you do
+ * not delete the provisions above, a recipient may use your version of this
+ * file under either the MPL or the GPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package org.mozilla.javascript.tools.shell;
+
+import java.io.*;
+import java.net.*;
+import java.lang.reflect.*;
+import org.mozilla.javascript.*;
+import org.mozilla.javascript.tools.ToolErrorReporter;
+import org.mozilla.javascript.serialize.*;
+
+/**
+ * This class provides for sharing functions across multiple threads.
+ * This is of particular interest to server applications.
+ *
+ * @author Norris Boyd
+ */
+public class Global extends ImporterTopLevel
+{
+ static final long serialVersionUID = 4029130780977538005L;
+
+ NativeArray history;
+ private InputStream inStream;
+ private PrintStream outStream;
+ private PrintStream errStream;
+ private boolean sealedStdLib = false;
+ boolean initialized;
+ private QuitAction quitAction;
+ private String[] prompts = { "js> ", " > " };
+
+ public Global()
+ {
+ }
+
+ public Global(Context cx)
+ {
+ init(cx);
+ }
+
+ public boolean isInitialized() {
+ return initialized;
+ }
+
+ /**
+ * Set the action to call from quit().
+ */
+ public void initQuitAction(QuitAction quitAction)
+ {
+ if (quitAction == null)
+ throw new IllegalArgumentException("quitAction is null");
+ if (this.quitAction != null)
+ throw new IllegalArgumentException("The method is once-call.");
+
+ this.quitAction = quitAction;
+ }
+
+ public void init(ContextFactory factory)
+ {
+ factory.call(new ContextAction() {
+ public Object run(Context cx)
+ {
+ init(cx);
+ return null;
+ }
+ });
+ }
+
+ public void init(Context cx)
+ {
+ // Define some global functions particular to the shell. Note
+ // that these functions are not part of ECMA.
+ initStandardObjects(cx, sealedStdLib);
+ String[] names = {
+ "defineClass",
+ "deserialize",
+ "gc",
+ "help",
+ "load",
+ "loadClass",
+ "print",
+ "quit",
+ "readFile",
+ "readUrl",
+ "runCommand",
+ "seal",
+ "serialize",
+ "spawn",
+ "sync",
+ "toint32",
+ "version",
+ };
+ defineFunctionProperties(names, Global.class,
+ ScriptableObject.DONTENUM);
+
+ // Set up "environment" in the global scope to provide access to the
+ // System environment variables.
+ Environment.defineClass(this);
+ Environment environment = new Environment(this);
+ defineProperty("environment", environment,
+ ScriptableObject.DONTENUM);
+
+ history = (NativeArray) cx.newArray(this, 0);
+ defineProperty("history", history, ScriptableObject.DONTENUM);
+ initialized = true;
+ }
+
+ /**
+ * Print a help message.
+ *
+ * This method is defined as a JavaScript function.
+ */
+ public static void help(Context cx, Scriptable thisObj,
+ Object[] args, Function funObj)
+ {
+ PrintStream out = getInstance(funObj).getOut();
+ out.println(ToolErrorReporter.getMessage("msg.help"));
+ }
+
+ public static void gc(Context cx, Scriptable thisObj,
+ Object[] args, Function funObj)
+ {
+ System.gc();
+ }
+
+
+ /**
+ * Print the string values of its arguments.
+ *
+ * This method is defined as a JavaScript function.
+ * Note that its arguments are of the "varargs" form, which
+ * allows it to handle an arbitrary number of arguments
+ * supplied to the JavaScript function.
+ *
+ */
+ public static Object print(Context cx, Scriptable thisObj,
+ Object[] args, Function funObj)
+ {
+ PrintStream out = getInstance(funObj).getOut();
+ for (int i=0; i < args.length; i++) {
+ if (i > 0)
+ out.print(" ");
+
+ // Convert the arbitrary JavaScript value into a string form.
+ String s = Context.toString(args[i]);
+
+ out.print(s);
+ }
+ out.println();
+ return Context.getUndefinedValue();
+ }
+
+ /**
+ * Call embedding-specific quit action passing its argument as
+ * int32 exit code.
+ *
+ * This method is defined as a JavaScript function.
+ */
+ public static void quit(Context cx, Scriptable thisObj,
+ Object[] args, Function funObj)
+ {
+ Global global = getInstance(funObj);
+ if (global.quitAction != null) {
+ int exitCode = (args.length == 0 ? 0
+ : ScriptRuntime.toInt32(args[0]));
+ global.quitAction.quit(cx, exitCode);
+ }
+ }
+
+ /**
+ * Get and set the language version.
+ *
+ * This method is defined as a JavaScript function.
+ */
+ public static double version(Context cx, Scriptable thisObj,
+ Object[] args, Function funObj)
+ {
+ double result = cx.getLanguageVersion();
+ if (args.length > 0) {
+ double d = Context.toNumber(args[0]);
+ cx.setLanguageVersion((int) d);
+ }
+ return result;
+ }
+
+ /**
+ * Load and execute a set of JavaScript source files.
+ *
+ * This method is defined as a JavaScript function.
+ *
+ */
+ public static void load(Context cx, Scriptable thisObj,
+ Object[] args, Function funObj)
+ {
+ for (int i = 0; i < args.length; i++) {
+ Main.processFile(cx, thisObj, Context.toString(args[i]));
+ }
+ }
+
+ /**
+ * Load a Java class that defines a JavaScript object using the
+ * conventions outlined in ScriptableObject.defineClass.
+ * <p>
+ * This method is defined as a JavaScript function.
+ * @exception IllegalAccessException if access is not available
+ * to a reflected class member
+ * @exception InstantiationException if unable to instantiate
+ * the named class
+ * @exception InvocationTargetException if an exception is thrown
+ * during execution of methods of the named class
+ * @see org.mozilla.javascript.ScriptableObject#defineClass(Scriptable,Class)
+ */
+ public static void defineClass(Context cx, Scriptable thisObj,
+ Object[] args, Function funObj)
+ throws IllegalAccessException, InstantiationException,
+ InvocationTargetException
+ {
+ Class clazz = getClass(args);
+ ScriptableObject.defineClass(thisObj, clazz);
+ }
+
+ /**
+ * Load and execute a script compiled to a class file.
+ * <p>
+ * This method is defined as a JavaScript function.
+ * When called as a JavaScript function, a single argument is
+ * expected. This argument should be the name of a class that
+ * implements the Script interface, as will any script
+ * compiled by jsc.
+ *
+ * @exception IllegalAccessException if access is not available
+ * to the class
+ * @exception InstantiationException if unable to instantiate
+ * the named class
+ */
+ public static void loadClass(Context cx, Scriptable thisObj,
+ Object[] args, Function funObj)
+ throws IllegalAccessException, InstantiationException
+ {
+ Class clazz = getClass(args);
+ if (!Script.class.isAssignableFrom(clazz)) {
+ throw reportRuntimeError("msg.must.implement.Script");
+ }
+ Script script = (Script) clazz.newInstance();
+ script.exec(cx, thisObj);
+ }
+
+ private static Class getClass(Object[] args) {
+ if (args.length == 0) {
+ throw reportRuntimeError("msg.expected.string.arg");
+ }
+ Object arg0 = args[0];
+ if (arg0 instanceof Wrapper) {
+ Object wrapped = ((Wrapper)arg0).unwrap();
+ if (wrapped instanceof Class)
+ return (Class)wrapped;
+ }
+ String className = Context.toString(args[0]);
+ try {
+ return Class.forName(className);
+ }
+ catch (ClassNotFoundException cnfe) {
+ throw reportRuntimeError("msg.class.not.found", className);
+ }
+ }
+
+ public static void serialize(Context cx, Scriptable thisObj,
+ Object[] args, Function funObj)
+ throws IOException
+ {
+ if (args.length < 2) {
+ throw Context.reportRuntimeError(
+ "Expected an object to serialize and a filename to write " +
+ "the serialization to");
+ }
+ Object obj = args[0];
+ String filename = Context.toString(args[1]);
+ FileOutputStream fos = new FileOutputStream(filename);
+ Scriptable scope = ScriptableObject.getTopLevelScope(thisObj);
+ ScriptableOutputStream out = new ScriptableOutputStream(fos, scope);
+ out.writeObject(obj);
+ out.close();
+ }
+
+ public static Object deserialize(Context cx, Scriptable thisObj,
+ Object[] args, Function funObj)
+ throws IOException, ClassNotFoundException
+ {
+ if (args.length < 1) {
+ throw Context.reportRuntimeError(
+ "Expected a filename to read the serialization from");
+ }
+ String filename = Context.toString(args[0]);
+ FileInputStream fis = new FileInputStream(filename);
+ Scriptable scope = ScriptableObject.getTopLevelScope(thisObj);
+ ObjectInputStream in = new ScriptableInputStream(fis, scope);
+ Object deserialized = in.readObject();
+ in.close();
+ return Context.toObject(deserialized, scope);
+ }
+
+ public String[] getPrompts(Context cx) {
+ if (ScriptableObject.hasProperty(this, "prompts")) {
+ Object promptsJS = ScriptableObject.getProperty(this,
+ "prompts");
+ if (promptsJS instanceof Scriptable) {
+ Scriptable s = (Scriptable) promptsJS;
+ if (ScriptableObject.hasProperty(s, 0) &&
+ ScriptableObject.hasProperty(s, 1))
+ {
+ Object elem0 = ScriptableObject.getProperty(s, 0);
+ if (elem0 instanceof Function) {
+ elem0 = ((Function) elem0).call(cx, this, s,
+ new Object[0]);
+ }
+ prompts[0] = Context.toString(elem0);
+ Object elem1 = ScriptableObject.getProperty(s, 1);
+ if (elem1 instanceof Function) {
+ elem1 = ((Function) elem1).call(cx, this, s,
+ new Object[0]);
+ }
+ prompts[1] = Context.toString(elem1);
+ }
+ }
+ }
+ return prompts;
+ }
+
+ /**
+ * The spawn function runs a given function or script in a different
+ * thread.
+ *
+ * js> function g() { a = 7; }
+ * js> a = 3;
+ * 3
+ * js> spawn(g)
+ * Thread[Thread-1,5,main]
+ * js> a
+ * 3
+ */
+ public static Object spawn(Context cx, Scriptable thisObj, Object[] args,
+ Function funObj)
+ {
+ Scriptable scope = funObj.getParentScope();
+ Runner runner;
+ if (args.length != 0 && args[0] instanceof Function) {
+ Object[] newArgs = null;
+ if (args.length > 1 && args[1] instanceof Scriptable) {
+ newArgs = cx.getElements((Scriptable) args[1]);
+ }
+ if (newArgs == null) { newArgs = ScriptRuntime.emptyArgs; }
+ runner = new Runner(scope, (Function) args[0], newArgs);
+ } else if (args.length != 0 && args[0] instanceof Script) {
+ runner = new Runner(scope, (Script) args[0]);
+ } else {
+ throw reportRuntimeError("msg.spawn.args");
+ }
+ runner.factory = cx.getFactory();
+ Thread thread = new Thread(runner);
+ thread.start();
+ return thread;
+ }
+
+ /**
+ * The sync function creates a synchronized function (in the sense
+ * of a Java synchronized method) from an existing function. The
+ * new function synchronizes on the <code>this</code> object of
+ * its invocation.
+ * js> var o = { f : sync(function(x) {
+ * print("entry");
+ * Packages.java.lang.Thread.sleep(x*1000);
+ * print("exit");
+ * })};
+ * js> spawn(function() {o.f(5);});
+ * Thread[Thread-0,5,main]
+ * entry
+ * js> spawn(function() {o.f(5);});
+ * Thread[Thread-1,5,main]
+ * js>
+ * exit
+ * entry
+ * exit
+ */
+ public static Object sync(Context cx, Scriptable thisObj, Object[] args,
+ Function funObj)
+ {
+ if (args.length == 1 && args[0] instanceof Function) {
+ return new Synchronizer((Function)args[0]);
+ }
+ else {
+ throw reportRuntimeError("msg.sync.args");
+ }
+ }
+
+ /**
+ * Execute the specified command with the given argument and options
+ * as a separate process and return the exit status of the process.
+ * <p>
+ * Usage:
+ * <pre>
+ * runCommand(command)
+ * runCommand(command, arg1, ..., argN)
+ * runCommand(command, arg1, ..., argN, options)
+ * </pre>
+ * All except the last arguments to runCommand are converted to strings
+ * and denote command name and its arguments. If the last argument is a
+ * JavaScript object, it is an option object. Otherwise it is converted to
+ * string denoting the last argument and options objects assumed to be
+ * empty.
+ * Te following properties of the option object are processed:
+ * <ul>
+ * <li><tt>args</tt> - provides an array of additional command arguments
+ * <li><tt>env</tt> - explicit environment object. All its enumeratable
+ * properties define the corresponding environment variable names.
+ * <li><tt>input</tt> - the process input. If it is not
+ * java.io.InputStream, it is converted to string and sent to the process
+ * as its input. If not specified, no input is provided to the process.
+ * <li><tt>output</tt> - the process output instead of
+ * java.lang.System.out. If it is not instance of java.io.OutputStream,
+ * the process output is read, converted to a string, appended to the
+ * output property value converted to string and put as the new value of
+ * the output property.
+ * <li><tt>err</tt> - the process error output instead of
+ * java.lang.System.err. If it is not instance of java.io.OutputStream,
+ * the process error output is read, converted to a string, appended to
+ * the err property value converted to string and put as the new
+ * value of the err property.
+ * </ul>
+ */
+ public static Object runCommand(Context cx, Scriptable thisObj,
+ Object[] args, Function funObj)
+ throws IOException
+ {
+ int L = args.length;
+ if (L == 0 || (L == 1 && args[0] instanceof Scriptable)) {
+ throw reportRuntimeError("msg.runCommand.bad.args");
+ }
+
+ InputStream in = null;
+ OutputStream out = null, err = null;
+ ByteArrayOutputStream outBytes = null, errBytes = null;
+ Object outObj = null, errObj = null;
+ String[] environment = null;
+ Scriptable params = null;
+ Object[] addArgs = null;
+ if (args[L - 1] instanceof Scriptable) {
+ params = (Scriptable)args[L - 1];
+ --L;
+ Object envObj = ScriptableObject.getProperty(params, "env");
+ if (envObj != Scriptable.NOT_FOUND) {
+ if (envObj == null) {
+ environment = new String[0];
+ } else {
+ if (!(envObj instanceof Scriptable)) {
+ throw reportRuntimeError("msg.runCommand.bad.env");
+ }
+ Scriptable envHash = (Scriptable)envObj;
+ Object[] ids = ScriptableObject.getPropertyIds(envHash);
+ environment = new String[ids.length];
+ for (int i = 0; i != ids.length; ++i) {
+ Object keyObj = ids[i], val;
+ String key;
+ if (keyObj instanceof String) {
+ key = (String)keyObj;
+ val = ScriptableObject.getProperty(envHash, key);
+ } else {
+ int ikey = ((Number)keyObj).intValue();
+ key = Integer.toString(ikey);
+ val = ScriptableObject.getProperty(envHash, ikey);
+ }
+ if (val == ScriptableObject.NOT_FOUND) {
+ val = Undefined.instance;
+ }
+ environment[i] = key+'='+ScriptRuntime.toString(val);
+ }
+ }
+ }
+ Object inObj = ScriptableObject.getProperty(params, "input");
+ if (inObj != Scriptable.NOT_FOUND) {
+ in = toInputStream(inObj);
+ }
+ outObj = ScriptableObject.getProperty(params, "output");
+ if (outObj != Scriptable.NOT_FOUND) {
+ out = toOutputStream(outObj);
+ if (out == null) {
+ outBytes = new ByteArrayOutputStream();
+ out = outBytes;
+ }
+ }
+ errObj = ScriptableObject.getProperty(params, "err");
+ if (errObj != Scriptable.NOT_FOUND) {
+ err = toOutputStream(errObj);
+ if (err == null) {
+ errBytes = new ByteArrayOutputStream();
+ err = errBytes;
+ }
+ }
+ Object addArgsObj = ScriptableObject.getProperty(params, "args");
+ if (addArgsObj != Scriptable.NOT_FOUND) {
+ Scriptable s = Context.toObject(addArgsObj,
+ getTopLevelScope(thisObj));
+ addArgs = cx.getElements(s);
+ }
+ }
+ Global global = getInstance(funObj);
+ if (out == null) {
+ out = (global != null) ? global.getOut() : System.out;
+ }
+ if (err == null) {
+ err = (global != null) ? global.getErr() : System.err;
+ }
+ // If no explicit input stream, do not send any input to process,
+ // in particular, do not use System.in to avoid deadlocks
+ // when waiting for user input to send to process which is already
+ // terminated as it is not always possible to interrupt read method.
+
+ String[] cmd = new String[(addArgs == null) ? L : L + addArgs.length];
+ for (int i = 0; i != L; ++i) {
+ cmd[i] = ScriptRuntime.toString(args[i]);
+ }
+ if (addArgs != null) {
+ for (int i = 0; i != addArgs.length; ++i) {
+ cmd[L + i] = ScriptRuntime.toString(addArgs[i]);
+ }
+ }
+
+ int exitCode = runProcess(cmd, environment, in, out, err);
+ if (outBytes != null) {
+ String s = ScriptRuntime.toString(outObj) + outBytes.toString();
+ ScriptableObject.putProperty(params, "output", s);
+ }
+ if (errBytes != null) {
+ String s = ScriptRuntime.toString(errObj) + errBytes.toString();
+ ScriptableObject.putProperty(params, "err", s);
+ }
+
+ return new Integer(exitCode);
+ }
+
+ /**
+ * The seal function seals all supplied arguments.
+ */
+ public static void seal(Context cx, Scriptable thisObj, Object[] args,
+ Function funObj)
+ {
+ for (int i = 0; i != args.length; ++i) {
+ Object arg = args[i];
+ if (!(arg instanceof ScriptableObject) || arg == Undefined.instance)
+ {
+ if (!(arg instanceof Scriptable) || arg == Undefined.instance)
+ {
+ throw reportRuntimeError("msg.shell.seal.not.object");
+ } else {
+ throw reportRuntimeError("msg.shell.seal.not.scriptable");
+ }
+ }
+ }
+
+ for (int i = 0; i != args.length; ++i) {
+ Object arg = args[i];
+ ((ScriptableObject)arg).sealObject();
+ }
+ }
+
+ /**
+ * The readFile reads the given file content and convert it to a string
+ * using the specified character coding or default character coding if
+ * explicit coding argument is not given.
+ * <p>
+ * Usage:
+ * <pre>
+ * readFile(filePath)
+ * readFile(filePath, charCoding)
+ * </pre>
+ * The first form converts file's context to string using the default
+ * character coding.
+ */
+ public static Object readFile(Context cx, Scriptable thisObj, Object[] args,
+ Function funObj)
+ throws IOException
+ {
+ if (args.length == 0) {
+ throw reportRuntimeError("msg.shell.readFile.bad.args");
+ }
+ String path = ScriptRuntime.toString(args[0]);
+ String charCoding = null;
+ if (args.length >= 2) {
+ charCoding = ScriptRuntime.toString(args[1]);
+ }
+
+ return readUrl(path, charCoding, true);
+ }
+
+ /**
+ * The readUrl opens connection to the given URL, read all its data
+ * and converts them to a string
+ * using the specified character coding or default character coding if
+ * explicit coding argument is not given.
+ * <p>
+ * Usage:
+ * <pre>
+ * readUrl(url)
+ * readUrl(url, charCoding)
+ * </pre>
+ * The first form converts file's context to string using the default
+ * charCoding.
+ */
+ public static Object readUrl(Context cx, Scriptable thisObj, Object[] args,
+ Function funObj)
+ throws IOException
+ {
+ if (args.length == 0) {
+ throw reportRuntimeError("msg.shell.readUrl.bad.args");
+ }
+ String url = ScriptRuntime.toString(args[0]);
+ String charCoding = null;
+ if (args.length >= 2) {
+ charCoding = ScriptRuntime.toString(args[1]);
+ }
+
+ return readUrl(url, charCoding, false);
+ }
+
+ /**
+ * Convert the argumnet to int32 number.
+ */
+ public static Object toint32(Context cx, Scriptable thisObj, Object[] args,
+ Function funObj)
+ {
+ Object arg = (args.length != 0 ? args[0] : Undefined.instance);
+ if (arg instanceof Integer)
+ return arg;
+ return ScriptRuntime.wrapInt(ScriptRuntime.toInt32(arg));
+ }
+
+ public InputStream getIn() {
+ return inStream == null ? System.in : inStream;
+ }
+
+ public void setIn(InputStream in) {
+ inStream = in;
+ }
+
+ public PrintStream getOut() {
+ return outStream == null ? System.out : outStream;
+ }
+
+ public void setOut(PrintStream out) {
+ outStream = out;
+ }
+
+ public PrintStream getErr() {
+ return errStream == null ? System.err : errStream;
+ }
+
+ public void setErr(PrintStream err) {
+ errStream = err;
+ }
+
+ public void setSealedStdLib(boolean value)
+ {
+ sealedStdLib = value;
+ }
+
+ private static Global getInstance(Function function)
+ {
+ Scriptable scope = function.getParentScope();
+ if (!(scope instanceof Global))
+ throw reportRuntimeError("msg.bad.shell.function.scope",
+ String.valueOf(scope));
+ return (Global)scope;
+ }
+
+ /**
+ * Runs the given process using Runtime.exec().
+ * If any of in, out, err is null, the corresponding process stream will
+ * be closed immediately, otherwise it will be closed as soon as
+ * all data will be read from/written to process
+ *
+ * @return Exit value of process.
+ * @throws IOException If there was an error executing the process.
+ */
+ private static int runProcess(String[] cmd, String[] environment,
+ InputStream in, OutputStream out,
+ OutputStream err)
+ throws IOException
+ {
+ Process p;
+ if (environment == null) {
+ p = Runtime.getRuntime().exec(cmd);
+ } else {
+ p = Runtime.getRuntime().exec(cmd, environment);
+ }
+
+ try {
+ PipeThread inThread = null;
+ if (in != null) {
+ inThread = new PipeThread(false, in, p.getOutputStream());
+ inThread.start();
+ } else {
+ p.getOutputStream().close();
+ }
+
+ PipeThread outThread = null;
+ if (out != null) {
+ outThread = new PipeThread(true, p.getInputStream(), out);
+ outThread.start();
+ } else {
+ p.getInputStream().close();
+ }
+
+ PipeThread errThread = null;
+ if (err != null) {
+ errThread = new PipeThread(true, p.getErrorStream(), err);
+ errThread.start();
+ } else {
+ p.getErrorStream().close();
+ }
+
+ // wait for process completion
+ for (;;) {
+ try {
+ p.waitFor();
+ if (outThread != null) {
+ outThread.join();
+ }
+ if (inThread != null) {
+ inThread.join();
+ }
+ if (errThread != null) {
+ errThread.join();
+ }
+ break;
+ } catch (InterruptedException ignore) {
+ }
+ }
+
+ return p.exitValue();
+ } finally {
+ p.destroy();
+ }
+ }
+
+ static void pipe(boolean fromProcess, InputStream from, OutputStream to)
+ throws IOException
+ {
+ try {
+ final int SIZE = 4096;
+ byte[] buffer = new byte[SIZE];
+ for (;;) {
+ int n;
+ if (!fromProcess) {
+ n = from.read(buffer, 0, SIZE);
+ } else {
+ try {
+ n = from.read(buffer, 0, SIZE);
+ } catch (IOException ex) {
+ // Ignore exception as it can be cause by closed pipe
+ break;
+ }
+ }
+ if (n < 0) { break; }
+ if (fromProcess) {
+ to.write(buffer, 0, n);
+ to.flush();
+ } else {
+ try {
+ to.write(buffer, 0, n);
+ to.flush();
+ } catch (IOException ex) {
+ // Ignore exception as it can be cause by closed pipe
+ break;
+ }
+ }
+ }
+ } finally {
+ try {
+ if (fromProcess) {
+ from.close();
+ } else {
+ to.close();
+ }
+ } catch (IOException ex) {
+ // Ignore errors on close. On Windows JVM may throw invalid
+ // refrence exception if process terminates too fast.
+ }
+ }
+ }
+
+ private static InputStream toInputStream(Object value)
+ throws IOException
+ {
+ InputStream is = null;
+ String s = null;
+ if (value instanceof Wrapper) {
+ Object unwrapped = ((Wrapper)value).unwrap();
+ if (unwrapped instanceof InputStream) {
+ is = (InputStream)unwrapped;
+ } else if (unwrapped instanceof byte[]) {
+ is = new ByteArrayInputStream((byte[])unwrapped);
+ } else if (unwrapped instanceof Reader) {
+ s = readReader((Reader)unwrapped);
+ } else if (unwrapped instanceof char[]) {
+ s = new String((char[])unwrapped);
+ }
+ }
+ if (is == null) {
+ if (s == null) { s = ScriptRuntime.toString(value); }
+ is = new ByteArrayInputStream(s.getBytes());
+ }
+ return is;
+ }
+
+ private static OutputStream toOutputStream(Object value) {
+ OutputStream os = null;
+ if (value instanceof Wrapper) {
+ Object unwrapped = ((Wrapper)value).unwrap();
+ if (unwrapped instanceof OutputStream) {
+ os = (OutputStream)unwrapped;
+ }
+ }
+ return os;
+ }
+
+ private static String readUrl(String filePath, String charCoding,
+ boolean urlIsFile)
+ throws IOException
+ {
+ int chunkLength;
+ InputStream is = null;
+ try {
+ if (!urlIsFile) {
+ URL urlObj = new URL(filePath);
+ URLConnection uc = urlObj.openConnection();
+ is = uc.getInputStream();
+ chunkLength = uc.getContentLength();
+ if (chunkLength <= 0)
+ chunkLength = 1024;
+ if (charCoding == null) {
+ String type = uc.getContentType();
+ if (type != null) {
+ charCoding = getCharCodingFromType(type);
+ }
+ }
+ } else {
+ File f = new File(filePath);
+
+ long length = f.length();
+ chunkLength = (int)length;
+ if (chunkLength != length)
+ throw new IOException("Too big file size: "+length);
+
+ if (chunkLength == 0) { return ""; }
+
+ is = new FileInputStream(f);
+ }
+
+ Reader r;
+ if (charCoding == null) {
+ r = new InputStreamReader(is);
+ } else {
+ r = new InputStreamReader(is, charCoding);
+ }
+ return readReader(r, chunkLength);
+
+ } finally {
+ if (is != null)
+ is.close();
+ }
+ }
+
+ private static String getCharCodingFromType(String type)
+ {
+ int i = type.indexOf(';');
+ if (i >= 0) {
+ int end = type.length();
+ ++i;
+ while (i != end && type.charAt(i) <= ' ') {
+ ++i;
+ }
+ String charset = "charset";
+ if (charset.regionMatches(true, 0, type, i, charset.length()))
+ {
+ i += charset.length();
+ while (i != end && type.charAt(i) <= ' ') {
+ ++i;
+ }
+ if (i != end && type.charAt(i) == '=') {
+ ++i;
+ while (i != end && type.charAt(i) <= ' ') {
+ ++i;
+ }
+ if (i != end) {
+ // i is at the start of non-empty
+ // charCoding spec
+ while (type.charAt(end -1) <= ' ') {
+ --end;
+ }
+ return type.substring(i, end);
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ private static String readReader(Reader reader)
+ throws IOException
+ {
+ return readReader(reader, 4096);
+ }
+
+ private static String readReader(Reader reader, int initialBufferSize)
+ throws IOException
+ {
+ char[] buffer = new char[initialBufferSize];
+ int offset = 0;
+ for (;;) {
+ int n = reader.read(buffer, offset, buffer.length - offset);
+ if (n < 0) { break; }
+ offset += n;
+ if (offset == buffer.length) {
+ char[] tmp = new char[buffer.length * 2];
+ System.arraycopy(buffer, 0, tmp, 0, offset);
+ buffer = tmp;
+ }
+ }
+ return new String(buffer, 0, offset);
+ }
+
+ static RuntimeException reportRuntimeError(String msgId) {
+ String message = ToolErrorReporter.getMessage(msgId);
+ return Context.reportRuntimeError(message);
+ }
+
+ static RuntimeException reportRuntimeError(String msgId, String msgArg)
+ {
+ String message = ToolErrorReporter.getMessage(msgId, msgArg);
+ return Context.reportRuntimeError(message);
+ }
+}
+
+
+class Runner implements Runnable, ContextAction {
+
+ Runner(Scriptable scope, Function func, Object[] args) {
+ this.scope = scope;
+ f = func;
+ this.args = args;
+ }
+
+ Runner(Scriptable scope, Script script) {
+ this.scope = scope;
+ s = script;
+ }
+
+ public void run()
+ {
+ factory.call(this);
+ }
+
+ public Object run(Context cx)
+ {
+ if (f != null)
+ return f.call(cx, scope, scope, args);
+ else
+ return s.exec(cx, scope);
+ }
+
+ ContextFactory factory;
+ private Scriptable scope;
+ private Function f;
+ private Script s;
+ private Object[] args;
+}
+
+class PipeThread extends Thread {
+
+ PipeThread(boolean fromProcess, InputStream from, OutputStream to) {
+ setDaemon(true);
+ this.fromProcess = fromProcess;
+ this.from = from;
+ this.to = to;
+ }
+
+ public void run() {
+ try {
+ Global.pipe(fromProcess, from, to);
+ } catch (IOException ex) {
+ throw Context.throwAsScriptRuntimeEx(ex);
+ }
+ }
+
+ private boolean fromProcess;
+ private InputStream from;
+ private OutputStream to;
+}
+
diff --git a/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/JSConsole.java b/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/JSConsole.java
new file mode 100644
index 0000000..f6fe3a1
--- /dev/null
+++ b/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/JSConsole.java
@@ -0,0 +1,225 @@
+/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Rhino JavaScript Debugger code, released
+ * November 21, 2000.
+ *
+ * The Initial Developer of the Original Code is
+ * See Beyond Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Christopher Oliver
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * the GNU General Public License Version 2 or later (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of those above. If
+ * you wish to allow use of your version of this file only under the terms of
+ * the GPL and not to allow others to use your version of this file under the
+ * MPL, indicate your decision by deleting the provisions above and replacing
+ * them with the notice and other provisions required by the GPL. If you do
+ * not delete the provisions above, a recipient may use your version of this
+ * file under either the MPL or the GPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+package org.mozilla.javascript.tools.shell;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.io.File;
+
+import javax.swing.ButtonGroup;
+import javax.swing.JFileChooser;
+import javax.swing.JFrame;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JMenuItem;
+import javax.swing.JOptionPane;
+import javax.swing.JRadioButtonMenuItem;
+import javax.swing.JScrollPane;
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
+
+import org.mozilla.javascript.SecurityUtilities;
+
+public class JSConsole extends JFrame implements ActionListener
+{
+ static final long serialVersionUID = 2551225560631876300L;
+
+ private File CWD;
+ private JFileChooser dlg;
+ private ConsoleTextArea consoleTextArea;
+
+ public String chooseFile() {
+ if(CWD == null) {
+ String dir = SecurityUtilities.getSystemProperty("user.dir");
+ if(dir != null) {
+ CWD = new File(dir);
+ }
+ }
+ if(CWD != null) {
+ dlg.setCurrentDirectory(CWD);
+ }
+ dlg.setDialogTitle("Select a file to load");
+ int returnVal = dlg.showOpenDialog(this);
+ if(returnVal == JFileChooser.APPROVE_OPTION) {
+ String result = dlg.getSelectedFile().getPath();
+ CWD = new File(dlg.getSelectedFile().getParent());
+ return result;
+ }
+ return null;
+ }
+
+ public static void main(String args[]) {
+ new JSConsole(args);
+ }
+
+ public void createFileChooser() {
+ dlg = new JFileChooser();
+ javax.swing.filechooser.FileFilter filter =
+ new javax.swing.filechooser.FileFilter() {
+ public boolean accept(File f) {
+ if(f.isDirectory()) {
+ return true;
+ }
+ String name = f.getName();
+ int i = name.lastIndexOf('.');
+ if(i > 0 && i < name.length() -1) {
+ String ext = name.substring(i + 1).toLowerCase();
+ if(ext.equals("js")) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public String getDescription() {
+ return "JavaScript Files (*.js)";
+ }
+ };
+ dlg.addChoosableFileFilter(filter);
+
+ }
+
+ public JSConsole(String[] args) {
+ super("Rhino JavaScript Console");
+ JMenuBar menubar = new JMenuBar();
+ createFileChooser();
+ String[] fileItems = {"Load...", "Exit"};
+ String[] fileCmds = {"Load", "Exit"};
+ char[] fileShortCuts = {'L', 'X'};
+ String[] editItems = {"Cut", "Copy", "Paste"};
+ char[] editShortCuts = {'T', 'C', 'P'};
+ String[] plafItems = {"Metal", "Windows", "Motif"};
+ boolean [] plafState = {true, false, false};
+ JMenu fileMenu = new JMenu("File");
+ fileMenu.setMnemonic('F');
+ JMenu editMenu = new JMenu("Edit");
+ editMenu.setMnemonic('E');
+ JMenu plafMenu = new JMenu("Platform");
+ plafMenu.setMnemonic('P');
+ for(int i = 0; i < fileItems.length; ++i) {
+ JMenuItem item = new JMenuItem(fileItems[i],
+ fileShortCuts[i]);
+ item.setActionCommand(fileCmds[i]);
+ item.addActionListener(this);
+ fileMenu.add(item);
+ }
+ for(int i = 0; i < editItems.length; ++i) {
+ JMenuItem item = new JMenuItem(editItems[i],
+ editShortCuts[i]);
+ item.addActionListener(this);
+ editMenu.add(item);
+ }
+ ButtonGroup group = new ButtonGroup();
+ for(int i = 0; i < plafItems.length; ++i) {
+ JRadioButtonMenuItem item = new JRadioButtonMenuItem(plafItems[i],
+ plafState[i]);
+ group.add(item);
+ item.addActionListener(this);
+ plafMenu.add(item);
+ }
+ menubar.add(fileMenu);
+ menubar.add(editMenu);
+ menubar.add(plafMenu);
+ setJMenuBar(menubar);
+ consoleTextArea = new ConsoleTextArea(args);
+ JScrollPane scroller = new JScrollPane(consoleTextArea);
+ setContentPane(scroller);
+ consoleTextArea.setRows(24);
+ consoleTextArea.setColumns(80);
+ addWindowListener(new WindowAdapter() {
+ public void windowClosing(WindowEvent e) {
+ System.exit(0);
+ }
+ });
+ pack();
+ setVisible(true);
+ // System.setIn(consoleTextArea.getIn());
+ // System.setOut(consoleTextArea.getOut());
+ // System.setErr(consoleTextArea.getErr());
+ Main.setIn(consoleTextArea.getIn());
+ Main.setOut(consoleTextArea.getOut());
+ Main.setErr(consoleTextArea.getErr());
+ Main.main(args);
+ }
+
+ public void actionPerformed(ActionEvent e) {
+ String cmd = e.getActionCommand();
+ String plaf_name = null;
+ if(cmd.equals("Load")) {
+ String f = chooseFile();
+ if(f != null) {
+ f = f.replace('\\', '/');
+ consoleTextArea.eval("load(\"" + f + "\");");
+ }
+ } else if(cmd.equals("Exit")) {
+ System.exit(0);
+ } else if(cmd.equals("Cut")) {
+ consoleTextArea.cut();
+ } else if(cmd.equals("Copy")) {
+ consoleTextArea.copy();
+ } else if(cmd.equals("Paste")) {
+ consoleTextArea.paste();
+ } else {
+ if(cmd.equals("Metal")) {
+ plaf_name = "javax.swing.plaf.metal.MetalLookAndFeel";
+ } else if(cmd.equals("Windows")) {
+ plaf_name = "com.sun.java.swing.plaf.windows.WindowsLookAndFeel";
+ } else if(cmd.equals("Motif")) {
+ plaf_name = "com.sun.java.swing.plaf.motif.MotifLookAndFeel";
+ }
+ if(plaf_name != null) {
+ try {
+ UIManager.setLookAndFeel(plaf_name);
+ SwingUtilities.updateComponentTreeUI(this);
+ consoleTextArea.postUpdateUI();
+ // updateComponentTreeUI seems to mess up the file
+ // chooser dialog, so just create a new one
+ createFileChooser();
+ } catch(Exception exc) {
+ JOptionPane.showMessageDialog(this,
+ exc.getMessage(),
+ "Platform",
+ JOptionPane.ERROR_MESSAGE);
+ }
+ }
+ }
+
+ }
+
+}
diff --git a/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/JavaPolicySecurity.java b/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/JavaPolicySecurity.java
new file mode 100644
index 0000000..de39a5e
--- /dev/null
+++ b/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/JavaPolicySecurity.java
@@ -0,0 +1,240 @@
+/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Rhino code, released
+ * May 6, 1999.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1997-1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Igor Bukanov
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * the GNU General Public License Version 2 or later (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of those above. If
+ * you wish to allow use of your version of this file only under the terms of
+ * the GPL and not to allow others to use your version of this file under the
+ * MPL, indicate your decision by deleting the provisions above and replacing
+ * them with the notice and other provisions required by the GPL. If you do
+ * not delete the provisions above, a recipient may use your version of this
+ * file under either the MPL or the GPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package org.mozilla.javascript.tools.shell;
+
+import java.security.*;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Enumeration;
+
+import org.mozilla.javascript.*;
+
+public class JavaPolicySecurity extends SecurityProxy
+{
+
+ public Class getStaticSecurityDomainClassInternal() {
+ return ProtectionDomain.class;
+ }
+
+ private static class Loader extends ClassLoader
+ implements GeneratedClassLoader
+ {
+ private ProtectionDomain domain;
+
+ Loader(ClassLoader parent, ProtectionDomain domain) {
+ super(parent != null ? parent : getSystemClassLoader());
+ this.domain = domain;
+ }
+
+ public Class defineClass(String name, byte[] data) {
+ return super.defineClass(name, data, 0, data.length, domain);
+ }
+
+ public void linkClass(Class cl) {
+ resolveClass(cl);
+ }
+ }
+
+ private static class ContextPermissions extends PermissionCollection
+ {
+ static final long serialVersionUID = -1721494496320750721L;
+
+// Construct PermissionCollection that permits an action only
+// if it is permitted by staticDomain and by security context of Java stack on
+// the moment of constructor invocation
+ ContextPermissions(ProtectionDomain staticDomain) {
+ _context = AccessController.getContext();
+ if (staticDomain != null) {
+ _statisPermissions = staticDomain.getPermissions();
+ }
+ setReadOnly();
+ }
+
+ public void add(Permission permission) {
+ throw new RuntimeException("NOT IMPLEMENTED");
+ }
+
+ public boolean implies(Permission permission) {
+ if (_statisPermissions != null) {
+ if (!_statisPermissions.implies(permission)) {
+ return false;
+ }
+ }
+ try {
+ _context.checkPermission(permission);
+ return true;
+ }catch (AccessControlException ex) {
+ return false;
+ }
+ }
+
+ public Enumeration elements()
+ {
+ return new Enumeration() {
+ public boolean hasMoreElements() { return false; }
+ public Object nextElement() { return null; }
+ };
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append(getClass().getName());
+ sb.append('@');
+ sb.append(Integer.toHexString(System.identityHashCode(this)));
+ sb.append(" (context=");
+ sb.append(_context);
+ sb.append(", static_permitions=");
+ sb.append(_statisPermissions);
+ sb.append(')');
+ return sb.toString();
+ }
+
+ AccessControlContext _context;
+ PermissionCollection _statisPermissions;
+ }
+
+ public JavaPolicySecurity()
+ {
+ // To trigger error on jdk-1.1 with lazy load
+ new CodeSource(null, (java.security.cert.Certificate[])null);
+ }
+
+ protected void callProcessFileSecure(final Context cx,
+ final Scriptable scope,
+ final String filename)
+ {
+ AccessController.doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ URL url = getUrlObj(filename);
+ ProtectionDomain staticDomain = getUrlDomain(url);
+ Main.processFileSecure(cx, scope, url.toExternalForm(),
+ staticDomain);
+ return null;
+ }
+ });
+ }
+
+ private URL getUrlObj(String url)
+ {
+ URL urlObj;
+ try {
+ urlObj = new URL(url);
+ } catch (MalformedURLException ex) {
+ // Assume as Main.processFileSecure it is file, need to build its
+ // URL
+ String curDir = System.getProperty("user.dir");
+ curDir = curDir.replace('\\', '/');
+ if (!curDir.endsWith("/")) {
+ curDir = curDir+'/';
+ }
+ try {
+ URL curDirURL = new URL("file:"+curDir);
+ urlObj = new URL(curDirURL, url);
+ } catch (MalformedURLException ex2) {
+ throw new RuntimeException
+ ("Can not construct file URL for '"+url+"':"
+ +ex2.getMessage());
+ }
+ }
+ return urlObj;
+ }
+
+ private ProtectionDomain getUrlDomain(URL url)
+ {
+ CodeSource cs;
+ cs = new CodeSource(url, (java.security.cert.Certificate[])null);
+ PermissionCollection pc = Policy.getPolicy().getPermissions(cs);
+ return new ProtectionDomain(cs, pc);
+ }
+
+ public GeneratedClassLoader
+ createClassLoader(ClassLoader parentLoader, Object securityDomain)
+ {
+ ProtectionDomain domain = (ProtectionDomain)securityDomain;
+ return new Loader(parentLoader, domain);
+ }
+
+ public Object getDynamicSecurityDomain(Object securityDomain)
+ {
+ ProtectionDomain staticDomain = (ProtectionDomain)securityDomain;
+ return getDynamicDomain(staticDomain);
+ }
+
+ private ProtectionDomain getDynamicDomain(ProtectionDomain staticDomain) {
+ ContextPermissions p = new ContextPermissions(staticDomain);
+ ProtectionDomain contextDomain = new ProtectionDomain(null, p);
+ return contextDomain;
+ }
+
+ public Object callWithDomain(Object securityDomain,
+ final Context cx,
+ final Callable callable,
+ final Scriptable scope,
+ final Scriptable thisObj,
+ final Object[] args)
+ {
+ ProtectionDomain staticDomain = (ProtectionDomain)securityDomain;
+ // There is no direct way in Java to intersect permitions according
+ // stack context with additional domain.
+ // The following implementation first constructs ProtectionDomain
+ // that allows actions only allowed by both staticDomain and current
+ // stack context, and then constructs AccessController for this dynamic
+ // domain.
+ // If this is too slow, alternative solution would be to generate
+ // class per domain with a proxy method to call to infect
+ // java stack.
+ // Another optimization in case of scripts coming from "world" domain,
+ // that is having minimal default privileges is to construct
+ // one AccessControlContext based on ProtectionDomain
+ // with least possible privileges and simply call
+ // AccessController.doPrivileged with this untrusted context
+
+ ProtectionDomain dynamicDomain = getDynamicDomain(staticDomain);
+ ProtectionDomain[] tmp = { dynamicDomain };
+ AccessControlContext restricted = new AccessControlContext(tmp);
+
+ PrivilegedAction action = new PrivilegedAction() {
+ public Object run() {
+ return callable.call(cx, scope, thisObj, args);
+ }
+ };
+
+ return AccessController.doPrivileged(action, restricted);
+ }
+}
diff --git a/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/Main.java b/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/Main.java
new file mode 100644
index 0000000..9120892
--- /dev/null
+++ b/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/Main.java
@@ -0,0 +1,638 @@
+/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Rhino code, released
+ * May 6, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1997-1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Patrick Beard
+ * Norris Boyd
+ * Igor Bukanov
+ * Rob Ginda
+ * Kurt Westerfeld
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * the GNU General Public License Version 2 or later (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of those above. If
+ * you wish to allow use of your version of this file only under the terms of
+ * the GPL and not to allow others to use your version of this file under the
+ * MPL, indicate your decision by deleting the provisions above and replacing
+ * them with the notice and other provisions required by the GPL. If you do
+ * not delete the provisions above, a recipient may use your version of this
+ * file under either the MPL or the GPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package org.mozilla.javascript.tools.shell;
+
+import java.io.*;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.MalformedURLException;
+import java.util.*;
+import org.mozilla.javascript.*;
+import org.mozilla.javascript.tools.ToolErrorReporter;
+
+/**
+ * The shell program.
+ *
+ * Can execute scripts interactively or in batch mode at the command line.
+ * An example of controlling the JavaScript engine.
+ *
+ * @author Norris Boyd
+ */
+public class Main
+{
+ public static ShellContextFactory
+ shellContextFactory = new ShellContextFactory();
+
+ public static Global global = new Global();
+ static protected ToolErrorReporter errorReporter;
+ static protected int exitCode = 0;
+ static private final int EXITCODE_RUNTIME_ERROR = 3;
+ static private final int EXITCODE_FILE_NOT_FOUND = 4;
+ static boolean processStdin = true;
+ static Vector fileList = new Vector(5);
+ private static SecurityProxy securityImpl;
+
+ static {
+ global.initQuitAction(new IProxy(IProxy.SYSTEM_EXIT));
+ }
+
+ /**
+ * Proxy class to avoid proliferation of anonymous classes.
+ */
+ private static class IProxy implements ContextAction, QuitAction
+ {
+ private static final int PROCESS_FILES = 1;
+ private static final int EVAL_INLINE_SCRIPT = 2;
+ private static final int SYSTEM_EXIT = 3;
+
+ private int type;
+ String[] args;
+ String scriptText;
+
+ IProxy(int type)
+ {
+ this.type = type;
+ }
+
+ public Object run(Context cx)
+ {
+ if (type == PROCESS_FILES) {
+ processFiles(cx, args);
+ } else if (type == EVAL_INLINE_SCRIPT) {
+ Script script = loadScriptFromSource(cx, scriptText,
+ "<command>", 1, null);
+ if (script != null) {
+ evaluateScript(script, cx, getGlobal());
+ }
+ } else {
+ throw Kit.codeBug();
+ }
+ return null;
+ }
+
+ public void quit(Context cx, int exitCode)
+ {
+ if (type == SYSTEM_EXIT) {
+ System.exit(exitCode);
+ return;
+ }
+ throw Kit.codeBug();
+ }
+ }
+
+ /**
+ * Main entry point.
+ *
+ * Process arguments as would a normal Java program. Also
+ * create a new Context and associate it with the current thread.
+ * Then set up the execution environment and begin to
+ * execute scripts.
+ */
+ public static void main(String args[]) {
+ try {
+ if (Boolean.getBoolean("rhino.use_java_policy_security")) {
+ initJavaPolicySecuritySupport();
+ }
+ } catch (SecurityException ex) {
+ ex.printStackTrace(System.err);
+ }
+
+ int result = exec(args);
+ if (result != 0) {
+ System.exit(result);
+ }
+ }
+
+ /**
+ * Execute the given arguments, but don't System.exit at the end.
+ */
+ public static int exec(String origArgs[])
+ {
+ errorReporter = new ToolErrorReporter(false, global.getErr());
+ shellContextFactory.setErrorReporter(errorReporter);
+ String[] args = processOptions(origArgs);
+ if (processStdin)
+ fileList.addElement(null);
+
+ if (!global.initialized) {
+ global.init(shellContextFactory);
+ }
+ IProxy iproxy = new IProxy(IProxy.PROCESS_FILES);
+ iproxy.args = args;
+ shellContextFactory.call(iproxy);
+
+ return exitCode;
+ }
+
+ static void processFiles(Context cx, String[] args)
+ {
+ // define "arguments" array in the top-level object:
+ // need to allocate new array since newArray requires instances
+ // of exactly Object[], not ObjectSubclass[]
+ Object[] array = new Object[args.length];
+ System.arraycopy(args, 0, array, 0, args.length);
+ Scriptable argsObj = cx.newArray(global, array);
+ global.defineProperty("arguments", argsObj,
+ ScriptableObject.DONTENUM);
+
+ for (int i=0; i < fileList.size(); i++) {
+ processSource(cx, (String) fileList.elementAt(i));
+ }
+
+ }
+
+ public static Global getGlobal()
+ {
+ return global;
+ }
+
+ /**
+ * Parse arguments.
+ */
+ public static String[] processOptions(String args[])
+ {
+ String usageError;
+ goodUsage: for (int i = 0; ; ++i) {
+ if (i == args.length) {
+ return new String[0];
+ }
+ String arg = args[i];
+ if (!arg.startsWith("-")) {
+ processStdin = false;
+ fileList.addElement(arg);
+ String[] result = new String[args.length - i - 1];
+ System.arraycopy(args, i+1, result, 0, args.length - i - 1);
+ return result;
+ }
+ if (arg.equals("-version")) {
+ if (++i == args.length) {
+ usageError = arg;
+ break goodUsage;
+ }
+ int version;
+ try {
+ version = Integer.parseInt(args[i]);
+ } catch (NumberFormatException ex) {
+ usageError = args[i];
+ break goodUsage;
+ }
+ if (!Context.isValidLanguageVersion(version)) {
+ usageError = args[i];
+ break goodUsage;
+ }
+ shellContextFactory.setLanguageVersion(version);
+ continue;
+ }
+ if (arg.equals("-opt") || arg.equals("-O")) {
+ if (++i == args.length) {
+ usageError = arg;
+ break goodUsage;
+ }
+ int opt;
+ try {
+ opt = Integer.parseInt(args[i]);
+ } catch (NumberFormatException ex) {
+ usageError = args[i];
+ break goodUsage;
+ }
+ if (opt == -2) {
+ // Compatibility with Cocoon Rhino fork
+ opt = -1;
+ } else if (!Context.isValidOptimizationLevel(opt)) {
+ usageError = args[i];
+ break goodUsage;
+ }
+ shellContextFactory.setOptimizationLevel(opt);
+ continue;
+ }
+ if (arg.equals("-strict")) {
+ shellContextFactory.setStrictMode(true);
+ errorReporter.setIsReportingWarnings(true);
+ continue;
+ }
+ if (arg.equals("-fatal-warnings")) {
+ shellContextFactory.setWarningAsError(true);
+ continue;
+ }
+ if (arg.equals("-e")) {
+ processStdin = false;
+ if (++i == args.length) {
+ usageError = arg;
+ break goodUsage;
+ }
+ if (!global.initialized) {
+ global.init(shellContextFactory);
+ }
+ IProxy iproxy = new IProxy(IProxy.EVAL_INLINE_SCRIPT);
+ iproxy.scriptText = args[i];
+ shellContextFactory.call(iproxy);
+ continue;
+ }
+ if (arg.equals("-w")) {
+ errorReporter.setIsReportingWarnings(true);
+ continue;
+ }
+ if (arg.equals("-f")) {
+ processStdin = false;
+ if (++i == args.length) {
+ usageError = arg;
+ break goodUsage;
+ }
+ fileList.addElement(args[i].equals("-") ? null : args[i]);
+ continue;
+ }
+ if (arg.equals("-sealedlib")) {
+ global.setSealedStdLib(true);
+ continue;
+ }
+ if (arg.equals("-debug")) {
+ shellContextFactory.setGeneratingDebug(true);
+ continue;
+ }
+ if (arg.equals("-?") ||
+ arg.equals("-help")) {
+ // print usage message
+ global.getOut().println(
+ ToolErrorReporter.getMessage("msg.shell.usage", Main.class.getName()));
+ System.exit(1);
+ }
+ usageError = arg;
+ break goodUsage;
+ }
+ // print error and usage message
+ global.getOut().println(
+ ToolErrorReporter.getMessage("msg.shell.invalid", usageError));
+ global.getOut().println(
+ ToolErrorReporter.getMessage("msg.shell.usage", Main.class.getName()));
+ System.exit(1);
+ return null;
+ }
+
+ private static void initJavaPolicySecuritySupport()
+ {
+ Throwable exObj;
+ try {
+ Class cl = Class.forName
+ ("org.mozilla.javascript.tools.shell.JavaPolicySecurity");
+ securityImpl = (SecurityProxy)cl.newInstance();
+ SecurityController.initGlobal(securityImpl);
+ return;
+ } catch (ClassNotFoundException ex) {
+ exObj = ex;
+ } catch (IllegalAccessException ex) {
+ exObj = ex;
+ } catch (InstantiationException ex) {
+ exObj = ex;
+ } catch (LinkageError ex) {
+ exObj = ex;
+ }
+ throw Kit.initCause(new IllegalStateException(
+ "Can not load security support: "+exObj), exObj);
+ }
+
+ /**
+ * Evaluate JavaScript source.
+ *
+ * @param cx the current context
+ * @param filename the name of the file to compile, or null
+ * for interactive mode.
+ */
+ public static void processSource(Context cx, String filename)
+ {
+ if (filename == null || filename.equals("-")) {
+ PrintStream ps = global.getErr();
+ if (filename == null) {
+ // print implementation version
+ ps.println(cx.getImplementationVersion());
+ }
+
+ // Use the interpreter for interactive input
+ cx.setOptimizationLevel(-1);
+
+ BufferedReader in = new BufferedReader
+ (new InputStreamReader(global.getIn()));
+ int lineno = 1;
+ boolean hitEOF = false;
+ while (!hitEOF) {
+ String[] prompts = global.getPrompts(cx);
+ if (filename == null)
+ ps.print(prompts[0]);
+ ps.flush();
+ String source = "";
+
+ // Collect lines of source to compile.
+ while (true) {
+ String newline;
+ try {
+ newline = in.readLine();
+ }
+ catch (IOException ioe) {
+ ps.println(ioe.toString());
+ break;
+ }
+ if (newline == null) {
+ hitEOF = true;
+ break;
+ }
+ source = source + newline + "\n";
+ lineno++;
+ if (cx.stringIsCompilableUnit(source))
+ break;
+ ps.print(prompts[1]);
+ }
+ Script script = loadScriptFromSource(cx, source, "<stdin>",
+ lineno, null);
+ if (script != null) {
+ Object result = evaluateScript(script, cx, global);
+ // Avoid printing out undefined or function definitions.
+ if (result != Context.getUndefinedValue() &&
+ !(result instanceof Function &&
+ source.trim().startsWith("function")))
+ {
+ try {
+ ps.println(Context.toString(result));
+ } catch (RhinoException rex) {
+ ToolErrorReporter.reportException(
+ cx.getErrorReporter(), rex);
+ }
+ }
+ NativeArray h = global.history;
+ h.put((int)h.getLength(), h, source);
+ }
+ }
+ ps.println();
+ } else {
+ processFile(cx, global, filename);
+ }
+ System.gc();
+ }
+
+ public static void processFile(Context cx, Scriptable scope,
+ String filename)
+ {
+ if (securityImpl == null) {
+ processFileSecure(cx, scope, filename, null);
+ } else {
+ securityImpl.callProcessFileSecure(cx, scope, filename);
+ }
+ }
+
+ static void processFileSecure(Context cx, Scriptable scope,
+ String path, Object securityDomain)
+ {
+ Script script;
+ if (path.endsWith(".class")) {
+ script = loadCompiledScript(cx, path, securityDomain);
+ } else {
+ String source = (String)readFileOrUrl(path, true);
+ if (source == null) {
+ exitCode = EXITCODE_FILE_NOT_FOUND;
+ return;
+ }
+
+ // Support the executable script #! syntax: If
+ // the first line begins with a '#', treat the whole
+ // line as a comment.
+ if (source.length() > 0 && source.charAt(0) == '#') {
+ for (int i = 1; i != source.length(); ++i) {
+ int c = source.charAt(i);
+ if (c == '\n' || c == '\r') {
+ source = source.substring(i);
+ break;
+ }
+ }
+ }
+ script = loadScriptFromSource(cx, source, path, 1, securityDomain);
+ }
+ if (script != null) {
+ evaluateScript(script, cx, scope);
+ }
+ }
+
+ public static Script loadScriptFromSource(Context cx, String scriptSource,
+ String path, int lineno,
+ Object securityDomain)
+ {
+ try {
+ return cx.compileString(scriptSource, path, lineno,
+ securityDomain);
+ } catch (EvaluatorException ee) {
+ // Already printed message.
+ exitCode = EXITCODE_RUNTIME_ERROR;
+ } catch (RhinoException rex) {
+ ToolErrorReporter.reportException(
+ cx.getErrorReporter(), rex);
+ exitCode = EXITCODE_RUNTIME_ERROR;
+ } catch (VirtualMachineError ex) {
+ // Treat StackOverflow and OutOfMemory as runtime errors
+ ex.printStackTrace();
+ String msg = ToolErrorReporter.getMessage(
+ "msg.uncaughtJSException", ex.toString());
+ exitCode = EXITCODE_RUNTIME_ERROR;
+ Context.reportError(msg);
+ }
+ return null;
+ }
+
+ private static Script loadCompiledScript(Context cx, String path,
+ Object securityDomain)
+ {
+ byte[] data = (byte[])readFileOrUrl(path, false);
+ if (data == null) {
+ exitCode = EXITCODE_FILE_NOT_FOUND;
+ return null;
+ }
+ // XXX: For now extract class name of compiled Script from path
+ // instead of parsing class bytes
+ int nameStart = path.lastIndexOf('/');
+ if (nameStart < 0) {
+ nameStart = 0;
+ } else {
+ ++nameStart;
+ }
+ int nameEnd = path.lastIndexOf('.');
+ if (nameEnd < nameStart) {
+ // '.' does not exist in path (nameEnd < 0)
+ // or it comes before nameStart
+ nameEnd = path.length();
+ }
+ String name = path.substring(nameStart, nameEnd);
+ try {
+ GeneratedClassLoader loader = SecurityController.createLoader(cx.getApplicationClassLoader(), securityDomain);
+ Class clazz = loader.defineClass(name, data);
+ loader.linkClass(clazz);
+ if (!Script.class.isAssignableFrom(clazz)) {
+ throw Context.reportRuntimeError("msg.must.implement.Script");
+ }
+ return (Script) clazz.newInstance();
+ } catch (RhinoException rex) {
+ ToolErrorReporter.reportException(
+ cx.getErrorReporter(), rex);
+ exitCode = EXITCODE_RUNTIME_ERROR;
+ } catch (IllegalAccessException iaex) {
+ exitCode = EXITCODE_RUNTIME_ERROR;
+ Context.reportError(iaex.toString());
+ } catch (InstantiationException inex) {
+ exitCode = EXITCODE_RUNTIME_ERROR;
+ Context.reportError(inex.toString());
+ }
+ return null;
+ }
+
+ public static Object evaluateScript(Script script, Context cx,
+ Scriptable scope)
+ {
+ try {
+ return script.exec(cx, scope);
+ } catch (RhinoException rex) {
+ ToolErrorReporter.reportException(
+ cx.getErrorReporter(), rex);
+ exitCode = EXITCODE_RUNTIME_ERROR;
+ } catch (VirtualMachineError ex) {
+ // Treat StackOverflow and OutOfMemory as runtime errors
+ ex.printStackTrace();
+ String msg = ToolErrorReporter.getMessage(
+ "msg.uncaughtJSException", ex.toString());
+ exitCode = EXITCODE_RUNTIME_ERROR;
+ Context.reportError(msg);
+ }
+ return Context.getUndefinedValue();
+ }
+
+ public static InputStream getIn() {
+ return getGlobal().getIn();
+ }
+
+ public static void setIn(InputStream in) {
+ getGlobal().setIn(in);
+ }
+
+ public static PrintStream getOut() {
+ return getGlobal().getOut();
+ }
+
+ public static void setOut(PrintStream out) {
+ getGlobal().setOut(out);
+ }
+
+ public static PrintStream getErr() {
+ return getGlobal().getErr();
+ }
+
+ public static void setErr(PrintStream err) {
+ getGlobal().setErr(err);
+ }
+
+ /**
+ * Read file or url specified by <tt>path</tt>.
+ * @return file or url content as <tt>byte[]</tt> or as <tt>String</tt> if
+ * <tt>convertToString</tt> is true.
+ */
+ private static Object readFileOrUrl(String path, boolean convertToString)
+ {
+ URL url = null;
+ // Assume path is URL if it contains dot and there are at least
+ // 2 characters in the protocol part. The later allows under Windows
+ // to interpret paths with driver letter as file, not URL.
+ if (path.indexOf(':') >= 2) {
+ try {
+ url = new URL(path);
+ } catch (MalformedURLException ex) {
+ }
+ }
+
+ InputStream is = null;
+ int capacityHint = 0;
+ if (url == null) {
+ File file = new File(path);
+ capacityHint = (int)file.length();
+ try {
+ is = new FileInputStream(file);
+ } catch (IOException ex) {
+ Context.reportError(ToolErrorReporter.getMessage(
+ "msg.couldnt.open", path));
+ return null;
+ }
+ } else {
+ try {
+ URLConnection uc = url.openConnection();
+ is = uc.getInputStream();
+ capacityHint = uc.getContentLength();
+ // Ignore insane values for Content-Length
+ if (capacityHint > (1 << 20)) {
+ capacityHint = -1;
+ }
+ } catch (IOException ex) {
+ Context.reportError(ToolErrorReporter.getMessage(
+ "msg.couldnt.open.url", url.toString(), ex.toString()));
+ return null;
+ }
+ }
+ if (capacityHint <= 0) {
+ capacityHint = 4096;
+ }
+
+ byte[] data;
+ try {
+ try {
+ data = Kit.readStream(is, capacityHint);
+ } finally {
+ is.close();
+ }
+ } catch (IOException ex) {
+ Context.reportError(ex.toString());
+ return null;
+ }
+
+ Object result;
+ if (!convertToString) {
+ result = data;
+ } else {
+ // Convert to String using the default encoding
+ // XXX: Use 'charset=' argument of Content-Type if URL?
+ result = new String(data);
+ }
+ return result;
+ }
+
+}
diff --git a/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/QuitAction.java b/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/QuitAction.java
new file mode 100644
index 0000000..dcad90e
--- /dev/null
+++ b/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/QuitAction.java
@@ -0,0 +1,50 @@
+/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Rhino code, released
+ * May 6, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1997-1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Igor Bukanov
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * the GNU General Public License Version 2 or later (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of those above. If
+ * you wish to allow use of your version of this file only under the terms of
+ * the GPL and not to allow others to use your version of this file under the
+ * MPL, indicate your decision by deleting the provisions above and replacing
+ * them with the notice and other provisions required by the GPL. If you do
+ * not delete the provisions above, a recipient may use your version of this
+ * file under either the MPL or the GPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package org.mozilla.javascript.tools.shell;
+
+import org.mozilla.javascript.Context;
+
+/**
+ * Defines action to perform in response to quit command.
+ */
+public interface QuitAction
+{
+ public void quit(Context cx, int exitCode);
+}
+
diff --git a/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/SecurityProxy.java b/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/SecurityProxy.java
new file mode 100644
index 0000000..8f029ea
--- /dev/null
+++ b/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/SecurityProxy.java
@@ -0,0 +1,48 @@
+/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Rhino code, released
+ * May 6, 1999.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1997-1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Igor Bukanov
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * the GNU General Public License Version 2 or later (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of those above. If
+ * you wish to allow use of your version of this file only under the terms of
+ * the GPL and not to allow others to use your version of this file under the
+ * MPL, indicate your decision by deleting the provisions above and replacing
+ * them with the notice and other provisions required by the GPL. If you do
+ * not delete the provisions above, a recipient may use your version of this
+ * file under either the MPL or the GPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package org.mozilla.javascript.tools.shell;
+
+import org.mozilla.javascript.*;
+
+public abstract class SecurityProxy extends SecurityController
+{
+ protected abstract void callProcessFileSecure(Context cx, Scriptable scope,
+ String filename);
+
+}
diff --git a/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/ShellContextFactory.java b/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/ShellContextFactory.java
new file mode 100644
index 0000000..ba7e62c
--- /dev/null
+++ b/trunk/infrastructure/rhino1_7R1/toolsrc/org/mozilla/javascript/tools/shell/ShellContextFactory.java
@@ -0,0 +1,114 @@
+/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Rhino code, released
+ * May 6, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1997-1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Igor Bukanov
+ * Bob Jervis
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * the GNU General Public License Version 2 or later (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of those above. If
+ * you wish to allow use of your version of this file only under the terms of
+ * the GPL and not to allow others to use your version of this file under the
+ * MPL, indicate your decision by deleting the provisions above and replacing
+ * them with the notice and other provisions required by the GPL. If you do
+ * not delete the provisions above, a recipient may use your version of this
+ * file under either the MPL or the GPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package org.mozilla.javascript.tools.shell;
+
+import org.mozilla.javascript.*;
+
+public class ShellContextFactory extends ContextFactory
+{
+ private boolean strictMode;
+ private boolean warningAsError;
+ private int languageVersion;
+ private int optimizationLevel;
+ private boolean generatingDebug;
+ private ErrorReporter errorReporter;
+
+ protected boolean hasFeature(Context cx, int featureIndex)
+ {
+ switch (featureIndex) {
+ case Context.FEATURE_STRICT_VARS:
+ case Context.FEATURE_STRICT_EVAL:
+ case Context.FEATURE_STRICT_MODE:
+ return strictMode;
+
+ case Context.FEATURE_WARNING_AS_ERROR:
+ return warningAsError;
+ }
+ return super.hasFeature(cx, featureIndex);
+ }
+
+ protected void onContextCreated(Context cx)
+ {
+ cx.setLanguageVersion(languageVersion);
+ cx.setOptimizationLevel(optimizationLevel);
+ if (errorReporter != null) {
+ cx.setErrorReporter(errorReporter);
+ }
+ cx.setGeneratingDebug(generatingDebug);
+ super.onContextCreated(cx);
+ }
+
+ public void setStrictMode(boolean flag)
+ {
+ checkNotSealed();
+ this.strictMode = flag;
+ }
+
+ public void setWarningAsError(boolean flag)
+ {
+ checkNotSealed();
+ this.warningAsError = flag;
+ }
+
+ public void setLanguageVersion(int version)
+ {
+ Context.checkLanguageVersion(version);
+ checkNotSealed();
+ this.languageVersion = version;
+ }
+
+ public void setOptimizationLevel(int optimizationLevel)
+ {
+ Context.checkOptimizationLevel(optimizationLevel);
+ checkNotSealed();
+ this.optimizationLevel = optimizationLevel;
+ }
+
+ public void setErrorReporter(ErrorReporter errorReporter)
+ {
+ if (errorReporter == null) throw new IllegalArgumentException();
+ this.errorReporter = errorReporter;
+ }
+
+ public void setGeneratingDebug(boolean generatingDebug)
+ {
+ this.generatingDebug = generatingDebug;
+ }
+}