Package org.jruby

Source Code of org.jruby.RubyArgsFile$ArgsFileData

/***** BEGIN LICENSE BLOCK *****
* Version: CPL 1.0/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Common Public
* License Version 1.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.eclipse.org/legal/cpl-v10.html
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* Copyright (C) 2002-2004 Anders Bengtsson <ndrsbngtssn@yahoo.se>
* Copyright (C) 2002-2004 Jan Arne Petersen <jpetersen@uni-bonn.de>
* Copyright (C) 2004 Thomas E Enebo <enebo@acm.org>
* Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de>
* Copyright (C) 2007 Ola Bini <ola@ologix.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the CPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the CPL, the GPL or the LGPL.
***** END LICENSE BLOCK *****/
package org.jruby;

import static org.jruby.RubyEnumerator.enumeratorize;

import org.jruby.anno.FrameField;
import org.jruby.anno.JRubyMethod;
import org.jruby.runtime.Block;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.util.ByteList;

public class RubyArgsFile {
    private static final class ArgsFileData {
        private final Ruby runtime;
        public ArgsFileData(Ruby runtime) {
            this.runtime = runtime;
        }

        public IRubyObject currentFile;
        public int currentLineNumber;
        public boolean startedProcessing = false;
        public boolean finishedProcessing = false;

        public boolean nextArgsFile(ThreadContext context) {
            if (finishedProcessing) {
                return false;
            }

            RubyArray args = (RubyArray)runtime.getGlobalVariables().get("$*");
            if (args.getLength() == 0) {
                if (!startedProcessing) {
                    currentFile = runtime.getGlobalVariables().get("$stdin");
                    ((RubyString) runtime.getGlobalVariables().get("$FILENAME")).setValue(new ByteList(new byte[]{'-'}));
                    currentLineNumber = 0;
                    startedProcessing = true;
                    return true;
                } else {
                    finishedProcessing = true;
                    return false;
                }
            }

            IRubyObject arg = args.shift(context);
            RubyString filename = (RubyString)((RubyObject)arg).to_s();
            ByteList filenameBytes = filename.getByteList();
            ((RubyString) runtime.getGlobalVariables().get("$FILENAME")).setValue(filenameBytes);

            if (filenameBytes.length() == 1 && filenameBytes.get(0) == '-') {
                currentFile = runtime.getGlobalVariables().get("$stdin");
            } else {
                currentFile = RubyFile.open(context, runtime.getFile(),
                        new IRubyObject[] {filename.strDup(context.getRuntime())}, Block.NULL_BLOCK);
            }
           
            startedProcessing = true;
            return true;
        }

        public static ArgsFileData getDataFrom(IRubyObject recv) {
            ArgsFileData data = (ArgsFileData)recv.dataGetStruct();
            if(data == null) {
                data = new ArgsFileData(recv.getRuntime());
                recv.dataWrapStruct(data);
            }
            return data;
        }
    }   
   
    public static void setCurrentLineNumber(IRubyObject recv, int newLineNumber) {
        ArgsFileData.getDataFrom(recv).currentLineNumber = newLineNumber;
    }

    public static void initArgsFile(Ruby runtime) {
        RubyObject argsFile = new RubyObject(runtime, runtime.getObject());

        runtime.getEnumerable().extend_object(argsFile);
       
        runtime.defineReadonlyVariable("$<", argsFile);
        runtime.defineGlobalConstant("ARGF", argsFile);
       
        RubyClass argfClass = argsFile.getMetaClass();
        argfClass.defineAnnotatedMethods(RubyArgsFile.class);
        runtime.defineReadonlyVariable("$FILENAME", runtime.newString("-"));
    }

    @JRubyMethod(name = {"fileno", "to_i"})
    public static IRubyObject fileno(ThreadContext context, IRubyObject recv) {
        ArgsFileData data = ArgsFileData.getDataFrom(recv);

        if (data.currentFile == null && !data.nextArgsFile(context)) {
            throw context.getRuntime().newArgumentError("no stream");
        }
        return ((RubyIO) data.currentFile).fileno(context);
    }

