Index: src/org/jruby/Main.java
===================================================================
RCS file: /cvsroot/jruby/jruby/src/org/jruby/Main.java,v
retrieving revision 1.36
diff -u -r1.36 Main.java
--- src/org/jruby/Main.java	8 Mar 2006 17:00:31 -0000	1.36
+++ src/org/jruby/Main.java	6 Apr 2006 09:56:25 -0000
@@ -16,7 +16,7 @@
  * Copyright (C) 2001-2004 Jan Arne Petersen <jpetersen@uni-bonn.de>
  * Copyright (C) 2002-2004 Anders Bengtsson <ndrsbngtssn@yahoo.se>
  * Copyright (C) 2004 Thomas E Enebo <enebo@acm.org>
- * Copyright (C) 2004-2005 Charles O Nutter <headius@headius.com>
+ * Copyright (C) 2004-2006 Charles O Nutter <headius@headius.com>
  * Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de>
  * Copyright (C) 2005 Kiel Hodges <jruby-devel@selfsosoft.com>
  * Copyright (C) 2005 Jason Voegele <jason@jvoegele.com>
@@ -36,6 +36,7 @@
  ***** END LICENSE BLOCK *****/
 package org.jruby;
 
+import java.io.InputStream;
 import java.io.PrintStream;
 import java.io.Reader;
 import java.util.Iterator;
