private void setupModes() {
    data.closedWrite = false;
    data.closedRead = false;

    if (data.modes.isReadOnly()) data.closedWrite = true;
    if (!data.modes.isReadable()) data.closedRead = true;
  }
  @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());
  }
Esempio n. 3
0
 @JRubyMethod(name = "string=", required = 1)
 public IRubyObject set_string(IRubyObject arg) {
   checkFrozen();
   ptr.flags &= ~OpenFile.READWRITE;
   RubyString str = arg.convertToString();
   ptr.flags = str.isFrozen() ? OpenFile.READABLE : OpenFile.READWRITE;
   ptr.pos = 0;
   ptr.lineno = 0;
   return ptr.string = str;
 }
  @JRubyMethod
  @Override
  public IRubyObject close() {
    checkInitialized();
    checkOpen();

    data.closedRead = true;
    data.closedWrite = true;

    return getRuntime().getNil();
  }
  @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(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();
  }
Esempio n. 8
0
  @JRubyMethod(required = 1, optional = 1)
  public IRubyObject seek(ThreadContext context, IRubyObject[] args) {
    Ruby runtime = context.runtime;

    checkFrozen();
    checkFinalized();

    int offset = RubyNumeric.num2int(args[0]);
    IRubyObject whence = context.nil;

    if (args.length > 1 && !args[0].isNil()) whence = args[1];

    checkOpen();

    switch (whence.isNil() ? 0 : RubyNumeric.num2int(whence)) {
      case 0:
        break;
      case 1:
        offset += ptr.pos;
        break;
      case 2:
        offset += ptr.string.size();
        break;
      default:
        throw runtime.newErrnoEINVALError("invalid whence");
    }

    if (offset < 0) throw runtime.newErrnoEINVALError("invalid seek value");

    ptr.pos = offset;

    return RubyFixnum.zero(runtime);
  }
  @JRubyMethod(name = "lineno=", required = 1)
  @Override
  public IRubyObject set_lineno(IRubyObject arg) {
    data.lineno = RubyNumeric.fix2int(arg);

    return getRuntime().getNil();
  }
Esempio n. 10
0
  @JRubyMethod(
      name = {"write"},
      required = 1)
  public IRubyObject write(ThreadContext context, IRubyObject arg) {
    checkWritable();

    Ruby runtime = context.runtime;

    RubyString str = arg.asString();
    int len, olen;
    Encoding enc, enc2;

    enc = ptr.string.getEncoding();
    enc2 = str.getEncoding();
    if (enc != enc2
        && enc != EncodingUtils.ascii8bitEncoding(runtime)
        // this is a hack because we don't seem to handle incoming ASCII-8BIT properly in transcoder
        && enc2 != ASCIIEncoding.INSTANCE) {
      str = runtime.newString(Transcoder.strConvEnc(context, str.getByteList(), enc2, enc));
    }
    len = str.size();
    if (len == 0) return RubyFixnum.zero(runtime);
    checkModifiable();
    olen = ptr.string.size();
    if ((ptr.flags & OpenFile.APPEND) != 0) {
      ptr.pos = olen;
    }
    if (ptr.pos == olen
        // this is a hack because we don't seem to handle incoming ASCII-8BIT properly in transcoder
        && enc2 != ASCIIEncoding.INSTANCE) {
      EncodingUtils.encStrBufCat(runtime, ptr.string, str.getByteList(), enc);
    } else {
      strioExtend(ptr.pos, len);
      ByteList ptrByteList = ptr.string.getByteList();
      System.arraycopy(
          str.getByteList().getUnsafeBytes(),
          str.getByteList().getBegin(),
          ptrByteList.getUnsafeBytes(),
          ptrByteList.begin + ptr.pos,
          len);
      ptr.string.infectBy(str);
    }
    ptr.string.infectBy(this);
    ptr.pos += len;
    return RubyFixnum.newFixnum(runtime, len);
  }
Esempio n. 11
0
  @JRubyMethod
  @Override
  public IRubyObject close_read() {
    checkReadable();
    data.closedRead = true;

    return getRuntime().getNil();
  }