    @JRubyMethod(name = "to_io")
    public static IRubyObject to_io(ThreadContext context, IRubyObject recv) {
        ArgsFileData data = ArgsFileData.getDataFrom(recv);

        if (data.currentFile == null && !data.nextArgsFile(context)) {
            throw context.getRuntime().newArgumentError("no stream");
        }
        return data.currentFile;
    }

    public static IRubyObject internalGets(ThreadContext context, IRubyObject recv, IRubyObject[] args) {
        ArgsFileData data = ArgsFileData.getDataFrom(recv);

        if(data.currentFile == null && !data.nextArgsFile(context)) {
            return context.getRuntime().getNil();
        }
       
        IRubyObject line = data.currentFile.callMethod(context, "gets", args);
       
        while (line instanceof RubyNil) {
            data.currentFile.callMethod(context, "close");
            if (!data.nextArgsFile(context)) {
                data.currentFile = null;
                return line;
          }
            line = data.currentFile.callMethod(context, "gets", args);
        }
       
        data.currentLineNumber++;
        context.getRuntime().getGlobalVariables().set("$.", context.getRuntime().newFixnum(data.currentLineNumber));
       
        return line;
    }
   
    // ARGF methods

    /** Read a line.
     *
     */
    @JRubyMethod(name = "gets", optional = 1, frame = true, writes = FrameField.LASTLINE)
    public static IRubyObject gets(ThreadContext context, IRubyObject recv, IRubyObject[] args) {
        IRubyObject result = internalGets(context, recv, args);

        if (!result.isNil()) {
            context.getCurrentFrame().setLastLine(result);
        }

        return result;
    }
   
    /** Read a line.
     *
     */
    @JRubyMethod(name = "readline", optional = 1, frame = true, writes = FrameField.LASTLINE)
    public static IRubyObject readline(ThreadContext context, IRubyObject recv, IRubyObject[] args) {
        IRubyObject line = gets(context, recv, args);

        if (line.isNil()) {
            throw context.getRuntime().newEOFError();
        }
       
        return line;
    }

    @JRubyMethod(name = "readlines", optional = 1, frame = true)
    public static RubyArray readlines(ThreadContext context, IRubyObject recv, IRubyObject[] args) {
        IRubyObject[] separatorArgument;
        if (args.length > 0) {
            if (!context.getRuntime().getNilClass().isInstance(args[0]) &&
                !context.getRuntime().getString().isInstance(args[0])) {
                throw context.getRuntime().newTypeError(args[0], context.getRuntime().getString());
            }
            separatorArgument = new IRubyObject[] { args[0] };
        } else {
            separatorArgument = IRubyObject.NULL_ARRAY;
        }

        RubyArray result = context.getRuntime().newArray();
        IRubyObject line;
        while (! (line = internalGets(context, recv, separatorArgument)).isNil()) {
            result.append(line);
        }
        return result;
    }
   
    @JRubyMethod(name = "each_byte", frame = true)
    public static IRubyObject each_byte(ThreadContext context, IRubyObject recv, Block block) {
        IRubyObject bt;

        while(!(bt = getc(context, recv)).isNil()) {
            block.yield(context, bt);
        }

        return recv;
    }

    @JRubyMethod(name = "each_byte", optional = 1, frame = true, compat = CompatVersion.RUBY1_9)
    public static IRubyObject each_byte19(final ThreadContext context, IRubyObject recv, IRubyObject[] args, final Block block) {
        return block.isGiven() ? each_byte(context, recv, block) : enumeratorize(context.getRuntime(), recv, "each_byte");
    }

    /** Invoke a block for each line.
     *
     */
    @JRubyMethod(name = {"each_line", "each"}, optional = 1, frame = true)
    public static IRubyObject each_line(ThreadContext context, IRubyObject recv, IRubyObject[] args, Block block) {
        IRubyObject nextLine = internalGets(context, recv, args);
       
        while (!nextLine.isNil()) {
          block.yield(context, nextLine);
          nextLine = internalGets(context, recv, args);
        }
       
        return recv;
    }

