/** flo_to_s */ @JRubyMethod(name = "to_s") @Override public IRubyObject to_s() { Ruby runtime = getRuntime(); if (Double.isInfinite(value)) return RubyString.newString(runtime, value < 0 ? "-Infinity" : "Infinity"); if (Double.isNaN(value)) return RubyString.newString(runtime, "NaN"); ByteList buf = new ByteList(); // Under 1.9, use full-precision float formatting (JRUBY-4846). // Double-precision can represent around 16 decimal digits; // we use 20 to ensure full representation. Sprintf.sprintf(buf, Locale.US, "%#.20g", this); int e = buf.indexOf('e'); if (e == -1) e = buf.getRealSize(); ASCIIEncoding ascii = ASCIIEncoding.INSTANCE; if (!ascii.isDigit(buf.get(e - 1))) { buf.setRealSize(0); Sprintf.sprintf(buf, Locale.US, "%#.14e", this); e = buf.indexOf('e'); if (e == -1) e = buf.getRealSize(); } int p = e; while (buf.get(p - 1) == '0' && ascii.isDigit(buf.get(p - 2))) p--; System.arraycopy(buf.getUnsafeBytes(), e, buf.getUnsafeBytes(), p, buf.getRealSize() - e); buf.setRealSize(p + buf.getRealSize() - e); buf.setEncoding(USASCIIEncoding.INSTANCE); return runtime.newString(buf); }
// Make string based on internal data encoding (which ironically is its // external encoding. This seems messy and we should consider a more // uniform method for makeing strings (we have a slightly different variant // of this in RubyIO. private RubyString makeString(Ruby runtime, ByteList buf, boolean setEncoding) { if (runtime.is1_9() && setEncoding) buf.setEncoding(ptr.string.getEncoding()); RubyString str = RubyString.newString(runtime, buf); str.setTaint(true); return str; }
// Make string based on internal data encoding (which ironically is its // external encoding. This seems messy and we should consider a more // uniform method for makeing strings (we have a slightly different variant // of this in RubyIO. private RubyString makeString(Ruby runtime, ByteList buf) { if (runtime.is1_9()) buf.setEncoding(data.internal.getEncoding()); RubyString str = RubyString.newString(runtime, buf); str.setTaint(true); return str; }
@Override public int parseString(RubyLexer lexer) throws java.io.IOException { ByteList str = null; ByteList eos = nd_lit; int len = nd_lit.length() - 1; boolean indent = (flags & STR_FUNC_INDENT) != 0; int c = lexer.nextc(); if (c == EOF) return error(lexer, len, str, eos); // Found end marker for this heredoc if (lexer.was_bol() && lexer.whole_match_p(nd_lit, indent)) { lexer.heredoc_restore(this); return Tokens.tSTRING_END; } if ((flags & STR_FUNC_EXPAND) == 0) { do { ByteList lbuf = lexer.lex_lastline; int p = 0; int pend = lexer.lex_pend; if (pend > p) { switch (lexer.p(pend - 1)) { case '\n': pend--; if (pend == p || lexer.p(pend - 1) == '\r') { pend++; break; } break; case '\r': pend--; break; } } if (lexer.getHeredocIndent() > 0) { for (long i = 0; p + i < pend && lexer.update_heredoc_indent(lexer.p(p)); i++) {} lexer.setHeredocLineIndent(0); } if (str != null) { str.append(lbuf.makeShared(p, pend - p)); } else { str = new ByteList(lbuf.makeShared(p, pend - p)); } if (pend < lexer.lex_pend) str.append('\n'); lexer.lex_goto_eol(); if (lexer.getHeredocIndent() > 0) { lexer.setValue(str); return Tokens.tSTRING_CONTENT; } // MRI null checks str in this case but it is unconditionally non-null? if (lexer.nextc() == -1) return error(lexer, len, null, eos); } while (!lexer.whole_match_p(eos, indent)); } else { ByteList tok = new ByteList(); tok.setEncoding(lexer.getEncoding()); if (c == '#') { switch (c = lexer.nextc()) { case '$': case '@': lexer.pushback(c); return Tokens.tSTRING_DVAR; case '{': lexer.commandStart = true; return Tokens.tSTRING_DBEG; } tok.append('#'); } // MRI has extra pointer which makes our code look a little bit more strange in comparison do { lexer.pushback(c); Encoding enc[] = new Encoding[1]; enc[0] = lexer.getEncoding(); if ((c = new StringTerm(flags, '\0', '\n').parseStringIntoBuffer(lexer, tok, enc)) == EOF) { if (lexer.eofp) return error(lexer, len, str, eos); return restore(lexer); } if (c != '\n') { lexer.setValue(lexer.createStr(tok, 0)); return Tokens.tSTRING_CONTENT; } tok.append(lexer.nextc()); if (lexer.getHeredocIndent() > 0) { lexer.lex_goto_eol(); lexer.setValue(lexer.createStr(tok, 0)); return Tokens.tSTRING_CONTENT; } if ((c = lexer.nextc()) == EOF) return error(lexer, len, str, eos); } while (!lexer.whole_match_p(eos, indent)); str = tok; } lexer.heredoc_restore(this); lexer.setStrTerm(new StringTerm(-1, '\0', '\0')); lexer.setValue(lexer.createStr(str, 0)); return Tokens.tSTRING_CONTENT; }
@JRubyMethod(required = 2, optional = 4) public IRubyObject primitive_convert(ThreadContext context, IRubyObject[] args) { Ruby runtime = context.runtime; RubyString input; RubyString output; int outputByteoffset = -1; int outputBytesize = 0; int flags = 0; int hashArg = -1; if (args.length > 2 && !args[2].isNil()) { if (args.length == 3 && args[2] instanceof RubyHash) { hashArg = 2; } else { outputByteoffset = (int) args[2].convertToInteger().getLongValue(); if (outputByteoffset < 0) throw runtime.newArgumentError("negative offset"); } } if (args.length > 3 && !args[3].isNil()) { if (args.length == 4 && args[3] instanceof RubyHash) { hashArg = 3; } else { outputBytesize = (int) args[3].convertToInteger().getLongValue(); if (outputBytesize < 0) throw runtime.newArgumentError("negative bytesize"); } } if (args.length > 4 && !args[4].isNil()) { if (args.length > 5 && !args[5].isNil()) { throw runtime.newArgumentError(args.length, 5); } if (args[4] instanceof RubyHash) { hashArg = 4; } else { flags = (int) args[4].convertToInteger().getLongValue(); } } IRubyObject opt = context.nil; if (hashArg != -1 && !(opt = TypeConverter.checkHashType(runtime, args[hashArg])).isNil()) { IRubyObject v = ((RubyHash) opt).op_aref(context, runtime.newSymbol("partial_input")); if (v.isTrue()) { flags |= EncodingUtils.ECONV_PARTIAL_INPUT; } v = ((RubyHash) opt).op_aref(context, runtime.newSymbol("after_output")); if (v.isTrue()) { flags |= EncodingUtils.ECONV_AFTER_OUTPUT; } } else { flags = 0; } ByteList inBytes; ByteList outBytes; if (args[0].isNil()) { inBytes = new ByteList(); } else { input = args[0].convertToString(); input.modify19(); inBytes = input.getByteList(); } output = args[1].convertToString(); output.modify19(); outBytes = output.getByteList(); if (outputByteoffset == -1) { outputByteoffset = outBytes.getRealSize(); } else if (outputByteoffset > outBytes.getRealSize()) { throw runtime.newArgumentError("offset too big"); } int outputByteEnd = outputByteoffset + outputBytesize; if (outputByteEnd > outBytes.getRealSize()) { outBytes.ensure(outputByteEnd); } RubyCoderResult result = transcoder.primitiveConvert( context, inBytes, output.getByteList(), outputByteoffset, outputBytesize, inBytes.getEncoding(), inBytes.getEncoding().isAsciiCompatible(), flags); outBytes.setEncoding( transcoder.outEncoding != null ? transcoder.outEncoding : inBytes.getEncoding()); return symbolFromResult(result, runtime, flags, context); }
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(); }
// FIXME: We are assuming that original string will be raw bytes. If -Ku is provided // this will not be true, but that is ok for now. Deal with that when someone needs it. private IRubyObject _iconv(RubyString str, int start, int length) { if (fromEncoding == null) { throw getRuntime().newArgumentError("closed iconv"); } ByteList bytes = str.getByteList(); // treat start and end as start...end for end >= 0, start..end for end < 0 if (start < 0) { start += bytes.length(); } if (start < 0 || start > bytes.length()) { // invalid ranges result in an empty string return RubyString.newEmptyString(getRuntime()); } if (length < 0 || length > bytes.length() - start) { length = bytes.length() - start; } ByteBuffer buf = ByteBuffer.wrap(bytes.getUnsafeBytes(), bytes.begin() + start, length); try { CharBuffer cbuf = fromEncoding.decode(buf); buf = toEncoding.encode(cbuf); } catch (MalformedInputException e) { throw getRuntime().newIllegalSequence(str.toString()); } catch (UnmappableCharacterException e) { throw getRuntime().newIllegalSequence(str.toString()); } catch (CharacterCodingException e) { throw getRuntime().newInvalidEncoding("invalid sequence"); } catch (IllegalStateException e) { throw getRuntime().newIllegalSequence(str.toString()); } byte[] arr = buf.array(); start = 0; String displayName = toEncoding.charset().displayName(); if (arr.length >= 2) { // minimum Byte Order Mark (BOM) length if (displayName.toLowerCase().startsWith("utf-16")) { if ((arr[0] == (byte) 0xfe && arr[1] == (byte) 0xff)) { if (count > 0) start = 2; endian = "BE"; } else if (arr[0] == (byte) 0xff && arr[1] == (byte) 0xfe) { if (count > 0) start = 2; endian = "LE"; } } else if (displayName.toLowerCase().startsWith("utf-32") && arr.length >= 4) { if (arr[0] == (byte) 0x00 && arr[1] == (byte) 0x00 && arr[2] == (byte) 0xfe && arr[3] == (byte) 0xff) { if (count > 0) start = 4; endian = "BE"; } else if (arr[0] == (byte) 0xff && arr[1] == (byte) 0xfe && arr[2] == (byte) 0x00 && arr[3] == (byte) 0x00) { if (count > 0) start = 4; endian = "LE"; } } } count++; if (displayName.equalsIgnoreCase("utf-16") || displayName.equalsIgnoreCase("utf-32")) { displayName += endian; } ByteList r = new ByteList(arr, start, buf.limit() - start); EncodingDB.Entry entry = EncodingDB.getEncodings().get(displayName.getBytes()); if (entry != null) { Encoding charset = entry.getEncoding(); r.setEncoding(charset); } return getRuntime().newString(r); }