Make sure that the classcache gets reset if someone changes the loader for RubyInstan...
[jruby.git] / src / org / jruby / RubyInstanceConfig.java
blobd6e87747527c1ec738bc83a34aca260b0edcc7d6
1 /***** BEGIN LICENSE BLOCK *****
2 * Version: CPL 1.0/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Common Public
5 * License Version 1.0 (the "License"); you may not use this file
6 * except in compliance with the License. You may obtain a copy of
7 * the License at http://www.eclipse.org/legal/cpl-v10.html
9 * Software distributed under the License is distributed on an "AS
10 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
11 * implied. See the License for the specific language governing
12 * rights and limitations under the License.
14 * Copyright (C) 2007 Nick Sieger <nicksieger@gmail.com>
16 * Alternatively, the contents of this file may be used under the terms of
17 * either of the GNU General Public License Version 2 or later (the "GPL"),
18 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
19 * in which case the provisions of the GPL or the LGPL are applicable instead
20 * of those above. If you wish to allow use of your version of this file only
21 * under the terms of either the GPL or the LGPL, and not to allow others to
22 * use your version of this file under the terms of the CPL, indicate your
23 * decision by deleting the provisions above and replace them with the notice
24 * and other provisions required by the GPL or the LGPL. If you do not delete
25 * the provisions above, a recipient may use your version of this file under
26 * the terms of any one of the CPL, the GPL or the LGPL.
27 ***** END LICENSE BLOCK *****/
28 package org.jruby;
30 import java.io.ByteArrayInputStream;
31 import java.io.File;
32 import java.io.FileInputStream;
33 import java.io.IOException;
34 import java.io.InputStream;
35 import java.io.PrintStream;
36 import java.io.UnsupportedEncodingException;
37 import java.util.ArrayList;
38 import java.util.List;
39 import java.util.Map;
40 import org.jruby.ast.executable.Script;
41 import org.jruby.exceptions.MainExitException;
42 import org.jruby.runtime.Constants;
43 import org.jruby.runtime.load.LoadService;
44 import org.jruby.util.ClassCache;
45 import org.jruby.util.JRubyFile;
46 import org.jruby.util.KCode;
47 import org.jruby.util.SafePropertyAccessor;
49 public class RubyInstanceConfig {
51 public enum CompileMode {
52 JIT, FORCE, OFF;
54 public boolean shouldPrecompileCLI() {
55 switch (this) {
56 case JIT: case FORCE:
57 return true;
59 return false;
62 public boolean shouldJIT() {
63 switch (this) {
64 case JIT: case FORCE:
65 return true;
67 return false;
70 public boolean shouldPrecompileAll() {
71 return this == FORCE;
74 private InputStream input = System.in;
75 private PrintStream output = System.out;
76 private PrintStream error = System.err;
77 private Profile profile = Profile.DEFAULT;
78 private boolean objectSpaceEnabled
79 = SafePropertyAccessor.getBoolean("jruby.objectspace.enabled", false);
81 private CompileMode compileMode = CompileMode.JIT;
82 private boolean runRubyInProcess = true;
83 private String currentDirectory;
84 private Map environment;
85 private String[] argv = {};
87 private final boolean jitLogging;
88 private final boolean jitLoggingVerbose;
89 private final int jitLogEvery;
90 private final int jitThreshold;
91 private final int jitMax;
92 private final boolean samplingEnabled;
93 private CompatVersion compatVersion;
95 private ClassLoader loader = Thread.currentThread().getContextClassLoader();
97 private ClassCache<Script> classCache;
99 // from CommandlineParser
100 private List<String> loadPaths = new ArrayList<String>();
101 private StringBuffer inlineScript = new StringBuffer();
102 private boolean hasInlineScript = false;
103 private String scriptFileName = null;
104 private List<String> requiredLibraries = new ArrayList<String>();
105 private boolean benchmarking = false;
106 private boolean assumeLoop = false;
107 private boolean assumePrinting = false;
108 private boolean processLineEnds = false;
109 private boolean split = false;
110 // This property is a Boolean, to allow three values, so it can match MRI's nil, false and true
111 private Boolean verbose = Boolean.FALSE;
112 private boolean debug = false;
113 private boolean showVersion = false;
114 private boolean showCopyright = false;
115 private boolean endOfArguments = false;
116 private boolean shouldRunInterpreter = true;
117 private boolean shouldPrintUsage = false;
118 private boolean shouldPrintProperties=false;
119 private boolean yarv = false;
120 private boolean rubinius = false;
121 private boolean yarvCompile = false;
122 private KCode kcode = KCode.NONE;
123 private String recordSeparator = "\n";
124 private boolean shouldCheckSyntax = false;
125 private String inputFieldSeparator = null;
127 private int safeLevel = 0;
129 public static final boolean FASTEST_COMPILE_ENABLED
130 = SafePropertyAccessor.getBoolean("jruby.compile.fastest");
131 public static final boolean BOXED_COMPILE_ENABLED
132 = FASTEST_COMPILE_ENABLED
133 || SafePropertyAccessor.getBoolean("jruby.compile.boxed");
134 public static final boolean FASTOPS_COMPILE_ENABLED
135 = FASTEST_COMPILE_ENABLED
136 || SafePropertyAccessor.getBoolean("jruby.compile.fastops");
137 public static final boolean FRAMELESS_COMPILE_ENABLED
138 = FASTEST_COMPILE_ENABLED
139 || SafePropertyAccessor.getBoolean("jruby.compile.frameless");
140 public static final boolean POSITIONLESS_COMPILE_ENABLED
141 = FASTEST_COMPILE_ENABLED
142 || SafePropertyAccessor.getBoolean("jruby.compile.positionless");
143 public static final boolean THREADLESS_COMPILE_ENABLED
144 = FASTEST_COMPILE_ENABLED
145 || SafePropertyAccessor.getBoolean("jruby.compile.threadless");
146 public static final boolean INDEXED_METHODS
147 = SafePropertyAccessor.getBoolean("jruby.indexed.methods");
148 public static final boolean FORK_ENABLED
149 = SafePropertyAccessor.getBoolean("jruby.fork.enabled");
150 public static boolean nativeEnabled = true;
152 public static interface LoadServiceCreator {
153 LoadService create(Ruby runtime);
155 LoadServiceCreator DEFAULT = new LoadServiceCreator() {
156 public LoadService create(Ruby runtime) {
157 return new LoadService(runtime);
162 private LoadServiceCreator creator = LoadServiceCreator.DEFAULT;
165 static {
166 try {
167 if (System.getProperty("jruby.native.enabled") != null) {
168 nativeEnabled = Boolean.getBoolean("jruby.native.enabled");
170 } catch (SecurityException se) {
171 nativeEnabled = false;
175 public int characterIndex = 0;
177 public RubyInstanceConfig() {
178 if (Ruby.isSecurityRestricted())
179 currentDirectory = "/";
180 else {
181 currentDirectory = JRubyFile.getFileProperty("user.dir");
184 samplingEnabled = SafePropertyAccessor.getBoolean("jruby.sampling.enabled", false);
185 String compatString = SafePropertyAccessor.getProperty("jruby.compat.version", "RUBY1_8");
186 if (compatString.equalsIgnoreCase("RUBY1_8")) {
187 compatVersion = CompatVersion.RUBY1_8;
188 } else if (compatString.equalsIgnoreCase("RUBY1_9")) {
189 compatVersion = CompatVersion.RUBY1_9;
190 } else {
191 System.err.println("Compatibility version `" + compatString + "' invalid; use RUBY1_8 or RUBY1_9. Using RUBY1_8.");
192 compatVersion = CompatVersion.RUBY1_8;
195 if (Ruby.isSecurityRestricted()) {
196 compileMode = CompileMode.OFF;
197 jitLogging = false;
198 jitLoggingVerbose = false;
199 jitLogEvery = 0;
200 jitThreshold = -1;
201 jitMax = 0;
202 } else {
203 String threshold = SafePropertyAccessor.getProperty("jruby.jit.threshold");
204 String max = SafePropertyAccessor.getProperty("jruby.jit.max");
206 runRubyInProcess = SafePropertyAccessor.getBoolean("jruby.launch.inproc", true);
207 boolean jitProperty = SafePropertyAccessor.getProperty("jruby.jit.enabled") != null;
208 if (jitProperty) {
209 error.print("jruby.jit.enabled property is deprecated; use jruby.compile.mode=(OFF|JIT|FORCE) for -C, default, and +C flags");
210 compileMode = SafePropertyAccessor.getBoolean("jruby.jit.enabled") ? CompileMode.JIT : CompileMode.OFF;
211 } else {
212 String jitModeProperty = SafePropertyAccessor.getProperty("jruby.compile.mode", "JIT");
214 if (jitModeProperty.equals("OFF")) {
215 compileMode = CompileMode.OFF;
216 } else if (jitModeProperty.equals("JIT")) {
217 compileMode = CompileMode.JIT;
218 } else if (jitModeProperty.equals("FORCE")) {
219 compileMode = CompileMode.FORCE;
220 } else {
221 error.print("jruby.compile.mode property must be OFF, JIT, FORCE, or unset; defaulting to JIT");
222 compileMode = CompileMode.JIT;
225 jitLogging = SafePropertyAccessor.getBoolean("jruby.jit.logging");
226 jitLoggingVerbose = SafePropertyAccessor.getBoolean("jruby.jit.logging.verbose");
227 String logEvery = SafePropertyAccessor.getProperty("jruby.jit.logEvery");
228 jitLogEvery = logEvery == null ? 0 : Integer.parseInt(logEvery);
229 jitThreshold = threshold == null ? 20 : Integer.parseInt(threshold);
230 jitMax = max == null ? 2048 : Integer.parseInt(max);
233 // default ClassCache using jitMax as a soft upper bound
234 classCache = new ClassCache<Script>(loader, jitMax);
236 if (FORK_ENABLED) {
237 error.print("WARNING: fork is highly unlikely to be safe or stable on the JVM. Have fun!\n");
241 public LoadServiceCreator getLoadServiceCreator() {
242 return creator;
245 public void setLoadServiceCreator(LoadServiceCreator creator) {
246 this.creator = creator;
249 public LoadService createLoadService(Ruby runtime) {
250 return this.creator.create(runtime);
253 public String getBasicUsageHelp() {
254 StringBuffer sb = new StringBuffer();
256 .append("Usage: jruby [switches] [--] [programfile] [arguments]\n")
257 .append(" -0[octal] specify record separator (\0, if no argument)\n")
258 .append(" -a autosplit mode with -n or -p (splits $_ into $F)\n")
259 .append(" -b benchmark mode, times the script execution\n")
260 .append(" -c check syntax only\n")
261 .append(" -Cdirectory cd to directory, before executing your script\n")
262 .append(" -d set debugging flags (set $DEBUG to true)\n")
263 .append(" -e 'command' one line of script. Several -e's allowed. Omit [programfile]\n")
264 .append(" -Fpattern split() pattern for autosplit (-a)\n")
265 //.append(" -i[extension] edit ARGV files in place (make backup if extension supplied)\n")
266 .append(" -Idirectory specify $LOAD_PATH directory (may be used more than once)\n")
267 .append(" -J[java option] pass an option on to the JVM (e.g. -J-Xmx512m)\n")
268 .append(" use --properties to list JRuby properties\n")
269 .append(" -Kkcode specifies KANJI (Japanese) code-set\n")
270 .append(" -l enable line ending processing\n")
271 .append(" -n assume 'while gets(); ... end' loop around your script\n")
272 .append(" -p assume loop like -n but print line also like sed\n")
273 .append(" -rlibrary require the library, before executing your script\n")
274 //.append(" -s enable some switch parsing for switches after script name\n")
275 .append(" -S look for the script in bin or using PATH environment variable\n")
276 .append(" -T[level] turn on tainting checks\n")
277 .append(" -v print version number, then turn on verbose mode\n")
278 .append(" -w turn warnings on for your script\n")
279 .append(" -W[level] set warning level; 0=silence, 1=medium, 2=verbose (default)\n")
280 //.append(" -x[directory] strip off text before #!ruby line and perhaps cd to directory\n")
281 .append(" -X[option] enable extended option (omit option to list)\n")
282 .append(" --copyright print the copyright\n")
283 .append(" --properties List all configuration Java properties (pass -J-Dproperty=value)\n")
284 .append(" --version print the version\n");
286 return sb.toString();
289 public String getExtendedHelp() {
290 StringBuffer sb = new StringBuffer();
292 .append("These flags are for extended JRuby options.\n")
293 .append("Specify them by passing -X<option>\n")
294 .append(" -O run with ObjectSpace disabled (default; improves performance)\n")
295 .append(" +O run with ObjectSpace enabled (reduces performance)\n")
296 .append(" -C disable all compilation\n")
297 .append(" +C force compilation of all scripts before they are run (except eval)\n")
298 .append(" -y read a YARV-compiled Ruby script and run that (EXPERIMENTAL)\n")
299 .append(" -Y compile a Ruby script into YARV bytecodes and run this (EXPERIMENTAL)\n")
300 .append(" -R read a Rubinius-compiled Ruby script and run that (EXPERIMENTAL)");
302 return sb.toString();
305 public String getPropertyHelp() {
306 StringBuffer sb = new StringBuffer();
308 .append("These properties can be used to alter runtime behavior for perf or compatibility.\n")
309 .append("Specify them by passing -J-D<property>=<value>\n")
310 .append("\nCOMPILER SETTINGS:\n")
311 .append(" jruby.compile.mode=JIT|FORCE|OFF\n")
312 .append(" Set compilation mode. JIT is default; FORCE compiles all, OFF disables\n")
313 .append(" jruby.compile.fastest=true|false\n")
314 .append(" (EXPERIMENTAL) Turn on all experimental compiler optimizations\n")
315 .append(" jruby.compile.boxed=true|false\n")
316 .append(" (EXPERIMENTAL) Use boxed variables; this can speed up some methods. Default is false\n")
317 .append(" jruby.compile.frameless=true|false\n")
318 .append(" (EXPERIMENTAL) Turn on frameless compilation where possible\n")
319 .append(" jruby.compile.positionless=true|false\n")
320 .append(" (EXPERIMENTAL) Turn on compilation that avoids updating Ruby position info. Default is false\n")
321 .append(" jruby.compile.threadless=true|false\n")
322 .append(" (EXPERIMENTAL) Turn on compilation without polling for \"unsafe\" thread events. Default is false\n")
323 .append(" jruby.compile.fastops=true|false\n")
324 .append(" (EXPERIMENTAL) Turn on fast operators for Fixnum. Default is false\n")
325 .append("\nJIT SETTINGS:\n")
326 .append(" jruby.jit.threshold=<invocation count>\n")
327 .append(" Set the JIT threshold to the specified method invocation count. Default is 20\n")
328 .append(" jruby.jit.max=<method count>\n")
329 .append(" Set the max count of active methods eligible for JIT-compilation.\n")
330 .append(" Default is 2048 per runtime. A value of 0 disables JIT, -1 disables max.\n")
331 .append(" jruby.jit.logging=true|false\n")
332 .append(" Enable JIT logging (reports successful compilation). Default is false\n")
333 .append(" jruby.jit.logging.verbose=true|false\n")
334 .append(" Enable verbose JIT logging (reports failed compilation). Default is false\n")
335 .append(" jruby.jit.logEvery=<method count>\n")
336 .append(" Log a message every n methods JIT compiled. Default is 0 (off).\n")
337 .append("\nNATIVE SUPPORT:\n")
338 .append(" jruby.native.enabled=true|false\n")
339 .append(" Enable/disable native extensions (like JNA for non-Java APIs; Default is true\n")
340 .append(" (This affects all JRuby instances in a given JVM)\n")
341 .append(" jruby.native.verbose=true|false\n")
342 .append(" Enable verbose logging of native extension loading. Default is false.\n")
343 .append(" jruby.fork.enabled=true|false\n")
344 .append(" (EXPERIMENTAL, maybe dangerous) Enable fork(2) on platforms that support it.\n")
345 .append("\nMISCELLANY:\n")
346 .append(" jruby.compat.version=RUBY1_8|RUBY1_9\n")
347 .append(" Specify the major Ruby version to be compatible with; Default is RUBY1_8\n")
348 .append(" jruby.indexed.methods=true|false\n")
349 .append(" Generate \"invokers\" for core classes using a single indexed class\n")
350 .append(" jruby.objectspace.enabled=true|false\n")
351 .append(" Enable or disable ObjectSpace.each_object (default is disabled)\n")
352 .append(" jruby.launch.inproc=true|false\n")
353 .append(" Set in-process launching of e.g. system('ruby ...'). Default is true\n");
355 return sb.toString();
358 public String getVersionString() {
359 StringBuffer buf = new StringBuffer("ruby ");
360 switch (compatVersion) {
361 case RUBY1_8:
362 buf.append(Constants.RUBY_VERSION);
363 break;
364 case RUBY1_9:
365 buf.append(Constants.RUBY1_9_VERSION);
366 break;
369 .append(" (")
370 .append(Constants.COMPILE_DATE + " rev " + Constants.REVISION)
371 .append(") [")
372 .append(SafePropertyAccessor.getProperty("os.arch", "unknown") + "-jruby" + Constants.VERSION)
373 .append("]")
374 .append("\n");
376 return buf.toString();
379 public String getCopyrightString() {
380 return "JRuby - Copyright (C) 2001-2008 The JRuby Community (and contribs)\n";
383 public void processArguments(String[] arguments) {
384 new ArgumentProcessor(arguments).processArguments();
387 public CompileMode getCompileMode() {
388 return compileMode;
391 public void setCompileMode(CompileMode compileMode) {
392 this.compileMode = compileMode;
395 public boolean isJitLogging() {
396 return jitLogging;
399 public boolean isJitLoggingVerbose() {
400 return jitLoggingVerbose;
403 public int getJitLogEvery() {
404 return jitLogEvery;
407 public boolean isSamplingEnabled() {
408 return samplingEnabled;
411 public int getJitThreshold() {
412 return jitThreshold;
415 public int getJitMax() {
416 return jitMax;
419 public boolean isRunRubyInProcess() {
420 return runRubyInProcess;
423 public void setRunRubyInProcess(boolean flag) {
424 this.runRubyInProcess = flag;
427 public void setInput(InputStream newInput) {
428 input = newInput;
431 public InputStream getInput() {
432 return input;
435 public CompatVersion getCompatVersion() {
436 return compatVersion;
439 public void setOutput(PrintStream newOutput) {
440 output = newOutput;
443 public PrintStream getOutput() {
444 return output;
447 public void setError(PrintStream newError) {
448 error = newError;
451 public PrintStream getError() {
452 return error;
455 public void setCurrentDirectory(String newCurrentDirectory) {
456 currentDirectory = newCurrentDirectory;
459 public String getCurrentDirectory() {
460 return currentDirectory;
463 public void setProfile(Profile newProfile) {
464 profile = newProfile;
467 public Profile getProfile() {
468 return profile;
471 public void setObjectSpaceEnabled(boolean newObjectSpaceEnabled) {
472 objectSpaceEnabled = newObjectSpaceEnabled;
475 public boolean isObjectSpaceEnabled() {
476 return objectSpaceEnabled;
479 public void setEnvironment(Map newEnvironment) {
480 environment = newEnvironment;
483 public Map getEnvironment() {
484 return environment;
487 public ClassLoader getLoader() {
488 return loader;
491 public void setLoader(ClassLoader loader) {
492 // Setting the loader needs to reset the class cache
493 if(this.loader != loader) {
494 this.classCache = new ClassCache<Script>(loader, this.classCache.getMax());
496 this.loader = loader;
499 public String[] getArgv() {
500 return argv;
503 public void setArgv(String[] argv) {
504 this.argv = argv;
507 private class ArgumentProcessor {
508 private String[] arguments;
509 private int argumentIndex = 0;
511 public ArgumentProcessor(String[] arguments) {
512 this.arguments = arguments;
515 public void processArguments() {
516 while (argumentIndex < arguments.length && isInterpreterArgument(arguments[argumentIndex])) {
517 processArgument();
518 argumentIndex++;
521 if (!hasInlineScript) {
522 if (argumentIndex < arguments.length) {
523 setScriptFileName(arguments[argumentIndex]); //consume the file name
524 argumentIndex++;
529 // Remaining arguments are for the script itself
530 argv = new String[arguments.length - argumentIndex];
531 System.arraycopy(arguments, argumentIndex, argv, 0, argv.length);
534 private boolean isInterpreterArgument(String argument) {
535 return (argument.charAt(0) == '-' || argument.charAt(0) == '+') && !endOfArguments;
538 private String getArgumentError(String argument, String additionalError) {
539 return "jruby: invalid argument " + argument + "\n" + additionalError + "\n";
542 private String getArgumentError(String additionalError) {
543 return "jruby: invalid argument\n" + additionalError + "\n";
546 private void processArgument() {
547 String argument = arguments[argumentIndex];
548 FOR : for (characterIndex = 1; characterIndex < argument.length(); characterIndex++) {
549 switch (argument.charAt(characterIndex)) {
550 case '0': {
551 String temp = grabOptionalValue();
552 if (null == temp) {
553 recordSeparator = "\u0000";
554 } else if (temp.equals("0")) {
555 recordSeparator = "\n\n";
556 } else if (temp.equals("777")) {
557 recordSeparator = "\uFFFF"; // Specify something that can't separate
558 } else {
559 try {
560 int val = Integer.parseInt(temp, 8);
561 recordSeparator = "" + (char) val;
562 } catch (Exception e) {
563 MainExitException mee = new MainExitException(1, getArgumentError(" -0 must be followed by either 0, 777, or a valid octal value"));
564 mee.setUsageError(true);
565 throw mee;
568 break FOR;
570 case 'a':
571 split = true;
572 break;
573 case 'b':
574 benchmarking = true;
575 break;
576 case 'c':
577 shouldCheckSyntax = true;
578 break;
579 case 'C':
580 try {
581 String saved = grabValue(getArgumentError(" -C must be followed by a directory expression"));
582 File base = new File(currentDirectory);
583 File newDir = new File(saved);
584 if (newDir.isAbsolute()) {
585 currentDirectory = newDir.getCanonicalPath();
586 } else {
587 currentDirectory = new File(base, newDir.getPath()).getCanonicalPath();
589 if (!(new File(currentDirectory).isDirectory())) {
590 MainExitException mee = new MainExitException(1, "jruby: Can't chdir to " + saved + " (fatal)");
591 mee.setUsageError(true);
592 throw mee;
594 } catch (IOException e) {
595 MainExitException mee = new MainExitException(1, getArgumentError(" -C must be followed by a valid directory"));
596 mee.setUsageError(true);
597 throw mee;
599 break;
600 case 'd':
601 debug = true;
602 verbose = Boolean.TRUE;
603 break;
604 case 'e':
605 inlineScript.append(grabValue(getArgumentError(" -e must be followed by an expression to evaluate")));
606 inlineScript.append('\n');
607 hasInlineScript = true;
608 break FOR;
609 case 'F':
610 inputFieldSeparator = grabValue(getArgumentError(" -F must be followed by a pattern for input field separation"));
611 break;
612 case 'h':
613 shouldPrintUsage = true;
614 shouldRunInterpreter = false;
615 break;
616 // FIXME: -i flag not supported
617 // case 'i' :
618 // break;
619 case 'I':
620 String s = grabValue(getArgumentError("-I must be followed by a directory name to add to lib path"));
621 String[] ls = s.split(java.io.File.pathSeparator);
622 for (int i = 0; i < ls.length; i++) {
623 loadPaths.add(ls[i]);
625 break FOR;
626 case 'K':
627 // FIXME: No argument seems to work for -K in MRI plus this should not
628 // siphon off additional args 'jruby -K ~/scripts/foo'. Also better error
629 // processing.
630 String eArg = grabValue(getArgumentError("provide a value for -K"));
631 kcode = KCode.create(null, eArg);
632 break;
633 case 'l':
634 processLineEnds = true;
635 break;
636 case 'n':
637 assumeLoop = true;
638 break;
639 case 'p':
640 assumePrinting = true;
641 assumeLoop = true;
642 break;
643 case 'r':
644 requiredLibraries.add(grabValue(getArgumentError("-r must be followed by a package to require")));
645 break FOR;
646 // FIXME: -s flag not supported
647 // case 's' :
648 // break;
649 case 'S':
650 runBinScript();
651 break FOR;
652 case 'T' :{
653 String temp = grabOptionalValue();
654 int value = 1;
656 if(temp!=null) {
657 try {
658 value = Integer.parseInt(temp, 8);
659 } catch(Exception e) {
660 value = 1;
664 safeLevel = value;
666 break FOR;
668 case 'v':
669 verbose = Boolean.TRUE;
670 setShowVersion(true);
671 break;
672 case 'w':
673 verbose = Boolean.TRUE;
674 break;
675 case 'W': {
676 String temp = grabOptionalValue();
677 int value = 2;
678 if (null != temp) {
679 if (temp.equals("2")) {
680 value = 2;
681 } else if (temp.equals("1")) {
682 value = 1;
683 } else if (temp.equals("0")) {
684 value = 0;
685 } else {
686 MainExitException mee = new MainExitException(1, getArgumentError(" -W must be followed by either 0, 1, 2 or nothing"));
687 mee.setUsageError(true);
688 throw mee;
691 switch (value) {
692 case 0:
693 verbose = null;
694 break;
695 case 1:
696 verbose = Boolean.FALSE;
697 break;
698 case 2:
699 verbose = Boolean.TRUE;
700 break;
704 break FOR;
706 // FIXME: -x flag not supported
707 // case 'x' :
708 // break;
709 case 'X':
710 String extendedOption = grabValue("jruby: missing extended option, listing available options\n" + getExtendedHelp());
712 if (extendedOption.equals("-O")) {
713 objectSpaceEnabled = false;
714 } else if (extendedOption.equals("+O")) {
715 objectSpaceEnabled = true;
716 } else if (extendedOption.equals("-C")) {
717 compileMode = CompileMode.OFF;
718 } else if (extendedOption.equals("+C")) {
719 compileMode = CompileMode.FORCE;
720 } else if (extendedOption.equals("y")) {
721 yarv = true;
722 } else if (extendedOption.equals("Y")) {
723 yarvCompile = true;
724 } else if (extendedOption.equals("R")) {
725 rubinius = true;
726 } else {
727 MainExitException mee =
728 new MainExitException(1, "jruby: invalid extended option " + extendedOption + " (-X will list valid options)\n");
729 mee.setUsageError(true);
731 throw mee;
733 break FOR;
734 case '-':
735 if (argument.equals("--command") || argument.equals("--bin")) {
736 characterIndex = argument.length();
737 runBinScript();
738 break;
739 } else if (argument.equals("--compat")) {
740 characterIndex = argument.length();
741 compatVersion = CompatVersion.getVersionFromString(grabValue(getArgumentError("--compat must be RUBY1_8 or RUBY1_9")));
742 if (compatVersion == null) {
743 compatVersion = CompatVersion.RUBY1_8;
745 break FOR;
746 } else if (argument.equals("--copyright")) {
747 setShowCopyright(true);
748 shouldRunInterpreter = false;
749 break FOR;
750 } else if (argument.equals("--debug")) {
751 debug = true;
752 verbose = Boolean.TRUE;
753 break;
754 } else if (argument.equals("--help")) {
755 shouldPrintUsage = true;
756 shouldRunInterpreter = false;
757 break;
758 } else if (argument.equals("--properties")) {
759 shouldPrintProperties = true;
760 shouldRunInterpreter = false;
761 break;
762 } else if (argument.equals("--version")) {
763 setShowVersion(true);
764 break FOR;
765 } else {
766 if (argument.equals("--")) {
767 // ruby interpreter compatibilty
768 // Usage: ruby [switches] [--] [programfile] [arguments])
769 endOfArguments = true;
770 break;
773 default:
774 throw new MainExitException(1, "jruby: unknown option " + argument);
779 private void runBinScript() {
780 requiredLibraries.add("jruby/commands");
781 String scriptName = grabValue("jruby: provide a bin script to execute");
782 if (scriptName.equals("irb")) {
783 scriptName = "jirb";
785 inlineScript.append("JRuby::Commands." + scriptName);
786 inlineScript.append("\n");
787 hasInlineScript = true;
788 try {
789 String jrubyHome = JRubyFile.create(System.getProperty("user.dir"), JRubyFile.getFileProperty("jruby.home")).getCanonicalPath();
790 scriptFileName = JRubyFile.create(jrubyHome + JRubyFile.separator + "bin", scriptName).getCanonicalPath();
791 } catch (IOException io) {
792 MainExitException mee = new MainExitException(1, "jruby: Can't determine script filename");
793 mee.setUsageError(true);
794 throw mee;
796 endOfArguments = true;
799 private String grabValue(String errorMessage) {
800 characterIndex++;
801 if (characterIndex < arguments[argumentIndex].length()) {
802 return arguments[argumentIndex].substring(characterIndex);
804 argumentIndex++;
805 if (argumentIndex < arguments.length) {
806 return arguments[argumentIndex];
809 MainExitException mee = new MainExitException(1, errorMessage);
810 mee.setUsageError(true);
812 throw mee;
815 private String grabOptionalValue() {
816 characterIndex++;
817 if (characterIndex < arguments[argumentIndex].length()) {
818 return arguments[argumentIndex].substring(characterIndex);
820 return null;
824 public byte[] inlineScript() {
825 try {
826 return inlineScript.toString().getBytes("UTF-8");
827 } catch (UnsupportedEncodingException e) {
828 return inlineScript.toString().getBytes();
832 public List<String> requiredLibraries() {
833 return requiredLibraries;
836 public List<String> loadPaths() {
837 return loadPaths;
840 public boolean shouldRunInterpreter() {
841 if(isShowVersion() && (hasInlineScript || scriptFileName != null)) {
842 return true;
844 return isShouldRunInterpreter();
847 public boolean shouldPrintUsage() {
848 return shouldPrintUsage;
851 public boolean shouldPrintProperties() {
852 return shouldPrintProperties;
855 private boolean isSourceFromStdin() {
856 return getScriptFileName() == null;
859 public boolean isInlineScript() {
860 return hasInlineScript;
863 public InputStream getScriptSource() {
864 try {
865 // KCode.NONE is used because KCODE does not affect parse in Ruby 1.8
866 // if Ruby 2.0 encoding pragmas are implemented, this will need to change
867 if (hasInlineScript) {
868 return new ByteArrayInputStream(inlineScript());
869 } else if (isSourceFromStdin()) {
870 // can't use -v and stdin
871 if (isShowVersion()) {
872 return null;
874 return getInput();
875 } else {
876 File file = JRubyFile.create(getCurrentDirectory(), getScriptFileName());
877 return new FileInputStream(file);
879 } catch (IOException e) {
880 throw new MainExitException(1, "Error opening script file: " + e.getMessage());
884 public String displayedFileName() {
885 if (hasInlineScript) {
886 if (scriptFileName != null) {
887 return scriptFileName;
888 } else {
889 return "-e";
891 } else if (isSourceFromStdin()) {
892 return "-";
893 } else {
894 return getScriptFileName();
898 private void setScriptFileName(String scriptFileName) {
899 this.scriptFileName = scriptFileName;
902 public String getScriptFileName() {
903 return scriptFileName;
906 public boolean isBenchmarking() {
907 return benchmarking;
910 public boolean isAssumeLoop() {
911 return assumeLoop;
914 public boolean isAssumePrinting() {
915 return assumePrinting;
918 public boolean isProcessLineEnds() {
919 return processLineEnds;
922 public boolean isSplit() {
923 return split;
926 public boolean isVerbose() {
927 return verbose == Boolean.TRUE;
930 public Boolean getVerbose() {
931 return verbose;
934 public boolean isDebug() {
935 return debug;
938 public boolean isShowVersion() {
939 return showVersion;
942 public boolean isShowCopyright() {
943 return showCopyright;
946 protected void setShowVersion(boolean showVersion) {
947 this.showVersion = showVersion;
950 protected void setShowCopyright(boolean showCopyright) {
951 this.showCopyright = showCopyright;
954 public boolean isShouldRunInterpreter() {
955 return shouldRunInterpreter;
958 public boolean isShouldCheckSyntax() {
959 return shouldCheckSyntax;
962 public boolean isYARVEnabled() {
963 return yarv;
966 public String getInputFieldSeparator() {
967 return inputFieldSeparator;
970 public boolean isRubiniusEnabled() {
971 return rubinius;
974 public boolean isYARVCompileEnabled() {
975 return yarvCompile;
978 public KCode getKCode() {
979 return kcode;
982 public String getRecordSeparator() {
983 return recordSeparator;
986 public int getSafeLevel() {
987 return safeLevel;
990 public void setRecordSeparator(String recordSeparator) {
991 this.recordSeparator = recordSeparator;
994 public ClassCache getClassCache() {
995 return classCache;
998 public void setClassCache(ClassCache classCache) {
999 this.classCache = classCache;