@@ -61,17 +62,44 @@
  * @author  jpetersen
  */
 public class Main {
-    private static CommandlineParser commandline;
-    private static boolean hasPrintedUsage = false;
+    private CommandlineParser commandline;
+    private boolean hasPrintedUsage = false;
+    private InputStream in;
+    private PrintStream out;
+    private PrintStream err;
+    
+    public Main(InputStream in, PrintStream out, PrintStream err) {
+    	this.in = in;
+    	this.out = out;
+    	this.err = err;
+    }
+    
+    public Main() {
+    	this(System.in, System.out, System.err);
+    }
 
     public static void main(String[] args) {
-        commandline = new CommandlineParser(args, System.out);
+    	Main main = new Main();
+    	
+    	try {
+    		main.run(args);
+    	} catch (MainExitException mee) {
+    		main.err.println(mee.getMessage());
+    		if (mee.isUsageError()) {
+    			main.printUsage();
+    		}
+    		System.exit(mee.getStatus());
+    	}
+    }
+    
+    public int run(String[] args) {
+        commandline = new CommandlineParser(this, args);
 
         if (commandline.isShowVersion()) {
             showVersion();
         }
         if (! commandline.shouldRunInterpreter()) {
-            return;
+            return 0;
         }
 
         long now = -1;
@@ -82,39 +110,34 @@
         int status = runInterpreter(commandline.getScriptSource(), commandline.displayedFileName());
 
         if (commandline.isBenchmarking()) {
-            System.out.println("Runtime: " + (System.currentTimeMillis() - now) + " ms");
+            out.println("Runtime: " + (System.currentTimeMillis() - now) + " ms");
         }
         
-        // Only do an explicit exit if the interpreter has had an error.  We
-        // do not want to exit on non-errors since the interpreter may have
-        // started background threads (ala samples/swing2.rb)
-        if (status != 0) {
-        	System.exit(status);
-        }
+        return status;
     }
 
-    private static void showVersion() {
-        System.out.print("ruby ");
-        System.out.print(Constants.RUBY_VERSION);
-        System.out.print(" (");
-        System.out.print(Constants.COMPILE_DATE);
-        System.out.print(") [");
-        System.out.print("java");
-        System.out.println("]");
+    private void showVersion() {
+        out.print("ruby ");
+        out.print(Constants.RUBY_VERSION);
+        out.print(" (");
+        out.print(Constants.COMPILE_DATE);
+        out.print(") [");
+        out.print("java");
+        out.println("]");
     }
 
-    public static void printUsage(PrintStream printStream) {
+    public void printUsage() {
         if (!hasPrintedUsage) {
-			printStream.println("Usage: jruby [switches] [--] [rubyfile.rb] [arguments]");
-			printStream.println("    -e 'command'    one line of script. Several -e's allowed. Omit [programfile]");
-			printStream.println("    -b              benchmark mode, times the script execution");
-			printStream.println("    -Idirectory     specify $LOAD_PATH directory (may be used more than once)");
-			printStream.println("    --              optional -- before rubyfile.rb for compatibility with ruby");
+			out.println("Usage: jruby [switches] [--] [rubyfile.rb] [arguments]");
+			out.println("    -e 'command'    one line of script. Several -e's allowed. Omit [programfile]");
+			out.println("    -b              benchmark mode, times the script execution");
+			out.println("    -Idirectory     specify $LOAD_PATH directory (may be used more than once)");
+			out.println("    --              optional -- before rubyfile.rb for compatibility with ruby");
             hasPrintedUsage = true;
         }
     }
 
-    private static int runInterpreter(Reader reader, String filename) {
+    private int runInterpreter(Reader reader, String filename) {
         IRuby runtime = Ruby.getDefaultInstance();
 
         try {
@@ -145,7 +168,7 @@
         }
     }
     
-    private static void runInterpreter(IRuby runtime, Reader reader, String filename) {
+    private void runInterpreter(IRuby runtime, Reader reader, String filename) {
     	try {
     		initializeRuntime(runtime, filename);
     		Node parsedScript = getParsedScript(runtime, reader, filename);
@@ -156,7 +179,7 @@
     	}
     }
 
-    private static Node getParsedScript(IRuby runtime, Reader reader, String filename) {
+    private Node getParsedScript(IRuby runtime, Reader reader, String filename) {
         Node result = runtime.parse(reader, filename);
         if (commandline.isAssumePrinting()) {
             result = new ParserSupport().appendPrintToBlock(result);
@@ -167,7 +190,7 @@
         return result;
     }
 
-    private static void initializeRuntime(final IRuby runtime, String filename) {
+    private void initializeRuntime(final IRuby runtime, String filename) {
         IRubyObject argumentArray = runtime.newArray(JavaUtil.convertJavaArrayToRuby(runtime, commandline.getScriptArguments()));
         runtime.setVerbose(runtime.newBoolean(commandline.isVerbose()));
 
@@ -192,7 +215,7 @@
         }
     }
 
-    private static void defineGlobalVERBOSE(final IRuby runtime) {
+    private void defineGlobalVERBOSE(final IRuby runtime) {
         // $VERBOSE can be true, false, or nil.  Any non-false-nil value will get stored as true  
         runtime.getGlobalVariables().define("$VERBOSE", new IAccessor() {
             public IRubyObject getValue() {
@@ -211,7 +234,7 @@
         });
     }
 
-    private static void defineGlobal(IRuby runtime, String name, boolean value) {
+    private void defineGlobal(IRuby runtime, String name, boolean value) {
         runtime.getGlobalVariables().defineReadonly(name, new ValueAccessor(value ? runtime.getTrue() : runtime.getNil()));
     }
 
Index: src/org/jruby/RubyKernel.java
===================================================================
RCS file: /cvsroot/jruby/jruby/src/org/jruby/RubyKernel.java,v
retrieving revision 1.45
diff -u -r1.45 RubyKernel.java
--- src/org/jruby/RubyKernel.java	28 Mar 2006 03:06:16 -0000	1.45
+++ src/org/jruby/RubyKernel.java	6 Apr 2006 09:56:26 -0000
@@ -35,11 +35,14 @@
  ***** END LICENSE BLOCK *****/
 package org.jruby;
 
-import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.IOException;
-import java.io.InputStreamReader;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
 import java.util.Iterator;
+import java.util.List;
 import java.util.StringTokenizer;
 import java.util.regex.Pattern;
 
@@ -55,6 +58,7 @@
 import org.jruby.runtime.load.IAutoloadMethod;
 import org.jruby.runtime.load.LoadService;
 import org.jruby.util.PrintfFormat;
+import org.jruby.util.UnsynchronizedStack;
 
 /**
  * Note: For CVS history, see KernelModule.java.
@@ -683,10 +687,12 @@
     }
 
     public static IRubyObject backquote(IRubyObject recv, IRubyObject aString) {
-        StringBuffer output = new StringBuffer();
         IRuby runtime = recv.getRuntime();
-        runtime.getGlobalVariables().set("$?", runtime.newFixnum(
-            runInShell(runtime, aString.toString(), output)));
+        ByteArrayOutputStream output = new ByteArrayOutputStream();
+        
+        int resultCode = runInShell(runtime, new IRubyObject[] {aString}, output);
+        
+        recv.getRuntime().getGlobalVariables().set("$?", runtime.newFixnum(resultCode));
         
         return recv.getRuntime().newString(output.toString());
     }
@@ -702,93 +708,173 @@
      * @return The "fixed" full command line
      */
     private static String repairDirSeps(String command) {
-        // TODO: This could be improved and optimized
-        StringTokenizer toker = new StringTokenizer(command, " ");
-        StringBuffer executable = new StringBuffer();
-        
-        boolean insideQuotes = false;
-        char quoteChar = 0;
-        loop: while (true) {
-            String token = toker.nextToken();
+        String executable = "", remainder = "";
+        command = command.trim();
+        if (command.startsWith("'")) {
+            String [] tokens = command.split("'", 3);
+            executable = "'"+tokens[1]+"'";
+            if (tokens.length > 2)
+                remainder = tokens[2];
+        } else if (command.startsWith("\"")) {
+            String [] tokens = command.split("\"", 3);
+            executable = "\""+tokens[1]+"\"";
+            if (tokens.length > 2)
+                remainder = tokens[2];
+        } else {
+            String [] tokens = command.split(" ", 2);
+            executable = tokens[0];
+            if (tokens.length > 1)
+                remainder = " "+tokens[1];
+        }
+        
+        // Matcher.replaceAll treats backslashes in the replacement string as escaped characters
+        String replacement = File.separator;
+        if (File.separatorChar == '\\')
+            replacement = "\\\\";
             
-            if (!insideQuotes) {
-                char first = token.charAt(0);
-                switch (first) {
-                    case '"':
-                    case '\'':
-                        insideQuotes = true;
-                        quoteChar = first;
-                        executable.append(token + " ");
-                        break;
-                    default:
-                        executable.append(token);
-                        break loop;
+        return PATH_SEPARATORS.matcher(executable).replaceAll(replacement) + remainder;
+                }
+
+    private static List parseCommandLine(IRubyObject[] rawArgs) {
+        // first parse the first element of rawArgs since this may contain
+        // the whole command line
+        String command = rawArgs[0].toString();
+        UnsynchronizedStack args = new UnsynchronizedStack();
+        StringTokenizer st = new StringTokenizer(command, " ");
+        String quoteChar = null;
+
+        while (st.hasMoreTokens()) {
+            String token = st.nextToken();
+            if (quoteChar == null) {
+                // not currently in the middle of a quoted token
+                if (token.startsWith("'") || token.startsWith("\"")) {
+                    // note quote char and remove from beginning of token
+                    quoteChar = token.substring(0, 1);
+                    token = token.substring(1);
                 }
+                if (quoteChar!=null && token.endsWith(quoteChar)) {
+                    // quoted token self contained, remove from end of token
+                    token = token.substring(0, token.length()-1);
+                    quoteChar = null;
+                }
+                // add new token to list
+                args.push(token);
             } else {
-                char last = token.charAt(token.length() - 1);
-                executable.append(token);
-                if (last == quoteChar) {
-                    insideQuotes = false;
-                    break loop;
-                } else {
-                    executable.append(" ");
+                // in the middle of quoted token
+                if (token.endsWith(quoteChar)) {
+                    // end of quoted token
+                    token = token.substring(0, token.length()-1);
+                    quoteChar = null;
                 }
+                // update token at end of list
+                token = args.pop() + " " + token;
+                args.push(token);
             }
         }
         
-        String remainder = command.substring(executable.length());
+        // now append the remaining raw args to the cooked arg list
+        for (int i=1;i<rawArgs.length;i++) {
+            args.push(rawArgs[i].toString());
+        }
         
-        // Matcher.replaceAll treats backslashes in the replacement string as escaped characters
-        String replacement = File.separator;
-        if (File.separatorChar == '\\') replacement = "\\\\";
+        return args;
+    }
         
-        return PATH_SEPARATORS.matcher(executable).replaceAll(replacement) + remainder;
+    private static boolean isRubyCommand(String command) {
+        command = command.trim();
+        String [] spaceDelimitedTokens = command.split(" ", 2);
+        String [] slashDelimitedTokens = spaceDelimitedTokens[0].split("/");
+        String finalToken = slashDelimitedTokens[slashDelimitedTokens.length-1];
+        if (finalToken.contains("ruby") || finalToken.endsWith(".rb"))
+            return true;
+        else
+            return false;
     }
 
-    private static int runInShell(IRuby runtime, String command, StringBuffer output) {
+    private static int runInShell(IRuby runtime, IRubyObject[] rawArgs, OutputStream output) {
         try {
+            // startup scripts set jruby.shell to /bin/sh for Unix, cmd.exe for Windows
             String shell = System.getProperty("jruby.shell");
-            Process aProcess;
-            String shellSwitch = "-c";
+            rawArgs[0] = runtime.newString(repairDirSeps(rawArgs[0].toString()));
+            Process aProcess = null;
             
-            command = repairDirSeps(command);
+            if (isRubyCommand(rawArgs[0].toString())) {
+                final List args = parseCommandLine(rawArgs);
+                final PrintStream redirect = new PrintStream(output);
+                final String command = (String)args.get(0);
+                
+                Thread t = new Thread() {
+                    public void run() {
+                        try {
+                            String[] argArray = new String[args.size()-1];
+                            // snip off ruby or jruby command from list of arguments
+                            // leave alone if the command is the name of a script
+                            int startIndex = command.endsWith(".rb") ? 0 : 1;
+                            args.subList(startIndex,args.size()).toArray(argArray);
+                            
+                            // FIXME: Where should we get in and err from?
+                            new Main(System.in, redirect, redirect).run(argArray);
+                        } catch (Throwable t) {
+                        }
+                    }
+                };
+                
+                // execute ruby command in new thread
+                t.start();
+                t.join();
+            } else if (shell != null && rawArgs.length == 1) {
+                // execute command with sh -c or cmd.exe /c
+                // this does shell expansion of wildcards
+                String shellSwitch = shell.endsWith("sh") ? "-c" : "/c";
+                String[] argArray = new String[3];
+                argArray[0] = shell;
+                argArray[1] = shellSwitch;
+                argArray[2] = rawArgs[0].toString();
+                aProcess = Runtime.getRuntime().exec(argArray);
+            } else {
+                // execute command directly, no wildcard expansion
+                if (rawArgs.length > 1) {
+                    String[] argArray = new String[rawArgs.length];
+                    for (int i=0;i<rawArgs.length;i++) {
+                        argArray[i] = rawArgs[i].toString();
+                    }
+                    aProcess = Runtime.getRuntime().exec(argArray);
+                } else {
+                    aProcess = Runtime.getRuntime().exec(rawArgs[0].toString());
+                }
+            }
             
-            if (shell != null) {
-                if (!shell.endsWith("sh")) {
-                    shellSwitch = "/c";
+            if (aProcess != null) {
+                InputStream processOutput = aProcess.getInputStream();
+                
+                // Fairly innefficient impl, but readLine is unable to tell
+                // whether the last line in a process ended with a newline or not.
+                int b;
+                boolean crSeen = false;
+                while ((b = processOutput.read()) != -1) {
+                    if (b == '\r') {
+                        crSeen = true;
+                    } else {
+                        if (crSeen) {
+                            if (b != '\n') {
+                                output.write('\r');
+                            }
+                            crSeen = false;
+                        }
+                        output.write(b);
+                    }
+                }
+                if (crSeen) {
+                    output.write('\r');
                 }
-                aProcess = Runtime.getRuntime().exec(new String[] { shell, shellSwitch, command });
+                aProcess.getErrorStream().close();
+                aProcess.getOutputStream().close();
+                processOutput.close();
+                
+                return aProcess.waitFor();
             } else {
-                aProcess = Runtime.getRuntime().exec(command);
+                return 0;
             }
-
-            final BufferedReader reader = new BufferedReader(new InputStreamReader(aProcess.getInputStream()));
-
-            // Fairly innefficient impl, but readLine is unable to tell 
-            // whether the last line in a process ended with a newline or not.
-            int c;
-            boolean crSeen = false;
-            while ((c = reader.read()) != -1) {
-            	if (c == '\r') {
-            		crSeen = true;
-            	} else {
-            		if (crSeen) {
-            			if (c != '\n') {
-            				output.append('\r');
-            			}
-            			crSeen = false;
-            		}
-            		output.append((char)c);
-            	}
-            }
-            if (crSeen) {
-            	output.append('\r');
-            }
-            aProcess.getErrorStream().close();
-            aProcess.getOutputStream().close();
-            reader.close();
-            
-            return aProcess.waitFor();
         } catch (IOException e) {
             throw runtime.newIOErrorFromException(e);
         } catch (InterruptedException e) {
@@ -839,11 +925,8 @@
 
     public static RubyBoolean system(IRubyObject recv, IRubyObject[] args) {
         IRuby runtime = recv.getRuntime();
-        if (args.length > 1) {
-            throw runtime.newArgumentError("more arguments not yet supported");
-        }
-        StringBuffer output = new StringBuffer();
-        int resultCode = runInShell(runtime, args[0].toString(), output);
+        ByteArrayOutputStream output = new ByteArrayOutputStream();
+        int resultCode = runInShell(runtime, args, output);
         recv.getRuntime().getGlobalVariables().set("$?", runtime.newFixnum(resultCode));
         return runtime.newBoolean(resultCode == 0);
     }
Index: src/org/jruby/util/CommandlineParser.java
===================================================================
RCS file: /cvsroot/jruby/jruby/src/org/jruby/util/CommandlineParser.java,v
retrieving revision 1.14
diff -u -r1.14 CommandlineParser.java
--- src/org/jruby/util/CommandlineParser.java	24 Dec 2005 12:00:24 -0000	1.14
+++ src/org/jruby/util/CommandlineParser.java	6 Apr 2006 09:56:26 -0000
@@ -16,6 +16,7 @@
  * Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de>
  * Copyright (C) 2005 Jason Voegele <jason@jvoegele.com>
  * Copyright (C) 2005 Tim Azzopardi <tim@tigerfive.com>
+ * Copyright (C) 2006 Charles O Nutter <headius@headius.com>
  * 
  * Alternatively, the contents of this file may be used under the terms of
  * either of the GNU General Public License Version 2 or later (the "GPL"),
@@ -36,16 +37,17 @@
 import java.io.FileReader;
 import java.io.IOException;
 import java.io.InputStreamReader;
-import java.io.PrintStream;
 import java.io.Reader;
 import java.io.StringReader;
 import java.util.ArrayList;
 import java.util.List;
 
 import org.jruby.Main;
+import org.jruby.MainExitException;
 
 public class CommandlineParser {
     private final String[] arguments;
+    private Main main;
 
     private ArrayList loadPaths = new ArrayList();
     private StringBuffer inlineScript = new StringBuffer();
@@ -64,11 +66,9 @@
     public int argumentIndex = 0;
     public int characterIndex = 0;
 
-	private final PrintStream outStream;
-
-    public CommandlineParser(String[] arguments, PrintStream outStream) {
+    public CommandlineParser(Main main, String[] arguments) {
         this.arguments = arguments;
-        this.outStream = outStream;
+        this.main = main;
         processArguments();
     }
 
@@ -97,7 +97,7 @@
         FOR : for (characterIndex = 1; characterIndex < argument.length(); characterIndex++) {
             switch (argument.charAt(characterIndex)) {
                 case 'h' :
-                    Main.printUsage(outStream);
+                    main.printUsage();
                     shouldRunInterpreter = false;
                     break;
                 case 'I' :
@@ -145,20 +145,11 @@
                         }                    	
                     }
                 default :
-                    System.err.println("unknown option " + argument.charAt(characterIndex));
-                    systemExit();
+                    throw new MainExitException(1, "unknown option " + argument.charAt(characterIndex));
             }
         }
     }
 
-    /**
-     * Perform system.exit().
-     * This method exists so that unit tests can override it.
-     */
-    protected void systemExit() {
-      System.exit(1);
-    }
-
     private String grabValue(String errorMessage) {
         characterIndex++;
         if (characterIndex < arguments[argumentIndex].length()) {
@@ -168,11 +159,11 @@
         if (argumentIndex < arguments.length) {
             return arguments[argumentIndex];
         }
-		System.err.println("invalid argument " + argumentIndex);
-		System.err.println(errorMessage);
-		Main.printUsage(outStream);
-		systemExit();
-        return null;
+		
+		MainExitException mee = new MainExitException(1, "invalid argument " + argumentIndex + "\n" + errorMessage);
+		mee.setUsageError(true);
+		
+		throw mee;
     }
 
     public boolean hasInlineScript() {
@@ -209,12 +200,9 @@
             try {
                 return new BufferedReader(new FileReader(file));
             } catch (IOException e) {
-                System.err.println("Error opening script file: " + e.getMessage());
-                systemExit();
+            	throw new MainExitException(1, "Error opening script file: " + e.getMessage());
             }
         }
-        assert false;
-        return null;
     }
 
     public String displayedFileName() {
Index: test/org/jruby/test/TestCommandlineParser.java
===================================================================
RCS file: /cvsroot/jruby/jruby/test/org/jruby/test/TestCommandlineParser.java,v
retrieving revision 1.7
diff -u -r1.7 TestCommandlineParser.java
--- test/org/jruby/test/TestCommandlineParser.java	24 Dec 2005 12:00:24 -0000	1.7
+++ test/org/jruby/test/TestCommandlineParser.java	6 Apr 2006 09:56:26 -0000
@@ -14,6 +14,7 @@
  * Copyright (C) 2002 Anders Bengtsson <ndrsbngtssn@yahoo.se>
  * Copyright (C) 2005 Jason Voegele <jason@jvoegele.com>
  * Copyright (C) 2005 Tim Azzopardi <tim@tigerfive.com>
+ * Copyright (C) 2006 Charles O Nutter <headius@headius.com>
  * 
  * Alternatively, the contents of this file may be used under the terms of
  * either of the GNU General Public License Version 2 or later (the "GPL"),
@@ -34,29 +35,32 @@
 
 import junit.framework.TestCase;
 
+import org.jruby.Main;
 import org.jruby.util.CommandlineParser;
 
 public class TestCommandlineParser extends TestCase {
-	private PrintStream outStream;
+	private PrintStream out;
+	private PrintStream err;
 
 	public void setUp() {
-		outStream = new PrintStream(new ByteArrayOutputStream());
+		out = new PrintStream(new ByteArrayOutputStream());
+		err = new PrintStream(new ByteArrayOutputStream());
 	}
     public void testParsing() {
-        CommandlineParser c = new CommandlineParser(new String[] { "-e", "hello", "-e", "world" }, outStream);
+        CommandlineParser c = new CommandlineParser(new Main(System.in, out, err), new String[] { "-e", "hello", "-e", "world" });
         assertEquals("hello\nworld\n", c.inlineScript());
         assertNull(c.getScriptFileName());
         assertEquals("-e", c.displayedFileName());
 
-        c = new CommandlineParser(new String[] { "--version" }, outStream);
+        c = new CommandlineParser(new Main(System.in, out, err), new String[] { "--version" });
         assertTrue(c.isShowVersion());
 
-        c = new CommandlineParser(new String[] { "-n", "myfile.rb" }, outStream);
+        c = new CommandlineParser(new Main(System.in, out, err), new String[] { "-n", "myfile.rb" });
         assertTrue(c.isAssumeLoop());
         assertEquals("myfile.rb", c.getScriptFileName());
         assertEquals("myfile.rb", c.displayedFileName());
 
-        c = new CommandlineParser(new String[0], outStream);
+        c = new CommandlineParser(new Main(System.in, out, err), new String[0]);
         assertEquals("-", c.displayedFileName());
     }
 
@@ -66,12 +70,7 @@
       class TestableCommandlineParser extends CommandlineParser {
 
         public TestableCommandlineParser(String[] arguments) {
-          super(arguments, outStream);
-        }
-        
-        protected void systemExit() {
-          throw new IllegalStateException("Real CommandlineParser would perform " +
-              "System.exit() because of a command line option error.");
+          super(new Main(System.in, out, err), arguments);
         }
       }      
       CommandlineParser c = new TestableCommandlineParser(new String[] { "-I", "someLoadPath", "--", "simple.rb", "-v", "--version" });
@@ -86,19 +85,19 @@
     
     public void testPrintVersionDoesNotRunInterpreter() {
         String[] args = new String[] { "-v" };
-        CommandlineParser parser = new CommandlineParser(args, outStream);
+        CommandlineParser parser = new CommandlineParser(new Main(System.in, out, err), args);
         assertTrue(parser.isShowVersion());
         assertFalse(parser.isShouldRunInterpreter());
 
         args = new String[] { "--version" };
-        parser = new CommandlineParser(args, outStream);
+        parser = new CommandlineParser(new Main(System.in, out, err), args);
         assertTrue(parser.isShowVersion());
         assertFalse(parser.isShouldRunInterpreter());
     }
     
     public void testHelpDoesNotRunIntepreter() {
         String[] args = new String[] { "-h" };
-        CommandlineParser parser = new CommandlineParser(args, outStream);
+        CommandlineParser parser = new CommandlineParser(new Main(System.in, out, err), args);
         assertFalse(parser.isShouldRunInterpreter());
     	
     }
Index: src/org/jruby/MainExitException.java
===================================================================
RCS file: src/org/jruby/MainExitException.java
diff -N src/org/jruby/MainExitException.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/org/jruby/MainExitException.java	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,55 @@
+/***** BEGIN LICENSE BLOCK *****
+ * Version: CPL 1.0/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Common Public
+ * License Version 1.0 (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.eclipse.org/legal/cpl-v10.html
+ *
+ * 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.
+ * Copyright (C) 2006 Charles O Nutter <headius@headius.com>
+ *  
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the CPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the CPL, the GPL or the LGPL.
+ ***** END LICENSE BLOCK *****/
+package org.jruby;
+
+public class MainExitException extends RuntimeException {
+	private static final long serialVersionUID = -8585821821150293755L;
+	boolean usageError;
+	int status;
+	
+	public MainExitException(int status, String message) {
+		super(message);
+		
+		this.status = status;
+	}
+
+	public int getStatus() {
+		return status;
+	}
+
+	public void setStatus(int status) {
+		this.status = status;
+	}
+
+	public boolean isUsageError() {
+		return usageError;
+	}
+
+	public void setUsageError(boolean usageError) {
+		this.usageError = usageError;
+	}
+}