Esempio n. 12
0
  @JRubyMethod
  @Override
  public IRubyObject close_write() {
    checkWritable();
    data.closedWrite = true;

    return getRuntime().getNil();
  }
Esempio n. 13
0
  @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;
  }
Esempio n. 14
0
  @JRubyMethod(name = "pos=", required = 1)
  public IRubyObject set_pos(IRubyObject arg) {
    checkInitialized();

    int p = RubyNumeric.fix2int(arg);

    if (p < 0) throw getRuntime().newErrnoEINVALError(arg.toString());

    ptr.pos = p;

    return arg;
  }
Esempio n. 15
0
  @JRubyMethod(name = "getc")
  public IRubyObject getc(ThreadContext context) {
    checkReadable();

    if (isEndOfString()) return context.runtime.getNil();

    int start = ptr.pos;
    int total =
        1 + StringSupport.bytesToFixBrokenTrailingCharacter(ptr.string.getByteList(), start + 1);

    ptr.pos += total;

    return context.runtime.newString(ptr.string.getByteList().makeShared(start, total));
  }
Esempio n. 16
0
  private void ungetbyteCommon(int c) {
    ptr.string.modify();
    ptr.pos--;

    ByteList bytes = ptr.string.getByteList();

    if (isEndOfString()) bytes.length((int) ptr.pos + 1);

    if (ptr.pos == -1) {
      bytes.prepend((byte) c);
      ptr.pos = 0;
    } else {
      bytes.set((int) ptr.pos, c);
    }
  }
Esempio n. 17
0
  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();
  }
Esempio n. 18
0
  @JRubyMethod(meta = true, rest = true)
  public static IRubyObject open(
      ThreadContext context, IRubyObject recv, IRubyObject[] args, Block block) {
    StringIO strio = (StringIO) ((RubyClass) recv).newInstance(context, args, Block.NULL_BLOCK);
    IRubyObject val = strio;

    if (block.isGiven()) {
      try {
        val = block.yield(context, strio);
      } finally {
        strio.ptr.string = null;
        strio.flags &= ~STRIO_READWRITE;
      }
    }
    return val;
  }
Esempio n. 19
0
  @JRubyMethod(name = "putc", required = 1)
  public IRubyObject putc(IRubyObject ch) {
    checkWritable();
    byte c = RubyNumeric.num2chr(ch);
    int olen;

    checkModifiable();

    olen = ptr.string.size();
    if ((ptr.flags & OpenFile.APPEND) != 0) {
      ptr.pos = olen;
    }
    strioExtend(ptr.pos, 1);
    ptr.string.getByteList().set(ptr.pos++, c);
    ptr.string.infectBy(this);
    return ch;
  }
Esempio n. 20
0
  private void strioInit(ThreadContext context, IRubyObject[] args) {
    Ruby runtime = context.runtime;
    RubyString string;
    IRubyObject mode;
    boolean trunc = false;

    switch (args.length) {
      case 2:
        mode = args[1];
        if (mode instanceof RubyFixnum) {
          int flags = RubyFixnum.fix2int(mode);
          ptr.flags = ModeFlags.getOpenFileFlagsFor(flags);
          trunc = (flags & ModeFlags.TRUNC) != 0;
        } else {
          String m = args[1].convertToString().toString();
          ptr.flags = OpenFile.ioModestrFmode(runtime, m);
          trunc = m.charAt(0) == 'w';
        }
        string = args[0].convertToString();
        if ((ptr.flags & OpenFile.WRITABLE) != 0 && string.isFrozen()) {
          throw runtime.newErrnoEACCESError("Permission denied");
        }
        if (trunc) {
          string.resize(0);
        }
        break;
      case 1:
        string = args[0].convertToString();
        ptr.flags = string.isFrozen() ? OpenFile.READABLE : OpenFile.READWRITE;
        break;
      case 0:
        string = RubyString.newEmptyString(runtime, runtime.getDefaultExternalEncoding());
        ptr.flags = OpenFile.READWRITE;
        break;
      default:
        throw runtime.newArgumentError(args.length, 2);
    }

    ptr.string = string;
    ptr.pos = 0;
    ptr.lineno = 0;
    // funky way of shifting readwrite flags into object flags
    flags |= (ptr.flags & OpenFile.READWRITE) * (STRIO_READABLE / OpenFile.READABLE);
  }
