Source Code Cross Referenced for RubyIO.java in  » Scripting » jruby » org » jruby » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Scripting » jruby » org.jruby 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /***** BEGIN LICENSE BLOCK *****
0002:         * Version: CPL 1.0/GPL 2.0/LGPL 2.1
0003:         *
0004:         * The contents of this file are subject to the Common Public
0005:         * License Version 1.0 (the "License"); you may not use this file
0006:         * except in compliance with the License. You may obtain a copy of
0007:         * the License at http://www.eclipse.org/legal/cpl-v10.html
0008:         *
0009:         * Software distributed under the License is distributed on an "AS
0010:         * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
0011:         * implied. See the License for the specific language governing
0012:         * rights and limitations under the License.
0013:         *
0014:         * Copyright (C) 2001-2004 Jan Arne Petersen <jpetersen@uni-bonn.de>
0015:         * Copyright (C) 2002 Benoit Cerrina <b.cerrina@wanadoo.fr>
0016:         * Copyright (C) 2002-2004 Anders Bengtsson <ndrsbngtssn@yahoo.se>
0017:         * Copyright (C) 2002-2006 Thomas E Enebo <enebo@acm.org>
0018:         * Copyright (C) 2004-2006 Charles O Nutter <headius@headius.com>
0019:         * Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de>
0020:         * Copyright (C) 2006 Evan Buswell <ebuswell@gmail.com>
0021:         * Copyright (C) 2007 Miguel Covarrubias <mlcovarrubias@gmail.com>
0022:         * 
0023:         * Alternatively, the contents of this file may be used under the terms of
0024:         * either of the GNU General Public License Version 2 or later (the "GPL"),
0025:         * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
0026:         * in which case the provisions of the GPL or the LGPL are applicable instead
0027:         * of those above. If you wish to allow use of your version of this file only
0028:         * under the terms of either the GPL or the LGPL, and not to allow others to
0029:         * use your version of this file under the terms of the CPL, indicate your
0030:         * decision by deleting the provisions above and replace them with the notice
0031:         * and other provisions required by the GPL or the LGPL. If you do not delete
0032:         * the provisions above, a recipient may use your version of this file under
0033:         * the terms of any one of the CPL, the GPL or the LGPL.
0034:         ***** END LICENSE BLOCK *****/package org.jruby;
0035:
0036:        import java.io.EOFException;
0037:        import java.io.FileNotFoundException;
0038:        import java.io.IOException;
0039:        import java.io.InputStream;
0040:        import java.io.OutputStream;
0041:        import java.lang.ref.WeakReference;
0042:        import java.nio.channels.Channel;
0043:        import java.nio.channels.Pipe;
0044:        import java.nio.channels.SelectableChannel;
0045:        import java.nio.channels.SelectionKey;
0046:        import java.nio.channels.Selector;
0047:        import java.util.ArrayList;
0048:        import java.util.HashSet;
0049:        import java.util.Iterator;
0050:        import java.util.List;
0051:        import java.util.Set;
0052:
0053:        import org.jruby.runtime.Arity;
0054:        import org.jruby.runtime.Block;
0055:        import org.jruby.runtime.CallbackFactory;
0056:        import org.jruby.runtime.MethodIndex;
0057:        import org.jruby.runtime.ObjectAllocator;
0058:        import org.jruby.runtime.ThreadContext;
0059:        import org.jruby.runtime.builtin.IRubyObject;
0060:        import org.jruby.util.ByteList;
0061:        import org.jruby.util.IOHandler;
0062:        import org.jruby.util.IOHandlerJavaIO;
0063:        import org.jruby.util.IOHandlerNio;
0064:        import org.jruby.util.IOHandlerNull;
0065:        import org.jruby.util.IOHandlerProcess;
0066:        import org.jruby.util.IOHandlerSeekable;
0067:        import org.jruby.util.IOHandlerUnseekable;
0068:        import org.jruby.util.IOModes;
0069:        import org.jruby.util.ShellLauncher;
0070:
0071:        /**
0072:         * 
0073:         * @author jpetersen
0074:         */
0075:        public class RubyIO extends RubyObject {
0076:            public static final int STDIN = 0;
0077:            public static final int STDOUT = 1;
0078:            public static final int STDERR = 2;
0079:
0080:            protected IOHandler handler;
0081:            protected IOModes modes = null;
0082:            protected int lineNumber = 0;
0083:
0084:            // Does THIS IO object think it is still open
0085:            // as opposed to the IO Handler which knows the
0086:            // actual truth.  If two IO objects share the
0087:            // same IO Handler, then it is possible for
0088:            // one object to think that the handler is open
0089:            // when it really isn't.  Keeping track of this yields
0090:            // the right errors.
0091:            protected boolean isOpen = true;
0092:            private boolean atEOF = false;
0093:
0094:            /*
0095:             * Random notes:
0096:             *  
0097:             * 1. When a second IO object is created with the same fileno odd
0098:             * concurrency issues happen when the underlying implementation
0099:             * commits data.   So:
0100:             * 
0101:             * f = File.new("some file", "w")
0102:             * f.puts("heh")
0103:             * g = IO.new(f.fileno)
0104:             * g.puts("hoh")
0105:             * ... more operations of g and f ...
0106:             * 
0107:             * Will generate a mess in "some file".  The problem is that most
0108:             * operations are buffered.  When those buffers flush and get
0109:             * written to the physical file depends on the implementation
0110:             * (semantically I would think that it should be last op wins -- but 
0111:             * it isn't).  I doubt java could mimic ruby in this way.  I also 
0112:             * doubt many people are taking advantage of this.  How about 
0113:             * syswrite/sysread though?  I think the fact that sysread/syswrite 
0114:             * are defined to be a low-level system calls, allows implementations 
0115:             * to be somewhat different?
0116:             * 
0117:             * 2. In the case of:
0118:             * f = File.new("some file", "w")
0119:             * f.puts("heh")
0120:             * print f.pos
0121:             * g = IO.new(f.fileno)
0122:             * print g.pos
0123:             * Both printed positions will be the same.  But:
0124:             * f = File.new("some file", "w")
0125:             * f.puts("heh")
0126:             * g = IO.new(f.fileno)
0127:             * print f.pos, g.pos
0128:             * won't be the same position.  Seem peculiar enough not to touch
0129:             * (this involves pos() actually causing a seek?)
0130:             * 
0131:             * 3. All IO objects reference a IOHandler.  If multiple IO objects
0132:             * have the same fileno, then they also share the same IOHandler.
0133:             * It is possible that some IO objects may share the same IOHandler
0134:             * but not have the same permissions.  However, all subsequent IO
0135:             * objects created after the first must be a subset of the original
0136:             * IO Object (see below for an example). 
0137:             *
0138:             * The idea that two or more IO objects can have different access
0139:             * modes means that IO objects must keep track of their own
0140:             * permissions.  In addition the IOHandler itself must know what
0141:             * access modes it has.
0142:             * 
0143:             * The above sharing situation only occurs in a situation like:
0144:             * f = File.new("some file", "r+")
0145:             * g = IO.new(f.fileno, "r")
0146:             * Where g has reduced (subset) permissions.
0147:             * 
0148:             * On reopen, the fileno's IOHandler gets replaced by a new handler. 
0149:             */
0150:
0151:            /*
0152:             * I considered making all callers of this be moved into IOHandlers
0153:             * constructors (since it would be less error prone to forget there).
0154:             * However, reopen() makes doing this a little funky. 
0155:             */
0156:            public void registerIOHandler(IOHandler newHandler) {
0157:                getRuntime().getIoHandlers().put(
0158:                        new Integer(newHandler.getFileno()),
0159:                        new WeakReference(newHandler));
0160:            }
0161:
0162:            public void unregisterIOHandler(int aFileno) {
0163:                getRuntime().getIoHandlers().remove(new Integer(aFileno));
0164:            }
0165:
0166:            public IOHandler getIOHandlerByFileno(int aFileno) {
0167:                return (IOHandler) ((WeakReference) getRuntime()
0168:                        .getIoHandlers().get(new Integer(aFileno))).get();
0169:            }
0170:
0171:            // FIXME can't use static; would interfere with other runtimes in the same JVM
0172:            protected static int fileno = 2;
0173:
0174:            public static int getNewFileno() {
0175:                fileno++;
0176:
0177:                return fileno;
0178:            }
0179:
0180:            // This should only be called by this and RubyFile.
0181:            // It allows this object to be created without a IOHandler.
0182:            public RubyIO(Ruby runtime, RubyClass type) {
0183:                super (runtime, type);
0184:            }
0185:
0186:            public RubyIO(Ruby runtime, OutputStream outputStream) {
0187:                super (runtime, runtime.getClass("IO"));
0188:
0189:                // We only want IO objects with valid streams (better to error now). 
0190:                if (outputStream == null) {
0191:                    throw runtime.newIOError("Opening invalid stream");
0192:                }
0193:
0194:                try {
0195:                    handler = new IOHandlerUnseekable(runtime, null,
0196:                            outputStream);
0197:                } catch (IOException e) {
0198:                    throw runtime.newIOError(e.getMessage());
0199:                }
0200:                modes = handler.getModes();
0201:
0202:                registerIOHandler(handler);
0203:            }
0204:
0205:            public RubyIO(Ruby runtime, InputStream inputStream) {
0206:                super (runtime, runtime.getClass("IO"));
0207:
0208:                if (inputStream == null) {
0209:                    throw runtime.newIOError("Opening invalid stream");
0210:                }
0211:
0212:                try {
0213:                    handler = new IOHandlerUnseekable(runtime, inputStream,
0214:                            null);
0215:                } catch (IOException e) {
0216:                    throw runtime.newIOError(e.getMessage());
0217:                }
0218:
0219:                modes = handler.getModes();
0220:
0221:                registerIOHandler(handler);
0222:            }
0223:
0224:            public RubyIO(Ruby runtime, Channel channel) {
0225:                super (runtime, runtime.getClass("IO"));
0226:
0227:                // We only want IO objects with valid streams (better to error now). 
0228:                if (channel == null) {
0229:                    throw runtime.newIOError("Opening invalid stream");
0230:                }
0231:
0232:                try {
0233:                    handler = new IOHandlerNio(runtime, channel);
0234:                } catch (IOException e) {
0235:                    throw runtime.newIOError(e.getMessage());
0236:                }
0237:                modes = handler.getModes();
0238:
0239:                registerIOHandler(handler);
0240:            }
0241:
0242:            public RubyIO(Ruby runtime, Process process) {
0243:                super (runtime, runtime.getClass("IO"));
0244:
0245:                modes = new IOModes(runtime, "w+");
0246:
0247:                try {
0248:                    handler = new IOHandlerProcess(runtime, process, modes);
0249:                } catch (IOException e) {
0250:                    throw runtime.newIOError(e.getMessage());
0251:                }
0252:                modes = handler.getModes();
0253:
0254:                registerIOHandler(handler);
0255:            }
0256:
0257:            public RubyIO(Ruby runtime, int descriptor) {
0258:                super (runtime, runtime.getClass("IO"));
0259:
0260:                try {
0261:                    handler = new IOHandlerUnseekable(runtime, descriptor);
0262:                } catch (IOException e) {
0263:                    throw runtime.newIOError(e.getMessage());
0264:                }
0265:                modes = handler.getModes();
0266:
0267:                registerIOHandler(handler);
0268:            }
0269:
0270:            private static ObjectAllocator IO_ALLOCATOR = new ObjectAllocator() {
0271:                public IRubyObject allocate(Ruby runtime, RubyClass klass) {
0272:                    return new RubyIO(runtime, klass);
0273:                }
0274:            };
0275:
0276:            public static RubyClass createIOClass(Ruby runtime) {
0277:                RubyClass ioClass = runtime.defineClass("IO", runtime
0278:                        .getObject(), IO_ALLOCATOR);
0279:                CallbackFactory callbackFactory = runtime
0280:                        .callbackFactory(RubyIO.class);
0281:                RubyClass ioMetaClass = ioClass.getMetaClass();
0282:
0283:                ioClass.includeModule(runtime.getModule("Enumerable"));
0284:
0285:                // TODO: Implement tty? and isatty.  We have no real capability to
0286:                // determine this from java, but if we could set tty status, then
0287:                // we could invoke jruby differently to allow stdin to return true
0288:                // on this.  This would allow things like cgi.rb to work properly.
0289:
0290:                ioMetaClass.defineMethod("foreach", callbackFactory
0291:                        .getOptSingletonMethod("foreach"));
0292:                ioMetaClass.defineMethod("read", callbackFactory
0293:                        .getOptSingletonMethod("read"));
0294:                ioMetaClass.defineMethod("readlines", callbackFactory
0295:                        .getOptSingletonMethod("readlines"));
0296:                ioMetaClass.defineMethod("popen", callbackFactory
0297:                        .getOptSingletonMethod("popen"));
0298:                ioMetaClass.defineFastMethod("select", callbackFactory
0299:                        .getFastOptSingletonMethod("select"));
0300:                ioMetaClass.defineFastMethod("pipe", callbackFactory
0301:                        .getFastSingletonMethod("pipe"));
0302:
0303:                ioClass.defineFastMethod("<<", callbackFactory.getFastMethod(
0304:                        "addString", IRubyObject.class));
0305:                ioClass.defineFastMethod("binmode", callbackFactory
0306:                        .getFastMethod("binmode"));
0307:                ioClass.defineFastMethod("close", callbackFactory
0308:                        .getFastMethod("close"));
0309:                ioClass.defineFastMethod("close_write", callbackFactory
0310:                        .getFastMethod("closeWrite"));
0311:                ioClass.defineFastMethod("closed?", callbackFactory
0312:                        .getFastMethod("closed"));
0313:                ioClass.defineMethod("each", callbackFactory
0314:                        .getOptMethod("each_line"));
0315:                ioClass.defineMethod("each_byte", callbackFactory
0316:                        .getMethod("each_byte"));
0317:                ioClass.defineMethod("each_line", callbackFactory
0318:                        .getOptMethod("each_line"));
0319:                ioClass.defineFastMethod("eof", callbackFactory
0320:                        .getFastMethod("eof"));
0321:                ioClass.defineAlias("eof?", "eof");
0322:                ioClass.defineFastMethod("fcntl", callbackFactory
0323:                        .getFastMethod("fcntl", IRubyObject.class,
0324:                                IRubyObject.class));
0325:                ioClass.defineFastMethod("fileno", callbackFactory
0326:                        .getFastMethod("fileno"));
0327:                ioClass.defineFastMethod("flush", callbackFactory
0328:                        .getFastMethod("flush"));
0329:                ioClass.defineFastMethod("fsync", callbackFactory
0330:                        .getFastMethod("fsync"));
0331:                ioClass.defineFastMethod("getc", callbackFactory
0332:                        .getFastMethod("getc"));
0333:                ioClass.defineFastMethod("gets", callbackFactory
0334:                        .getFastOptMethod("gets"));
0335:                ioClass.defineMethod("initialize", callbackFactory
0336:                        .getOptMethod("initialize"));
0337:                ioClass.defineFastMethod("initialize_copy", callbackFactory
0338:                        .getFastMethod("initialize_copy", IRubyObject.class));
0339:                ioClass.defineFastMethod("lineno", callbackFactory
0340:                        .getFastMethod("lineno"));
0341:                ioClass.defineFastMethod("lineno=", callbackFactory
0342:                        .getFastMethod("lineno_set", IRubyObject.class));
0343:                ioClass.defineFastMethod("pid", callbackFactory
0344:                        .getFastMethod("pid"));
0345:                ioClass.defineFastMethod("pos", callbackFactory
0346:                        .getFastMethod("pos"));
0347:                ioClass.defineFastMethod("pos=", callbackFactory.getFastMethod(
0348:                        "pos_set", IRubyObject.class));
0349:                ioClass.defineFastMethod("print", callbackFactory
0350:                        .getFastOptMethod("print"));
0351:                ioClass.defineFastMethod("printf", callbackFactory
0352:                        .getFastOptMethod("printf"));
0353:                ioClass.defineFastMethod("putc", callbackFactory.getFastMethod(
0354:                        "putc", IRubyObject.class));
0355:                ioClass.defineFastMethod("puts", callbackFactory
0356:                        .getFastOptMethod("puts"));
0357:                ioClass.defineFastMethod("readpartial", callbackFactory
0358:                        .getFastOptMethod("readpartial"));
0359:                ioClass.defineFastMethod("read", callbackFactory
0360:                        .getFastOptMethod("read"));
0361:                ioClass.defineFastMethod("readchar", callbackFactory
0362:                        .getFastMethod("readchar"));
0363:                ioClass.defineFastMethod("readline", callbackFactory
0364:                        .getFastOptMethod("readline"));
0365:                ioClass.defineFastMethod("readlines", callbackFactory
0366:                        .getFastOptMethod("readlines"));
0367:                ioClass.defineFastMethod("reopen", callbackFactory
0368:                        .getFastOptMethod("reopen"));
0369:                ioClass.defineFastMethod("rewind", callbackFactory
0370:                        .getFastMethod("rewind"));
0371:                ioClass.defineFastMethod("seek", callbackFactory
0372:                        .getFastOptMethod("seek"));
0373:                ioClass.defineFastMethod("sync", callbackFactory
0374:                        .getFastMethod("sync"));
0375:                ioClass.defineFastMethod("sync=", callbackFactory
0376:                        .getFastMethod("sync_set", IRubyObject.class));
0377:                ioClass.defineFastMethod("sysread", callbackFactory
0378:                        .getFastOptMethod("sysread"));
0379:                ioClass.defineFastMethod("syswrite", callbackFactory
0380:                        .getFastMethod("syswrite", IRubyObject.class));
0381:                ioClass.defineAlias("tell", "pos");
0382:                ioClass.defineAlias("to_i", "fileno");
0383:                ioClass.defineFastMethod("to_io", callbackFactory
0384:                        .getFastMethod("to_io"));
0385:                ioClass.defineFastMethod("ungetc", callbackFactory
0386:                        .getFastMethod("ungetc", IRubyObject.class));
0387:                ioClass.defineFastMethod("write", callbackFactory
0388:                        .getFastMethod("write", IRubyObject.class));
0389:                ioClass.defineFastMethod("tty?", callbackFactory
0390:                        .getFastMethod("tty"));
0391:                ioClass.defineAlias("isatty", "tty?");
0392:
0393:                // Constants for seek
0394:                ioClass.setConstant("SEEK_SET", runtime
0395:                        .newFixnum(IOHandler.SEEK_SET));
0396:                ioClass.setConstant("SEEK_CUR", runtime
0397:                        .newFixnum(IOHandler.SEEK_CUR));
0398:                ioClass.setConstant("SEEK_END", runtime
0399:                        .newFixnum(IOHandler.SEEK_END));
0400:
0401:                return ioClass;
0402:            }
0403:
0404:            /**
0405:             * <p>Open a file descriptor, unless it is already open, then return
0406:             * it.</p> 
0407:             */
0408:            public static IRubyObject fdOpen(Ruby runtime, int descriptor) {
0409:                return new RubyIO(runtime, descriptor);
0410:            }
0411:
0412:            /*
0413:             * See checkReadable for commentary.
0414:             */
0415:            protected void checkWriteable() {
0416:                if (!isOpen() || !modes.isWriteable()) {
0417:                    throw getRuntime().newIOError("not opened for writing");
0418:                }
0419:            }
0420:
0421:            /*
0422:             * What the IO object "thinks" it can do.  If two IO objects share
0423:             * the same fileno (IOHandler), then it is possible for one to pull
0424:             * the rug out from the other.  This will make the second object still
0425:             * "think" that the file is open.  Secondly, if two IO objects share
0426:             * the same fileno, but the second one only has a subset of the access
0427:             * permissions, then it will "think" that it cannot do certain 
0428:             * operations.
0429:             */
0430:            protected void checkReadable() {
0431:                if (!isOpen() || !modes.isReadable()) {
0432:                    throw getRuntime().newIOError("not opened for reading");
0433:                }
0434:            }
0435:
0436:            public boolean isOpen() {
0437:                return isOpen;
0438:            }
0439:
0440:            public OutputStream getOutStream() {
0441:                if (handler instanceof  IOHandlerJavaIO) {
0442:                    return ((IOHandlerJavaIO) handler).getOutputStream();
0443:                } else {
0444:                    return null;
0445:                }
0446:            }
0447:
0448:            public InputStream getInStream() {
0449:                if (handler instanceof  IOHandlerJavaIO) {
0450:                    return ((IOHandlerJavaIO) handler).getInputStream();
0451:                } else {
0452:                    return null;
0453:                }
0454:            }
0455:
0456:            public Channel getChannel() {
0457:                if (handler instanceof  IOHandlerNio) {
0458:                    return ((IOHandlerNio) handler).getChannel();
0459:                } else {
0460:                    return null;
0461:                }
0462:            }
0463:
0464:            public IRubyObject reopen(IRubyObject[] args) {
0465:                if (args.length < 1) {
0466:                    throw getRuntime().newArgumentError(
0467:                            "wrong number of arguments");
0468:                }
0469:
0470:                if (args[0].isKindOf(getRuntime().getClass("IO"))) {
0471:                    RubyIO ios = (RubyIO) args[0];
0472:
0473:                    int keepFileno = handler.getFileno();
0474:
0475:                    // close the old handler before it gets overwritten
0476:                    if (handler.isOpen()) {
0477:                        try {
0478:                            handler.close();
0479:                        } catch (IOHandler.BadDescriptorException e) {
0480:                            throw getRuntime().newErrnoEBADFError();
0481:                        } catch (EOFException e) {
0482:                            return getRuntime().getNil();
0483:                        } catch (IOException e) {
0484:                            throw getRuntime().newIOError(e.getMessage());
0485:                        }
0486:                    }
0487:
0488:                    // When we reopen, we want our fileno to be preserved even
0489:                    // though we have a new IOHandler.
0490:                    // Note: When we clone we get a new fileno...then we replace it.
0491:                    // This ends up incrementing our fileno index up, which makes the
0492:                    // fileno we choose different from ruby.  Since this seems a bit
0493:                    // too implementation specific, I did not bother trying to get
0494:                    // these to agree (what scary code would depend on fileno generating
0495:                    // a particular way?)
0496:                    try {
0497:                        handler = ios.handler.cloneIOHandler();
0498:                    } catch (IOHandler.InvalidValueException e) {
0499:                        throw getRuntime().newErrnoEINVALError();
0500:                    } catch (IOHandler.PipeException e) {
0501:                        throw getRuntime().newErrnoESPIPEError();
0502:                    } catch (FileNotFoundException e) {
0503:                        throw getRuntime().newErrnoENOENTError();
0504:                    } catch (IOException e) {
0505:                        throw getRuntime().newIOError(e.getMessage());
0506:                    }
0507:                    handler.setFileno(keepFileno);
0508:
0509:                    // Update fileno list with our new handler
0510:                    registerIOHandler(handler);
0511:                } else if (args[0].isKindOf(getRuntime().getString())) {
0512:                    String path = ((RubyString) args[0]).toString();
0513:                    IOModes newModes = null;
0514:
0515:                    if (args.length > 1) {
0516:                        if (!args[1].isKindOf(getRuntime().getString())) {
0517:                            throw getRuntime().newTypeError(args[1],
0518:                                    getRuntime().getString());
0519:                        }
0520:
0521:                        newModes = new IOModes(getRuntime(),
0522:                                ((RubyString) args[1]).toString());
0523:                    }
0524:
0525:                    try {
0526:                        if (handler != null) {
0527:                            close();
0528:                        }
0529:
0530:                        if (newModes != null) {
0531:                            modes = newModes;
0532:                        }
0533:                        if ("/dev/null".equals(path)) {
0534:                            handler = new IOHandlerNull(getRuntime(), modes);
0535:                        } else {
0536:                            handler = new IOHandlerSeekable(getRuntime(), path,
0537:                                    modes);
0538:                        }
0539:
0540:                        registerIOHandler(handler);
0541:                    } catch (IOHandler.InvalidValueException e) {
0542:                        throw getRuntime().newErrnoEINVALError();
0543:                    } catch (IOException e) {
0544:                        throw getRuntime().newIOError(e.toString());
0545:                    }
0546:                }
0547:
0548:                // A potentially previously close IO is being 'reopened'.
0549:                isOpen = true;
0550:                return this ;
0551:            }
0552:
0553:            /** Read a line.
0554:             * 
0555:             */
0556:            // TODO: Most things loop over this and always pass it the same arguments
0557:            // meaning they are an invariant of the loop.  Think about fixing this.
0558:            public IRubyObject internalGets(IRubyObject[] args) {
0559:                checkReadable();
0560:
0561:                IRubyObject sepVal;
0562:
0563:                if (args.length > 0) {
0564:                    sepVal = args[0];
0565:                } else {
0566:                    sepVal = getRuntime().getGlobalVariables().get("$/");
0567:                }
0568:
0569:                ByteList separator = sepVal.isNil() ? null
0570:                        : ((RubyString) sepVal).getByteList();
0571:
0572:                if (separator != null && separator.realSize == 0) {
0573:                    separator = IOHandler.PARAGRAPH_DELIMETER;
0574:                }
0575:
0576:                try {
0577:
0578:                    ByteList newLine = handler.gets(separator);
0579:
0580:                    if (newLine != null) {
0581:                        lineNumber++;
0582:                        getRuntime().getGlobalVariables().set("$.",
0583:                                getRuntime().newFixnum(lineNumber));
0584:                        RubyString result = RubyString.newString(getRuntime(),
0585:                                newLine);
0586:                        result.taint();
0587:
0588:                        return result;
0589:                    }
0590:
0591:                    return getRuntime().getNil();
0592:                } catch (EOFException e) {
0593:                    return getRuntime().getNil();
0594:                } catch (IOHandler.BadDescriptorException e) {
0595:                    throw getRuntime().newErrnoEBADFError();
0596:                } catch (IOException e) {
0597:                    throw getRuntime().newIOError(e.getMessage());
0598:                }
0599:            }
0600:
0601:            // IO class methods.
0602:
0603:            public IRubyObject initialize(IRubyObject[] args, Block unusedBlock) {
0604:                int count = Arity.checkArgumentCount(getRuntime(), args, 1, 2);
0605:                int newFileno = RubyNumeric.fix2int(args[0]);
0606:                String mode = null;
0607:
0608:                if (count > 1) {
0609:                    mode = args[1].convertToString().toString();
0610:                }
0611:
0612:                // See if we already have this descriptor open.
0613:                // If so then we can mostly share the handler (keep open
0614:                // file, but possibly change the mode).
0615:                IOHandler existingIOHandler = getIOHandlerByFileno(newFileno);
0616:
0617:                if (existingIOHandler == null) {
0618:                    if (mode == null) {
0619:                        mode = "r";
0620:                    }
0621:
0622:                    try {
0623:                        handler = new IOHandlerUnseekable(getRuntime(),
0624:                                newFileno, mode);
0625:                    } catch (IOException e) {
0626:                        throw getRuntime().newIOError(e.getMessage());
0627:                    }
0628:                    modes = new IOModes(getRuntime(), mode);
0629:
0630:                    registerIOHandler(handler);
0631:                } else {
0632:                    // We are creating a new IO object that shares the same
0633:                    // IOHandler (and fileno).  
0634:                    handler = existingIOHandler;
0635:
0636:                    // Inherit if no mode specified otherwise create new one
0637:                    modes = mode == null ? handler.getModes() : new IOModes(
0638:                            getRuntime(), mode);
0639:
0640:                    // Reset file based on modes.
0641:                    try {
0642:                        handler.reset(modes);
0643:                    } catch (IOHandler.InvalidValueException e) {
0644:                        throw getRuntime().newErrnoEINVALError();
0645:                    } catch (IOException e) {
0646:                        throw getRuntime().newIOError(e.getMessage());
0647:                    }
0648:                }
0649:
0650:                return this ;
0651:            }
0652:
0653:            // This appears to be some windows-only mode.  On a java platform this is a no-op
0654:            public IRubyObject binmode() {
0655:                return this ;
0656:            }
0657:
0658:            public IRubyObject syswrite(IRubyObject obj) {
0659:                try {
0660:                    if (obj instanceof  RubyString) {
0661:                        return getRuntime().newFixnum(
0662:                                handler.syswrite(((RubyString) obj)
0663:                                        .getByteList()));
0664:                    } else {
0665:                        // FIXME: unlikely to be efficient, but probably correct
0666:                        return getRuntime().newFixnum(
0667:                                handler.syswrite(((RubyString) obj.callMethod(
0668:                                        obj.getRuntime().getCurrentContext(),
0669:                                        MethodIndex.TO_S, "to_s"))
0670:                                        .getByteList()));
0671:                    }
0672:                } catch (IOHandler.BadDescriptorException e) {
0673:                    throw getRuntime().newErrnoEBADFError();
0674:                } catch (IOException e) {
0675:                    throw getRuntime().newSystemCallError(e.getMessage());
0676:                }
0677:            }
0678:
0679:            /** io_write
0680:             * 
0681:             */
0682:            public IRubyObject write(IRubyObject obj) {
0683:                checkWriteable();
0684:
0685:                try {
0686:                    if (obj instanceof  RubyString) {
0687:                        return getRuntime()
0688:                                .newFixnum(
0689:                                        handler.write(((RubyString) obj)
0690:                                                .getByteList()));
0691:                    } else {
0692:                        // FIXME: unlikely to be efficient, but probably correct
0693:                        return getRuntime().newFixnum(
0694:                                handler.write(((RubyString) obj.callMethod(obj
0695:                                        .getRuntime().getCurrentContext(),
0696:                                        MethodIndex.TO_S, "to_s"))
0697:                                        .getByteList()));
0698:                    }
0699:                } catch (IOHandler.BadDescriptorException e) {
0700:                    return RubyFixnum.zero(getRuntime());
0701:                } catch (IOException e) {
0702:                    return RubyFixnum.zero(getRuntime());
0703:                }
0704:            }
0705:
0706:            /** rb_io_addstr
0707:             * 
0708:             */
0709:            public IRubyObject addString(IRubyObject anObject) {
0710:                // Claims conversion is done via 'to_s' in docs.
0711:                IRubyObject strObject = anObject.callMethod(getRuntime()
0712:                        .getCurrentContext(), MethodIndex.TO_S, "to_s");
0713:
0714:                write(strObject);
0715:
0716:                return this ;
0717:            }
0718:
0719:            public RubyFixnum fileno() {
0720:                return getRuntime().newFixnum(handler.getFileno());
0721:            }
0722:
0723:            /** Returns the current line number.
0724:             * 
0725:             * @return the current line number.
0726:             */
0727:            public RubyFixnum lineno() {
0728:                return getRuntime().newFixnum(lineNumber);
0729:            }
0730:
0731:            /** Sets the current line number.
0732:             * 
0733:             * @param newLineNumber The new line number.
0734:             */
0735:            public RubyFixnum lineno_set(IRubyObject newLineNumber) {
0736:                lineNumber = RubyNumeric.fix2int(newLineNumber);
0737:
0738:                return (RubyFixnum) newLineNumber;
0739:            }
0740:
0741:            /** Returns the current sync mode.
0742:             * 
0743:             * @return the current sync mode.
0744:             */
0745:            public RubyBoolean sync() {
0746:                return getRuntime().newBoolean(handler.isSync());
0747:            }
0748:
0749:            /**
0750:             * <p>Return the process id (pid) of the process this IO object
0751:             * spawned.  If no process exists (popen was not called), then
0752:             * nil is returned.  This is not how it appears to be defined
0753:             * but ruby 1.8 works this way.</p>
0754:             * 
0755:             * @return the pid or nil
0756:             */
0757:            public IRubyObject pid() {
0758:                int pid = handler.pid();
0759:
0760:                return pid == -1 ? getRuntime().getNil() : getRuntime()
0761:                        .newFixnum(pid);
0762:            }
0763:
0764:            public boolean hasPendingBuffered() {
0765:                return handler.hasPendingBuffered();
0766:            }
0767:
0768:            public RubyFixnum pos() {
0769:                try {
0770:                    return getRuntime().newFixnum(handler.pos());
0771:                } catch (IOHandler.PipeException e) {
0772:                    throw getRuntime().newErrnoESPIPEError();
0773:                } catch (IOException e) {
0774:                    throw getRuntime().newIOError(e.getMessage());
0775:                }
0776:            }
0777:
0778:            public RubyFixnum pos_set(IRubyObject newPosition) {
0779:                long offset = RubyNumeric.fix2long(newPosition);
0780:
0781:                if (offset < 0) {
0782:                    throw getRuntime().newSystemCallError(
0783:                            "Negative seek offset");
0784:                }
0785:
0786:                try {
0787:                    handler.seek(offset, IOHandler.SEEK_SET);
0788:                } catch (IOHandler.InvalidValueException e) {
0789:                    throw getRuntime().newErrnoEINVALError();
0790:                } catch (IOHandler.PipeException e) {
0791:                    throw getRuntime().newErrnoESPIPEError();
0792:                } catch (IOException e) {
0793:                    throw getRuntime().newIOError(e.getMessage());
0794:                }
0795:
0796:                return (RubyFixnum) newPosition;
0797:            }
0798:
0799:            /** Print some objects to the stream.
0800:             * 
0801:             */
0802:            public IRubyObject print(IRubyObject[] args) {
0803:                if (args.length == 0) {
0804:                    args = new IRubyObject[] { getRuntime().getCurrentContext()
0805:                            .getLastline() };
0806:                }
0807:
0808:                IRubyObject fs = getRuntime().getGlobalVariables().get("$,");
0809:                IRubyObject rs = getRuntime().getGlobalVariables().get("$\\");
0810:                ThreadContext context = getRuntime().getCurrentContext();
0811:
0812:                for (int i = 0; i < args.length; i++) {
0813:                    if (i > 0 && !fs.isNil()) {
0814:                        callMethod(context, "write", fs);
0815:                    }
0816:                    if (args[i].isNil()) {
0817:                        callMethod(context, "write", getRuntime().newString(
0818:                                "nil"));
0819:                    } else {
0820:                        callMethod(context, "write", args[i]);
0821:                    }
0822:                }
0823:                if (!rs.isNil()) {
0824:                    callMethod(context, "write", rs);
0825:                }
0826:
0827:                return getRuntime().getNil();
0828:            }
0829:
0830:            public IRubyObject printf(IRubyObject[] args) {
0831:                Arity.checkArgumentCount(getRuntime(), args, 1, -1);
0832:                callMethod(getRuntime().getCurrentContext(), "write",
0833:                        RubyKernel.sprintf(this , args));
0834:                return getRuntime().getNil();
0835:            }
0836:
0837:            public IRubyObject putc(IRubyObject object) {
0838:                int c;
0839:
0840:                if (object.isKindOf(getRuntime().getString())) {
0841:                    String value = ((RubyString) object).toString();
0842:
0843:                    if (value.length() > 0) {
0844:                        c = value.charAt(0);
0845:                    } else {
0846:                        throw getRuntime().newTypeError(
0847:                                "Cannot convert String to Integer");
0848:                    }
0849:                } else if (object.isKindOf(getRuntime().getFixnum())) {
0850:                    c = RubyNumeric.fix2int(object);
0851:                } else { // What case will this work for?
0852:                    c = RubyNumeric.fix2int(object.callMethod(getRuntime()
0853:                            .getCurrentContext(), MethodIndex.TO_I, "to_i"));
0854:                }
0855:
0856:                try {
0857:                    handler.putc(c);
0858:                } catch (IOHandler.BadDescriptorException e) {
0859:                    return RubyFixnum.zero(getRuntime());
0860:                } catch (IOException e) {
0861:                    return RubyFixnum.zero(getRuntime());
0862:                }
0863:
0864:                return object;
0865:            }
0866:
0867:            // This was a getOpt with one mandatory arg, but it did not work
0868:            // so I am parsing it for now.
0869:            public RubyFixnum seek(IRubyObject[] args) {
0870:                if (args.length == 0) {
0871:                    throw getRuntime().newArgumentError(
0872:                            "wrong number of arguments");
0873:                }
0874:
0875:                long offset = RubyNumeric.fix2long(args[0]);
0876:                int type = IOHandler.SEEK_SET;
0877:
0878:                if (args.length > 1) {
0879:                    type = RubyNumeric.fix2int(args[1].convertToInteger());
0880:                }
0881:
0882:                try {
0883:                    handler.seek(offset, type);
0884:                } catch (IOHandler.InvalidValueException e) {
0885:                    throw getRuntime().newErrnoEINVALError();
0886:                } catch (IOHandler.PipeException e) {
0887:                    throw getRuntime().newErrnoESPIPEError();
0888:                } catch (IOException e) {
0889:                    throw getRuntime().newIOError(e.getMessage());
0890:                }
0891:
0892:                return RubyFixnum.zero(getRuntime());
0893:            }
0894:
0895:            public RubyFixnum rewind() {
0896:                try {
0897:                    handler.rewind();
0898:                } catch (IOHandler.InvalidValueException e) {
0899:                    throw getRuntime().newErrnoEINVALError();
0900:                } catch (IOHandler.PipeException e) {
0901:                    throw getRuntime().newErrnoESPIPEError();
0902:                } catch (IOException e) {
0903:                    throw getRuntime().newIOError(e.getMessage());
0904:                }
0905:
0906:                // Must be back on first line on rewind.
0907:                lineNumber = 0;
0908:
0909:                return RubyFixnum.zero(getRuntime());
0910:            }
0911:
0912:            public RubyFixnum fsync() {
0913:                checkWriteable();
0914:
0915:                try {
0916:                    handler.sync();
0917:                } catch (IOException e) {
0918:                    throw getRuntime().newIOError(e.getMessage());
0919:                } catch (IOHandler.BadDescriptorException e) {
0920:                    throw getRuntime().newErrnoEBADFError();
0921:                }
0922:
0923:                return RubyFixnum.zero(getRuntime());
0924:            }
0925:
0926:            /** Sets the current sync mode.
0927:             * 
0928:             * @param newSync The new sync mode.
0929:             */
0930:            public IRubyObject sync_set(IRubyObject newSync) {
0931:                handler.setIsSync(newSync.isTrue());
0932:
0933:                return this ;
0934:            }
0935:
0936:            public RubyBoolean eof() {
0937:                try {
0938:                    boolean isEOF = handler.isEOF();
0939:                    return isEOF ? getRuntime().getTrue() : getRuntime()
0940:                            .getFalse();
0941:                } catch (IOHandler.BadDescriptorException e) {
0942:                    throw getRuntime().newErrnoEBADFError();
0943:                } catch (IOException e) {
0944:                    throw getRuntime().newIOError(e.getMessage());
0945:                }
0946:            }
0947:
0948:            public RubyBoolean tty() {
0949:                // TODO: this is less than ideal but might be as close as we'll get
0950:                int fileno = handler.getFileno();
0951:                if (fileno == STDOUT || fileno == STDIN || fileno == STDERR) {
0952:                    return getRuntime().getTrue();
0953:                } else {
0954:                    return getRuntime().getFalse();
0955:                }
0956:            }
0957:
0958:            public IRubyObject initialize_copy(IRubyObject original) {
0959:                if (this  == original)
0960:                    return this ;
0961:
0962:                RubyIO originalIO = (RubyIO) original;
0963:
0964:                // Two pos pointers?  
0965:                // http://blade.nagaokaut.ac.jp/ruby/ruby-talk/81513
0966:                // So if I understand this correctly, the descriptor level stuff
0967:                // shares things like position, but the higher level stuff uses
0968:                // a different set of libc functions (FILE*), which does not share
0969:                // position.  Our current implementation implements our higher 
0970:                // level operations on top of our 'sys' versions.  So we could in
0971:                // fact share everything.  Unfortunately, we want to clone ruby's
0972:                // behavior (i.e. show how this interface bleeds their 
0973:                // implementation). So our best bet, is to just create a yet another
0974:                // copy of the handler.  In fact, ruby 1.8 must do this as the cloned
0975:                // resource is in fact a different fileno.  What is clone for again?        
0976:
0977:                handler = originalIO.handler;
0978:                modes = (IOModes) originalIO.modes.clone();
0979:
0980:                return this ;
0981:            }
0982:
0983:            /** Closes the IO.
0984:             * 
0985:             * @return The IO.
0986:             */
0987:            public RubyBoolean closed() {
0988:                return isOpen() ? getRuntime().getFalse() : getRuntime()
0989:                        .getTrue();
0990:            }
0991:
0992:            /** 
0993:             * <p>Closes all open resources for the IO.  It also removes
0994:             * it from our magical all open file descriptor pool.</p>
0995:             * 
0996:             * @return The IO.
0997:             */
0998:            public IRubyObject close() {
0999:                isOpen = false;
1000:
1001:                try {
1002:                    handler.close();
1003:                } catch (IOHandler.BadDescriptorException e) {
1004:                    throw getRuntime().newErrnoEBADFError();
1005:                } catch (IOException e) {
1006:                    throw getRuntime().newIOError(e.getMessage());
1007:                }
1008:
1009:                unregisterIOHandler(handler.getFileno());
1010:
1011:                return this ;
1012:            }
1013:
1014:            public IRubyObject closeWrite() {
1015:                return this ;
1016:            }
1017:
1018:            /** Flushes the IO output stream.
1019:             * 
1020:             * @return The IO.
1021:             */
1022:            public RubyIO flush() {
1023:                try {
1024:                    handler.flush();
1025:                } catch (IOHandler.BadDescriptorException e) {
1026:                    throw getRuntime().newErrnoEBADFError();
1027:                } catch (IOException e) {
1028:                    throw getRuntime().newIOError(e.getMessage());
1029:                }
1030:
1031:                return this ;
1032:            }
1033:
1034:            /** Read a line.
1035:             * 
1036:             */
1037:            public IRubyObject gets(IRubyObject[] args) {
1038:                IRubyObject result = internalGets(args);
1039:
1040:                if (!result.isNil())
1041:                    getRuntime().getCurrentContext().setLastline(result);
1042:
1043:                return result;
1044:            }
1045:
1046:            public boolean getBlocking() {
1047:                if (!(handler instanceof  IOHandlerNio))
1048:                    return true;
1049:
1050:                return ((IOHandlerNio) handler).getBlocking();
1051:            }
1052:
1053:            public IRubyObject fcntl(IRubyObject cmd, IRubyObject arg)
1054:                    throws IOException {
1055:                long realCmd = cmd.convertToInteger().getLongValue();
1056:
1057:                // FIXME: Arg may also be true, false, and nil and still be valid.  Strangely enough, 
1058:                // protocol conversion is not happening in Ruby on this arg?
1059:                if (!(arg instanceof  RubyNumeric))
1060:                    return getRuntime().newFixnum(0);
1061:
1062:                long realArg = ((RubyNumeric) arg).getLongValue();
1063:
1064:                // Fixme: Only F_SETFL is current supported
1065:                if (realCmd == 1L) { // cmd is F_SETFL
1066:                    boolean block = true;
1067:
1068:                    if ((realArg & IOModes.NONBLOCK) == IOModes.NONBLOCK) {
1069:                        block = false;
1070:                    }
1071:
1072:                    if (!(handler instanceof  IOHandlerNio)) {
1073:                        // cryptic for the uninitiated...
1074:                        throw getRuntime().newNotImplementedError(
1075:                                "FCNTL only works with Nio based handlers");
1076:                    }
1077:
1078:                    try {
1079:                        ((IOHandlerNio) handler).setBlocking(block);
1080:                    } catch (IOException e) {
1081:                        throw getRuntime().newIOError(e.getMessage());
1082:                    }
1083:                }
1084:
1085:                return getRuntime().newFixnum(0);
1086:            }
1087:
1088:            public IRubyObject puts(IRubyObject[] args) {
1089:                Arity.checkArgumentCount(getRuntime(), args, 0, -1);
1090:
1091:                ThreadContext context = getRuntime().getCurrentContext();
1092:
1093:                if (args.length == 0) {
1094:                    callMethod(context, "write", getRuntime().newString("\n"));
1095:                    return getRuntime().getNil();
1096:                }
1097:
1098:                for (int i = 0; i < args.length; i++) {
1099:                    String line = null;
1100:                    if (args[i].isNil()) {
1101:                        line = "nil";
1102:                    } else if (args[i] instanceof  RubyArray) {
1103:                        puts(((RubyArray) args[i]).toJavaArray());
1104:                        continue;
1105:                    } else {
1106:                        line = args[i].toString();
1107:                    }
1108:                    callMethod(getRuntime().getCurrentContext(), "write",
1109:                            getRuntime().newString(
1110:                                    line + (line.endsWith("\n") ? "" : "\n")));
1111:                }
1112:                return getRuntime().getNil();
1113:            }
1114:
1115:            /** Read a line.
1116:             * 
1117:             */
1118:            public IRubyObject readline(IRubyObject[] args) {
1119:                IRubyObject line = gets(args);
1120:
1121:                if (line.isNil()) {
1122:                    throw getRuntime().newEOFError();
1123:                }
1124:
1125:                return line;
1126:            }
1127:
1128:            /** Read a byte. On EOF returns nil.
1129:             * 
1130:             */
1131:            public IRubyObject getc() {
1132:                checkReadable();
1133:
1134:                try {
1135:                    int c = handler.getc();
1136:
1137:                    return c == -1 ? getRuntime().getNil() : getRuntime()
1138:                            .newFixnum(c);
1139:                } catch (IOHandler.BadDescriptorException e) {
1140:                    throw getRuntime().newErrnoEBADFError();
1141:                } catch (EOFException e) {
1142:                    throw getRuntime().newEOFError();
1143:                } catch (IOException e) {
1144:                    throw getRuntime().newIOError(e.getMessage());
1145:                }
1146:            }
1147:
1148:            /** 
1149:             * <p>Pushes char represented by int back onto IOS.</p>
1150:             * 
1151:             * @param number to push back
1152:             */
1153:            public IRubyObject ungetc(IRubyObject number) {
1154:                handler.ungetc(RubyNumeric.fix2int(number));
1155:
1156:                return getRuntime().getNil();
1157:            }
1158:
1159:            public IRubyObject readpartial(IRubyObject[] args) {
1160:                if (!(handler instanceof  IOHandlerNio)) {
1161:                    // cryptic for the uninitiated...
1162:                    throw getRuntime().newNotImplementedError(
1163:                            "readpartial only works with Nio based handlers");
1164:                }
1165:                try {
1166:                    ByteList buf = ((IOHandlerNio) handler)
1167:                            .readpartial(RubyNumeric.fix2int(args[0]));
1168:                    IRubyObject strbuf = RubyString.newString(getRuntime(),
1169:                            buf == null ? new ByteList(ByteList.NULL_ARRAY)
1170:                                    : buf);
1171:                    if (args.length > 1) {
1172:                        args[1].callMethod(getRuntime().getCurrentContext(),
1173:                                MethodIndex.OP_LSHIFT, "<<", strbuf);
1174:                        return args[1];
1175:                    }
1176:
1177:                    return strbuf;
1178:                } catch (IOHandler.BadDescriptorException e) {
1179:                    throw getRuntime().newErrnoEBADFError();
1180:                } catch (EOFException e) {
1181:                    return getRuntime().getNil();
1182:                } catch (IOException e) {
1183:                    throw getRuntime().newIOError(e.getMessage());
1184:                }
1185:            }
1186:
1187:            public IRubyObject sysread(IRubyObject[] args) {
1188:                Arity.checkArgumentCount(getRuntime(), args, 1, 2);
1189:
1190:                int len = (int) RubyNumeric.num2long(args[0]);
1191:                if (len < 0)
1192:                    throw getRuntime().newArgumentError("Negative size");
1193:
1194:                try {
1195:                    RubyString str;
1196:                    if (args.length == 1 || args[1].isNil()) {
1197:                        if (len == 0)
1198:                            return RubyString.newString(getRuntime(), "");
1199:                        str = RubyString.newString(getRuntime(), handler
1200:                                .sysread(len));
1201:                    } else {
1202:                        str = args[1].convertToString();
1203:                        if (len == 0) {
1204:                            str.setValue(new ByteList());
1205:                            return str;
1206:                        }
1207:                        str.setValue(handler.sysread(len)); // should preserve same instance
1208:                    }
1209:                    str.setTaint(true);
1210:                    return str;
1211:
1212:                } catch (IOHandler.BadDescriptorException e) {
1213:                    throw getRuntime().newErrnoEBADFError();
1214:                } catch (EOFException e) {
1215:                    throw getRuntime().newEOFError();
1216:                } catch (IOException e) {
1217:                    // All errors to sysread should be SystemCallErrors, but on a closed stream
1218:                    // Ruby returns an IOError.  Java throws same exception for all errors so
1219:                    // we resort to this hack...
1220:                    if ("File not open".equals(e.getMessage())) {
1221:                        throw getRuntime().newIOError(e.getMessage());
1222:                    }
1223:                    throw getRuntime().newSystemCallError(e.getMessage());
1224:                }
1225:            }
1226:
1227:            public IRubyObject read(IRubyObject[] args) {
1228:
1229:                int argCount = Arity.checkArgumentCount(getRuntime(), args, 0,
1230:                        2);
1231:                RubyString callerBuffer = null;
1232:                boolean readEntireStream = (argCount == 0 || args[0].isNil());
1233:
1234:                try {
1235:                    // Reads when already at EOF keep us at EOF
1236:                    // We do retain the possibility of un-EOFing if the handler
1237:                    // gets new data
1238:                    if (atEOF && handler.isEOF())
1239:                        throw new EOFException();
1240:
1241:                    if (argCount == 2) {
1242:                        callerBuffer = args[1].convertToString();
1243:                    }
1244:
1245:                    ByteList buf;
1246:                    if (readEntireStream) {
1247:                        buf = handler.getsEntireStream();
1248:                    } else {
1249:                        long len = RubyNumeric.num2long(args[0]);
1250:                        if (len < 0)
1251:                            throw getRuntime().newArgumentError(
1252:                                    "negative length " + len + " given");
1253:                        buf = handler.read((int) len);
1254:                    }
1255:
1256:                    if (buf == null)
1257:                        throw new EOFException();
1258:
1259:                    // If we get here then no EOFException was thrown in the handler.  We
1260:                    // might still need to set our atEOF flag back to true depending on
1261:                    // whether we were reading the entire stream (see the finally block below)
1262:                    atEOF = false;
1263:                    if (callerBuffer != null) {
1264:                        callerBuffer.setValue(buf);
1265:                        return callerBuffer;
1266:                    }
1267:
1268:                    return RubyString.newString(getRuntime(), buf);
1269:                } catch (IOHandler.BadDescriptorException e) {
1270:                    throw getRuntime().newErrnoEBADFError();
1271:                } catch (EOFException e) {
1272:                    // on EOF, IO#read():
1273:                    // with no args or a nil first arg will return an empty string
1274:                    // with a non-nil first arg will return nil
1275:                    atEOF = true;
1276:                    if (callerBuffer != null) {
1277:                        callerBuffer.setValue("");
1278:                        return readEntireStream ? callerBuffer : getRuntime()
1279:                                .getNil();
1280:                    }
1281:
1282:                    return readEntireStream ? getRuntime().newString("")
1283:                            : getRuntime().getNil();
1284:                } catch (IOException e) {
1285:                    throw getRuntime().newIOError(e.getMessage());
1286:                } finally {
1287:                    // reading the entire stream always puts us at EOF
1288:                    if (readEntireStream) {
1289:                        atEOF = true;
1290:                    }
1291:                }
1292:            }
1293:
1294:            /** Read a byte. On EOF throw EOFError.
1295:             * 
1296:             */
1297:            public IRubyObject readchar() {
1298:                checkReadable();
1299:
1300:                try {
1301:                    int c = handler.getc();
1302:
1303:                    if (c == -1)
1304:                        throw getRuntime().newEOFError();
1305:
1306:                    return getRuntime().newFixnum(c);
1307:                } catch (IOHandler.BadDescriptorException e) {
1308:                    throw getRuntime().newErrnoEBADFError();
1309:                } catch (EOFException e) {
1310:                    throw getRuntime().newEOFError();
1311:                } catch (IOException e) {
1312:                    throw getRuntime().newIOError(e.getMessage());
1313:                }
1314:            }
1315:
1316:            /** 
1317:             * <p>Invoke a block for each byte.</p>
1318:             */
1319:            public IRubyObject each_byte(Block block) {
1320:                try {
1321:                    ThreadContext context = getRuntime().getCurrentContext();
1322:                    for (int c = handler.getc(); c != -1; c = handler.getc()) {
1323:                        assert c < 256;
1324:                        block.yield(context, getRuntime().newFixnum(c));
1325:                    }
1326:
1327:                    return getRuntime().getNil();
1328:                } catch (IOHandler.BadDescriptorException e) {
1329:                    throw getRuntime().newErrnoEBADFError();
1330:                } catch (EOFException e) {
1331:                    return getRuntime().getNil();
1332:                } catch (IOException e) {
1333:                    throw getRuntime().newIOError(e.getMessage());
1334:                }
1335:            }
1336:
1337:            /** 
1338:             * <p>Invoke a block for each line.</p>
1339:             */
1340:            public RubyIO each_line(IRubyObject[] args, Block block) {
1341:                IRubyObject rs;
1342:
1343:                if (args.length == 0) {
1344:                    rs = getRuntime().getGlobalVariables().get("$/");
1345:                } else {
1346:                    Arity.checkArgumentCount(getRuntime(), args, 1, 1);
1347:                    rs = args[0];
1348:                    if (!rs.isNil())
1349:                        rs = rs.convertToString();
1350:                }
1351:
1352:                ThreadContext context = getRuntime().getCurrentContext();
1353:                for (IRubyObject line = internalGets(args); !line.isNil(); line = internalGets(args)) {
1354:                    block.yield(context, line);
1355:                }
1356:
1357:                return this ;
1358:            }
1359:
1360:            public RubyArray readlines(IRubyObject[] args) {
1361:                IRubyObject[] separatorArgument;
1362:                if (args.length > 0) {
1363:                    if (!args[0].isKindOf(getRuntime().getNilClass())
1364:                            && !args[0].isKindOf(getRuntime().getString())) {
1365:                        throw getRuntime().newTypeError(args[0],
1366:                                getRuntime().getString());
1367:                    }
1368:                    separatorArgument = new IRubyObject[] { args[0] };
1369:                } else {
1370:                    separatorArgument = IRubyObject.NULL_ARRAY;
1371:                }
1372:
1373:                RubyArray result = getRuntime().newArray();
1374:                IRubyObject line;
1375:                while (!(line = internalGets(separatorArgument)).isNil()) {
1376:                    result.append(line);
1377:                }
1378:                return result;
1379:            }
1380:
1381:            public RubyIO to_io() {
1382:                return this ;
1383:            }
1384:
1385:            public String toString() {
1386:                return "RubyIO(" + modes + ", " + fileno + ")";
1387:            }
1388:
1389:            /* class methods for IO */
1390:
1391:            /** rb_io_s_foreach
1392:             *
1393:             */
1394:            public static IRubyObject foreach(IRubyObject recv,
1395:                    IRubyObject[] args, Block block) {
1396:                Ruby runtime = recv.getRuntime();
1397:                int count = Arity.checkArgumentCount(runtime, args, 1, -1);
1398:                IRubyObject filename = args[0].convertToString();
1399:                runtime.checkSafeString(filename);
1400:                RubyIO io = (RubyIO) RubyFile.open(recv,
1401:                        new IRubyObject[] { filename }, false, block);
1402:
1403:                if (!io.isNil() && io.isOpen()) {
1404:                    try {
1405:                        IRubyObject[] newArgs = new IRubyObject[count - 1];
1406:                        System.arraycopy(args, 1, newArgs, 0, count - 1);
1407:
1408:                        IRubyObject nextLine = io.internalGets(newArgs);
1409:                        while (!nextLine.isNil()) {
1410:                            block.yield(runtime.getCurrentContext(), nextLine);
1411:                            nextLine = io.internalGets(newArgs);
1412:                        }
1413:                    } finally {
1414:                        io.close();
1415:                    }
1416:                }
1417:
1418:                return runtime.getNil();
1419:            }
1420:
1421:            private static RubyIO registerSelect(Selector selector,
1422:                    IRubyObject obj, int ops) throws IOException {
1423:                RubyIO ioObj;
1424:
1425:                if (!(obj instanceof  RubyIO)) {
1426:                    // invoke to_io
1427:                    if (!obj.respondsTo("to_io"))
1428:                        return null;
1429:
1430:                    ioObj = (RubyIO) obj.callMethod(obj.getRuntime()
1431:                            .getCurrentContext(), "to_io");
1432:                } else {
1433:                    ioObj = (RubyIO) obj;
1434:                }
1435:
1436:                Channel channel = ioObj.getChannel();
1437:                if (channel == null || !(channel instanceof  SelectableChannel)) {
1438:                    return null;
1439:                }
1440:
1441:                ((SelectableChannel) channel).configureBlocking(false);
1442:                int real_ops = ((SelectableChannel) channel).validOps() & ops;
1443:                SelectionKey key = ((SelectableChannel) channel)
1444:                        .keyFor(selector);
1445:
1446:                if (key == null) {
1447:                    ((SelectableChannel) channel).register(selector, real_ops,
1448:                            obj);
1449:                } else {
1450:                    key.interestOps(key.interestOps() | real_ops);
1451:                }
1452:
1453:                return ioObj;
1454:            }
1455:
1456:            public static IRubyObject select(IRubyObject recv,
1457:                    IRubyObject[] args) {
1458:                return select_static(recv.getRuntime(), args);
1459:            }
1460:
1461:            public static IRubyObject select_static(Ruby runtime,
1462:                    IRubyObject[] args) {
1463:                try {
1464:                    boolean atLeastOneDescriptor = false;
1465:
1466:                    Set pending = new HashSet();
1467:                    Selector selector = Selector.open();
1468:                    if (!args[0].isNil()) {
1469:                        atLeastOneDescriptor = true;
1470:
1471:                        // read
1472:                        for (Iterator i = ((RubyArray) args[0]).getList()
1473:                                .iterator(); i.hasNext();) {
1474:                            IRubyObject obj = (IRubyObject) i.next();
1475:                            RubyIO ioObj = registerSelect(selector, obj,
1476:                                    SelectionKey.OP_READ
1477:                                            | SelectionKey.OP_ACCEPT);
1478:
1479:                            if (ioObj != null && ioObj.hasPendingBuffered())
1480:                                pending.add(obj);
1481:                        }
1482:                    }
1483:                    if (args.length > 1 && !args[1].isNil()) {
1484:                        atLeastOneDescriptor = true;
1485:                        // write
1486:                        for (Iterator i = ((RubyArray) args[1]).getList()
1487:                                .iterator(); i.hasNext();) {
1488:                            IRubyObject obj = (IRubyObject) i.next();
1489:                            registerSelect(selector, obj, SelectionKey.OP_WRITE);
1490:                        }
1491:                    }
1492:                    if (args.length > 2 && !args[2].isNil()) {
1493:                        atLeastOneDescriptor = true;
1494:                        // Java's select doesn't do anything about this, so we leave it be.
1495:                    }
1496:
1497:                    long timeout = 0;
1498:                    if (args.length > 3 && !args[3].isNil()) {
1499:                        if (args[3] instanceof  RubyFloat) {
1500:                            timeout = Math.round(((RubyFloat) args[3])
1501:                                    .getDoubleValue() * 1000);
1502:                        } else {
1503:                            timeout = Math.round(((RubyFixnum) args[3])
1504:                                    .getDoubleValue() * 1000);
1505:                        }
1506:
1507:                        if (timeout < 0) {
1508:                            throw runtime
1509:                                    .newArgumentError("negative timeout given");
1510:                        }
1511:                    }
1512:
1513:                    if (!atLeastOneDescriptor) {
1514:                        return runtime.getNil();
1515:                    }
1516:
1517:                    if (pending.isEmpty()) {
1518:                        if (args.length > 3) {
1519:                            if (timeout == 0) {
1520:                                selector.selectNow();
1521:                            } else {
1522:                                selector.select(timeout);
1523:                            }
1524:                        } else {
1525:                            selector.select();
1526:                        }
1527:                    } else {
1528:                        selector.selectNow();
1529:                    }
1530:
1531:                    List r = new ArrayList();
1532:                    List w = new ArrayList();
1533:                    List e = new ArrayList();
1534:                    for (Iterator i = selector.selectedKeys().iterator(); i
1535:                            .hasNext();) {
1536:                        SelectionKey key = (SelectionKey) i.next();
1537:                        if ((key.interestOps() & key.readyOps() & (SelectionKey.OP_READ
1538:                                | SelectionKey.OP_ACCEPT | SelectionKey.OP_CONNECT)) != 0) {
1539:                            r.add(key.attachment());
1540:                            pending.remove(key.attachment());
1541:                        }
1542:                        if ((key.interestOps() & key.readyOps() & (SelectionKey.OP_WRITE)) != 0) {
1543:                            w.add(key.attachment());
1544:                        }
1545:                    }
1546:                    r.addAll(pending);
1547:
1548:                    // make all sockets blocking as configured again
1549:                    for (Iterator i = selector.keys().iterator(); i.hasNext();) {
1550:                        SelectionKey key = (SelectionKey) i.next();
1551:                        SelectableChannel channel = key.channel();
1552:                        synchronized (channel.blockingLock()) {
1553:                            boolean blocking = ((RubyIO) key.attachment())
1554:                                    .getBlocking();
1555:                            key.cancel();
1556:                            channel.configureBlocking(blocking);
1557:                        }
1558:                    }
1559:                    selector.close();
1560:
1561:                    if (r.size() == 0 && w.size() == 0 && e.size() == 0) {
1562:                        return runtime.getNil();
1563:                    }
1564:
1565:                    List ret = new ArrayList();
1566:
1567:                    ret.add(RubyArray.newArray(runtime, r));
1568:                    ret.add(RubyArray.newArray(runtime, w));
1569:                    ret.add(RubyArray.newArray(runtime, e));
1570:
1571:                    return RubyArray.newArray(runtime, ret);
1572:                } catch (IOException e) {
1573:                    throw runtime.newIOError(e.getMessage());
1574:                }
1575:            }
1576:
1577:            public static IRubyObject read(IRubyObject recv,
1578:                    IRubyObject[] args, Block block) {
1579:                Ruby runtime = recv.getRuntime();
1580:                Arity.checkArgumentCount(runtime, args, 1, 3);
1581:                IRubyObject[] fileArguments = new IRubyObject[] { args[0] };
1582:                RubyIO file = (RubyIO) RubyKernel.open(recv, fileArguments,
1583:                        block);
1584:                IRubyObject[] readArguments;
1585:
1586:                if (args.length >= 2) {
1587:                    readArguments = new IRubyObject[] { args[1].convertToType(
1588:                            runtime.getFixnum(), MethodIndex.TO_INT, "to_int",
1589:                            true) };
1590:                } else {
1591:                    readArguments = new IRubyObject[] {};
1592:                }
1593:
1594:                try {
1595:
1596:                    if (args.length == 3) {
1597:                        file.seek(new IRubyObject[] { args[2].convertToType(
1598:                                runtime.getFixnum(), MethodIndex.TO_INT,
1599:                                "to_int", true) });
1600:                    }
1601:
1602:                    return file.read(readArguments);
1603:                } finally {
1604:                    file.close();
1605:                }
1606:            }
1607:
1608:            public static RubyArray readlines(IRubyObject recv,
1609:                    IRubyObject[] args, Block block) {
1610:                int count = Arity.checkArgumentCount(recv.getRuntime(), args,
1611:                        1, 2);
1612:
1613:                IRubyObject[] fileArguments = new IRubyObject[] { args[0] };
1614:                IRubyObject[] separatorArguments = count >= 2 ? new IRubyObject[] { args[1] }
1615:                        : IRubyObject.NULL_ARRAY;
1616:                RubyIO file = (RubyIO) RubyKernel.open(recv, fileArguments,
1617:                        block);
1618:                try {
1619:                    return file.readlines(separatorArguments);
1620:                } finally {
1621:                    file.close();
1622:                }
1623:            }
1624:
1625:            //XXX Hacked incomplete popen implementation to make
1626:            public static IRubyObject popen(IRubyObject recv,
1627:                    IRubyObject[] args, Block block) {
1628:                Ruby runtime = recv.getRuntime();
1629:                Arity.checkArgumentCount(runtime, args, 1, 2);
1630:                IRubyObject cmdObj = args[0].convertToString();
1631:                runtime.checkSafeString(cmdObj);
1632:
1633:                try {
1634:                    Process process = new ShellLauncher(runtime).run(cmdObj);
1635:                    RubyIO io = new RubyIO(runtime, process);
1636:
1637:                    if (block.isGiven()) {
1638:                        try {
1639:                            block.yield(runtime.getCurrentContext(), io);
1640:                            return runtime.getNil();
1641:                        } finally {
1642:                            io.close();
1643:                            runtime
1644:                                    .getGlobalVariables()
1645:                                    .set(
1646:                                            "$?",
1647:                                            RubyProcess.RubyStatus
1648:                                                    .newProcessStatus(
1649:                                                            runtime,
1650:                                                            (process.waitFor() * 256)));
1651:                        }
1652:                    }
1653:                    return io;
1654:                } catch (IOException e) {
1655:                    throw runtime.newIOErrorFromException(e);
1656:                } catch (InterruptedException e) {
1657:                    throw runtime.newThreadError("unexpected interrupt");
1658:                }
1659:            }
1660:
1661:            // NIO based pipe
1662:            public static IRubyObject pipe(IRubyObject recv) throws Exception {
1663:                Ruby runtime = recv.getRuntime();
1664:                Pipe pipe = Pipe.open();
1665:                return runtime.newArrayNoCopy(new IRubyObject[] {
1666:                        new RubyIO(runtime, pipe.source()),
1667:                        new RubyIO(runtime, pipe.sink()) });
1668:            }
1669:
1670:            /**
1671:             * returns non-nil if input available without blocking, false if EOF or not open/readable, otherwise nil.
1672:             */
1673:            public IRubyObject ready() {
1674:                try {
1675:                    if (!handler.isOpen() || !handler.isReadable()
1676:                            || handler.isEOF()) {
1677:                        return getRuntime().getFalse();
1678:                    }
1679:
1680:                    int avail = handler.ready();
1681:                    if (avail > 0) {
1682:                        return getRuntime().newFixnum(avail);
1683:                    }
1684:                } catch (Exception anyEx) {
1685:                    return getRuntime().getFalse();
1686:                }
1687:                return getRuntime().getNil();
1688:            }
1689:
1690:            /**
1691:             * waits until input available or timed out and returns self, or nil when EOF reached.
1692:             */
1693:            public IRubyObject io_wait() {
1694:                try {
1695:                    if (handler.isEOF()) {
1696:                        return getRuntime().getNil();
1697:                    }
1698:                    handler.waitUntilReady();
1699:                } catch (Exception anyEx) {
1700:                    return getRuntime().getNil();
1701:                }
1702:                return this;
1703:            }
1704:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.