From 6259c87d02fce0a77ac90b6786ed1f2bc5baea32 Mon Sep 17 00:00:00 2001 From: matz Date: Mon, 20 Oct 2008 08:05:44 +0000 Subject: * include/ruby/ruby.h (ExportStringValue): new macro to convert string in internal encoding to external to export. * string.c (rb_str_export): new function to do conversion to external encoding. * ext/sdbm/init.c: encoding conversion support. * ext/dbm/dbm.c: ditto. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@19855 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- string.c | 97 +++++++++++++++++++++++++++++++++++++++------------------------- 1 file changed, 59 insertions(+), 38 deletions(-) (limited to 'string.c') diff --git a/string.c b/string.c index 054a1eb72b..fe6d1d600e 100644 --- a/string.c +++ b/string.c @@ -472,52 +472,61 @@ rb_tainted_str_new_cstr(const char *ptr) RUBY_ALIAS_FUNCTION(rb_tainted_str_new2(const char *ptr), rb_tainted_str_new_cstr, (ptr)) #define rb_tainted_str_new2 rb_tainted_str_new_cstr +static VALUE +str_conv_enc(VALUE str, rb_encoding *from, rb_encoding *to) +{ + rb_econv_t *ec; + rb_econv_result_t ret; + long len; + VALUE newstr; + const unsigned char *sp; + unsigned char *dp; + + if (!to) return str; + if (from == to) return str; + if (rb_enc_asciicompat(to) && ENC_CODERANGE(str) == ENC_CODERANGE_7BIT) + return str; + + len = RSTRING_LEN(str); + newstr = rb_str_new(0, len); + + retry: + ec = rb_econv_open_opts(from->name, to->name, 0, Qnil); + if (!ec) return str; + + sp = (unsigned char*)RSTRING_PTR(str); + dp = (unsigned char*)RSTRING_PTR(newstr); + ret = rb_econv_convert(ec, &sp, (unsigned char*)RSTRING_END(str), + &dp, (unsigned char*)RSTRING_END(newstr), 0); + rb_econv_close(ec); + switch (ret) { + case econv_destination_buffer_full: + /* destination buffer short */ + len *= 2; + rb_str_resize(newstr, len); + goto retry; + + case econv_finished: + len = dp - (unsigned char*)RSTRING_PTR(newstr); + rb_str_set_len(newstr, len); + rb_enc_associate(newstr, to); + return newstr; + + default: + /* some error, return original */ + return str; + } +} + VALUE rb_external_str_new_with_enc(const char *ptr, long len, rb_encoding *eenc) { VALUE str; - rb_encoding *ienc; if (len == 0 && !ptr) len = strlen(ptr); str = rb_tainted_str_new(ptr, len); rb_enc_associate(str, eenc); - ienc = rb_default_internal_encoding(); - if (ienc) { - rb_econv_t *ec; - rb_econv_result_t ret; - VALUE newstr = rb_str_new(0, len); - long nlen = len; - const unsigned char *sp; - unsigned char *dp; - - retry: - ec = rb_econv_open_opts(eenc->name, ienc->name, 0, Qnil); - if (!ec) return str; - - sp = (unsigned char*)RSTRING_PTR(str); - dp = (unsigned char*)RSTRING_PTR(newstr); - ret = rb_econv_convert(ec, &sp, (unsigned char*)RSTRING_END(str), - &dp, (unsigned char*)RSTRING_END(newstr), 0); - rb_econv_close(ec); - switch (ret) { - case econv_destination_buffer_full: - /* destination buffer short */ - nlen *= 2; - rb_str_resize(newstr, nlen); - goto retry; - - case econv_finished: - nlen = dp - (unsigned char*)RSTRING_PTR(newstr); - rb_str_set_len(newstr, nlen); - rb_enc_associate(newstr, ienc); - return newstr; - - default: - /* some error, return original */ - return str; - } - } - return str; + return str_conv_enc(str, eenc, rb_default_internal_encoding()); } VALUE @@ -532,6 +541,18 @@ rb_locale_str_new(const char *ptr, long len) return rb_external_str_new_with_enc(ptr, len, rb_locale_encoding()); } +VALUE +rb_str_export(VALUE str) +{ + return str_conv_enc(str, STR_ENC_GET(str), rb_default_external_encoding()); +} + +VALUE +rb_str_export_to_enc(VALUE str, rb_encoding *enc) +{ + return str_conv_enc(str, STR_ENC_GET(str), enc); +} + static VALUE str_replace_shared(VALUE str2, VALUE str) { -- cgit v1.2.3