Esempio n. 21
0
  @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;
  }
Esempio n. 22
0
  @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;
  }
Esempio n. 23
0
  @JRubyMethod(name = "each_codepoint")
  public IRubyObject each_codepoint(ThreadContext context, Block block) {
    Ruby runtime = context.runtime;

    if (!block.isGiven()) return enumeratorize(runtime, this, "each_codepoint");

    checkReadable();

    Encoding enc = ptr.string.getEncoding();
    byte[] unsafeBytes = ptr.string.getByteList().getUnsafeBytes();
    int begin = ptr.string.getByteList().getBegin();
    for (; ; ) {
      if (ptr.pos >= ptr.string.size()) {
        return this;
      }

      int c =
          StringSupport.codePoint(runtime, enc, unsafeBytes, begin + ptr.pos, unsafeBytes.length);
      int n = StringSupport.codeLength(runtime, enc, c);
      block.yield(context, runtime.newFixnum(c));
      ptr.pos += n;
    }
  }
Esempio n. 24
0
  private void ungetbyteCommon(RubyString ungetBytes) {
    ByteList ungetByteList = ungetBytes.getByteList();
    int len = ungetByteList.getRealSize();
    int start = ptr.pos;

    if (len == 0) return;

    ptr.string.modify();

    if (len > ptr.pos) {
      start = 0;
    } else {
      start = ptr.pos - len;
    }

    ByteList bytes = ptr.string.getByteList();

    if (isEndOfString()) bytes.length(Math.max(ptr.pos, len));

    bytes.replace(start, ptr.pos - start, ungetBytes.getByteList());

    ptr.pos = start;
  }
Esempio n. 25
0
  @JRubyMethod(name = "read", optional = 2)
  public IRubyObject read(ThreadContext context, IRubyObject[] args) {
    checkReadable();

    Ruby runtime = context.runtime;
    IRubyObject str = runtime.getNil();
    int len;
    boolean binary = false;

    switch (args.length) {
      case 2:
        str = args[1];
        if (!str.isNil()) {
          str = str.convertToString();
          ((RubyString) str).modify();
        }
      case 1:
        if (!args[0].isNil()) {
          len = RubyNumeric.fix2int(args[0]);

          if (len < 0) {
            throw getRuntime().newArgumentError("negative length " + len + " given");
          }
          if (len > 0 && isEndOfString()) {
            if (!str.isNil()) ((RubyString) str).resize(0);
            return getRuntime().getNil();
          }
          binary = true;
          break;
        }
      case 0:
        len = ptr.string.size();
        if (len <= ptr.pos) {
          if (str.isNil()) {
            str = runtime.newString();
          } else {
            ((RubyString) str).resize(0);
          }

          return str;
        } else {
          len -= ptr.pos;
        }
        break;
      default:
        throw getRuntime().newArgumentError(args.length, 0);
    }

    if (str.isNil()) {
      str = strioSubstr(runtime, ptr.pos, len);
      if (binary) ((RubyString) str).setEncoding(ASCIIEncoding.INSTANCE);
    } else {
      int rest = ptr.string.size() - ptr.pos;
      if (len > rest) len = rest;
      ((RubyString) str).resize(len);
      ByteList strByteList = ((RubyString) str).getByteList();
      byte[] strBytes = strByteList.getUnsafeBytes();
      ByteList dataByteList = ptr.string.getByteList();
      byte[] dataBytes = dataByteList.getUnsafeBytes();
      System.arraycopy(
          dataBytes, dataByteList.getBegin() + ptr.pos, strBytes, strByteList.getBegin(), len);
      if (binary) {
        ((RubyString) str).setEncoding(ASCIIEncoding.INSTANCE);
      } else {
        ((RubyString) str).setEncoding(ptr.string.getEncoding());
      }
    }
    ptr.pos += ((RubyString) str).size();
    return str;
  }
