package org.jruby.util;
import org.jcodings.Encoding;
import org.jcodings.specific.USASCIIEncoding;
import org.jcodings.unicode.UnicodeEncoding;
import org.jruby.*;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.util.io.EncodingUtils;
import static org.jruby.util.StringSupport.MBCLEN_CHARFOUND_LEN;
import static org.jruby.util.StringSupport.MBCLEN_CHARFOUND_P;
import static org.jruby.util.StringSupport.codePoint;
public class RubyStringBuilder {
public static RubyString types(Ruby runtime, RubyModule type) {
ThreadContext context = runtime.getCurrentContext();
return inspectIdentifierByteList(runtime, type.toRubyString(context).getByteList());
}
public static RubyString types(Ruby runtime, RubyModule type1, RubyModule type2) {
ThreadContext context = runtime.getCurrentContext();
RubyString fullTypeName = type1.toRubyString(context).catString("::").cat(type2.toRubyString(context));
return inspectIdentifierByteList(runtime, fullTypeName.getByteList());
}
public static RubyString ids(Ruby runtime, String id) {
ByteList identifier = runtime.newSymbol(id).getBytes();
return inspectIdentifierByteList(runtime, identifier);
}
public static RubyString ids(Ruby runtime, IRubyObject object) {
ByteList identifier;
if (object instanceof RubyString) {
identifier = ((RubyString) object).getByteList();
} else if (object instanceof RubySymbol) {
identifier = ((RubySymbol) object).getBytes();
} else {
identifier = object.convertToString().getByteList();
}
return inspectIdentifierByteList(runtime, identifier);
}
public static RubyString inspectIdentifierByteList(final Ruby runtime, ByteList byteList) {
Encoding enc = byteList.getEncoding();
byte bytes[] = byteList.getUnsafeBytes();
int p = byteList.getBegin();
int end = p + byteList.getRealSize();
RubyString result = RubyString.newStringLight(runtime, new ByteList(end - p + 2));
result.getByteList().setBegin(1);
Encoding resultEnc = runtime.getDefaultInternalEncoding();
boolean isUnicode = enc.isUnicode();
boolean asciiCompat = enc.isAsciiCompatible();
boolean needsQuotes = false;
if (resultEnc == null) resultEnc = runtime.getDefaultExternalEncoding();
if (!resultEnc.isAsciiCompatible()) resultEnc = USASCIIEncoding.INSTANCE;
result.associateEncoding(resultEnc);
int prev = p;
Encoding actEnc = EncodingUtils.getActualEncoding(enc, byteList);
if (actEnc != enc) {
enc = actEnc;
if (isUnicode) isUnicode = enc instanceof UnicodeEncoding;
}
while (p < end) {
int n = StringSupport.preciseLength(enc, bytes, p, end);
if (!MBCLEN_CHARFOUND_P(n)) {
if (p > prev) result.cat(bytes, prev, p - prev);
n = enc.minLength();
if (end < p + n) n = end - p;
while (n-- > 0) {
result.modifyExpand(result.size() + 4);
Sprintf.sprintf(runtime, result.getByteList() ,"\\x%02X", bytes[p] & 0377);
prev = ++p;
}
continue;
}
n = MBCLEN_CHARFOUND_LEN(n);
final int c = enc.mbcToCode(bytes, p, end); int cc = 0;
p += n;
if ((asciiCompat || isUnicode) &&
(c == '"' || c == '\\' ||
(c == '#' &&
p < end &&
MBCLEN_CHARFOUND_P(StringSupport.preciseLength(enc, bytes, p, end)) &&
((cc = codePoint(runtime, enc, bytes, p, end)) == '$' ||
cc == '@' || cc == '{')
)
)) {
if (p - n > prev) result.cat(bytes, prev, p - n - prev);
result.cat('\\');
if (asciiCompat || enc == resultEnc) {
prev = p - n;
continue;
}
}
switch (c) {
case '\n': cc = 'n'; break;
case '\r': cc = 'r'; break;
case '\t': cc = 't'; break;
case '\f': cc = 'f'; break;
case '\013': cc = 'v'; break;
case '\010': cc = 'b'; break;
case '\007': cc = 'a'; break;
case 033: cc = 'e'; break;
default: cc = 0; break;
}
if (cc != 0) {
if (p - n > prev) result.cat(bytes, prev, p - n - prev);
result.cat('\\');
result.cat(cc);
prev = p;
continue;
}
if ((enc == resultEnc && enc.isPrint(c)) || (asciiCompat && (c < 128 && c > 0) && enc.isPrint(c))) {
continue;
} else {
if (p - n > prev) result.cat(bytes, prev, p - n - prev);
String format = StringSupport.escapedCharFormat(c, isUnicode);
if (!format.equals("%c")) needsQuotes = true;
Sprintf.sprintf(runtime, result.getByteList() ,format, (c & 0xFFFFFFFFL));
prev = p;
continue;
}
}
if (p > prev) result.cat(bytes, prev, p - prev);
if (needsQuotes) {
result.prepend('"');
result.cat('"');
}
return result;
}
public static String str(Ruby runtime, IRubyObject value, String message) {
RubyString buf = (RubyString) value.asString().dup();
catUTF8(runtime, buf, message);
return buf.toString();
}
public static String str(Ruby runtime, String message, IRubyObject value) {
RubyString buf = runtime.newString(message);
buf.cat19(value.asString());
return buf.toString();
}
public static String str(Ruby runtime, String messageBegin, IRubyObject value, String messageEnd) {
RubyString buf = runtime.newString(messageBegin);
buf.cat19(value.asString());
catUTF8(runtime, buf, messageEnd);
return buf.toString();
}
public static String str(Ruby runtime, IRubyObject value, String message, IRubyObject value2) {
RubyString buf = (RubyString) value.asString().dup();
catUTF8(runtime, buf, message);
buf.cat19(value2.asString());
return buf.toString();
}
public static String str(Ruby runtime, IRubyObject value, String message, IRubyObject value2, String message2) {
RubyString buf = (RubyString) value.asString().dup();
catUTF8(runtime, buf, message);
buf.cat19(value2.asString());
catUTF8(runtime, buf, message2);
return buf.toString();
}
public static String str(Ruby runtime, String messageBegin, IRubyObject value, String messageMiddle, IRubyObject value2) {
RubyString buf = runtime.newString(messageBegin);
buf.cat19(value.asString());
catUTF8(runtime, buf, messageMiddle);
buf.cat19(value2.asString());
return buf.toString();
}
public static String str(Ruby runtime, String messageBegin, IRubyObject value, String messageMiddle, IRubyObject value2, String messageEnd) {
RubyString buf = runtime.newString(messageBegin);
buf.cat19(value.asString());
catUTF8(runtime, buf, messageMiddle);
buf.cat19(value2.asString());
catUTF8(runtime, buf, messageEnd);
return buf.toString();
}
public static String str(Ruby runtime, String messageBegin, IRubyObject value, String messageMiddle, RubyString value2,
String messageMiddle2, IRubyObject value3, String messageMiddle3, RubyString value4, String messageEnd) {
RubyString buf = runtime.newString(messageBegin);
buf.cat19(value.asString());
catUTF8(runtime, buf, messageMiddle);
buf.cat19(value2);
catUTF8(runtime, buf, messageMiddle2);
buf.cat19(value3.asString());
catUTF8(runtime, buf, messageMiddle3);
buf.cat19(value4);
catUTF8(runtime, buf, messageEnd);
return buf.toString();
}
private static void catUTF8(final Ruby runtime, final RubyString str, final String value) {
EncodingUtils.encStrBufCat(runtime, str, value);
}
}