@JRubyMethod(required = 1, optional = 1) @Override public IRubyObject seek(IRubyObject[] args) { checkOpen(); checkFinalized(); long amount = RubyNumeric.num2long(args[0]); int whence = Stream.SEEK_SET; long newPosition = data.pos; if (args.length > 1 && !args[0].isNil()) whence = RubyNumeric.fix2int(args[1]); if (whence == Stream.SEEK_CUR) { newPosition += amount; } else if (whence == Stream.SEEK_END) { newPosition = data.internal.getByteList().length() + amount; } else if (whence == Stream.SEEK_SET) { newPosition = amount; } else { throw getRuntime().newErrnoEINVALError("invalid whence"); } if (newPosition < 0) throw getRuntime().newErrnoEINVALError("invalid seek value"); data.pos = newPosition; data.eof = false; return RubyFixnum.zero(getRuntime()); }
private void setupModes() { data.closedWrite = false; data.closedRead = false; if (data.modes.isReadOnly()) data.closedWrite = true; if (!data.modes.isReadable()) data.closedRead = true; }
@JRubyMethod(name = "pos=", required = 1) @Override public IRubyObject set_pos(IRubyObject arg) { data.pos = RubyNumeric.fix2int(arg); if (data.pos < 0) throw getRuntime().newErrnoEINVALError("Invalid argument"); if (!isEndOfString()) data.eof = false; return getRuntime().getNil(); }
@JRubyMethod @Override public IRubyObject close() { checkInitialized(); checkOpen(); data.closedRead = true; data.closedWrite = true; return getRuntime().getNil(); }
@JRubyMethod(name = "reopen", required = 0, optional = 2) @Override public IRubyObject reopen(IRubyObject[] args) { if (args.length == 1 && !(args[0] instanceof RubyString)) { return initialize_copy(args[0]); } // reset the state doRewind(); data.closedRead = false; data.closedWrite = false; return initialize(args, Block.NULL_BLOCK); }
private void initializeModes(Object modeArgument) { Ruby runtime = getRuntime(); if (modeArgument == null) { data.modes = RubyIO.newModeFlags(runtime, "r+"); } else if (modeArgument instanceof Long) { data.modes = RubyIO.newModeFlags(runtime, ((Long) modeArgument).longValue()); } else { data.modes = RubyIO.newModeFlags(runtime, (String) modeArgument); } setupModes(); }
@JRubyMethod(name = "lineno=", required = 1) @Override public IRubyObject set_lineno(IRubyObject arg) { data.lineno = RubyNumeric.fix2int(arg); return getRuntime().getNil(); }
@JRubyMethod @Override public IRubyObject close_write() { checkWritable(); data.closedWrite = true; return getRuntime().getNil(); }
@JRubyMethod @Override public IRubyObject close_read() { checkReadable(); data.closedRead = true; return getRuntime().getNil(); }
@JRubyMethod(optional = 2, visibility = PRIVATE) @Override public IRubyObject initialize(IRubyObject[] args, Block unusedBlock) { Object modeArgument = null; Ruby runtime = getRuntime(); switch (args.length) { case 0: data.internal = runtime.is1_9() ? RubyString.newEmptyString(runtime, runtime.getDefaultExternalEncoding()) : RubyString.newEmptyString(getRuntime()); modeArgument = "r+"; break; case 1: data.internal = args[0].convertToString(); modeArgument = data.internal.isFrozen() ? "r" : "r+"; break; case 2: data.internal = args[0].convertToString(); if (args[1] instanceof RubyFixnum) { modeArgument = RubyFixnum.fix2long(args[1]); } else { modeArgument = args[1].convertToString().toString(); } break; } initializeModes(modeArgument); if (data.modes.isWritable() && data.internal.isFrozen()) { throw getRuntime().newErrnoEACCESError("Permission denied"); } if (data.modes.isTruncate()) { data.internal.modifyCheck(); data.internal.empty(); } return this; }
private int writeInternal(ThreadContext context, IRubyObject arg) { checkWritable(); checkFrozen(); RubyString val = arg.asString(); data.internal.modify(); if (data.modes.isAppendable()) { data.internal.getByteList().append(val.getByteList()); data.pos = data.internal.getByteList().length(); } else { int left = data.internal.getByteList().length() - (int) data.pos; data.internal .getByteList() .replace((int) data.pos, Math.min(val.getByteList().length(), left), val.getByteList()); data.pos += val.getByteList().length(); } if (val.isTaint()) { data.internal.setTaint(true); } return val.getByteList().length(); }
@JRubyMethod(name = "putc", required = 1) @Override public IRubyObject putc(IRubyObject obj) { checkWritable(); byte c = RubyNumeric.num2chr(obj); checkFrozen(); data.internal.modify(); ByteList bytes = data.internal.getByteList(); if (data.modes.isAppendable()) { data.pos = bytes.length(); bytes.append(c); } else { if (isEndOfString()) bytes.length((int) data.pos + 1); bytes.set((int) data.pos, c); data.pos++; } return obj; }
@Override public IRubyObject each_charInternal(final ThreadContext context, final Block block) { checkReadable(); Ruby runtime = context.runtime; ByteList bytes = data.internal.getByteList(); int len = bytes.getRealSize(); int end = bytes.getBegin() + len; Encoding enc = runtime.is1_9() ? bytes.getEncoding() : runtime.getKCode().getEncoding(); while (data.pos < len) { int pos = (int) data.pos; int n = StringSupport.length(enc, bytes.getUnsafeBytes(), pos, end); if (len < pos + n) n = len - pos; data.pos += n; block.yield(context, data.internal.makeShared19(runtime, pos, n)); } return this; }
@SuppressWarnings("fallthrough") @JRubyMethod(name = "read", optional = 2) @Override public IRubyObject read(IRubyObject[] args) { checkReadable(); ByteList buf = null; int length = 0; int oldLength = 0; RubyString originalString = null; switch (args.length) { case 2: originalString = args[1].convertToString(); // must let original string know we're modifying, so shared buffers aren't damaged originalString.modify(); buf = originalString.getByteList(); case 1: if (!args[0].isNil()) { length = RubyNumeric.fix2int(args[0]); oldLength = length; if (length < 0) { throw getRuntime().newArgumentError("negative length " + length + " given"); } if (length > 0 && isEndOfString()) { data.eof = true; if (buf != null) buf.setRealSize(0); return getRuntime().getNil(); } else if (data.eof) { if (buf != null) buf.setRealSize(0); return getRuntime().getNil(); } break; } case 0: oldLength = -1; length = data.internal.getByteList().length(); if (length <= data.pos) { data.eof = true; if (buf == null) { buf = new ByteList(); } else { buf.setRealSize(0); } return makeString(getRuntime(), buf); } else { length -= data.pos; } break; default: getRuntime().newArgumentError(args.length, 0); } if (buf == null) { int internalLength = data.internal.getByteList().length(); if (internalLength > 0) { if (internalLength >= data.pos + length) { buf = new ByteList(data.internal.getByteList(), (int) data.pos, length); } else { int rest = (int) (data.internal.getByteList().length() - data.pos); if (length > rest) length = rest; buf = new ByteList(data.internal.getByteList(), (int) data.pos, length); } } } else { int rest = (int) (data.internal.getByteList().length() - data.pos); if (length > rest) length = rest; // Yow...this is still ugly byte[] target = buf.getUnsafeBytes(); if (target.length > length) { System.arraycopy( data.internal.getByteList().getUnsafeBytes(), (int) data.pos, target, 0, length); buf.setBegin(0); buf.setRealSize(length); } else { target = new byte[length]; System.arraycopy( data.internal.getByteList().getUnsafeBytes(), (int) data.pos, target, 0, length); buf.setBegin(0); buf.setRealSize(length); buf.setUnsafeBytes(target); } } if (buf == null) { if (!data.eof) buf = new ByteList(); length = 0; } else { length = buf.length(); data.pos += length; } if (oldLength < 0 || oldLength > length) data.eof = true; return originalString != null ? originalString : makeString(getRuntime(), buf); }
private IRubyObject internalGets(ThreadContext context, IRubyObject[] args) { Ruby runtime = context.runtime; if (!isEndOfString() && !data.eof) { boolean isParagraph = false; boolean is19 = runtime.is1_9(); ByteList sep = ((RubyString) runtime.getGlobalVariables().get("$/")).getByteList(); IRubyObject sepArg; int limit = -1; if (is19) { IRubyObject limitArg = (args.length > 1 ? args[1] : (args.length > 0 && args[0] instanceof RubyFixnum ? args[0] : null)); if (limitArg != null) { limit = RubyNumeric.fix2int(limitArg); } sepArg = (args.length > 0 && !(args[0] instanceof RubyFixnum) ? args[0] : null); } else { sepArg = (args.length > 0 ? args[0] : null); } if (sepArg != null) { if (sepArg.isNil()) { int bytesAvailable = data.internal.getByteList().getRealSize() - (int) data.pos; int bytesToUse = (limit < 0 || limit >= bytesAvailable ? bytesAvailable : limit); ByteList buf = data.internal.getByteList().makeShared((int) data.pos, bytesToUse); data.pos += buf.getRealSize(); return makeString(runtime, buf); } sep = sepArg.convertToString().getByteList(); if (sep.getRealSize() == 0) { isParagraph = true; sep = Stream.PARAGRAPH_SEPARATOR; } } ByteList ss = data.internal.getByteList(); if (isParagraph) { swallowLF(ss); if (data.pos == ss.getRealSize()) { return runtime.getNil(); } } int ix = ss.indexOf(sep, (int) data.pos); ByteList add; if (-1 == ix) { ix = data.internal.getByteList().getRealSize(); add = ByteList.EMPTY_BYTELIST; } else { add = sep; } int bytes = ix - (int) data.pos; int bytesToUse = (limit < 0 || limit >= bytes ? bytes : limit); int bytesWithSep = ix - (int) data.pos + add.getRealSize(); int bytesToUseWithSep = (limit < 0 || limit >= bytesWithSep ? bytesWithSep : limit); ByteList line = new ByteList(bytesToUseWithSep); if (is19) line.setEncoding(data.internal.getByteList().getEncoding()); line.append(data.internal.getByteList(), (int) data.pos, bytesToUse); data.pos += bytesToUse; int sepBytesToUse = bytesToUseWithSep - bytesToUse; line.append(add, 0, sepBytesToUse); data.pos += sepBytesToUse; if (sepBytesToUse >= add.getRealSize()) { data.lineno++; } return makeString(runtime, line); } return runtime.getNil(); }
private void doFinalize() { data.closedRead = true; data.closedWrite = true; data.internal = null; }