* ext/iconv/iconv.c (iconv_create): strips glibc style option before

charset mapping.  retris without options if they seemed causing
  error, and warns.  [ruby-dev:36147]


git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@19147 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
nobu 2008-09-05 09:16:34 +00:00
parent f0bf74a07b
commit 07e08245d3
2 changed files with 74 additions and 13 deletions

View File

@ -1,3 +1,9 @@
Fri Sep 5 18:16:31 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
* ext/iconv/iconv.c (iconv_create): strips glibc style option before
charset mapping. retris without options if they seemed causing
error, and warns. [ruby-dev:36147]
Fri Sep 5 03:09:48 2008 Koichi Sasada <ko1@atdot.net>
* iseq.c (iseq_data_to_ary): make it static.

View File

@ -135,6 +135,21 @@ charset_map_get(void)
return charset_map;
}
static VALUE
strip_glibc_option(VALUE *code)
{
VALUE val = *code;
const char *ptr = RSTRING_PTR(val), *pend = RSTRING_END(val);
const char *slash = memchr(ptr, '/', pend - ptr);
if (slash && slash < pend - 1 && slash[1] == '/') {
VALUE opt = rb_str_subseq(val, slash - ptr, pend - slash);
val = rb_str_subseq(val, 0, slash - ptr);
*code = val;
return opt;
}
return 0;
}
static char *
map_charset(VALUE *code)
{
@ -153,29 +168,53 @@ map_charset(VALUE *code)
static iconv_t
iconv_create(VALUE to, VALUE from, struct rb_iconv_opt_t *opt, int *idx)
{
VALUE toopt = strip_glibc_option(&to);
VALUE fromopt = strip_glibc_option(&from);
VALUE toenc = 0, fromenc = 0;
const char* tocode = map_charset(&to);
const char* fromcode = map_charset(&from);
iconv_t cd;
int retry = 0;
if ((*idx = rb_enc_find_index(tocode)) < 0) {
const char *slash = strchr(tocode, '/');
if (slash && slash[1] == '/') {
VALUE tmp = rb_str_new(tocode, slash - tocode);
*idx = rb_enc_find_index(RSTRING_PTR(tmp));
}
*idx = rb_enc_find_index(tocode);
if (toopt) {
toenc = rb_str_plus(to, toopt);
tocode = RSTRING_PTR(toenc);
}
cd = iconv_open(tocode, fromcode);
if (cd == (iconv_t)-1) {
if (fromopt) {
fromenc = rb_str_plus(from, fromopt);
fromcode = RSTRING_PTR(fromenc);
}
while ((cd = iconv_open(tocode, fromcode)) == (iconv_t)-1) {
int inval = 0;
switch (errno) {
case EMFILE:
case ENFILE:
case ENOMEM:
rb_gc();
cd = iconv_open(tocode, fromcode);
if (!retry++) {
rb_gc();
continue;
}
break;
case EINVAL:
retry = 0;
inval = 1;
if (toenc) {
tocode = RSTRING_PTR(to);
rb_str_resize(toenc, 0);
toenc = 0;
continue;
}
if (fromenc) {
fromcode = RSTRING_PTR(from);
rb_str_resize(fromenc, 0);
fromenc = 0;
continue;
}
break;
}
if (cd == (iconv_t)-1) {
int inval = errno == EINVAL;
{
const char *s = inval ? "invalid encoding " : "iconv";
volatile VALUE msg = rb_str_new(0, strlen(s) + RSTRING_LEN(to) +
RSTRING_LEN(from) + 8);
@ -190,10 +229,25 @@ iconv_create(VALUE to, VALUE from, struct rb_iconv_opt_t *opt, int *idx)
}
}
if (toopt || fromopt) {
if (toopt && fromopt && RTEST(rb_str_equal(toopt, fromopt))) {
fromopt = 0;
}
if (toopt && fromopt) {
rb_warning("encoding option isn't portable: %s, %s",
RSTRING_PTR(toopt) + 2, RSTRING_PTR(fromopt) + 2);
}
else {
rb_warning("encoding option isn't portable: %s",
(toopt ? RSTRING_PTR(toopt) : RSTRING_PTR(fromopt)) + 2);
}
}
if (opt) {
#ifdef ICONV_SET_TRANSLITERATE
if (opt->transliterate != Qundef) {
int flag = RTEST(opt->transliterate);
rb_warning("encoding option isn't portable: transliterate");
if (iconvctl(cd, ICONV_SET_TRANSLITERATE, (void *)&flag))
rb_sys_fail("ICONV_SET_TRANSLITERATE");
}
@ -201,6 +255,7 @@ iconv_create(VALUE to, VALUE from, struct rb_iconv_opt_t *opt, int *idx)
#ifdef ICONV_SET_DISCARD_ILSEQ
if (opt->discard_ilseq != Qundef) {
int flag = RTEST(opt->discard_ilseq);
rb_warning("encoding option isn't portable: discard_ilseq");
if (iconvctl(cd, ICONV_SET_DISCARD_ILSEQ, (void *)&flag))
rb_sys_fail("ICONV_SET_DISCARD_ILSEQ");
}