Esempio n. 26
0
  @JRubyMethod(name = "lineno=", required = 1)
  public IRubyObject set_lineno(ThreadContext context, IRubyObject arg) {
    ptr.lineno = RubyNumeric.fix2int(arg);

    return context.nil;
  }
Esempio n. 27
0
  // strio_getline
  private IRubyObject getline(ThreadContext context, IRubyObject[] args) {
    Ruby runtime = context.runtime;

    IRubyObject str = context.nil;
    ;
    int n, limit = -1;

    switch (args.length) {
      case 0:
        str = runtime.getGlobalVariables().get("$/");
        break;

      case 1:
        {
          str = args[0];
          if (!str.isNil() && !(str instanceof RubyString)) {
            IRubyObject tmp = str.checkStringType19();
            if (tmp.isNil()) {
              limit = RubyNumeric.num2int(str);
              if (limit == 0) return runtime.newString();
              str = runtime.getGlobalVariables().get("$/");
            } else {
              str = tmp;
            }
          }
          break;
        }

      case 2:
        if (!args[0].isNil()) str = args[0].convertToString();
        // 2.0 ignores double nil, 1.9 raises
        if (runtime.is2_0()) {
          if (!args[1].isNil()) {
            limit = RubyNumeric.num2int(args[1]);
          }
        } else {
          limit = RubyNumeric.num2int(args[1]);
        }
        break;
    }

    if (isEndOfString()) {
      return context.nil;
    }

    ByteList dataByteList = ptr.string.getByteList();
    byte[] dataBytes = dataByteList.getUnsafeBytes();
    int begin = dataByteList.getBegin();
    int s = begin + ptr.pos;
    int e = begin + dataByteList.getRealSize();
    int p;

    if (limit > 0 && s + limit < e) {
      e = dataByteList.getEncoding().rightAdjustCharHead(dataBytes, s, s + limit, e);
    }
    if (str.isNil()) {
      str = strioSubstr(runtime, ptr.pos, e - s);
    } else if ((n = ((RubyString) str).size()) == 0) {
      // this is not an exact port; the original confused me
      p = s;
      // remove leading \n
      while (dataBytes[p] == '\n') {
        if (++p == e) {
          return context.nil;
        }
      }
      s = p;
      // find next \n or end; if followed by \n, include it too
      p = memchr(dataBytes, p, '\n', e - p);
      if (p != -1) {
        if (++p < e && dataBytes[p] == '\n') {
          e = p + 1;
        } else {
          e = p;
        }
      }
      str = strioSubstr(runtime, s - begin, e - s);
    } else if (n == 1) {
      RubyString strStr = (RubyString) str;
      ByteList strByteList = strStr.getByteList();
      if ((p = memchr(dataBytes, s, strByteList.get(0), e - s)) != -1) {
        e = p + 1;
      }
      str = strioSubstr(runtime, ptr.pos, e - s);
    } else {
      if (n < e - s) {
        RubyString strStr = (RubyString) str;
        ByteList strByteList = strStr.getByteList();
        byte[] strBytes = strByteList.getUnsafeBytes();

        int[] skip = new int[1 << CHAR_BIT];
        int pos;
        p = strByteList.getBegin();
        bm_init_skip(skip, strBytes, p, n);
        if ((pos = bm_search(strBytes, p, n, dataBytes, s, e - s, skip)) >= 0) {
          e = s + pos + n;
        }
      }
      str = strioSubstr(runtime, ptr.pos, e - s);
    }
    ptr.pos = e - begin;
    ptr.lineno++;
    return str;
  }
Esempio n. 28
0
  @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);
  }
Esempio n. 29
0
 private void doFinalize() {
   data.closedRead = true;
   data.closedWrite = true;
   data.internal = null;
 }
Esempio n. 30
0
  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();
  }