1
0
Fork 0
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:
nobu 2005-11-07 11:55:48 +00:00
parent f4413f1487
commit 1aa48a4ea9
3 changed files with 340 additions and 15 deletions

View file

@ -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
@ -5,9 +9,9 @@ Mon Nov 7 16:23:23 2005 NAKAMURA Usaku <usa@ruby-lang.org>
Mon Nov 7 13:43:51 2005 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
* ext/tk/stubs.c (_nativethread_consistency_check): use simpler
* ext/tk/stubs.c (_nativethread_consistency_check): use simpler
(low cost) way to check whether the Tcl interpreter was compiled
with threads enabled of not.
with threads enabled of not.
* ext/tk/tcltklib.c: reduce warnings.

View file

@ -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
View 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)