mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
* ext/iconv/iconv.c: iconvctl() support. [EXPERIMENTAL]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9514 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
f4413f1487
commit
1aa48a4ea9
3 changed files with 340 additions and 15 deletions
|
@ -1,3 +1,7 @@
|
|||
Mon Nov 7 20:54:57 2005 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
||||
|
||||
* ext/iconv/iconv.c: iconvctl() support. [EXPERIMENTAL]
|
||||
|
||||
Mon Nov 7 16:23:23 2005 NAKAMURA Usaku <usa@ruby-lang.org>
|
||||
|
||||
* ext/openssl/ossl.h: need to include winsock2.h before including
|
||||
|
|
|
@ -83,6 +83,14 @@ struct iconv_env_t
|
|||
VALUE (*append)_((VALUE, VALUE));
|
||||
};
|
||||
|
||||
struct rb_iconv_opt_t
|
||||
{
|
||||
VALUE transliterate;
|
||||
VALUE discard_ilseq;
|
||||
};
|
||||
|
||||
static ID id_transliterate, id_discard_ilseq;
|
||||
|
||||
static VALUE rb_eIconvInvalidEncoding;
|
||||
static VALUE rb_eIconvFailure;
|
||||
static VALUE rb_eIconvIllegalSeq;
|
||||
|
@ -96,20 +104,21 @@ static VALUE iconv_failure_initialize _((VALUE error, VALUE mesg, VALUE success,
|
|||
static VALUE iconv_failure_success _((VALUE self));
|
||||
static VALUE iconv_failure_failed _((VALUE self));
|
||||
|
||||
static iconv_t iconv_create _((VALUE to, VALUE from));
|
||||
static iconv_t iconv_create _((VALUE to, VALUE from, struct rb_iconv_opt_t *opt));
|
||||
static void iconv_dfree _((void *cd));
|
||||
static VALUE iconv_free _((VALUE cd));
|
||||
static VALUE iconv_try _((iconv_t cd, const char **inptr, size_t *inlen, char **outptr, size_t *outlen));
|
||||
static VALUE rb_str_derive _((VALUE str, const char* ptr, int len));
|
||||
static VALUE iconv_convert _((iconv_t cd, VALUE str, int start, int length, struct iconv_env_t* env));
|
||||
static VALUE iconv_s_allocate _((VALUE klass));
|
||||
static VALUE iconv_initialize _((VALUE self, VALUE to, VALUE from));
|
||||
static VALUE iconv_s_open _((VALUE self, VALUE to, VALUE from));
|
||||
static VALUE iconv_initialize _((int argc, VALUE *argv, VALUE self));
|
||||
static VALUE iconv_s_open _((int argc, VALUE *argv, VALUE self));
|
||||
static VALUE iconv_s_convert _((struct iconv_env_t* env));
|
||||
static VALUE iconv_s_iconv _((int argc, VALUE *argv, VALUE self));
|
||||
static VALUE iconv_init_state _((VALUE cd));
|
||||
static VALUE iconv_finish _((VALUE self));
|
||||
static VALUE iconv_iconv _((int argc, VALUE *argv, VALUE self));
|
||||
static VALUE iconv_conv _((int argc, VALUE *argv, VALUE self));
|
||||
|
||||
static VALUE charset_map;
|
||||
|
||||
|
@ -140,7 +149,7 @@ map_charset(VALUE *code)
|
|||
}
|
||||
|
||||
static iconv_t
|
||||
iconv_create(VALUE to, VALUE from)
|
||||
iconv_create(VALUE to, VALUE from, struct rb_iconv_opt_t *opt)
|
||||
{
|
||||
const char* tocode = map_charset(&to);
|
||||
const char* fromcode = map_charset(&from);
|
||||
|
@ -171,6 +180,24 @@ iconv_create(VALUE to, VALUE from)
|
|||
}
|
||||
}
|
||||
|
||||
if (opt) {
|
||||
int flag;
|
||||
#ifdef ICONV_SET_TRANSLITERATE
|
||||
if (opt->transliterate != Qundef) {
|
||||
flag = RTEST(opt->transliterate);
|
||||
if (iconvctl(cd, ICONV_SET_TRANSLITERATE, (void *)&flag))
|
||||
rb_sys_fail("ICONV_SET_TRANSLITERATE");
|
||||
}
|
||||
#endif
|
||||
#ifdef ICONV_SET_DISCARD_ILSEQ
|
||||
if (opt->discard_ilseq != Qundef) {
|
||||
flag = RTEST(opt->discard_ilseq);
|
||||
if (iconvctl(cd, ICONV_SET_DISCARD_ILSEQ, (void *)&flag))
|
||||
rb_sys_fail("ICONV_SET_DISCARD_ILSEQ");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return cd;
|
||||
}
|
||||
|
||||
|
@ -436,9 +463,76 @@ iconv_s_allocate(VALUE klass)
|
|||
return Data_Wrap_Struct(klass, 0, ICONV_FREE, 0);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
get_iconv_opt_i(VALUE i, VALUE arg)
|
||||
{
|
||||
struct rb_iconv_opt_t *opt = (struct rb_iconv_opt_t *)arg;
|
||||
VALUE name, val;
|
||||
i = rb_Array(i);
|
||||
name = rb_ary_entry(i, 0);
|
||||
val = rb_ary_entry(i, 1);
|
||||
do {
|
||||
if (SYMBOL_P(name)) {
|
||||
ID id = SYM2ID(name);
|
||||
if (id == id_transliterate) {
|
||||
#ifdef ICONV_SET_TRANSLITERATE
|
||||
opt->transliterate = val;
|
||||
#else
|
||||
rb_notimplement();
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
if (id == id_discard_ilseq) {
|
||||
#ifdef ICONV_SET_DISCARD_ILSEQ
|
||||
opt->discard_ilseq = val;
|
||||
#else
|
||||
rb_notimplement();
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
const char *s = StringValueCStr(name);
|
||||
if (strcmp(s, "transliterate") == 0) {
|
||||
#ifdef ICONV_SET_TRANSLITERATE
|
||||
opt->transliterate = val;
|
||||
#else
|
||||
rb_notimplement();
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
if (strcmp(s, "discard_ilseq") == 0) {
|
||||
#ifdef ICONV_SET_DISCARD_ILSEQ
|
||||
opt->discard_ilseq = val;
|
||||
#else
|
||||
rb_notimplement();
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
name = rb_inspect(name);
|
||||
rb_raise(rb_eArgError, "unknown option - %s", StringValueCStr(name));
|
||||
} while (0);
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
static void
|
||||
get_iconv_opt(struct rb_iconv_opt_t *opt, VALUE options)
|
||||
{
|
||||
opt->transliterate = Qundef;
|
||||
opt->discard_ilseq = Qundef;
|
||||
if (!NIL_P(options)) {
|
||||
rb_iterate(rb_each, options, get_iconv_opt_i, (VALUE)opt);
|
||||
}
|
||||
}
|
||||
|
||||
#define iconv_ctl(self, func, val) (\
|
||||
iconvctl(VALUE2ICONV(check_iconv(self)), func, (void *)&(val)) ? \
|
||||
rb_sys_fail(#func) : (void)0)
|
||||
|
||||
/*
|
||||
* Document-method: new
|
||||
* call-seq: Iconv.new(to, from)
|
||||
* call-seq: Iconv.new(to, from, [options])
|
||||
*
|
||||
* Creates new code converter from a coding-system designated with +from+
|
||||
* to another one designated with +to+.
|
||||
|
@ -447,6 +541,7 @@ iconv_s_allocate(VALUE klass)
|
|||
*
|
||||
* +to+:: encoding name for destination
|
||||
* +from+:: encoding name for source
|
||||
* +options+:: options for converter
|
||||
*
|
||||
* === Exceptions
|
||||
*
|
||||
|
@ -455,11 +550,16 @@ iconv_s_allocate(VALUE klass)
|
|||
* SystemCallError:: if <tt>iconv_open(3)</tt> fails
|
||||
*/
|
||||
static VALUE
|
||||
iconv_initialize(VALUE self, VALUE to, VALUE from)
|
||||
iconv_initialize(int argc, VALUE *argv, VALUE self)
|
||||
{
|
||||
VALUE to, from, options;
|
||||
struct rb_iconv_opt_t opt;
|
||||
|
||||
rb_scan_args(argc, argv, "21", &to, &from, &options);
|
||||
get_iconv_opt(&opt, options);
|
||||
iconv_free(check_iconv(self));
|
||||
DATA_PTR(self) = NULL;
|
||||
DATA_PTR(self) = (void *)ICONV2VALUE(iconv_create(to, from));
|
||||
DATA_PTR(self) = (void *)ICONV2VALUE(iconv_create(to, from, &opt));
|
||||
return self;
|
||||
}
|
||||
|
||||
|
@ -472,9 +572,14 @@ iconv_initialize(VALUE self, VALUE to, VALUE from)
|
|||
* returned from the block.
|
||||
*/
|
||||
static VALUE
|
||||
iconv_s_open(VALUE self, VALUE to, VALUE from)
|
||||
iconv_s_open(int argc, VALUE *argv, VALUE self)
|
||||
{
|
||||
VALUE cd = ICONV2VALUE(iconv_create(to, from));
|
||||
VALUE to, from, options, cd;
|
||||
struct rb_iconv_opt_t opt;
|
||||
|
||||
rb_scan_args(argc, argv, "21", &to, &from, &options);
|
||||
get_iconv_opt(&opt, options);
|
||||
cd = ICONV2VALUE(iconv_create(to, from, &opt));
|
||||
|
||||
self = Data_Wrap_Struct(self, NULL, ICONV_FREE, (void *)cd);
|
||||
if (rb_block_given_p()) {
|
||||
|
@ -534,7 +639,7 @@ iconv_s_iconv(int argc, VALUE *argv, VALUE self)
|
|||
arg.argv = argv + 2;
|
||||
arg.append = rb_ary_push;
|
||||
arg.ret = rb_ary_new2(argc);
|
||||
arg.cd = iconv_create(argv[0], argv[1]);
|
||||
arg.cd = iconv_create(argv[0], argv[1], NULL);
|
||||
return rb_ensure(iconv_s_convert, (VALUE)&arg, iconv_free, ICONV2VALUE(arg.cd));
|
||||
}
|
||||
|
||||
|
@ -555,7 +660,7 @@ iconv_s_conv(VALUE self, VALUE to, VALUE from, VALUE str)
|
|||
arg.argv = &str;
|
||||
arg.append = rb_str_append;
|
||||
arg.ret = rb_str_new(0, 0);
|
||||
arg.cd = iconv_create(to, from);
|
||||
arg.cd = iconv_create(to, from, NULL);
|
||||
return rb_ensure(iconv_s_convert, (VALUE)&arg, iconv_free, ICONV2VALUE(arg.cd));
|
||||
}
|
||||
|
||||
|
@ -693,6 +798,160 @@ iconv_iconv(int argc, VALUE *argv, VALUE self)
|
|||
NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Document-method: conv
|
||||
* call-seq: conv(str...)
|
||||
*
|
||||
* Equivalent to
|
||||
*
|
||||
* iconv(nil, str..., nil).join
|
||||
*/
|
||||
static VALUE
|
||||
iconv_conv(int argc, VALUE *argv, VALUE self)
|
||||
{
|
||||
iconv_t cd = VALUE2ICONV(check_iconv(self));
|
||||
VALUE str, s;
|
||||
|
||||
str = iconv_convert(cd, Qnil, 0, 0, NULL);
|
||||
if (argc > 0) {
|
||||
do {
|
||||
s = iconv_convert(cd, *argv++, 0, -1, NULL);
|
||||
if (RSTRING(s)->len)
|
||||
rb_str_buf_append(str, s);
|
||||
else
|
||||
str = s;
|
||||
} while (--argc);
|
||||
s = iconv_convert(cd, Qnil, 0, 0, NULL);
|
||||
if (RSTRING(s)->len)
|
||||
rb_str_buf_append(str, s);
|
||||
else
|
||||
str = s;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
/*
|
||||
* Document-method: trivial?
|
||||
* call-seq: trivial?
|
||||
*
|
||||
* Returns trivial flag.
|
||||
*/
|
||||
static VALUE
|
||||
iconv_trivialp(VALUE self)
|
||||
{
|
||||
#ifdef ICONV_TRIVIALP
|
||||
int trivial = 0;
|
||||
iconv_ctl(self, ICONV_TRIVIALP, trivial);
|
||||
if (trivial) return Qtrue;
|
||||
#else
|
||||
rb_notimplement();
|
||||
#endif
|
||||
return Qfalse;
|
||||
}
|
||||
|
||||
/*
|
||||
* Document-method: transliterate?
|
||||
* call-seq: transliterate?
|
||||
*
|
||||
* Returns transliterate flag.
|
||||
*/
|
||||
static VALUE
|
||||
iconv_get_transliterate(VALUE self)
|
||||
{
|
||||
#ifdef ICONV_GET_TRANSLITERATE
|
||||
int trans = 0;
|
||||
iconv_ctl(self, ICONV_GET_TRANSLITERATE, trans);
|
||||
if (trans) return Qtrue;
|
||||
#else
|
||||
rb_notimplement();
|
||||
#endif
|
||||
return Qfalse;
|
||||
}
|
||||
|
||||
/*
|
||||
* Document-method: transliterate=
|
||||
* call-seq: cd.transliterate = flag
|
||||
*
|
||||
* Sets transliterate flag.
|
||||
*/
|
||||
static VALUE
|
||||
iconv_set_transliterate(VALUE self, VALUE transliterate)
|
||||
{
|
||||
#ifdef ICONV_SET_TRANSLITERATE
|
||||
int trans = RTEST(transliterate);
|
||||
iconv_ctl(self, ICONV_SET_TRANSLITERATE, trans);
|
||||
#else
|
||||
rb_notimplement();
|
||||
#endif
|
||||
return self;
|
||||
}
|
||||
|
||||
/*
|
||||
* Document-method: discard_ilseq?
|
||||
* call-seq: discard_ilseq?
|
||||
*
|
||||
* Returns discard_ilseq flag.
|
||||
*/
|
||||
static VALUE
|
||||
iconv_get_discard_ilseq(VALUE self)
|
||||
{
|
||||
#ifdef ICONV_GET_DISCARD_ILSEQ
|
||||
int dis = 0;
|
||||
iconv_ctl(self, ICONV_GET_DISCARD_ILSEQ, dis);
|
||||
if (dis) return Qtrue;
|
||||
#else
|
||||
rb_notimplement();
|
||||
#endif
|
||||
return Qfalse;
|
||||
}
|
||||
|
||||
/*
|
||||
* Document-method: discard_ilseq=
|
||||
* call-seq: cd.discard_ilseq = flag
|
||||
*
|
||||
* Sets discard_ilseq flag.
|
||||
*/
|
||||
static VALUE
|
||||
iconv_set_discard_ilseq(VALUE self, VALUE discard_ilseq)
|
||||
{
|
||||
#ifdef ICONV_SET_DISCARD_ILSEQ
|
||||
int dis = RTEST(discard_ilseq);
|
||||
iconv_ctl(self, ICONV_SET_DISCARD_ILSEQ, dis);
|
||||
#else
|
||||
rb_notimplement();
|
||||
#endif
|
||||
return self;
|
||||
}
|
||||
|
||||
/*
|
||||
* Document-method: ctlmethods
|
||||
* call-seq: Iconv.ctlmethods => array
|
||||
*
|
||||
* Returns available iconvctl() method list.
|
||||
*/
|
||||
static VALUE
|
||||
iconv_s_ctlmethods(VALUE klass)
|
||||
{
|
||||
VALUE ary = rb_ary_new();
|
||||
#ifdef ICONV_TRIVIALP
|
||||
rb_ary_push(ary, ID2SYM(rb_intern("trivial?")));
|
||||
#endif
|
||||
#ifdef ICONV_GET_TRANSLITERATE
|
||||
rb_ary_push(ary, ID2SYM(rb_intern("transliterate?")));
|
||||
#endif
|
||||
#ifdef ICONV_SET_TRANSLITERATE
|
||||
rb_ary_push(ary, ID2SYM(rb_intern("transliterate=")));
|
||||
#endif
|
||||
#ifdef ICONV_GET_DISCARD_ILSEQ
|
||||
rb_ary_push(ary, ID2SYM(rb_intern("discard_ilseq?")));
|
||||
#endif
|
||||
#ifdef ICONV_SET_DISCARD_ILSEQ
|
||||
rb_ary_push(ary, ID2SYM(rb_intern("discard_ilseq=")));
|
||||
#endif
|
||||
return ary;
|
||||
}
|
||||
|
||||
/*
|
||||
* Document-class: Iconv::Failure
|
||||
*
|
||||
|
@ -787,13 +1046,20 @@ Init_iconv(void)
|
|||
VALUE rb_cIconv = rb_define_class("Iconv", rb_cData);
|
||||
|
||||
rb_define_alloc_func(rb_cIconv, iconv_s_allocate);
|
||||
rb_define_singleton_method(rb_cIconv, "open", iconv_s_open, 2);
|
||||
rb_define_singleton_method(rb_cIconv, "open", iconv_s_open, -1);
|
||||
rb_define_singleton_method(rb_cIconv, "iconv", iconv_s_iconv, -1);
|
||||
rb_define_singleton_method(rb_cIconv, "conv", iconv_s_conv, 3);
|
||||
rb_define_singleton_method(rb_cIconv, "list", iconv_s_list, 0);
|
||||
rb_define_method(rb_cIconv, "initialize", iconv_initialize, 2);
|
||||
rb_define_singleton_method(rb_cIconv, "ctlmethods", iconv_s_ctlmethods, 0);
|
||||
rb_define_method(rb_cIconv, "initialize", iconv_initialize, -1);
|
||||
rb_define_method(rb_cIconv, "close", iconv_finish, 0);
|
||||
rb_define_method(rb_cIconv, "iconv", iconv_iconv, -1);
|
||||
rb_define_method(rb_cIconv, "conv", iconv_conv, -1);
|
||||
rb_define_method(rb_cIconv, "trivial?", iconv_trivialp, 0);
|
||||
rb_define_method(rb_cIconv, "transliterate?", iconv_get_transliterate, 0);
|
||||
rb_define_method(rb_cIconv, "transliterate=", iconv_set_transliterate, 1);
|
||||
rb_define_method(rb_cIconv, "discard_ilseq?", iconv_get_discard_ilseq, 0);
|
||||
rb_define_method(rb_cIconv, "discard_ilseq=", iconv_set_discard_ilseq, 1);
|
||||
|
||||
rb_eIconvFailure = rb_define_module_under(rb_cIconv, "Failure");
|
||||
rb_define_method(rb_eIconvFailure, "initialize", iconv_failure_initialize, 3);
|
||||
|
@ -814,6 +1080,8 @@ Init_iconv(void)
|
|||
|
||||
rb_success = rb_intern("success");
|
||||
rb_failed = rb_intern("failed");
|
||||
id_transliterate = rb_intern("transliterate");
|
||||
id_discard_ilseq = rb_intern("discard_ilseq");
|
||||
|
||||
charset_map = rb_hash_new();
|
||||
rb_gc_register_address(&charset_map);
|
||||
|
|
53
ext/iconv/mkwrapper.rb
Normal file
53
ext/iconv/mkwrapper.rb
Normal file
|
@ -0,0 +1,53 @@
|
|||
#! /usr/bin/ruby
|
||||
require 'rbconfig'
|
||||
require 'optparse'
|
||||
|
||||
# http://www.ctan.org/tex-archive/macros/texinfo/texinfo/intl/config.charset
|
||||
# Fri, 30 May 2003 00:09:00 GMT'
|
||||
|
||||
HEADER = <<SRC
|
||||
require 'iconv.so'
|
||||
|
||||
class Iconv
|
||||
case RUBY_PLATFORM
|
||||
SRC
|
||||
|
||||
def charset_alias(config_charset, mapfile = nil)
|
||||
found = nil
|
||||
src = [HEADER]
|
||||
open(config_charset) do |input|
|
||||
input.find {|line| /^case "\$os" in/ =~ line} or return
|
||||
input.each do |line|
|
||||
case line
|
||||
when /^\s*([-\w\*]+(?:\s*\|\s*[-\w\*]+)*)(?=\))/
|
||||
(s = " when ") << $&.split('|').collect {|targ|
|
||||
targ.strip!
|
||||
tail = targ.chomp!("*") ? '' : '\z'
|
||||
head = targ.slice!(/\A\*/) ? '' : '\A'
|
||||
targ.gsub!(/\*/, '.*')
|
||||
"/#{head}#{targ}#{tail}/"
|
||||
}.join(", ")
|
||||
src << s
|
||||
found = {}
|
||||
when /^\s*echo "(?:\$\w+\.)?([-\w*]+)\s+([-\w]+)"/
|
||||
sys, can = $1, $2
|
||||
can.downcase!
|
||||
unless found[can] or (/\Aen_(?!US\z)/ =~ sys && /\ACP437\z/i =~ can)
|
||||
found[can] = true
|
||||
src << " charset_map['#{can}'] = '#{sys}'.freeze"
|
||||
end
|
||||
when /^\s*;;/
|
||||
found = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
src << " end" << "end"
|
||||
if mapfile
|
||||
open(mapfile, "wb") {|f| f.puts *src}
|
||||
else
|
||||
puts *src
|
||||
end
|
||||
end
|
||||
|
||||
(1..2) === ARGV.size or abort "usage: #{$0} config_charset [mapfile]"
|
||||
charset_alias(*ARGV)
|
Loading…
Reference in a new issue