KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jruby > RubyKernel


1 /***** BEGIN LICENSE BLOCK *****
2  * Version: CPL 1.0/GPL 2.0/LGPL 2.1
3  *
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
8  *
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.
13  *
14  * Copyright (C) 2001 Chad Fowler <chadfowler@chadfowler.com>
15  * Copyright (C) 2001 Alan Moore <alan_moore@gmx.net>
16  * Copyright (C) 2001-2002 Benoit Cerrina <b.cerrina@wanadoo.fr>
17  * Copyright (C) 2001-2004 Jan Arne Petersen <jpetersen@uni-bonn.de>
18  * Copyright (C) 2002-2006 Thomas E Enebo <enebo@acm.org>
19  * Copyright (C) 2002-2004 Anders Bengtsson <ndrsbngtssn@yahoo.se>
20  * Copyright (C) 2004-2005 Charles O Nutter <headius@headius.com>
21  * Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de>
22  * Copyright (C) 2005 Kiel Hodges <jruby-devel@selfsosoft.com>
23  * Copyright (C) 2006 Evan Buswell <evan@heron.sytes.net>
24  * Copyright (C) 2006 Ola Bini <ola@ologix.com>
25  * Copyright (C) 2006 Michael Studman <codehaus@michaelstudman.com>
26  * Copyright (C) 2006 Miguel Covarrubias <mlcovarrubias@gmail.com>
27  * Copyright (C) 2007 Nick Sieger <nicksieger@gmail.com>
28  *
29  * Alternatively, the contents of this file may be used under the terms of
30  * either of the GNU General Public License Version 2 or later (the "GPL"),
31  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
32  * in which case the provisions of the GPL or the LGPL are applicable instead
33  * of those above. If you wish to allow use of your version of this file only
34  * under the terms of either the GPL or the LGPL, and not to allow others to
35  * use your version of this file under the terms of the CPL, indicate your
36  * decision by deleting the provisions above and replace them with the notice
37  * and other provisions required by the GPL or the LGPL. If you do not delete
38  * the provisions above, a recipient may use your version of this file under
39  * the terms of any one of the CPL, the GPL or the LGPL.
40  ***** END LICENSE BLOCK *****/

41 package org.jruby;
42
43 import java.io.ByteArrayOutputStream JavaDoc;
44 import java.io.File JavaDoc;
45 import java.io.IOException JavaDoc;
46 import java.io.InputStream JavaDoc;
47 import java.io.OutputStream JavaDoc;
48 import java.io.PrintStream JavaDoc;
49 import java.util.Calendar JavaDoc;
50 import java.util.Iterator JavaDoc;
51 import java.util.List JavaDoc;
52 import java.util.HashMap JavaDoc;
53 import java.util.Map JavaDoc;
54 import java.util.StringTokenizer JavaDoc;
55 import java.util.regex.Pattern JavaDoc;
56
57 import org.jruby.ast.util.ArgsUtil;
58 import org.jruby.exceptions.JumpException;
59 import org.jruby.exceptions.RaiseException;
60 import org.jruby.exceptions.MainExitException;
61 import org.jruby.internal.runtime.methods.DynamicMethod;
62 import org.jruby.runtime.Block;
63 import org.jruby.runtime.CallType;
64 import org.jruby.runtime.CallbackFactory;
65 import org.jruby.runtime.ThreadContext;
66 import org.jruby.runtime.Visibility;
67 import org.jruby.runtime.builtin.IRubyObject;
68 import org.jruby.runtime.builtin.meta.FileMetaClass;
69 import org.jruby.runtime.builtin.meta.IOMetaClass;
70 import org.jruby.runtime.load.IAutoloadMethod;
71 import org.jruby.runtime.load.LoadService;
72 import org.jruby.util.PrintfFormat;
73 import org.jruby.util.UnsynchronizedStack;
74
75 /**
76  * Note: For CVS history, see KernelModule.java.
77  *
78  * @author jpetersen
79  */

