summaryrefslogtreecommitdiff
path: root/ext/iconv
diff options
context:
space:
mode:
Diffstat (limited to 'ext/iconv')
-rw-r--r--ext/iconv/MANIFEST1
-rw-r--r--ext/iconv/charset_alias.rb36
-rw-r--r--ext/iconv/extconf.rb21
-rw-r--r--ext/iconv/iconv.c77
4 files changed, 130 insertions, 5 deletions
diff --git a/ext/iconv/MANIFEST b/ext/iconv/MANIFEST
index 643f3b7f4d..fd7e22deda 100644
--- a/ext/iconv/MANIFEST
+++ b/ext/iconv/MANIFEST
@@ -2,3 +2,4 @@ MANIFEST
extconf.rb
iconv.c
depend
+charset_alias.rb
diff --git a/ext/iconv/charset_alias.rb b/ext/iconv/charset_alias.rb
new file mode 100644
index 0000000000..20a7f6406a
--- /dev/null
+++ b/ext/iconv/charset_alias.rb
@@ -0,0 +1,36 @@
+#! /usr/bin/ruby
+require 'rbconfig'
+
+# http://www.ctan.org/tex-archive/macros/texinfo/texinfo/intl/config.charset'
+# Fri, 30 May 2003 00:09:00 GMT'
+
+OS = Config::CONFIG["target"]
+SHELL = Config::CONFIG['SHELL']
+
+def charset_alias(config_charset, mapfile)
+ map = {}
+ comments = []
+ IO.foreach("|#{SHELL} #{config_charset} #{OS}") do |list|
+ next comments << list if /^\#/ =~ list
+ next unless /^(\S+)\s+(\S+)$/ =~ list
+ sys, can = $1, $2
+ next if sys == can
+ next if can.downcase! and sys == can
+ map[can] = sys
+ end
+ case OS
+ when /linux|-gnu/
+ map.delete('ascii')
+ end
+ open(mapfile, "w") do |f|
+ f.puts("require 'iconv.so'")
+ f.puts
+ f.puts(comments)
+ f.puts("class Iconv")
+ map.each {|can, sys| f.puts(" charset_map['#{can}'.freeze] = '#{sys}'.freeze")}
+ f.puts("end")
+ end
+end
+
+ARGV.size == 2 or abort "usage: #$0 config.status map.rb"
+charset_alias(*ARGV)
diff --git a/ext/iconv/extconf.rb b/ext/iconv/extconf.rb
index 55d9c5da5f..b81b7379fc 100644
--- a/ext/iconv/extconf.rb
+++ b/ext/iconv/extconf.rb
@@ -2,7 +2,28 @@ require 'mkmf'
dir_config("iconv")
+conf = File.exist?(File.join($srcdir, "config.charset"))
+conf = with_config("config-charset", enable_config("config-charset", conf))
+
if have_header("iconv.h")
have_library("iconv")
+ if conf
+ prefix = '$(srcdir)'
+ prefix = $nmake ? "{#{prefix}}" : "#{prefix}/"
+ $INSTALLFILES = [["./iconv.rb", "$(RUBYLIBDIR)"]]
+ if String === conf
+ require 'uri'
+ scheme = URI.parse(conf).scheme
+ else
+ conf = prefix + "config.charset"
+ end
+ end
create_makefile("iconv")
+ if conf
+ open("Makefile", "a") do |mf|
+ mf.print("\nall: iconv.rb\n\niconv.rb: ", prefix, "charset_alias.rb")
+ mf.print(" ", conf) unless scheme
+ mf.print("\n\t$(RUBY) ", prefix, "charset_alias.rb ", conf, " $@\n")
+ end
+ end
end
diff --git a/ext/iconv/iconv.c b/ext/iconv/iconv.c
index e9f2687858..9a3c377b6b 100644
--- a/ext/iconv/iconv.c
+++ b/ext/iconv/iconv.c
@@ -36,6 +36,7 @@ Which coding systems are available, it depends on the platform.
#include <errno.h>
#include <iconv.h>
#include <assert.h>
+#include "st.h"
#include "intern.h"
/* Invalid value for iconv_t is -1 but 0 for VALUE, I hope VALUE is
@@ -63,6 +64,7 @@ static VALUE iconv_failure_success _((VALUE self));
static VALUE iconv_failure_failed _((VALUE self));
static iconv_t iconv_create _((VALUE to, VALUE from));
+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));
@@ -88,6 +90,34 @@ static VALUE iconv_iconv _((int argc, VALUE *argv, VALUE self));
== Iconv
=end
*/
+static VALUE charset_map;
+
+static VALUE charset_map_get _((void))
+{
+ return charset_map;
+}
+
+static char *
+map_charset
+#ifdef HAVE_PROTOTYPES
+ (VALUE *code)
+#else /* HAVE_PROTOTYPES */
+ (code)
+ VALUE *code;
+#endif /* HAVE_PROTOTYPES */
+{
+ VALUE val = *code;
+
+ StringValuePtr(val);
+ if (RHASH(charset_map)->tbl && RHASH(charset_map)->tbl->num_entries) {
+ if (st_lookup(RHASH(charset_map)->tbl, val, &val)) {
+ StringValuePtr(val);
+ *code = val;
+ }
+ }
+ return RSTRING(val)->ptr;
+}
+
static iconv_t
iconv_create
#ifdef HAVE_PROTOTYPES
@@ -98,8 +128,8 @@ iconv_create
VALUE from;
#endif /* HAVE_PROTOTYPES */
{
- const char* tocode = StringValuePtr(to);
- const char* fromcode = StringValuePtr(from);
+ const char* tocode = map_charset(&to);
+ const char* fromcode = map_charset(&from);
iconv_t cd = iconv_open(tocode, fromcode);
@@ -122,6 +152,20 @@ iconv_create
return cd;
}
+static void
+iconv_dfree
+#ifdef HAVE_PROTOTYPES
+(void *cd)
+#else /* HAVE_PROTOTYPES */
+ (cd)
+ void *cd;
+#endif /* HAVE_PROTOTYPES */
+{
+ iconv_close(VALUE2ICONV(cd));
+}
+
+#define ICONV_FREE iconv_dfree
+
static VALUE
iconv_free
#ifdef HAVE_PROTOTYPES
@@ -136,8 +180,6 @@ iconv_free
return Qnil;
}
-#define ICONV_FREE (RUBY_DATA_FUNC)iconv_free
-
static VALUE
iconv_try
#ifdef HAVE_PROTOTYPES
@@ -188,7 +230,7 @@ iconv_failure_initialize
struct iconv_env_t *env;
#endif /* HAVE_PROTOTYPES */
{
- if (!rb_ivar_defined(error, rb_mesg) || NIL_P(rb_ivar_get(error, rb_mesg)))
+ if (NIL_P(rb_attr_get(error, rb_mesg)))
rb_ivar_set(error, rb_mesg, rb_inspect(failed));
if (env) {
success = rb_funcall3(env->ret, rb_inserter, 1, &success);
@@ -478,6 +520,24 @@ iconv_s_iconv
return rb_ensure(iconv_s_convert, (VALUE)&arg, iconv_free, ICONV2VALUE(arg.cd));
}
+static VALUE
+iconv_s_conv
+#ifdef HAVE_PROTOTYPES
+ (VALUE self, VALUE to, VALUE from, VALUE str)
+#else /* HAVE_PROTOTYPES */
+ (self, to, from, str)
+ VALUE self, to, from, str;
+#endif /* HAVE_PROTOTYPES */
+{
+ struct iconv_env_t arg;
+
+ arg.argc = 1;
+ arg.argv = &str;
+ arg.ret = rb_str_new(0, 0);
+ arg.cd = iconv_create(to, from);
+ return rb_ensure(iconv_s_convert, (VALUE)&arg, iconv_free, ICONV2VALUE(arg.cd));
+}
+
/*
=begin
@@ -690,9 +750,12 @@ void
Init_iconv _((void))
{
VALUE rb_cIconv = rb_define_class("Iconv", rb_cData);
+ VALUE metaclass = RBASIC(rb_cIconv)->klass;
+
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, "iconv", iconv_s_iconv, -1);
+ rb_define_singleton_method(rb_cIconv, "conv", iconv_s_conv, 3);
rb_define_method(rb_cIconv, "initialize", iconv_initialize, 2);
rb_define_method(rb_cIconv, "close", iconv_finish, 0);
rb_define_method(rb_cIconv, "iconv", iconv_iconv, -1);
@@ -713,6 +776,10 @@ Init_iconv _((void))
rb_success = rb_intern("success");
rb_failed = rb_intern("failed");
rb_mesg = rb_intern("mesg");
+
+ charset_map = rb_hash_new();
+ rb_gc_register_address(&charset_map);
+ rb_define_singleton_method(rb_cIconv, "charset_map", charset_map_get, 0);
}