    @JRubyMethod(name = "each_line", optional = 1, frame = true, compat = CompatVersion.RUBY1_9)
    public static IRubyObject each_line19(final ThreadContext context, IRubyObject recv, IRubyObject[] args, final Block block) {
        return block.isGiven() ? each_line(context, recv, args, block) : enumeratorize(context.getRuntime(), recv, "each_line", args);
    }

    @JRubyMethod(name = "each", optional = 1, frame = true, compat = CompatVersion.RUBY1_9)
    public static IRubyObject each19(final ThreadContext context, IRubyObject recv, IRubyObject[] args, final Block block) {
        return block.isGiven() ? each_line(context, recv, args, block) : enumeratorize(context.getRuntime(), recv, "each", args);
    }

    @JRubyMethod(name = "file")
    public static IRubyObject file(ThreadContext context, IRubyObject recv) {
        ArgsFileData data = ArgsFileData.getDataFrom(recv);

        if(data.currentFile == null && !data.nextArgsFile(context)) {
            return context.getRuntime().getNil();
        }
        return data.currentFile;
    }

    @JRubyMethod(name = "skip")
    public static IRubyObject skip(IRubyObject recv) {
        ArgsFileData data = ArgsFileData.getDataFrom(recv);
        data.currentFile = null;
        return recv;
    }

    @JRubyMethod(name = "close")
    public static IRubyObject close(ThreadContext context, IRubyObject recv) {
        ArgsFileData data = ArgsFileData.getDataFrom(recv);
        if(data.currentFile == null && !data.nextArgsFile(context)) {
            return recv;
        }
        data.currentFile = null;
        data.currentLineNumber = 0;
        return recv;
    }

    @JRubyMethod(name = "closed?")
    public static IRubyObject closed_p(ThreadContext context, IRubyObject recv) {
        ArgsFileData data = ArgsFileData.getDataFrom(recv);
        if(data.currentFile == null && !data.nextArgsFile(context)) {
            return recv;
        }
        return ((RubyIO)data.currentFile).closed_p(context);
    }

    @JRubyMethod(name = "binmode")
    public static IRubyObject binmode(ThreadContext context, IRubyObject recv) {
        ArgsFileData data = ArgsFileData.getDataFrom(recv);
        if(data.currentFile == null && !data.nextArgsFile(context)) {
            throw context.getRuntime().newArgumentError("no stream");
        }
       
        return ((RubyIO)data.currentFile).binmode();
    }

    @JRubyMethod(name = "lineno")
    public static IRubyObject lineno(ThreadContext context, IRubyObject recv) {
        return context.getRuntime().newFixnum(ArgsFileData.getDataFrom(recv).currentLineNumber);
    }

    @JRubyMethod(name = "tell", alias = {"pos"})
    public static IRubyObject tell(ThreadContext context, IRubyObject recv) {
        ArgsFileData data = ArgsFileData.getDataFrom(recv);
        if(data.currentFile == null && !data.nextArgsFile(context)) {
            throw context.getRuntime().newArgumentError("no stream to tell");
        }
        return ((RubyIO)data.currentFile).pos(context);
    }

    @JRubyMethod(name = "rewind")
    public static IRubyObject rewind(ThreadContext context, IRubyObject recv) {
        ArgsFileData data = ArgsFileData.getDataFrom(recv);
        if(data.currentFile == null && !data.nextArgsFile(context)) {
            throw context.getRuntime().newArgumentError("no stream to rewind");
        }
        return ((RubyIO)data.currentFile).rewind(context);
    }

    @JRubyMethod(name = {"eof", "eof?"})
    public static IRubyObject eof(ThreadContext context, IRubyObject recv) {
        ArgsFileData data = ArgsFileData.getDataFrom(recv);
        if (data.currentFile == null && !data.nextArgsFile(context)) {
            return context.getRuntime().getTrue();
        }

        return ((RubyIO) data.currentFile).eof_p(context);
    }