80 public class RubyKernel {
81     public final static Class JavaDoc IRUBY_OBJECT = IRubyObject.class;
82
83     public static RubyModule createKernelModule(Ruby runtime) {
84         RubyModule module = runtime.defineModule("Kernel");
85         CallbackFactory callbackFactory = runtime.callbackFactory(RubyKernel.class);
86         CallbackFactory objectCallbackFactory = runtime.callbackFactory(RubyObject.class);
87
88         module.defineFastModuleFunction("Array", callbackFactory.getFastSingletonMethod("new_array", IRUBY_OBJECT));
89         module.defineFastModuleFunction("Float", callbackFactory.getFastSingletonMethod("new_float", IRUBY_OBJECT));
90         module.defineFastModuleFunction("Integer", callbackFactory.getFastSingletonMethod("new_integer", IRUBY_OBJECT));
91         module.defineFastModuleFunction("String", callbackFactory.getFastSingletonMethod("new_string", IRUBY_OBJECT));
92         module.defineFastModuleFunction("`", callbackFactory.getFastSingletonMethod("backquote", IRUBY_OBJECT));
93         module.defineFastModuleFunction("abort", callbackFactory.getFastOptSingletonMethod("abort"));
94         module.defineModuleFunction("at_exit", callbackFactory.getSingletonMethod("at_exit"));
95         module.defineFastModuleFunction("autoload", callbackFactory.getFastSingletonMethod("autoload", IRUBY_OBJECT, IRUBY_OBJECT));
96         module.defineFastPublicModuleFunction("autoload?", callbackFactory.getFastSingletonMethod("autoload_p", IRUBY_OBJECT));
97         module.defineModuleFunction("binding", callbackFactory.getSingletonMethod("binding"));
98         module.defineModuleFunction("block_given?", callbackFactory.getSingletonMethod("block_given"));
99         // TODO: Implement Kernel#callcc
100
module.defineModuleFunction("caller", callbackFactory.getOptSingletonMethod("caller"));
101         module.defineModuleFunction("catch", callbackFactory.getSingletonMethod("rbCatch", IRUBY_OBJECT));
102         module.defineFastModuleFunction("chomp", callbackFactory.getFastOptSingletonMethod("chomp"));
103         module.defineFastModuleFunction("chomp!", callbackFactory.getFastOptSingletonMethod("chomp_bang"));
104         module.defineFastModuleFunction("chop", callbackFactory.getFastSingletonMethod("chop"));
105         module.defineFastModuleFunction("chop!", callbackFactory.getFastSingletonMethod("chop_bang"));
106         module.defineModuleFunction("eval", callbackFactory.getOptSingletonMethod("eval"));
107         module.defineFastModuleFunction("exit", callbackFactory.getFastOptSingletonMethod("exit"));
108         module.defineFastModuleFunction("exit!", callbackFactory.getFastOptSingletonMethod("exit_bang"));
109         module.defineModuleFunction("fail", callbackFactory.getOptSingletonMethod("raise"));
110         // TODO: Implement Kernel#fork
111
module.defineFastModuleFunction("format", callbackFactory.getFastOptSingletonMethod("sprintf"));
112         module.defineFastModuleFunction("gets", callbackFactory.getFastOptSingletonMethod("gets"));
113         module.defineFastModuleFunction("global_variables", callbackFactory.getFastSingletonMethod("global_variables"));
114         module.defineModuleFunction("gsub", callbackFactory.getOptSingletonMethod("gsub"));
115         module.defineModuleFunction("gsub!", callbackFactory.getOptSingletonMethod("gsub_bang"));
116         // TODO: Add deprecation to Kernel#iterator? (maybe formal deprecation mech.)
117
module.defineModuleFunction("iterator?", callbackFactory.getSingletonMethod("block_given"));
118         module.defineModuleFunction("lambda", callbackFactory.getSingletonMethod("proc"));
119         module.defineModuleFunction("load", callbackFactory.getOptSingletonMethod("load"));
120         module.defineFastModuleFunction("local_variables", callbackFactory.getFastSingletonMethod("local_variables"));
121         module.defineModuleFunction("loop", callbackFactory.getSingletonMethod("loop"));
122         // Note: method_missing is documented as being in Object, but ruby appears to stick it in Kernel.
123
module.defineModuleFunction("method_missing", callbackFactory.getOptSingletonMethod("method_missing"));
124         module.defineModuleFunction("open", callbackFactory.getOptSingletonMethod("open"));
125         module.defineFastModuleFunction("p", callbackFactory.getFastOptSingletonMethod("p"));
126         module.defineFastModuleFunction("print", callbackFactory.getFastOptSingletonMethod("print"));
127         module.defineFastModuleFunction("printf", callbackFactory.getFastOptSingletonMethod("printf"));
128         module.defineModuleFunction("proc", callbackFactory.getSingletonMethod("proc"));
129         // TODO: implement Kernel#putc
130
module.defineFastModuleFunction("puts", callbackFactory.getFastOptSingletonMethod("puts"));
131         module.defineModuleFunction("raise", callbackFactory.getOptSingletonMethod("raise"));
132         module.defineFastModuleFunction("rand", callbackFactory.getFastOptSingletonMethod("rand"));
133         module.defineFastModuleFunction("readline", callbackFactory.getFastOptSingletonMethod("readline"));
134         module.defineFastModuleFunction("readlines", callbackFactory.getFastOptSingletonMethod("readlines"));
135         module.defineModuleFunction("require", callbackFactory.getSingletonMethod("require", IRUBY_OBJECT));
136         module.defineModuleFunction("scan", callbackFactory.getSingletonMethod("scan", IRUBY_OBJECT));
137         module.defineFastModuleFunction("select", callbackFactory.getFastOptSingletonMethod("select"));
138         module.defineModuleFunction("set_trace_func", callbackFactory.getSingletonMethod("set_trace_func", IRUBY_OBJECT));
139         module.defineFastModuleFunction("sleep", callbackFactory.getFastSingletonMethod("sleep", IRUBY_OBJECT));
140         module.defineFastModuleFunction("split", callbackFactory.getFastOptSingletonMethod("split"));
141         module.defineFastModuleFunction("sprintf", callbackFactory.getFastOptSingletonMethod("sprintf"));
142         module.defineFastModuleFunction("srand", callbackFactory.getFastOptSingletonMethod("srand"));
143         module.defineModuleFunction("sub", callbackFactory.getOptSingletonMethod("sub"));
144         module.defineModuleFunction("sub!", callbackFactory.getOptSingletonMethod("sub_bang"));
145         // Skipping: Kernel#syscall (too system dependent)
146
module.defineFastModuleFunction("system", callbackFactory.getFastOptSingletonMethod("system"));
147         // TODO: Implement Kernel#exec differently?
148
module.defineFastModuleFunction("exec", callbackFactory.getFastOptSingletonMethod("system"));
149         module.defineFastModuleFunction("test", callbackFactory.getFastOptSingletonMethod("test"));
150         module.defineModuleFunction("throw", callbackFactory.getOptSingletonMethod("rbThrow"));
151         // TODO: Implement Kernel#trace_var
152
module.defineModuleFunction("trap", callbackFactory.getOptSingletonMethod("trap"));
153         // TODO: Implement Kernel#untrace_var
154
module.defineFastModuleFunction("warn", callbackFactory.getFastSingletonMethod("warn", IRUBY_OBJECT));
155         
156         // Defined p411 Pickaxe 2nd ed.
157
module.defineModuleFunction("singleton_method_added", callbackFactory.getSingletonMethod("singleton_method_added", IRUBY_OBJECT));
158         module.defineModuleFunction("singleton_method_removed", callbackFactory.getSingletonMethod("singleton_method_removed", IRUBY_OBJECT));
159         module.defineModuleFunction("singleton_method_undefined", callbackFactory.getSingletonMethod("singleton_method_undefined", IRUBY_OBJECT));
160         
161         // Object methods
162
module.defineFastPublicModuleFunction("==", objectCallbackFactory.getFastMethod("obj_equal", IRUBY_OBJECT));
163         module.defineFastPublicModuleFunction("===", objectCallbackFactory.getFastMethod("equal", IRUBY_OBJECT));
164
165         module.defineAlias("eql?", "==");
166         module.defineFastPublicModuleFunction("to_s", objectCallbackFactory.getFastMethod("to_s"));
167         module.defineFastPublicModuleFunction("nil?", objectCallbackFactory.getFastMethod("nil_p"));
168         module.defineFastPublicModuleFunction("to_a", callbackFactory.getFastSingletonMethod("to_a"));
169         module.defineFastPublicModuleFunction("hash", objectCallbackFactory.getFastMethod("hash"));
170         module.defineFastPublicModuleFunction("id", objectCallbackFactory.getFastMethod("id_deprecated"));
171         module.defineFastPublicModuleFunction("object_id", objectCallbackFactory.getFastMethod("id"));
172         module.defineAlias("__id__", "object_id");
173         module.defineFastPublicModuleFunction("is_a?", objectCallbackFactory.getFastMethod("kind_of", IRUBY_OBJECT));
174         module.defineAlias("kind_of?", "is_a?");
175         module.defineFastPublicModuleFunction("dup", objectCallbackFactory.getFastMethod("dup"));
176         module.defineFastPublicModuleFunction("equal?", objectCallbackFactory.getFastMethod("same", IRUBY_OBJECT));
177         module.defineFastPublicModuleFunction("type", objectCallbackFactory.getFastMethod("type_deprecated"));
178         module.defineFastPublicModuleFunction("class", objectCallbackFactory.getFastMethod("type"));
179         module.defineFastPublicModuleFunction("inspect", objectCallbackFactory.getFastMethod("inspect"));
180         module.defineFastPublicModuleFunction("=~", objectCallbackFactory.getFastMethod("match", IRUBY_OBJECT));
181         module.defineFastPublicModuleFunction("clone", objectCallbackFactory.getFastMethod("rbClone"));
182         module.defineFastPublicModuleFunction("display", objectCallbackFactory.getFastOptMethod("display"));
183         module.defineFastPublicModuleFunction("extend", objectCallbackFactory.getFastOptMethod("extend"));
184         module.defineFastPublicModuleFunction("freeze", objectCallbackFactory.getFastMethod("freeze"));
185         module.defineFastPublicModuleFunction("frozen?", objectCallbackFactory.getFastMethod("frozen"));
186         module.defineFastModuleFunction("initialize_copy", objectCallbackFactory.getFastMethod("initialize_copy", IRUBY_OBJECT));
187         module.definePublicModuleFunction("instance_eval", objectCallbackFactory.getOptMethod("instance_eval"));
188         module.defineFastPublicModuleFunction("instance_of?", objectCallbackFactory.getFastMethod("instance_of", IRUBY_OBJECT));
189         module.defineFastPublicModuleFunction("instance_variables", objectCallbackFactory.getFastMethod("instance_variables"));
190         module.defineFastPublicModuleFunction("instance_variable_get", objectCallbackFactory.getFastMethod("instance_variable_get", IRUBY_OBJECT));
191         module.defineFastPublicModuleFunction("instance_variable_set", objectCallbackFactory.getFastMethod("instance_variable_set", IRUBY_OBJECT, IRUBY_OBJECT));
192         module.defineFastPublicModuleFunction("method", objectCallbackFactory.getFastMethod("method", IRUBY_OBJECT));
193         module.defineFastPublicModuleFunction("methods", objectCallbackFactory.getFastOptMethod("methods"));
194         module.defineFastPublicModuleFunction("private_methods", objectCallbackFactory.getFastMethod("private_methods"));
195         module.defineFastPublicModuleFunction("protected_methods", objectCallbackFactory.getFastMethod("protected_methods"));
196         module.defineFastPublicModuleFunction("public_methods", objectCallbackFactory.getFastOptMethod("public_methods"));
197         module.defineFastModuleFunction("remove_instance_variable", objectCallbackFactory.getMethod("remove_instance_variable", IRUBY_OBJECT));
198         module.defineFastPublicModuleFunction("respond_to?", objectCallbackFactory.getFastOptMethod("respond_to"));
199         module.definePublicModuleFunction("send", objectCallbackFactory.getOptMethod("send"));
200         module.defineAlias("__send__", "send");
201         module.defineFastPublicModuleFunction("singleton_methods", objectCallbackFactory.getFastOptMethod("singleton_methods"));
202         module.defineFastPublicModuleFunction("taint", objectCallbackFactory.getFastMethod("taint"));
203         module.defineFastPublicModuleFunction("tainted?", objectCallbackFactory.getFastMethod("tainted"));
204         module.defineFastPublicModuleFunction("untaint", objectCallbackFactory.getFastMethod("untaint"));
205
206         return module;
207     }
208
209     public static IRubyObject at_exit(IRubyObject recv, Block block) {
210         return recv.getRuntime().pushExitBlock(recv.getRuntime().newProc(false, block));
211     }
212
213     public static IRubyObject autoload_p(final IRubyObject recv, IRubyObject symbol) {
214         String JavaDoc name = symbol.asSymbol();
215         if (recv instanceof RubyModule) {
216             name = ((RubyModule)recv).getName() + "::" + name;
217         }
218         
219         IAutoloadMethod autoloadMethod = recv.getRuntime().getLoadService().autoloadFor(name);
220         if(autoloadMethod == null) return recv.getRuntime().getNil();
221
222         return recv.getRuntime().newString(autoloadMethod.file());
223     }
224
225     public static IRubyObject autoload(final IRubyObject recv, IRubyObject symbol, final IRubyObject file) {
226         final LoadService loadService = recv.getRuntime().getLoadService();
227         final String JavaDoc baseName = symbol.asSymbol();
228         String JavaDoc nm = baseName;
229         if(recv instanceof RubyModule) {
230             nm = ((RubyModule)recv).getName() + "::" + nm;
231         }
232         loadService.addAutoload(nm, new IAutoloadMethod() {
233                 public String JavaDoc file() {
234                     return file.toString();
235                 }
236             /**
237              * @see org.jruby.runtime.load.IAutoloadMethod#load(Ruby, String)
238              */

239             public IRubyObject load(Ruby runtime, String JavaDoc name) {
240                 loadService.require(file.toString());
241                 if(recv instanceof RubyModule) {
242                     return ((RubyModule)recv).getConstant(baseName);
243                 }
244                 return runtime.getObject().getConstant(baseName);
245             }
246         });
247         return recv;
248     }
249
250     public static IRubyObject method_missing(IRubyObject recv, IRubyObject[] args, Block block) {
251         Ruby runtime = recv.getRuntime();
252         if (args.length == 0) {
253             throw recv.getRuntime().newArgumentError("no id given");
254         }
255
256         String JavaDoc name = args[0].asSymbol();
257         String JavaDoc description = null;
258         if("inspect".equals(name) || "to_s".equals(name)) {
259             description = recv.anyToString().toString();
260         } else {
261             description = recv.inspect().toString();
262         }
263         boolean noClass = description.length() > 0 && description.charAt(0) == '#';
264         ThreadContext tc = runtime.getCurrentContext();
265         Visibility lastVis = tc.getLastVisibility();
266         if(null == lastVis) {
267             lastVis = Visibility.PUBLIC;
268         }
269         CallType lastCallType = tc.getLastCallType();
270         String JavaDoc format = lastVis.errorMessageFormat(lastCallType, name);
271         String JavaDoc msg = new PrintfFormat(format).sprintf(new Object JavaDoc[] { name, description,
272                                                                      noClass ? "" : ":", noClass ? "" : recv.getType().getName()}, null);
273
274         throw lastCallType == CallType.VARIABLE ? runtime.newNameError(msg, name) : runtime.newNoMethodError(msg, name);
275     }
276
277     public static IRubyObject open(IRubyObject recv, IRubyObject[] args, Block block) {
278         recv.checkArgumentCount(args,1,3);
279         String JavaDoc arg = args[0].convertToString().toString();
280
281         // Should this logic be pushed into RubyIO Somewhere?
282
if (arg.startsWith("|")) {
283             String JavaDoc command = arg.substring(1);
284             // exec process, create IO with process
285
try {
286                 // TODO: may need to part cli parms out ourself?
287
Process JavaDoc p = Runtime.getRuntime().exec(command,getCurrentEnv(recv.getRuntime()));
288                 RubyIO io = new RubyIO(recv.getRuntime(), p);
289                 
290                 if (block.isGiven()) {
291                     try {
292                         recv.getRuntime().getCurrentContext().yield(io, block);
293                         
294                         return recv.getRuntime().getNil();
295                     } finally {
296                         io.close();
297                     }
298                 }
299
300                 return io;
301             } catch (IOException JavaDoc ioe) {
302                 throw recv.getRuntime().newIOErrorFromException(ioe);
303             }
304         }
305
306         return ((FileMetaClass) recv.getRuntime().getClass("File")).open(args, block);
307     }
308
309     public static IRubyObject gets(IRubyObject recv, IRubyObject[] args) {
310         return ((RubyArgsFile) recv.getRuntime().getGlobalVariables().get("$<")).gets(args);
311     }
312
313     public static IRubyObject abort(IRubyObject recv, IRubyObject[] args) {
314         if(recv.checkArgumentCount(args,0,1) == 1) {
315             recv.getRuntime().getGlobalVariables().get("$stderr").callMethod(recv.getRuntime().getCurrentContext(),"puts",args[0]);
316         }
317         throw new MainExitException(1,true);
318     }
319
320     public static IRubyObject new_array(IRubyObject recv, IRubyObject object) {
321         IRubyObject value = object.convertToTypeWithCheck("Array", "to_ary");
322         
323         if (value.isNil()) {
324             DynamicMethod method = object.getMetaClass().searchMethod("to_a");
325             
326             if (method.getImplementationClass() == recv.getRuntime().getKernel()) {
327                 return recv.getRuntime().newArray(object);
328             }
329             
330             // Strange that Ruby has custom code here and not convertToTypeWithCheck equivalent.
331
value = object.callMethod(recv.getRuntime().getCurrentContext(), "to_a");
332             if (value.getMetaClass() != recv.getRuntime().getClass("Array")) {
333                 throw recv.getRuntime().newTypeError("`to_a' did not return Array");
334                
335             }
336         }
337         
338         return value;
339     }
340     
341     public static IRubyObject new_float(IRubyObject recv, IRubyObject object) {
342         if(object instanceof RubyFixnum){
343             return RubyFloat.newFloat(object.getRuntime(), ((RubyFixnum)object).getDoubleValue());
344         }else if(object instanceof RubyFloat){
345             return object;
346         }else if(object instanceof RubyBignum){
347             return RubyFloat.newFloat(object.getRuntime(), RubyBignum.big2dbl((RubyBignum)object));
348         }else if(object instanceof RubyString){
349             if(((RubyString)object).getValue().length() == 0){ // rb_cstr_to_dbl case
350
throw recv.getRuntime().newArgumentError("invalid value for Float(): " + object.inspect());
351             }
352             return RubyNumeric.str2fnum(recv.getRuntime(),(RubyString)object,true);
353         }else if(object.isNil()){
354             throw recv.getRuntime().newTypeError("can't convert nil into Float");
355         } else {
356             RubyFloat rFloat = object.convertToFloat();
357             if(Double.isNaN(rFloat.getDoubleValue())){
358                 recv.getRuntime().newArgumentError("invalid value for Float()");
359         }
360             return rFloat;
361     }
362     }
363     
364     public static IRubyObject new_integer(IRubyObject recv, IRubyObject object) {
365         ThreadContext context = recv.getRuntime().getCurrentContext();
366         
367         if(object instanceof RubyString) {
368             return RubyNumeric.str2inum(recv.getRuntime(),(RubyString)object,0,true);
369                     }
370         return object.callMethod(context,"to_i");
371     }
372     
373     public static IRubyObject new_string(IRubyObject recv, IRubyObject object) {
374         return object.callMethod(recv.getRuntime().getCurrentContext(), "to_s");
375     }
376     
377     
378     public static IRubyObject p(IRubyObject recv, IRubyObject[] args) {
379         IRubyObject defout = recv.getRuntime().getGlobalVariables().get("$>");
380         ThreadContext context = recv.getRuntime().getCurrentContext();
381
382         for (int i = 0; i < args.length; i++) {
383             if (args[i] != null) {
384                 defout.callMethod(context, "write", args[i].callMethod(context, "inspect"));
385                 defout.callMethod(context, "write", recv.getRuntime().newString("\n"));
386             }
387         }
388         return recv.getRuntime().getNil();
389     }
390
391     public static IRubyObject puts(IRubyObject recv, IRubyObject[] args) {
392         IRubyObject defout = recv.getRuntime().getGlobalVariables().get("$>");
393         ThreadContext context = recv.getRuntime().getCurrentContext();
394         
395         defout.callMethod(context, "puts", args);
396
397         return recv.getRuntime().getNil();
398     }
399
400     public static IRubyObject print(IRubyObject recv, IRubyObject[] args) {
401         IRubyObject defout = recv.getRuntime().getGlobalVariables().get("$>");
402         ThreadContext context = recv.getRuntime().getCurrentContext();
403
404         defout.callMethod(context, "print", args);
405
406         return recv.getRuntime().getNil();
407     }
408
409     public static IRubyObject printf(IRubyObject recv, IRubyObject[] args) {
410         if (args.length != 0) {
411             IRubyObject defout = recv.getRuntime().getGlobalVariables().get("$>");
412
413             if (!(args[0] instanceof RubyString)) {
414                 defout = args[0];
415                 args = ArgsUtil.popArray(args);
416             }
417
418             ThreadContext context = recv.getRuntime().getCurrentContext();
419
420             defout.callMethod(context, "write", RubyKernel.sprintf(recv, args));
421         }
422
423         return recv.getRuntime().getNil();
424     }
425
426     public static IRubyObject readline(IRubyObject recv, IRubyObject[] args) {
427         IRubyObject line = gets(recv, args);
428
429         if (line.isNil()) {
430             throw recv.getRuntime().newEOFError();
431         }
432
433         return line;
434     }
435
436     public static RubyArray readlines(IRubyObject recv, IRubyObject[] args) {
437         return ((RubyArgsFile) recv.getRuntime().getGlobalVariables().get("$<")).readlines(args);
438     }
439
440     /** Returns value of $_.
441      *
442      * @throws TypeError if $_ is not a String or nil.
443      * @return value of $_ as String.
444      */

445     private static RubyString getLastlineString(Ruby runtime) {
446         IRubyObject line = runtime.getCurrentContext().getLastline();
447
448         if (line.isNil()) {
449             throw runtime.newTypeError("$_ value need to be String (nil given).");
450         } else if (!(line instanceof RubyString)) {
451             throw runtime.newTypeError("$_ value need to be String (" + line.getMetaClass().getName() + " given).");
452         } else {
453             return (RubyString) line;
454         }
455     }
456
457     public static IRubyObject sub_bang(IRubyObject recv, IRubyObject[] args, Block block) {
458         return getLastlineString(recv.getRuntime()).sub_bang(args, block);
459     }
460
461     public static IRubyObject sub(IRubyObject recv, IRubyObject[] args, Block block) {
462         RubyString str = (RubyString) getLastlineString(recv.getRuntime()).dup();
463
464         if (!str.sub_bang(args, block).isNil()) {
465             recv.getRuntime().getCurrentContext().setLastline(str);
466         }
467
468         return str;
469     }
470
471     public static IRubyObject gsub_bang(IRubyObject recv, IRubyObject[] args, Block block) {
472         return getLastlineString(recv.getRuntime()).gsub_bang(args, block);
473     }
474
475     public static IRubyObject gsub(IRubyObject recv, IRubyObject[] args, Block block) {
476         RubyString str = (RubyString) getLastlineString(recv.getRuntime()).dup();
477
478         if (!str.gsub_bang(args, block).isNil()) {
479             recv.getRuntime().getCurrentContext().setLastline(str);
480         }
481
482         return str;
483     }
484
485     public static IRubyObject chop_bang(IRubyObject recv) {
486         return getLastlineString(recv.getRuntime()).chop_bang();
487     }
488
489     public static IRubyObject chop(IRubyObject recv) {
490         RubyString str = getLastlineString(recv.getRuntime());
491
492         if (str.getValue().length() > 0) {
493             str = (RubyString) str.dup();
494             str.chop_bang();
495             recv.getRuntime().getCurrentContext().setLastline(str);
496         }
497
498         return str;
499     }
500
501     public static IRubyObject chomp_bang(IRubyObject recv, IRubyObject[] args) {
502         return getLastlineString(recv.getRuntime()).chomp_bang(args);
503     }
504
505     public static IRubyObject chomp(IRubyObject recv, IRubyObject[] args) {
506         RubyString str = getLastlineString(recv.getRuntime());
507         RubyString dup = (RubyString) str.dup();
508
509         if (dup.chomp_bang(args).isNil()) {
510             return str;
511         }
512
513         recv.getRuntime().getCurrentContext().setLastline(dup);
514         return dup;
515     }
516
517     public static IRubyObject split(IRubyObject recv, IRubyObject[] args) {
518         return getLastlineString(recv.getRuntime()).split(args);
519     }
520
521     public static IRubyObject scan(IRubyObject recv, IRubyObject pattern, Block block) {
522         return getLastlineString(recv.getRuntime()).scan(pattern, block);
523     }
524
525     public static IRubyObject select(IRubyObject recv, IRubyObject[] args) {
526         return IOMetaClass.select_static(recv.getRuntime(), args);
527     }
528
529     public static IRubyObject sleep(IRubyObject recv, IRubyObject seconds) {
530         long milliseconds = (long) (seconds.convertToFloat().getDoubleValue() * 1000);
531         long startTime = System.currentTimeMillis();
532         
533         RubyThread rubyThread = recv.getRuntime().getThreadService().getCurrentContext().getThread();
534         try {
535             rubyThread.sleep(milliseconds);
536         } catch (InterruptedException JavaDoc iExcptn) {
537         }
538
539         return recv.getRuntime().newFixnum(
540                 Math.round((System.currentTimeMillis() - startTime) / 1000.0));
541     }
542
543     // FIXME: Add at_exit and finalizers to exit, then make exit_bang not call those.
544
public static IRubyObject exit(IRubyObject recv, IRubyObject[] args) {
545         recv.getRuntime().secure(4);
546
547         int status = 1;
548         if (args.length > 0) {
549             RubyObject argument = (RubyObject)args[0];
550             if (argument instanceof RubyFixnum) {
551                 status = RubyNumeric.fix2int(argument);
552             } else {
553                 status = argument.isFalse() ? 1 : 0;
554             }
555         }
556
557         throw recv.getRuntime().newSystemExit(status);
558     }
559
560     public static IRubyObject exit_bang(IRubyObject recv, IRubyObject[] args) {
561         return exit(recv, args);
562     }
563
564
565     /** Returns an Array with the names of all global variables.
566      *
567      */

568     public static RubyArray global_variables(IRubyObject recv) {
569         RubyArray globalVariables = recv.getRuntime().newArray();
570
571         Iterator JavaDoc iter = recv.getRuntime().getGlobalVariables().getNames();
572         while (iter.hasNext()) {
573             String JavaDoc globalVariableName = (String JavaDoc) iter.next();
574
575             globalVariables.append(recv.getRuntime().newString(globalVariableName));
576         }
577
578         return globalVariables;
579     }
580
581     /** Returns an Array with the names of all local variables.
582      *
583      */

584     public static RubyArray local_variables(IRubyObject recv) {
585         final Ruby runtime = recv.getRuntime();
586         RubyArray localVariables = runtime.newArray();
587         
588         String JavaDoc[] names = runtime.getCurrentContext().getCurrentScope().getAllNamesInScope();
589         for (int i = 0; i < names.length; i++) {
590             localVariables.append(runtime.newString(names[i]));
591         }
592
593         return localVariables;
594     }
595
596     public static RubyBinding binding(IRubyObject recv, Block block) {
597         // FIXME: Pass block into binding
598
return recv.getRuntime().newBinding();
599     }
600
601     public static RubyBoolean block_given(IRubyObject recv, Block block) {
602         return recv.getRuntime().newBoolean(recv.getRuntime().getCurrentContext().getPreviousFrame().getBlock().isGiven());
603     }
604
605     public static IRubyObject sprintf(IRubyObject recv, IRubyObject[] args) {
606         if (args.length == 0) {
607             throw recv.getRuntime().newArgumentError("sprintf must have at least one argument");
608         }
609
610         RubyString str = RubyString.stringValue(args[0]);
611
612         RubyArray newArgs = recv.getRuntime().newArrayNoCopy(args);
613         newArgs.shift();
614
615         return str.format(newArgs);
616     }
617
618     public static IRubyObject raise(IRubyObject recv, IRubyObject[] args, Block block) {
619         // FIXME: Pass block down?
620
recv.checkArgumentCount(args, 0, 3);
621         Ruby runtime = recv.getRuntime();
622
623         if (args.length == 0) {
624             IRubyObject lastException = runtime.getGlobalVariables().get("$!");
625             if (lastException.isNil()) {
626                 throw new RaiseException(runtime, runtime.getClass("RuntimeError"), "", false);
627             }
628             throw new RaiseException((RubyException) lastException);
629         }
630
631         IRubyObject exception;
632         ThreadContext context = recv.getRuntime().getCurrentContext();
633         
634         if (args.length == 1) {
635             if (args[0] instanceof RubyString) {
636                 throw new RaiseException((RubyException)runtime.getClass("RuntimeError").newInstance(args, block));
637             }
638             
639             if (!args[0].respondsTo("exception")) {
640                 throw runtime.newTypeError("exception class/object expected");
641             }
642             exception = args[0].callMethod(context, "exception");
643         } else {
644             if (!args[0].respondsTo("exception")) {
645                 throw runtime.newTypeError("exception class/object expected");
646             }
647             
648             exception = args[0].callMethod(context, "exception", args[1]);
649         }
650         
651         if (!exception.isKindOf(runtime.getClass("Exception"))) {
652             throw runtime.newTypeError("exception object expected");
653         }
654         
655         if (args.length == 3) {
656             ((RubyException) exception).set_backtrace(args[2]);
657         }
658         
659         throw new RaiseException((RubyException) exception);
660     }
661     
662     /**
663      * Require.
664      * MRI allows to require ever .rb files or ruby extension dll (.so or .dll depending on system).
665      * we allow requiring either .rb files or jars.
666      * @param recv ruby object used to call require (any object will do and it won't be used anyway).
667      * @param name the name of the file to require
668      **/

669     public static IRubyObject require(IRubyObject recv, IRubyObject name, Block block) {
670         if (recv.getRuntime().getLoadService().require(name.toString())) {
671             return recv.getRuntime().getTrue();
672         }
673         return recv.getRuntime().getFalse();
674     }
675
676     public static IRubyObject load(IRubyObject recv, IRubyObject[] args, Block block) {
677         RubyString file = args[0].convertToString();
678         recv.getRuntime().getLoadService().load(file.toString());
679         return recv.getRuntime().getTrue();
680     }
681
682     public static IRubyObject eval(IRubyObject recv, IRubyObject[] args, Block block) {
683         if (args == null || args.length == 0) {
684             throw recv.getRuntime().newArgumentError(args.length, 1);
685         }
686             
687         RubyString src = args[0].convertToString();
688         IRubyObject scope = null;
689         String JavaDoc file = "(eval)";
690         
691         if (args.length > 1) {
692             if (!args[1].isNil()) {
693                 scope = args[1];
694             }
695             
696             if (args.length > 2) {
697                 file = args[2].toString();
698             }
699         }
700         // FIXME: line number is not supported yet
701
//int line = args.length > 3 ? RubyNumeric.fix2int(args[3]) : 1;
702

703         src.checkSafeString();
704         ThreadContext context = recv.getRuntime().getCurrentContext();
705         
706         if (scope == null) {
707             scope = recv.getRuntime().newBinding();
708         }
709         
710         return recv.evalWithBinding(context, src, scope, file);
711     }
712
713     public static IRubyObject caller(IRubyObject recv, IRubyObject[] args, Block block) {
714         int level = args.length > 0 ? RubyNumeric.fix2int(args[0]) : 1;
715
716         if (level < 0) {
717             throw recv.getRuntime().newArgumentError("negative level(" + level + ')');
718         }
719         
720         return recv.getRuntime().getCurrentContext().createBacktrace(level, false);
721     }
722
723     public static IRubyObject rbCatch(IRubyObject recv, IRubyObject tag, Block block) {
724         ThreadContext context = recv.getRuntime().getCurrentContext();
725         try {
726             context.pushCatch(tag.asSymbol());
727             return context.yield(tag, block);
728         } catch (JumpException je) {
729             if (je.getJumpType() == JumpException.JumpType.ThrowJump &&
730                 je.getTarget().equals(tag.asSymbol())) {
731                     return (IRubyObject) je.getValue();
732             }
733             throw je;
734         } finally {
735             context.popCatch();
736         }
737     }
738
739     public static IRubyObject rbThrow(IRubyObject recv, IRubyObject[] args, Block block) {
740         Ruby runtime = recv.getRuntime();
741
742         String JavaDoc tag = args[0].asSymbol();
743         String JavaDoc[] catches = runtime.getCurrentContext().getActiveCatches();
744
745         String JavaDoc message = "uncaught throw '" + tag + '\'';
746
747         //Ordering of array traversal not important, just intuitive
748
for (int i = catches.length - 1 ; i >= 0 ; i--) {
749             if (tag.equals(catches[i])) {
750                 //Catch active, throw for catch to handle
751
JumpException je = new JumpException(JumpException.JumpType.ThrowJump);
752
753                 je.setTarget(tag);
754                 je.setValue(args.length > 1 ? args[1] : runtime.getNil());
755                 throw je;
756             }
757         }
758
759         //No catch active for this throw
760
throw runtime.newNameError(message, tag);
761     }
762
763     public static IRubyObject trap(IRubyObject recv, IRubyObject[] args, Block block) {
764         // FIXME: We can probably fake some basic signals, but obviously can't do everything. For now, stub.
765
return recv.getRuntime().getNil();
766     }
767     
768     public static IRubyObject warn(IRubyObject recv, IRubyObject message) {
769         IRubyObject out = recv.getRuntime().getObject().getConstant("STDERR");
770         RubyIO io = (RubyIO) out.convertToType("IO", "to_io", true);
771
772         io.puts(new IRubyObject[] { message });
773         return recv.getRuntime().getNil();
774     }
775
776     public static IRubyObject set_trace_func(IRubyObject recv, IRubyObject trace_func, Block block) {
777         if (trace_func.isNil()) {
778             recv.getRuntime().setTraceFunction(null);
779         } else if (!(trace_func instanceof RubyProc)) {
780             throw recv.getRuntime().newTypeError("trace_func needs to be Proc.");
781         } else {
782             recv.getRuntime().setTraceFunction((RubyProc) trace_func);
783         }
784         return trace_func;
785     }
786
787     public static IRubyObject singleton_method_added(IRubyObject recv, IRubyObject symbolId, Block block) {
788         return recv.getRuntime().getNil();
789     }
790
791     public static IRubyObject singleton_method_removed(IRubyObject recv, IRubyObject symbolId, Block block) {
792         return recv.getRuntime().getNil();
793     }
794
795     public static IRubyObject singleton_method_undefined(IRubyObject recv, IRubyObject symbolId, Block block) {
796         return recv.getRuntime().getNil();
797     }
798     
799     
800     public static RubyProc proc(IRubyObject recv, Block block) {
801         return recv.getRuntime().newProc(true, block);
802     }
803
804     public static IRubyObject loop(IRubyObject recv, Block block) {
805         ThreadContext context = recv.getRuntime().getCurrentContext();
806         while (true) {
807             try {
808                 context.yield(recv.getRuntime().getNil(), block);
809
810                 Thread.yield();
811             } catch (JumpException je) {
812                 // JRUBY-530, specifically the Kernel#loop case:
813
// Kernel#loop always takes a block. But what we're looking
814
// for here is breaking an iteration where the block is one
815
// used inside loop's block, not loop's block itself. Set the
816
// appropriate flag on the JumpException if this is the case
817
// (the FCALLNODE case in EvaluationState will deal with it)
818
if (je.getJumpType() == JumpException.JumpType.BreakJump) {
819                     if (je.getTarget() != null && je.getTarget() != block) {
820                         je.setBreakInKernelLoop(true);
821                     }
822                 }
823                  
824                 throw je;
825             }
826         }
827     }
828     public static IRubyObject test(IRubyObject recv, IRubyObject[] args) {
829         int cmd = (int) args[0].convertToInteger().getLongValue();
830         Ruby runtime = recv.getRuntime();
831         File JavaDoc pwd = new File JavaDoc(recv.getRuntime().getCurrentDirectory());
832         File JavaDoc file1 = new File JavaDoc(pwd, args[1].toString());
833         Calendar JavaDoc calendar;
834         switch (cmd) {
835         // ?A | Time | Last access time for file1
836
// ?b | boolean | True if file1 is a block device
837
// ?c | boolean | True if file1 is a character device
838
// ?C | Time | Last change time for file1
839
// ?d | boolean | True if file1 exists and is a directory
840
// ?e | boolean | True if file1 exists
841
// ?f | boolean | True if file1 exists and is a regular file
842
case 'f':
843             return RubyBoolean.newBoolean(runtime, file1.isFile());
844         // ?g | boolean | True if file1 has the \CF{setgid} bit
845
// | | set (false under NT)
846
// ?G | boolean | True if file1 exists and has a group
847
// | | ownership equal to the caller's group
848
// ?k | boolean | True if file1 exists and has the sticky bit set
849
// ?l | boolean | True if file1 exists and is a symbolic link
850
// ?M | Time | Last modification time for file1
851
case 'M':
852             calendar = Calendar.getInstance();
853             calendar.setTimeInMillis(file1.lastModified());
854             return RubyTime.newTime(runtime, calendar);
855         // ?o | boolean | True if file1 exists and is owned by
856
// | | the caller's effective uid
857
// ?O | boolean | True if file1 exists and is owned by
858
// | | the caller's real uid
859
// ?p | boolean | True if file1 exists and is a fifo
860
// ?r | boolean | True if file1 is readable by the effective
861
// | | uid/gid of the caller
862
// ?R | boolean | True if file is readable by the real
863
// | | uid/gid of the caller
864
// ?s | int/nil | If file1 has nonzero size, return the size,
865
// | | otherwise return nil
866
// ?S | boolean | True if file1 exists and is a socket
867
// ?u | boolean | True if file1 has the setuid bit set
868
// ?w | boolean | True if file1 exists and is writable by
869
// | | the effective uid/gid
870
// ?W | boolean | True if file1 exists and is writable by
871
// | | the real uid/gid
872
// ?x | boolean | True if file1 exists and is executable by
873
// | | the effective uid/gid
874
// ?X | boolean | True if file1 exists and is executable by
875
// | | the real uid/gid
876
// ?z | boolean | True if file1 exists and has a zero length
877
//
878
// Tests that take two files:
879
//
880
// ?- | boolean | True if file1 and file2 are identical
881
// ?= | boolean | True if the modification times of file1
882
// | | and file2 are equal
883
// ?< | boolean | True if the modification time of file1
884
// | | is prior to that of file2
885
// ?> | boolean | True if the modification time of file1
886
// | | is after that of file2
887
}
888         throw RaiseException.createNativeRaiseException(runtime,
889             new UnsupportedOperationException JavaDoc("test flag " + ((char) cmd) + " is not implemented"));
890     }
891
892     public static IRubyObject backquote(IRubyObject recv, IRubyObject aString) {
893         Ruby runtime = recv.getRuntime();
894         ByteArrayOutputStream JavaDoc output = new ByteArrayOutputStream JavaDoc();
895         
896         int resultCode = runInShell(runtime, new IRubyObject[] {aString}, output);
897         
898         recv.getRuntime().getGlobalVariables().set("$?", RubyProcess.RubyStatus.newProcessStatus(runtime, resultCode));
899         
900         return recv.getRuntime().newString(output.toString());
901     }
902     
903     private static final Pattern JavaDoc PATH_SEPARATORS = Pattern.compile("[/\\\\]");
904     
905     /**
906      * For the first full token on the command, most likely the actual executable to run, replace
907      * all dir separators with that which is appropriate for the current platform. Return the new
908      * with this executable string at the beginning.
909      *
910      * @param command The all-forward-slashes command to be "fixed"
911      * @return The "fixed" full command line
912      */

913     private static String JavaDoc repairDirSeps(String JavaDoc command) {
914         String JavaDoc executable = "", remainder = "";
915         command = command.trim();
916         if (command.startsWith("'")) {
917             String JavaDoc [] tokens = command.split("'", 3);
918             executable = "'"+tokens[1]+"'";
919             if (tokens.length > 2)
920                 remainder = tokens[2];
921         } else if (command.startsWith("\"")) {
922             String JavaDoc [] tokens = command.split("\"", 3);
923             executable = "\""+tokens[1]+"\"";
924             if (tokens.length > 2)
925                 remainder = tokens[2];
926         } else {
927             String JavaDoc [] tokens = command.split(" ", 2);
928             executable = tokens[0];
929             if (tokens.length > 1)
930                 remainder = " "+tokens[1];
931         }
932         
933         // Matcher.replaceAll treats backslashes in the replacement string as escaped characters
934
String JavaDoc replacement = File.separator;
935         if (File.separatorChar == '\\')
936             replacement = "\\\\";
937             
938         return PATH_SEPARATORS.matcher(executable).replaceAll(replacement) + remainder;
939                 }
940
941     private static List JavaDoc parseCommandLine(IRubyObject[] rawArgs) {
942         // first parse the first element of rawArgs since this may contain
943
// the whole command line
944
String JavaDoc command = rawArgs[0].toString();
945         UnsynchronizedStack args = new UnsynchronizedStack();
946         StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(command, " ");
947         String JavaDoc quoteChar = null;
948
949         while (st.hasMoreTokens()) {
950             String JavaDoc token = st.nextToken();
951             if (quoteChar == null) {
952                 // not currently in the middle of a quoted token
953
if (token.startsWith("'") || token.startsWith("\"")) {
954                     // note quote char and remove from beginning of token
955
quoteChar = token.substring(0, 1);
956                     token = token.substring(1);
957                 }
958                 if (quoteChar!=null && token.endsWith(quoteChar)) {
959                     // quoted token self contained, remove from end of token
960
token = token.substring(0, token.length()-1);
961                     quoteChar = null;
962                 }
963                 // add new token to list
964
args.push(token);
965             } else {
966                 // in the middle of quoted token
967
if (token.endsWith(quoteChar)) {
968                     // end of quoted token
969
token = token.substring(0, token.length()-1);
970                     quoteChar = null;
971                 }
972                 // update token at end of list
973
token = args.pop() + " " + token;
974                 args.push(token);
975             }
976         }
977         
978         // now append the remaining raw args to the cooked arg list
979
for (int i=1;i<rawArgs.length;i++) {
980             args.push(rawArgs[i].toString());
981         }
982         
983         return args;
984     }
985         
986     /**
987      * Only run an in-process script if the script name has "ruby", ".rb", or "irb" in the name
988      */

989     private static boolean shouldRunInProcess(Ruby runtime, String JavaDoc command) {
990         command = command.trim();
991         String JavaDoc [] spaceDelimitedTokens = command.split(" ", 2);
992         String JavaDoc [] slashDelimitedTokens = spaceDelimitedTokens[0].split("/");
993         String JavaDoc finalToken = slashDelimitedTokens[slashDelimitedTokens.length-1];
994         return (finalToken.indexOf("ruby") != -1 || finalToken.endsWith(".rb") || finalToken.endsWith("irb"));
995     }
996     
997     private static class InProcessScript extends Thread JavaDoc {
998         private String JavaDoc[] argArray;
999         private int result;
1000        private RubyInstanceConfig config;
1001        
1002        public InProcessScript(final String JavaDoc[] argArray, final InputStream JavaDoc in,
1003                               final OutputStream JavaDoc out, final OutputStream JavaDoc err, final String JavaDoc[] env, final File JavaDoc dir) {
1004            this.argArray = argArray;
1005            this.config = new RubyInstanceConfig() {{
1006                setInput(in);
1007                setOutput(new PrintStream JavaDoc(out));
1008                setError(new PrintStream JavaDoc(err));
1009                setEnvironment(environmentMap(env));
1010                setCurrentDirectory(dir.toString());
1011            }};
1012        }
1013
1014        public int getResult() {
1015            return result;
1016        }
1017
1018        public void setResult(int result) {
1019            this.result = result;
1020        }
1021        
1022        public void run() {
1023            result = new Main(config).run(argArray);
1024        }
1025
1026        private Map JavaDoc environmentMap(String JavaDoc[] env) {
1027            Map JavaDoc m = new HashMap JavaDoc();
1028            for (int i = 0; i < env.length; i++) {
1029                String JavaDoc[] kv = env[i].split("=", 2);
1030                m.put(kv[0], kv[1]);
1031            }
1032            return m;
1033        }
1034    }
1035
1036    public static int runInShell(Ruby runtime, IRubyObject[] rawArgs) {
1037        return runInShell(runtime,rawArgs,runtime.getOutputStream());
1038    }
1039
1040    private static String JavaDoc[] getCurrentEnv(Ruby runtime) {
1041        Map JavaDoc h = ((RubyHash)runtime.getObject().getConstant("ENV")).getValueMap();
1042        String JavaDoc[] ret = new String JavaDoc[h.size()];
1043        int i=0;
1044        for(Iterator JavaDoc iter = h.entrySet().iterator();iter.hasNext();i++) {
1045            Map.Entry JavaDoc e = (Map.Entry JavaDoc)iter.next();
1046            ret[i] = e.getKey().toString() + "=" + e.getValue().toString();
1047        }
1048        return ret;
1049    }
1050
1051    public static int runInShell(Ruby runtime, IRubyObject[] rawArgs, OutputStream JavaDoc output) {
1052        OutputStream JavaDoc error = runtime.getErrorStream();
1053        InputStream JavaDoc input = runtime.getInputStream();
1054        try {
1055            String JavaDoc shell = runtime.evalScript("require 'rbconfig'; Config::CONFIG['SHELL']").toString();
1056            rawArgs[0] = runtime.newString(repairDirSeps(rawArgs[0].toString()));
1057            Process JavaDoc aProcess = null;
1058            InProcessScript ipScript = null;
1059            File JavaDoc pwd = new File JavaDoc(runtime.getCurrentDirectory());
1060            
1061            if (shouldRunInProcess(runtime, rawArgs[0].toString())) {
1062                List JavaDoc args = parseCommandLine(rawArgs);
1063                String JavaDoc command = (String JavaDoc)args.get(0);
1064
1065                // snip off ruby or jruby command from list of arguments
1066
// leave alone if the command is the name of a script
1067
int startIndex = command.endsWith(".rb") ? 0 : 1;
1068                if(command.trim().endsWith("irb")) {
1069                    startIndex = 0;
1070                    args.set(0,runtime.getJRubyHome() + File.separator + "bin" + File.separator + "jirb");
1071                }
1072                String JavaDoc[] argArray = (String JavaDoc[])args.subList(startIndex,args.size()).toArray(new String JavaDoc[0]);
1073                ipScript = new InProcessScript(argArray, input, output, error, getCurrentEnv(runtime), pwd);
1074                
1075                // execute ruby command in-process
1076
ipScript.start();
1077                ipScript.join();
1078            } else if (shell != null && rawArgs.length == 1) {
1079                // execute command with sh -c or cmd.exe /c
1080
// this does shell expansion of wildcards
1081
String JavaDoc shellSwitch = shell.endsWith("sh") ? "-c" : "/c";
1082                String JavaDoc[] argArray = new String JavaDoc[3];
1083                argArray[0] = shell;
1084                argArray[1] = shellSwitch;
1085                argArray[2] = rawArgs[0].toString();
1086                aProcess = Runtime.getRuntime().exec(argArray, getCurrentEnv(runtime), pwd);
1087            } else {
1088                // execute command directly, no wildcard expansion
1089
if (rawArgs.length > 1) {
1090                    String JavaDoc[] argArray = new String JavaDoc[rawArgs.length];
1091                    for (int i=0;i<rawArgs.length;i++) {
1092                        argArray[i] = rawArgs[i].toString();
1093                    }
1094                    aProcess = Runtime.getRuntime().exec(argArray,getCurrentEnv(runtime), pwd);
1095                } else {
1096                    aProcess = Runtime.getRuntime().exec(rawArgs[0].toString(), getCurrentEnv(runtime), pwd);
1097                }
1098            }
1099            
1100            if (aProcess != null) {
1101                handleStreams(aProcess,input,output,error);
1102                return aProcess.waitFor();
1103            } else if (ipScript != null) {
1104                return ipScript.getResult();
1105            } else {
1106                return 0;
1107            }
1108        } catch (IOException JavaDoc e) {
1109            throw runtime.newIOErrorFromException(e);
1110        } catch (InterruptedException JavaDoc e) {
1111            throw runtime.newThreadError("unexpected interrupt");
1112        }
1113    }
1114    
1115    private static void handleStreams(Process JavaDoc p, InputStream JavaDoc in, OutputStream JavaDoc out, OutputStream JavaDoc err) throws IOException JavaDoc {
1116        InputStream JavaDoc pOut = p.getInputStream();
1117        InputStream JavaDoc pErr = p.getErrorStream();
1118        OutputStream JavaDoc pIn = p.getOutputStream();
1119
1120        boolean done = false;
1121        int b;
1122        boolean proc = false;
1123        while(!done) {
1124            if(pOut.available() > 0) {
1125                byte[] input = new byte[pOut.available()];
1126                if((b = pOut.read(input)) == -1) {
1127                    done = true;
1128                } else {
1129                    out.write(input);
1130                }
1131                proc = true;
1132            }
1133            if(pErr.available() > 0) {
1134                byte[] input = new byte[pErr.available()];
1135                if((b = pErr.read(input)) != -1) {
1136                    err.write(input);
1137                }
1138                proc = true;
1139            }
1140            if(in.available() > 0) {
1141                byte[] input = new byte[in.available()];
1142                if((b = in.read(input)) != -1) {
1143                    pIn.write(input);
1144                }
1145                proc = true;
1146            }
1147            if(!proc) {
1148                if((b = pOut.read()) == -1) {
1149                    if((b = pErr.read()) == -1) {
1150                        done = true;
1151                    } else {
1152                        err.write(b);
1153                    }
1154                } else {
1155                    out.write(b);
1156                }
1157            }
1158            proc = false;
1159        }
1160        pOut.close();
1161        pErr.close();
1162        pIn.close();
1163    }
1164
1165    public static RubyInteger srand(IRubyObject recv, IRubyObject[] args) {
1166        Ruby runtime = recv.getRuntime();
1167        long oldRandomSeed = runtime.getRandomSeed();
1168
1169        if (args.length > 0) {
1170            RubyInteger integerSeed =
1171                (RubyInteger) args[0].convertToType("Integer", "to_i", true);
1172            runtime.setRandomSeed(integerSeed.getLongValue());
1173        } else {
1174            // Not sure how well this works, but it works much better than
1175
// just currentTimeMillis by itself.
1176
runtime.setRandomSeed(System.currentTimeMillis() ^
1177              recv.hashCode() ^ runtime.incrementRandomSeedSequence() ^
1178              runtime.getRandom().nextInt(Math.abs((int)runtime.getRandomSeed())));
1179        }
1180        runtime.getRandom().setSeed(runtime.getRandomSeed());
1181        return runtime.newFixnum(oldRandomSeed);
1182    }
1183
1184    public static RubyNumeric rand(IRubyObject recv, IRubyObject[] args) {
1185        long ceil;
1186        if (args.length == 0) {
1187            ceil = 0;
1188        } else if (args.length == 1) {
1189            RubyInteger integerCeil = (RubyInteger) args[0].convertToType("Integer", "to_i", true);
1190            ceil = integerCeil.getLongValue();
1191            ceil = Math.abs(ceil);
1192            if (ceil > Integer.MAX_VALUE) {
1193                throw recv.getRuntime().newNotImplementedError("Random values larger than Integer.MAX_VALUE not supported");
1194            }
1195        } else {
1196            throw recv.getRuntime().newArgumentError("wrong # of arguments(" + args.length + " for 1)");
1197        }
1198
1199        if (ceil == 0) {
1200            double result = recv.getRuntime().getRandom().nextDouble();
1201            return RubyFloat.newFloat(recv.getRuntime(), result);
1202        }
1203        return recv.getRuntime().newFixnum(recv.getRuntime().getRandom().nextInt((int) ceil));
1204    }
1205
1206    public static RubyBoolean system(IRubyObject recv, IRubyObject[] args) {
1207        Ruby runtime = recv.getRuntime();
1208        int resultCode = runInShell(runtime, args);
1209        recv.getRuntime().getGlobalVariables().set("$?", RubyProcess.RubyStatus.newProcessStatus(runtime, resultCode));
1210        return runtime.newBoolean(resultCode == 0);
1211    }
1212    
1213    public static RubyArray to_a(IRubyObject recv) {
1214        recv.getRuntime().getWarnings().warn("default 'to_a' will be obsolete");
1215        return recv.getRuntime().newArray(recv);
1216    }
1217}
1218
Popular Tags