package org.jruby;
import java.io.File;
import java.io.IOException;
import jnr.posix.FileStat;
import jnr.posix.util.Platform;
import static org.jruby.RubyEnumerator.enumeratorize;
import static org.jruby.runtime.Visibility.PRIVATE;
import org.jruby.anno.FrameField;
import org.jruby.anno.JRubyMethod;
import org.jruby.exceptions.RaiseException;
import org.jruby.internal.runtime.GlobalVariable;
import org.jruby.runtime.Block;
import org.jruby.runtime.CallSite;
import org.jruby.runtime.IAccessor;
import org.jruby.runtime.JavaSites;
import org.jruby.runtime.ObjectAllocator;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.util.ByteList;
import org.jruby.util.TypeConverter;
public class RubyArgsFile extends RubyObject {
public RubyArgsFile(Ruby runtime, RubyClass metaClass) {
super(runtime, metaClass);
}
public static void initArgsFile(final Ruby runtime) {
RubyClass argfClass = runtime.defineClass("ARGFClass", runtime.getObject(), ARGF_ALLOCATOR);
argfClass.includeModule(runtime.getEnumerable());
argfClass.defineAnnotatedMethods(RubyArgsFile.class);
IRubyObject argsFile = argfClass.newInstance(runtime.getCurrentContext(), new IRubyObject[] { null }, (Block) null);
runtime.setArgsFile(argsFile);
runtime.getGlobalVariables().defineReadonly("$<", new ArgsFileAccessor(runtime), GlobalVariable.Scope.GLOBAL);
runtime.defineGlobalConstant("ARGF", argsFile);
runtime.defineReadonlyVariable("$FILENAME", runtime.newString("-"), GlobalVariable.Scope.GLOBAL);
}
private static class ArgsFileAccessor implements IAccessor {
private final Ruby runtime;
ArgsFileAccessor(Ruby runtime) { this.runtime = runtime; }
public IRubyObject getValue() {
return runtime.getArgsFile();
}
public IRubyObject setValue(IRubyObject newValue) {
throw new UnsupportedOperationException("Not supported yet.");
}
}
private static final ObjectAllocator ARGF_ALLOCATOR = new ObjectAllocator() {
@Override
public IRubyObject allocate(Ruby runtime, RubyClass klass) {
return new RubyArgsFile(runtime, klass);
}
};
@JRubyMethod(name = "initialize", visibility = PRIVATE, rest = true)
public IRubyObject initialize(ThreadContext context, IRubyObject[] args) {
final Ruby runtime = context.runtime;
final RubyArray argv;
if (args.length == 1 && args[0] == null) {
argv = runtime.getObject().getConstant("ARGV").convertToArray();
} else {
argv = runtime.newArray(args);
}
if (runtime.getArgsFile() == null) {
dataWrapStruct(new ArgsFileData(runtime, argv));
} else {
ArgsFileData data = (ArgsFileData) runtime.getArgsFile().dataGetStruct();
dataWrapStruct(data);
data.setArgs(argv);
}
return this;
}
public static final class ArgsFileData {
private final Ruby runtime;
private RubyArray argv;
public IRubyObject currentFile;
private boolean inited = false;
public int next_p = 0;
public boolean binmode = false;
public ArgsFileData(Ruby runtime, RubyArray argv) {
this.runtime = runtime;
this.argv = argv;
this.currentFile = runtime.getNil();
}
@Deprecated
public void setCurrentLineNumber(Ruby runtime, int linenumber) {
runtime.setCurrentLine(linenumber);
}
void setArgs(RubyArray argv) {
inited = false;
this.argv = argv;
}
public boolean next_argv(ThreadContext context) {
if (!inited) {
next_p = argv.getLength() > 0 ? 1 : -1;
inited = true;
runtime.setCurrentLine(0);
} else {
if (argv.isNil()) {
next_p = -1;
} else if (next_p == -1 && argv.getLength() > 0) {
next_p = 1;
}
}
IRubyObject $FILENAME = runtime.getGlobalVariables().get("$FILENAME");
if (next_p == 1) {
if (argv.getLength() > 0) {
final RubyString filename = argv.shift(context).convertToString();
if ( ! filename.op_equal(context, $FILENAME).isTrue() ) {
runtime.defineReadonlyVariable("$FILENAME", filename, GlobalVariable.Scope.GLOBAL);
}
if (filenameEqlDash(filename)) {
currentFile = runtime.getGlobalVariables().get("$stdin");
} else {
currentFile = RubyFile.open(context, runtime.getFile(), new IRubyObject[]{ filename }, Block.NULL_BLOCK);
String extension = runtime.getInstanceConfig().getInPlaceBackupExtension();
if (extension != null) {
if (Platform.IS_WINDOWS) {
inplaceEditWindows(context, filename.asJavaString(), extension);
} else {
inplaceEdit(context, filename.asJavaString(), extension);
}
}
if (binmode) ((RubyIO) currentFile).binmode();
}
next_p = 0;
} else {
next_p = 1;
return false;
}
} else if (next_p == -1) {
currentFile = runtime.getGlobalVariables().get("$stdin");
if (!filenameEqlDash((RubyString) $FILENAME)) {
runtime.defineReadonlyVariable("$FILENAME", runtime.newString("-"), GlobalVariable.Scope.GLOBAL);
}
}
return true;
}
private static boolean filenameEqlDash(final RubyString filename) {
final ByteList filenameBytes = filename.getByteList();
return filenameBytes.length() == 1 && filenameBytes.get(0) == '-';
}
public static ArgsFileData getArgsFileData(Ruby runtime) {
return (ArgsFileData) runtime.getArgsFile().dataGetStruct();
}
@Deprecated
public static ArgsFileData getDataFrom(IRubyObject recv) {
return getArgsFileData(recv.getRuntime());
}
private void createNewFile(File file) {
try {
file.createNewFile();
} catch (IOException ex) {
throw runtime.newIOErrorFromException(ex);
}
}
private void inplaceEditWindows(ThreadContext context, String filename, String extension) throws RaiseException {
File file = new File(filename);
if (extension.length() > 0) {
String backup = filename + extension;
File backupFile = new File(backup);
((RubyIO) currentFile).close();
backupFile.delete();
file.renameTo(backupFile);
currentFile = RubyFile.open(context, runtime.getFile(),
new IRubyObject[]{runtime.newString(backup)}, Block.NULL_BLOCK);
} else {
throw runtime.newIOError("Windows doesn't support inplace editing without a backup");
}
createNewFile(file);
runtime.getGlobalVariables().set("$stdout", RubyFile.open(context, runtime.getFile(),
new IRubyObject[]{runtime.newString(filename), runtime.newString("w")}, Block.NULL_BLOCK));
}
private void inplaceEdit(ThreadContext context, String filename, String extension) throws RaiseException {
File file = new File(filename);
FileStat stat = runtime.getPosix().stat(filename);
if (extension.length() > 0) {
file.renameTo(new File(filename + extension));
} else {
file.delete();
}
createNewFile(file);
runtime.getPosix().chmod(filename, stat.mode());
runtime.getPosix().chown(filename, stat.uid(), stat.gid());
runtime.getGlobalVariables().set("$stdout", (RubyIO) RubyFile.open(context, runtime.getFile(),
new IRubyObject[]{runtime.newString(filename), runtime.newString("w")}, Block.NULL_BLOCK));
}
public boolean isCurrentFile(RubyIO io) {
return currentFile == io;
}
}
@Deprecated
public static void setCurrentLineNumber(IRubyObject recv, int newLineNumber) {
recv.getRuntime().setCurrentLine(newLineNumber);
}
@JRubyMethod(name = "argv")
public static IRubyObject argv(ThreadContext context, IRubyObject recv) {
return ArgsFileData.getArgsFileData(context.runtime).argv;
}
@JRubyMethod(name = {"fileno", "to_i"})
public static IRubyObject fileno(ThreadContext context, IRubyObject recv) {
return getCurrentDataFile(context, "no stream").fileno(context);
}
@JRubyMethod(name = "to_io")
public static IRubyObject to_io(ThreadContext context, IRubyObject recv) {
return getCurrentDataFile(context, "no stream");
}
@JRubyMethod
public static IRubyObject set_encoding(ThreadContext context, IRubyObject recv, IRubyObject encoding) {
return getCurrentDataFile(context, "no stream to set encoding").set_encoding(context, encoding);
}
@JRubyMethod
public static IRubyObject set_encoding(ThreadContext context, IRubyObject recv, IRubyObject encoding, IRubyObject internalEncoding) {
return getCurrentDataFile(context, "no stream to set encoding").set_encoding(context, encoding, internalEncoding);
}
@JRubyMethod
public static IRubyObject set_encoding(ThreadContext context, IRubyObject recv, IRubyObject encoding, IRubyObject internalEncoding, IRubyObject options) {
return getCurrentDataFile(context, "no stream to set encoding").set_encoding(context, encoding, internalEncoding, options);
}
@JRubyMethod
public static IRubyObject internal_encoding(ThreadContext context, IRubyObject recv) {
return getCurrentDataFile(context, "no stream to set encoding").internal_encoding(context);
}
@JRubyMethod
public static IRubyObject external_encoding(ThreadContext context, IRubyObject recv) {
return getCurrentDataFile(context, "no stream to set encoding").external_encoding(context);
}
private static IRubyObject argf_getline(ThreadContext context, IRubyObject recv, IRubyObject[] args) {
ArgsFileData data = ArgsFileData.getArgsFileData(context.runtime);
while (true) {
if (!data.next_argv(context)) return context.nil;
IRubyObject line = data.currentFile.callMethod(context, "gets", args);
if (line.isNil() && data.next_p != -1) {
argf_close(context, data.currentFile);
data.next_p = 1;
continue;
}
return line;
}
}
@JRubyMethod(name = "gets", optional = 1, writes = FrameField.LASTLINE)
public static IRubyObject gets(ThreadContext context, IRubyObject recv, IRubyObject[] args) {
return context.setLastLine(argf_getline(context, recv, args));
}
@JRubyMethod(name = "readline", optional = 1)
public static IRubyObject readline(ThreadContext context, IRubyObject recv, IRubyObject[] args) {
IRubyObject line = gets(context, recv, args);
if (line.isNil()) throw context.runtime.newEOFError();
return line;
}
@JRubyMethod(optional = 1)
public static IRubyObject readlines(ThreadContext context, IRubyObject recv, IRubyObject[] args) {
Ruby runtime = context.runtime;
ArgsFileData data = ArgsFileData.getArgsFileData(runtime);
if (!data.next_argv(context)) return runtime.newEmptyArray();
if (!(data.currentFile instanceof RubyIO)) return data.currentFile.callMethod(context, "readlines", args);
RubyArray ary = runtime.newArray();
IRubyObject line;
while(!(line = argf_getline(context, recv, args)).isNil()) {
ary.append(line);
}
return ary;
}
@JRubyMethod(optional = 1)
public static IRubyObject to_a(ThreadContext context, IRubyObject recv, IRubyObject[] args) {
Ruby runtime = context.runtime;
ArgsFileData data = ArgsFileData.getArgsFileData(runtime);
if (!data.next_argv(context)) return runtime.newEmptyArray();
if (!(data.currentFile instanceof RubyIO)) return data.currentFile.callMethod(context, "to_a", args);
RubyArray ary = runtime.newArray();
IRubyObject line;
while ((line = argf_getline(context, recv, args)) != context.nil) {
ary.append(line);
}
return ary;
}
@JRubyMethod
public static IRubyObject each_byte(final ThreadContext context, IRubyObject recv, final Block block) {
if (!block.isGiven()) return enumeratorize(context.runtime, recv, "each_byte");
IRubyObject bt;
while ((bt = getc(context, recv)) != context.nil) {
block.yield(context, bt);
}
return recv;
}
@JRubyMethod
public static IRubyObject each_byte(final ThreadContext context, IRubyObject recv, IRubyObject arg, final Block block) {
return block.isGiven() ? each_byte(context, recv, block) : enumeratorize(context.runtime, recv, "each_byte");
}
@JRubyMethod(optional = 1)
public static IRubyObject bytes(final ThreadContext context, IRubyObject recv, IRubyObject[] args, final Block block) {
return block.isGiven() ? each_byte(context, recv, block) : enumeratorize(context.runtime, recv, "bytes");
}
@JRubyMethod
public static IRubyObject each_char(final ThreadContext context, IRubyObject recv, Block block) {
return block.isGiven() ? each_charCommon(context, recv, block) : enumeratorize(context.runtime, recv, "each_char");
}
@JRubyMethod
public static IRubyObject chars(final ThreadContext context, IRubyObject recv, Block block) {
return block.isGiven() ? each_charCommon(context, recv, block) : enumeratorize(context.runtime, recv, "chars");
}
public static IRubyObject each_charCommon(ThreadContext context, IRubyObject recv, Block block) {
final Ruby runtime = context.runtime;
ArgsFileData data = ArgsFileData.getArgsFileData(runtime);
IRubyObject ch;
while ((ch = getc(context, recv)) != context.nil) {
boolean cont = true;
while (cont) {
cont = false;
byte c = (byte) RubyNumeric.fix2int(ch);
int n = runtime.getKCode().getEncoding().length(c);
IRubyObject file = data.currentFile;
RubyString str = runtime.newString();
str.setTaint(true);
str.cat(c);
while(--n > 0) {
if ((ch = getc(context, recv)) == context.nil) {
block.yield(context, str);
return recv;
}
if (data.currentFile != file) {
block.yield(context, str);
cont = true;
continue;
}
c = (byte) RubyNumeric.fix2int(ch);
str.cat(c);
}
block.yield(context, str);
}
}
return recv;
}
@JRubyMethod
public static IRubyObject each_codepoint(ThreadContext context, IRubyObject recv, Block block) {
if (!block.isGiven()) return RubyEnumerator.enumeratorize(context.runtime, recv, "each_line");
ArgsFileData data = ArgsFileData.getArgsFileData(context.runtime);
CallSite each_codepoint = sites(context).each_codepoint;
while (data.next_argv(context)) {
each_codepoint.call(context, recv, data.currentFile, block);
}
return context.nil;
}
@JRubyMethod
public static IRubyObject codepoints(ThreadContext context, IRubyObject recv, Block block) {
context.runtime.getWarnings().warn("ARGF#codepoints is deprecated; use #each_codepoint instead");
if (!block.isGiven()) return RubyEnumerator.enumeratorize(context.runtime, recv, "each_line");
return each_codepoint(context, recv, block);
}
@JRubyMethod(name = "each_line", optional = 1)
public static IRubyObject each_line(ThreadContext context, IRubyObject recv, IRubyObject[] args, Block block) {
if (!block.isGiven()) return enumeratorize(context.runtime, recv, "each_line", args);
ArgsFileData data = ArgsFileData.getArgsFileData(context.runtime);
if (!data.next_argv(context)) return context.nil;
if (!(data.currentFile instanceof RubyIO)) {
if (!data.next_argv(context)) return recv;
data.currentFile.callMethod(context, "each", NULL_ARRAY, block);
data.next_p = 1;
}
IRubyObject str;
while ((str = argf_getline(context, recv, args)) != context.nil) {
block.yield(context, str);
}
return recv;
}
@Deprecated
@JRubyMethod(optional = 1)
public static IRubyObject lines(ThreadContext context, IRubyObject recv, IRubyObject[] args, Block block) {
if (!block.isGiven()) return RubyEnumerator.enumeratorize(context.runtime, recv, "each_line");
return each_line(context, recv, args, block);
}
@Deprecated
public static IRubyObject each_line19(final ThreadContext context, IRubyObject recv, IRubyObject[] args, final Block block) {
return each_line(context, recv, args, block);
}
@JRubyMethod(name = "each", optional = 1)
public static IRubyObject each(final ThreadContext context, IRubyObject recv, IRubyObject[] args, final Block block) {
return block.isGiven() ? each_line(context, recv, args, block) : enumeratorize(context.runtime, recv, "each", args);
}
@Deprecated
public static IRubyObject each19(final ThreadContext context, IRubyObject recv, IRubyObject[] args, final Block block) {
return each(context, recv, args, block);
}
@JRubyMethod(name = "file")
public static IRubyObject file(ThreadContext context, IRubyObject recv) {
ArgsFileData data = ArgsFileData.getArgsFileData(context.runtime);
data.next_argv(context);
return data.currentFile;
}
@JRubyMethod(name = "skip")
public static IRubyObject skip(IRubyObject recv) {
Ruby runtime = recv.getRuntime();
ArgsFileData data = ArgsFileData.getArgsFileData(runtime);
if (data.inited && data.next_p == 0) {
argf_close(runtime.getCurrentContext(), data.currentFile);
data.next_p = 1;
}
return recv;
}
public static void argf_close(ThreadContext context, IRubyObject file) {
if (file instanceof RubyIO) {
((RubyIO) file).rbIoClose(context);
} else {
file.callMethod(context, "close");
}
}
@JRubyMethod(name = "close")
public static IRubyObject close(ThreadContext context, IRubyObject recv) {
ArgsFileData data = ArgsFileData.getArgsFileData(context.runtime);
data.next_argv(context);
if (data.currentFile == context.runtime.getGlobalVariables().get("$stdin")) return recv;
argf_close(context, data.currentFile);
if (data.next_p != -1) data.next_p = 1;
context.runtime.setCurrentLine(0);
return recv;
}
@JRubyMethod(name = "closed?")
public static IRubyObject closed_p(ThreadContext context, IRubyObject recv) {
ArgsFileData data = ArgsFileData.getArgsFileData(context.runtime);
data.next_argv(context);
return RubyBoolean.newBoolean(context.runtime, isClosed(context, data.currentFile));
}
private static boolean isClosed(ThreadContext context, IRubyObject currentFile) {
if (!(currentFile instanceof RubyIO)) return currentFile.callMethod(context, "closed?").isTrue();
return ((RubyIO)currentFile).closed_p(context).isTrue();
}
@JRubyMethod(name = "binmode")
public static IRubyObject binmode(ThreadContext context, IRubyObject recv) {
ArgsFileData data = ArgsFileData.getArgsFileData(context.runtime);
data.binmode = true;
if (data.currentFile != context.nil) ((RubyIO) data.currentFile).binmode();
return recv;
}
@JRubyMethod(name = "binmode?")
public static IRubyObject op_binmode(ThreadContext context, IRubyObject recv) {
return getCurrentDataFile(context, "no stream").op_binmode(context);
}
@JRubyMethod(name = "lineno")
public static IRubyObject lineno(ThreadContext context, IRubyObject recv) {
return context.runtime.newFixnum(context.runtime.getCurrentLine());
}
@JRubyMethod(name = "lineno=")
public static IRubyObject lineno_set(ThreadContext context, IRubyObject recv, IRubyObject line) {
context.runtime.setCurrentLine(RubyNumeric.fix2int(line));
return context.nil;
}
@JRubyMethod(name = "tell", alias = {"pos"})
public static IRubyObject tell(ThreadContext context, IRubyObject recv) {
return getCurrentDataFile(context, "no stream to tell").pos(context);
}
@JRubyMethod(name = "rewind")
public static IRubyObject rewind(ThreadContext context, IRubyObject recv) {
RubyIO currentFile = getCurrentDataFile(context, "no stream to rewind");
RubyFixnum retVal = currentFile.rewind(context);
currentFile.lineno_set(context, context.runtime.newFixnum(0));
return retVal;
}
@JRubyMethod(name = {"eof"})
public static IRubyObject eof(ThreadContext context, IRubyObject recv) {
ArgsFileData data = ArgsFileData.getArgsFileData(context.runtime);
if (!data.inited) return context.tru;
if (!(data.currentFile instanceof RubyIO)) {
return data.currentFile.callMethod(context, "eof");
} else {
return ((RubyIO) data.currentFile).eof_p(context);
}
}
@JRubyMethod(name = {"eof?"})
public static IRubyObject eof_p(ThreadContext context, IRubyObject recv) {
ArgsFileData data = ArgsFileData.getArgsFileData(context.runtime);
if (!data.inited) return context.tru;
if (!(data.currentFile instanceof RubyIO)) {
return data.currentFile.callMethod(context, "eof?");
} else {
return ((RubyIO) data.currentFile).eof_p(context);
}
}
@JRubyMethod(name = "pos=", required = 1)
public static IRubyObject set_pos(ThreadContext context, IRubyObject recv, IRubyObject offset) {
return getCurrentDataFile(context, "no stream to set position").pos_set(context, offset);
}
@JRubyMethod(name = "seek", required = 1, optional = 1)
public static IRubyObject seek(ThreadContext context, IRubyObject recv, IRubyObject[] args) {
return getCurrentDataFile(context, "no stream to seek").seek(context, args);
}
@JRubyMethod(name = "readchar")
public static IRubyObject readchar(ThreadContext context, IRubyObject recv) {
IRubyObject c = getc(context, recv);
if (c == context.nil) throw context.runtime.newEOFError();
return c;
}
@JRubyMethod
public static IRubyObject getbyte(ThreadContext context, IRubyObject recv) {
ArgsFileData data = ArgsFileData.getArgsFileData(context.runtime);
while (true) {
if (!data.next_argv(context)) return context.nil;
IRubyObject bt;
if (data.currentFile instanceof RubyFile) {
bt = ((RubyIO) data.currentFile).getbyte(context);
} else {
bt = data.currentFile.callMethod(context, "getbyte");
}
if (bt != context.nil) return bt;
argf_close(context, data.currentFile);
data.next_p = 1;
}
}
@JRubyMethod(required = 1, optional = 2)
public static IRubyObject read_nonblock(ThreadContext context, IRubyObject recv, IRubyObject[] args) {
return getPartial(context, recv, args, true);
}
@JRubyMethod(required = 1, optional = 1)
public static IRubyObject readpartial(ThreadContext context, IRubyObject recv, IRubyObject[] args) {
return getPartial(context, recv, args, false);
}
private static IRubyObject getPartial(ThreadContext context, IRubyObject recv, IRubyObject[] args, boolean nonBlocking) {
final Ruby runtime = context.runtime;
boolean noException = false;
RubyString str = null;
if ( args.length > 1 ) {
IRubyObject opts = TypeConverter.checkHashType(runtime, args[args.length - 1]);
if ( opts != context.nil &&
context.fals == ((RubyHash) opts).op_aref(context, runtime.newSymbol("exception")) ) {
noException = true;
}
if (args.length > 2 || opts == context.nil) {
if (args[1] != context.nil) {
args[1] = args[1].convertToString();
str = (RubyString) args[1];
}
}
}
final ArgsFileData data = ArgsFileData.getArgsFileData(runtime);
if (!data.next_argv(context)) {
if (str != null) str.clear();
return RubyIO.nonblockEOF(runtime, noException);
}
IRubyObject res = ((RubyIO) data.currentFile).getPartial(context, args, nonBlocking, noException);
if (res == context.nil) {
if (data.next_p == -1) return RubyIO.nonblockEOF(runtime, noException);
argf_close(context, data.currentFile);
data.next_p = 1;
if (data.argv.isEmpty()) return RubyIO.nonblockEOF(runtime, noException);
if (args.length > 1 && args[1] instanceof RubyString ) return args[1];
return RubyString.newEmptyString(runtime);
}
return res;
}
@JRubyMethod
public static IRubyObject readbyte(ThreadContext context, IRubyObject recv) {
IRubyObject c = getbyte(context, recv);
if (c.isNil()) throw context.runtime.newEOFError();
return c;
}
@JRubyMethod(name = "getc")
public static IRubyObject getc(ThreadContext context, IRubyObject recv) {
ArgsFileData data = ArgsFileData.getArgsFileData(context.runtime);
while (true) {
if (!data.next_argv(context)) return context.nil;
IRubyObject bt;
if (data.currentFile instanceof RubyFile) {
bt = ((RubyIO) data.currentFile).getbyte(context);
} else {
bt = data.currentFile.callMethod(context,"getc");
}
if (bt != context.nil) return bt;
argf_close(context, data.currentFile);
data.next_p = 1;
}
}
@JRubyMethod(name = "read", optional = 2)
public static IRubyObject read(ThreadContext context, IRubyObject recv, IRubyObject[] args) {
Ruby runtime = context.runtime;
ArgsFileData data = ArgsFileData.getArgsFileData(context.runtime);
IRubyObject tmp, str, length;
long len = 0;
if (args.length > 0) {
length = args[0];
str = args.length > 1 ? args[1] : context.nil;
} else {
str = length = context.nil;
}
if (length != context.nil) len = RubyNumeric.num2long(length);
if (str != context.nil) {
str = str.convertToString();
((RubyString) str).modify();
((RubyString) str).getByteList().length(0);
args[1] = context.nil;
}
while (true) {
if (!data.next_argv(context)) return str;
if (data.currentFile instanceof RubyIO) {
tmp = ((RubyIO) data.currentFile).read(args);
} else {
tmp = data.currentFile.callMethod(context, "read", args);
}
if (str == context.nil) {
str = tmp;
} else if (tmp != context.nil) {
((RubyString) str).append(tmp);
}
if (tmp == context.nil || length == context.nil) {
if(data.next_p != -1) {
argf_close(context, data.currentFile);
data.next_p = 1;
continue;
}
} else if(args.length >= 1) {
final int strLen = ((RubyString) str).getByteList().length();
if (strLen < len) {
len -= strLen;
args[0] = runtime.newFixnum(len);
continue;
}
}
return str;
}
}
@JRubyMethod(name = "filename", alias = {"path"})
public static IRubyObject filename(ThreadContext context, IRubyObject recv) {
ArgsFileData.getArgsFileData(context.runtime).next_argv(context);
return context.runtime.getGlobalVariables().get("$FILENAME");
}
@JRubyMethod(name = "to_s", alias = "inspect")
public static IRubyObject to_s(IRubyObject recv) {
return recv.getRuntime().newString("ARGF");
}
private static RubyIO getCurrentDataFile(ThreadContext context, String errorMessage) {
ArgsFileData data = ArgsFileData.getArgsFileData(context.runtime);
if (!data.next_argv(context)) throw context.runtime.newArgumentError(errorMessage);
return (RubyIO) data.currentFile;
}
private static JavaSites.ArgfSites sites(ThreadContext context) {
return context.sites.Argf;
}
}