    @JRubyMethod(name = "pos=", required = 1)
    public static IRubyObject set_pos(ThreadContext context, IRubyObject recv, IRubyObject offset) {
        ArgsFileData data = ArgsFileData.getDataFrom(recv);
        if(data.currentFile == null && !data.nextArgsFile(context)) {
            throw context.getRuntime().newArgumentError("no stream to set position");
        }
        return ((RubyIO)data.currentFile).pos_set(context, offset);
    }

    @JRubyMethod(name = "seek", required = 1, optional = 1)
    public static IRubyObject seek(ThreadContext context, IRubyObject recv, IRubyObject[] args) {
        ArgsFileData data = ArgsFileData.getDataFrom(recv);
        if(data.currentFile == null && !data.nextArgsFile(context)) {
            throw context.getRuntime().newArgumentError("no stream to seek");
        }
        return ((RubyIO)data.currentFile).seek(context, args);
    }

    @JRubyMethod(name = "lineno=", required = 1)
    public static IRubyObject set_lineno(ThreadContext context, IRubyObject recv, IRubyObject line) {
        ArgsFileData data = ArgsFileData.getDataFrom(recv);
        data.currentLineNumber = RubyNumeric.fix2int(line);
        return context.getRuntime().getNil();
    }

    @JRubyMethod(name = "readchar")
    public static IRubyObject readchar(ThreadContext context, IRubyObject recv) {
        IRubyObject c = getc(context, recv);
       
        if(c.isNil()) throw context.getRuntime().newEOFError();

        return c;
    }

    @JRubyMethod(name = "getc")
    public static IRubyObject getc(ThreadContext context, IRubyObject recv) {
        ArgsFileData data = ArgsFileData.getDataFrom(recv);
        IRubyObject bt;
        while(true) {
            if(data.currentFile == null && !data.nextArgsFile(context)) {
                return context.getRuntime().getNil();
            }
            if(!(data.currentFile instanceof RubyFile)) {
                bt = data.currentFile.callMethod(context,"getc");
            } else {
                bt = ((RubyIO)data.currentFile).getc();
            }
            if(bt.isNil()) {
                data.currentFile = null;
                continue;
            }
            return bt;
        }
    }

    @JRubyMethod(name = "read", optional = 2)
    public static IRubyObject read(ThreadContext context, IRubyObject recv, IRubyObject[] args) {
        Ruby runtime = context.getRuntime();
        ArgsFileData data = ArgsFileData.getDataFrom(recv);
        IRubyObject tmp, str, length;
        long len = 0;
        if(args.length > 0) {
            length = args[0];
            if(args.length > 1) {
                str = args[1];
            } else {
                str = runtime.getNil();
            }
        } else {
            length = str = runtime.getNil();
        }

        if(!length.isNil()) {
            len = RubyNumeric.num2long(length);
        }
        if(!str.isNil()) {
            str = str.convertToString();
            ((RubyString)str).modify();
            ((RubyString)str).getByteList().length(0);
            args[1] = runtime.getNil();
        }
        while(true) {
            if(data.currentFile == null && !data.nextArgsFile(context)) {
                return str;
            }
            if(!(data.currentFile instanceof RubyIO)) {
                tmp = data.currentFile.callMethod(context, "read", args);
            } else {
                tmp = ((RubyIO)data.currentFile).read(args);
            }
            if(str.isNil()) {
                str = tmp;
            } else if(!tmp.isNil()) {
                ((RubyString)str).append(tmp);
            }
            if(tmp.isNil() || length.isNil()) {
                data.currentFile = null;
                continue;
            } else if(args.length >= 1) {
                if(((RubyString)str).getByteList().length() < len) {
                    len -= ((RubyString)str).getByteList().length();
                    args[0] = runtime.newFixnum(len);
                    continue;
                }
            }
            return str;
        }
    }

    @JRubyMethod(name = "filename", alias = {"path"})
    public static RubyString filename(ThreadContext context, IRubyObject recv) {
        return (RubyString) context.getRuntime().getGlobalVariables().get("$FILENAME");
    }

    @JRubyMethod(name = "to_s")
    public static IRubyObject to_s(IRubyObject recv) {
        return recv.getRuntime().newString("ARGF");
    }
}
TOP

Related Classes of org.jruby.RubyArgsFile$ArgsFileData

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.