Description: ruby 1.9 patch for EB library
Author: Kubo Takehiro <kubo@jiubao.org>
Origin: https://github.com/kubo/rubyeb19

diff --git a/eb.c b/eb.c
index f21d825..4a7d2bd 100644
--- a/eb.c
+++ b/eb.c
@@ -19,6 +19,13 @@
 
 #if HAVE_EB_SYSDEFS_H
 #include <eb/sysdefs.h>
+#if (defined RUBY_EB_ENABLE_PTHREAD && !defined(EB_ENABLE_PTHREAD)) \
+ || (!defined RUBY_EB_ENABLE_PTHREAD && defined(EB_ENABLE_PTHREAD))
+#error The EB library is incompatible with EB heders.
+#endif
+
+#elif defined RUBY_EB_ENABLE_PTHREAD
+#define EBCONF_ENABLE_PTHREAD 1
 #endif
 
 #include <eb/eb.h>
@@ -55,6 +62,21 @@
 
 #define APPENDIX_EB_IVAR "__appendix"
 
+#ifdef HAVE_TYPE_RB_ENCODING
+#include <ruby/encoding.h>
+#define REB_TO_RB_ENCODING(reb) rb_enc_from_index(NUM2INT(rb_ivar_get(reb, id_eb_encidx)))
+#else
+#define rb_encoding void
+#define REB_TO_RB_ENCODING(reb) NULL
+#define rb_ascii8bit_encindex() 0
+#define rb_enc_find_index(name) 0
+#define rb_usascii_str_new_cstr(ptr) rb_str_new2(ptr)
+#define rb_filesystem_str_new_cstr(ptr) rb_str_new2(ptr)
+/* "((void)enc, ...)" is a hack to suppress warnings: unused variable 'enc' */
+#define rb_external_str_new_with_enc(ptr, len, enc) ((void)enc, rb_tainted_str_new((ptr), (len)))
+#define rb_str_export_to_enc(str, enc) ((void)enc, (str))
+#endif
+
 struct ExtFont {
     int code;
     int wideflag;               /* boolean */
@@ -67,20 +89,30 @@ static EB_Error_Code eb_error;
 
 
 
-VALUE mEB;
-VALUE cEBook;
-VALUE cEBCancel;
-VALUE cEBPosition;
-VALUE cEBExtFont;
-VALUE cEBHook;
-VALUE cEBAppendix;
+static VALUE mEB;
+static VALUE cEBook;
+static VALUE cEBCancel;
+static VALUE cEBPosition;
+static VALUE cEBExtFont;
+static VALUE cEBHook;
+static VALUE cEBAppendix;
 
-ID id_call;
+static ID id_call;
+static ID id_eb_encidx;
+
+static void
+reb_check_type(VALUE obj, VALUE klass)
+{
+    if (!rb_obj_is_kind_of(obj, klass)) {
+        rb_raise(rb_eTypeError, "wrong argument type %s (expected %s)",
+                 rb_obj_classname(obj), rb_class2name(klass));
+    }
+}
 
-int
+static int
 text_hook(EB_Book * book, EB_Appendix * appendix, void *container, EB_Hook_Code code, int argc, const int *argv)
 {
-    VALUE func, ret_buff, rb_argv, rb_eb, rb_hookset;
+    VALUE func, ret_buff, rargv, rb_eb, rb_hookset;
     int idx;
     char *tmpbuffer;
 
@@ -92,17 +124,17 @@ text_hook(EB_Book * book, EB_Appendix * appendix, void *container, EB_Hook_Code
 
     func = rb_ary_entry(rb_iv_get(rb_hookset, HOOKSET_PROCS_IVAR), code);
 
-    rb_argv = rb_ary_new2(argc);
+    rargv = rb_ary_new2(argc);
     for (idx = 0; idx < argc; idx++) {
-        rb_ary_store(rb_argv, idx, INT2FIX(argv[idx]));
+        rb_ary_store(rargv, idx, INT2FIX(argv[idx]));
     }
 
-    ret_buff = rb_funcall(func, id_call, 2, rb_eb, rb_argv);
+    ret_buff = rb_funcall(func, id_call, 2, rb_eb, rargv);
     if (ret_buff != Qnil) {
         if (TYPE(ret_buff) == T_STRING) {
             ret_buff = rb_funcall(ret_buff, rb_intern("to_str"), 0);
         }
-        tmpbuffer = STR2CSTR(ret_buff);
+        tmpbuffer = StringValueCStr(ret_buff);
         eb_write_text_string(book, tmpbuffer);
     }
     return 0;
@@ -164,6 +196,7 @@ reb_initialize(VALUE klass)
     reb_appendix = Data_Make_Struct(cEBAppendix, EB_Appendix, 0, finalize_appendix, appendix);
     eb_initialize_appendix(appendix);
     rb_iv_set(robj, APPENDIX_EB_IVAR, reb_appendix);
+    rb_ivar_set(robj, id_eb_encidx, INT2FIX(rb_ascii8bit_encindex()));
 
     return robj;
 }
@@ -185,13 +218,30 @@ reb_bind(VALUE obj, VALUE path)
 {
     EB_Book *eb;
     int r;
+    EB_Character_Code charcode = EB_CHARCODE_INVALID;
+    int encidx;
 
     Data_Get_Struct(obj, EB_Book, eb);
-    r = eb_bind(eb, STR2CSTR(path));
+    r = eb_bind(eb, StringValueCStr(path));
     if (r != EB_SUCCESS) {
-        rb_raise(rb_eRuntimeError, eb_error_message(r));
+        rb_raise(rb_eRuntimeError, "%s", eb_error_message(r));
         return Qfalse;
     }
+
+    eb_character_code(eb, &charcode);
+    switch (charcode) {
+    case EB_CHARCODE_ISO8859_1:
+        encidx = rb_enc_find_index("ISO-8859-1");
+        break;
+    case EB_CHARCODE_JISX0208:
+        encidx = rb_enc_find_index("EUC-JP");
+        break;
+    default:
+        encidx = rb_ascii8bit_encindex();
+        break;
+    }
+    rb_ivar_set(obj, id_eb_encidx, INT2FIX(encidx));
+
     return obj;
 }
 
@@ -206,13 +256,13 @@ reb_disktype(VALUE obj)
     eb_error = eb_disc_type(eb, &r);
     switch (r) {
     case EB_DISC_EB:
-        return rb_str_new2("EB/EBG/EBXA/EBXA-C/S-EBXA");
+        return rb_usascii_str_new_cstr("EB/EBG/EBXA/EBXA-C/S-EBXA");
         break;
     case EB_DISC_EPWING:
-        return rb_str_new2("EPWING");
+        return rb_usascii_str_new_cstr("EPWING");
         break;
     }
-    return rb_str_new2("Unknown");
+    return rb_usascii_str_new_cstr("Unknown");
 }
 
 static VALUE
@@ -241,29 +291,29 @@ static VALUE
 reb_path(VALUE obj)
 {
     EB_Book *eb;
-    char r[1024];               /*絶対値はまずいと思う */
+    char r[EB_MAX_PATH_LENGTH + 1];
 
     Data_Get_Struct(obj, EB_Book, eb);
     eb_error = eb_path(eb, r);
 
-    return rb_str_new2(r);
+    return rb_filesystem_str_new_cstr(r);
 }
 
 static VALUE
 reb_charcode(VALUE obj)
 {
     EB_Book *eb;
-    EB_Character_Code r;
+    EB_Character_Code r = EB_CHARCODE_INVALID;
 
     Data_Get_Struct(obj, EB_Book, eb);
     eb_error = eb_character_code(eb, &r);
 
     switch (r) {
     case EB_CHARCODE_ISO8859_1:
-        return rb_str_new2("ISO8859_1");
+        return rb_usascii_str_new_cstr("ISO8859_1");
         break;
     case EB_CHARCODE_JISX0208:
-        return rb_str_new2("JISX0208");
+        return rb_usascii_str_new_cstr("JISX0208");
         break;
     }
     return Qnil;
@@ -303,19 +353,21 @@ static VALUE
 reb_subbooktitle(int argc, VALUE * argv, VALUE obj)
 {
     EB_Book *eb;
-    char r[1024];               /*絶対値はまずいと思う */
+    char r[EB_MAX_TITLE_LENGTH + 1];
+    rb_encoding *enc = REB_TO_RB_ENCODING(obj);
 
     Data_Get_Struct(obj, EB_Book, eb);
     eb_error = (argc == 0) ?
         eb_subbook_title(eb, r) : eb_subbook_title2(eb, NUM2INT(argv[0]), r);
-    return rb_str_new2(r);
+
+    return rb_external_str_new_with_enc(r, strlen(r), enc);
 }
 
 static VALUE
 reb_subbookdirectory(int argc, VALUE * argv, VALUE obj)
 {
     EB_Book *eb;
-    char r[1024];               /*絶対値はまずいと思う */
+    char r[EB_MAX_DIRECTORY_NAME_LENGTH + 1];
 
     Data_Get_Struct(obj, EB_Book, eb);
     eb_error = (argc == 0) ?
@@ -371,7 +423,7 @@ reb_unsetsubbook(VALUE obj)
     return obj;
 }
 
-VALUE
+static VALUE
 have_search(VALUE obj, EB_Error_Code(*funct) (EB_Book *))
 {
     EB_Book *eb;
@@ -379,7 +431,7 @@ have_search(VALUE obj, EB_Error_Code(*funct) (EB_Book *))
     Data_Get_Struct(obj, EB_Book, eb);
     r = (*funct) (eb);
     if (!r && eb_error == EB_ERR_NO_CUR_SUB) {
-        rb_raise(rb_eRuntimeError, eb_error_message(eb_error));
+        rb_raise(rb_eRuntimeError, "%s", eb_error_message(eb_error));
         return Qfalse;
     }
     return (r) ? Qtrue : Qfalse;
@@ -432,8 +484,9 @@ get_eb_texthook(VALUE reb)
 static VALUE
 content_read(VALUE reb, EB_Book * eb, EB_Appendix * appendix, EB_Hookset * text_hookset)
 {
-    int len;
+    ssize_t len;
     char desc[MAX_STRLEN + 1];
+    rb_encoding *enc = REB_TO_RB_ENCODING(reb);
 
     eb_error = eb_read_text(eb, appendix, text_hookset, (void *) reb,
                             MAX_STRLEN, desc, &len);
@@ -442,7 +495,7 @@ content_read(VALUE reb, EB_Book * eb, EB_Appendix * appendix, EB_Hookset * text_
         rb_raise(rb_eRuntimeError, "fail fetching text");
         return Qfalse;
     }
-    return rb_str_new(desc, len);
+    return rb_external_str_new_with_enc(desc, len, enc);
 }
 
 static VALUE
@@ -455,14 +508,15 @@ content_fetch_from_pos(VALUE reb, EB_Book * eb, EB_Position * pos, EB_Appendix *
     return content_read(reb, eb, appendix, text_hookset);
 }
 
-VALUE
+static VALUE
 get_item(VALUE reb, EB_Book * eb, EB_Hit * hit)
 {
     EB_Hookset *text_hookset;
     EB_Appendix *appendix;
     VALUE item;
     char desc[MAX_STRLEN + 1];
-    int len;
+    ssize_t len;
+    rb_encoding *enc = REB_TO_RB_ENCODING(reb);
     item = rb_ary_new2(2);
 
     if (eb_seek_text(eb, &(hit->heading)) < 0) {
@@ -480,14 +534,14 @@ get_item(VALUE reb, EB_Book * eb, EB_Hit * hit)
         return Qfalse;
     }
 
-    rb_ary_push(item, rb_str_new(desc, len));
+    rb_ary_push(item, rb_external_str_new_with_enc(desc, len, enc));
     rb_ary_push(item, content_fetch_from_pos(reb, eb, &(hit->text), appendix, text_hookset));
 
     return item;
 }
 
 
-VALUE
+static VALUE
 hitmaker(VALUE reb, EB_Book * eb, unsigned int max, int flag)
 {
     int hitpushed, hitcount;
@@ -536,20 +590,22 @@ hitmaker(VALUE reb, EB_Book * eb, unsigned int max, int flag)
     return (flag == 0) ? robj : INT2NUM(hitpushed);
 }
 
-void
-set_keywords(VALUE array, char **buffer)
+static void
+set_keywords(VALUE array, char **buffer, volatile VALUE *gc_guard, rb_encoding *enc)
 {
     int i, sz;
+
     if (TYPE(array) != T_ARRAY) {
         rb_raise(rb_eTypeError, "wordlist must be array of String.");
     }
 
-    sz = RARRAY(array)->len;
+    sz = RARRAY_LEN(array);
     if (sz > MAX_KEYWORDS) {
         rb_raise(rb_eRuntimeError, "too many keywords(%d).", sz);
     }
     for (i = 0; i < sz; i++) {
-        buffer[i] = STR2CSTR(rb_ary_entry(array, i));
+        gc_guard[i] = rb_str_export_to_enc(rb_ary_entry(array, i), enc);
+        buffer[i] = RSTRING_PTR(gc_guard[i]);
     }
     buffer[sz] = NULL;
 }
@@ -563,6 +619,12 @@ easy_search(int argc, VALUE * argv, VALUE obj, int wordtype,
     char *buffer[MAX_KEYWORDS + 1];
     int max;
     int r;
+    rb_encoding *enc = REB_TO_RB_ENCODING(obj);
+    /* The following two variables are used to prevent GC from freeing
+     * temporary objects.
+     */
+    volatile VALUE gc_guard[MAX_KEYWORDS];
+    volatile VALUE str;
 
     if (argc < 1) {
         rb_raise(rb_eArgError, "missing searchstring");
@@ -570,10 +632,11 @@ easy_search(int argc, VALUE * argv, VALUE obj, int wordtype,
     }
 
     if (wordtype == SEARCHTYPE_WORD) {
-        word = STR2CSTR(argv[0]);
+        str = rb_str_export_to_enc(argv[0], enc);
+        word = RSTRING_PTR(str);
     }
     else {
-        set_keywords(argv[0], buffer);
+        set_keywords(argv[0], buffer, gc_guard, enc);
         word = buffer;
     }
     max = (argc > 1) ? NUM2INT(argv[1]) : -1;
@@ -616,10 +679,11 @@ reb_searchkeyword(int argc, VALUE * argv, VALUE obj)
 
 
 /*   Thanks for Kuroda-san  */
-VALUE
+static VALUE
 hitmaker2(VALUE reb, EB_Book * eb, unsigned int max, int flag)
 {
-    int hitcount, i, len, broken;
+    int hitcount, i, broken;
+    ssize_t len;
     int hitpushed;
     VALUE robj, item, can;
     EB_Hit hits[MAX_HITS];
@@ -629,6 +693,7 @@ hitmaker2(VALUE reb, EB_Book * eb, unsigned int max, int flag)
     char descbuf2[MAX_STRLEN + 1];
     char *prevdesc;
     int prevpage, prevoffset;
+    rb_encoding *enc = REB_TO_RB_ENCODING(reb);
     desc = descbuf1;
 
 /*** this 2 lines necessary? (2/4) eblook do like this ***/
@@ -669,7 +734,7 @@ hitmaker2(VALUE reb, EB_Book * eb, unsigned int max, int flag)
 
             item = rb_ary_new2(2);
             rb_ary_push(item, Data_Make_Struct(cEBPosition, EB_Position, 0, free, ebpos));
-            rb_ary_push(item, rb_str_new(desc, len));
+            rb_ary_push(item, rb_external_str_new_with_enc(desc, len, enc));
             ebpos->page = hits[i].text.page;
             ebpos->offset = hits[i].text.offset;
 
@@ -707,7 +772,7 @@ hitmaker2(VALUE reb, EB_Book * eb, unsigned int max, int flag)
     return (flag == 0) ? robj : INT2NUM(hitpushed);
 }
 
-VALUE
+static VALUE
 position_search(int argc, VALUE * argv, VALUE obj, int wordtype,
                 EB_Error_Code(*funct) ())
 {
@@ -716,6 +781,12 @@ position_search(int argc, VALUE * argv, VALUE obj, int wordtype,
     void *word;
     int max;
     int r;
+    rb_encoding *enc = REB_TO_RB_ENCODING(obj);
+    /* The following two variables are used to prevent GC from freeing
+     * temporary objects.
+     */
+    volatile VALUE gc_guard[MAX_KEYWORDS];
+    volatile VALUE str;
 
     if (argc < 1) {
         rb_raise(rb_eArgError, "missing searchstring");
@@ -723,10 +794,11 @@ position_search(int argc, VALUE * argv, VALUE obj, int wordtype,
     }
 
     if (wordtype == SEARCHTYPE_WORD) {
-        word = STR2CSTR(argv[0]);
+        str = rb_str_export_to_enc(argv[0], enc);
+        word = RSTRING_PTR(str);
     }
     else {
-        set_keywords(argv[0], buffer);
+        set_keywords(argv[0], buffer, gc_guard, enc);
         word = buffer;
     }
     max = (argc > 1) ? NUM2INT(argv[1]) : -1;
@@ -775,6 +847,7 @@ reb_content(VALUE obj, VALUE position)
     VALUE robj;
 
     Data_Get_Struct(obj, EB_Book, eb);
+    reb_check_type(position, cEBPosition);
     Data_Get_Struct(position, EB_Position, ppos);
     apx = get_eb_appendix(obj);
     thook = get_eb_texthook(obj);
@@ -785,7 +858,7 @@ reb_content(VALUE obj, VALUE position)
         do {
             rb_yield(robj);
             robj = content_read(obj, eb, apx, thook);
-            dlen = MAX_STRLEN - RSTRING(robj)->len;
+            dlen = MAX_STRLEN - RSTRING_LEN(robj);
         } while (dlen == 0);
     }
     return robj;
@@ -803,7 +876,7 @@ reb_content_noseek(VALUE obj)
 static VALUE
 reb_sethookset(VALUE obj, VALUE hkset)
 {
-    if (rb_funcall(hkset, rb_intern("is_a?"), 1, cEBHook) != Qtrue && hkset != Qnil) {
+    if (!rb_obj_is_kind_of(hkset, cEBHook) && !NIL_P(hkset)) {
         rb_raise(rb_eArgError, "hookset must be nil or an instance of Hookset");
         return Qfalse;
     }
@@ -874,7 +947,7 @@ reb_font_list(VALUE obj)
     return robj;
 }
 
-EB_Font_Code
+static EB_Font_Code
 get_fontcode(EB_Book * eb)
 {
     EB_Font_Code r;
@@ -991,7 +1064,7 @@ read_binary(EB_Book * eb, long maxlen, int iterateflag)
 {
     char buffer[MAX_STRLEN];
     long readbytes;
-    int bitmap_len;
+    ssize_t bitmap_len;
     int blocksize;
     EB_Error_Code retcode;
     VALUE robj;
@@ -1010,7 +1083,7 @@ read_binary(EB_Book * eb, long maxlen, int iterateflag)
     while (bitmap_len != 0) {
         retcode = eb_read_binary(eb, blocksize, buffer, &bitmap_len);
         if (retcode != EB_SUCCESS) {
-            rb_raise(rb_eRuntimeError, eb_error_message(retcode));
+            rb_raise(rb_eRuntimeError, "%s", eb_error_message(retcode));
             return Qfalse;
         }
         if (iterateflag) {
@@ -1024,6 +1097,7 @@ read_binary(EB_Book * eb, long maxlen, int iterateflag)
                 break;
         }
     }
+    rb_obj_taint(robj);
 
     return iterateflag ? INT2NUM(readbytes) : robj;
 }
@@ -1036,6 +1110,7 @@ reb_read_monographic(VALUE obj, VALUE pos, VALUE width, VALUE height)
     EB_Position *epos;
 
     Data_Get_Struct(obj, EB_Book, eb);
+    reb_check_type(pos, cEBPosition);
     Data_Get_Struct(pos, EB_Position, epos);
 
     retcode = eb_set_binary_mono_graphic(eb, epos, NUM2UINT(width), NUM2UINT(height));
@@ -1086,7 +1161,9 @@ reb_read_wavedata(int argc, VALUE * argv, VALUE obj)
     maxlen = (argc > 2) ? NUM2UINT(argv[2]) : MAX_STRLEN;
 
     Data_Get_Struct(obj, EB_Book, eb);
+    reb_check_type(argv[0], cEBPosition);
     Data_Get_Struct(argv[0], EB_Position, spos);
+    reb_check_type(argv[1], cEBPosition);
     Data_Get_Struct(argv[1], EB_Position, epos);
 
     retcode = eb_set_binary_wave(eb, spos, epos);
@@ -1104,7 +1181,7 @@ reb_read_mpeg(int argc, VALUE * argv, VALUE obj)
     EB_Error_Code retcode;
     EB_Book *eb;
     long maxlen;
-    int param[4];
+    unsigned int param[4];
     int i;
 
     if (argc < 4) {
@@ -1129,8 +1206,8 @@ static VALUE
 reb_compose_mpegfilename(int argc, VALUE * argv, VALUE obj)
 {
     EB_Error_Code retcode;
-    char buffer[1024];
-    int param[4];
+    char buffer[EB_MAX_DIRECTORY_NAME_LENGTH + 1];
+    unsigned int param[4];
     int i;
     if (argc != 4) {
         rb_raise(rb_eArgError, "4 args needed.(code1-code4)");
@@ -1174,7 +1251,7 @@ reb_menu(VALUE obj)
         return Qnil;
     }
     else if (err != EB_SUCCESS) {
-        rb_raise(rb_eRuntimeError, eb_error_message(err));
+        rb_raise(rb_eRuntimeError, "%s", eb_error_message(err));
         return Qfalse;
     }
     return content_fetch_from_pos(obj, eb, &pos,
@@ -1212,7 +1289,7 @@ reb_appendixpath(VALUE obj, VALUE path)
     EB_Appendix *appendix;
     appendix = get_eb_appendix(obj);
     if (path != Qnil) {
-        eb_bind_appendix(appendix, STR2CSTR(path));
+        eb_bind_appendix(appendix, StringValueCStr(path));
     }
     else {
         eb_finalize_appendix(appendix);
@@ -1291,7 +1368,7 @@ font2bitmapformat(struct ExtFont *font,
     };
 
     (*conv_func) (font->bitmap, width, height, buffer, &size);
-    robj = rb_str_new(buffer, size);
+    robj = rb_tainted_str_new(buffer, size);
     free(buffer);
     return robj;
 }
@@ -1439,13 +1516,17 @@ rebhk_register(int argc, VALUE * argv, VALUE self)
         break;
     case 2:
         proc = argv[1];
+        if (!rb_respond_to(proc, id_call)) {
+            rb_raise(rb_eArgError, "wrong type argument %s (should respond to 'call')",
+                     rb_obj_classname(proc));
+        }
         break;
     default:
         rb_raise(rb_eArgError, "wrong # of arguments");
         break;
     }
 
-    hook_type = FIX2UINT(argv[0]);
+    hook_type = NUM2UINT(argv[0]);
     rb_ary_store(rb_iv_get(self, HOOKSET_PROCS_IVAR), hook_type, proc);
     Data_Get_Struct(self, EB_Hookset, text_hookset);
     hook.code = hook_type;
@@ -1485,7 +1566,7 @@ reb_dontuseexception(VALUE obj)
     return Qfalse;
 }
 
-void
+static void
 define_constants_under(VALUE mod)
 {
     rb_define_const(mod, "HOOK_INITIALIZE", INT2FIX(EB_HOOK_INITIALIZE));
@@ -1557,7 +1638,19 @@ define_constants_under(VALUE mod)
 void
 Init_eb()
 {
+#ifdef HAVE_EB_PTHREAD_ENABLED
+#ifdef RUBY_EB_ENABLE_PTHREAD
+    if (!eb_pthread_enabled()) {
+       rb_raise(rb_eRuntimeError, "The RubyEB is compiled for pthread-enabled EB library.");
+     }
+#else
+    if (eb_pthread_enabled()) {
+       rb_raise(rb_eRuntimeError, "The RubyEB is compiled for pthread-disabled EB library.");
+     }
+#endif
+#endif
     id_call = rb_intern("call");
+    id_eb_encidx = rb_intern("@__ruby_eb_encidx__");
 
     mEB = rb_define_module("EB");
     rb_define_const(mEB,"RUBYEB_VERSION",rb_str_new2(RUBYEB_VERSION));
diff --git a/extconf.rb b/extconf.rb
index 8893290..e9acc19 100644
--- a/extconf.rb
+++ b/extconf.rb
@@ -5,9 +5,26 @@ have_library("intl") if /freebsd/ =~ RUBY_PLATFORM
 have_library('eb')
 have_func("rb_block_proc")
 have_func("eb_bitmap_to_png")
-have_header('eb/sysdefs.h')                                                    
+have_header('eb/sysdefs.h')
+have_type('rb_encoding', ['ruby/ruby.h', 'ruby/encoding.h'])
 
-# uncomment the following line if you use eb-4.0beta* with pthread support.
-# $defs << '-DEBCONF_ENABLE_PTHREAD'
+if have_func("eb_pthread_enabled")
+  print "checking that the EB library is pthread enabled... "
+  STDOUT.flush
+  if try_run(<<EOS)
+#include <eb/eb.h>
+
+int main()
+{
+    printf("eb_pthread_enabled() => %d\\n", eb_pthread_enabled());
+    return eb_pthread_enabled() ? 0 : 1;
+}
+EOS
+    puts "yes"
+    $defs << '-DRUBY_EB_ENABLE_PTHREAD'
+  else
+    puts "no"
+  end
+end
 
 create_makefile("eb")
diff --git a/test.rb b/test.rb
index b245868..3ed1800 100644
--- a/test.rb
+++ b/test.rb
@@ -1,8 +1,13 @@
 #!/bin/env ruby -Ke
+# -*- coding: euc-jp -*-
 require "eb"
 
-if $KCODE!="EUC" then
-  raise RuntimeError,"lib eb requires EUC coding system"
+if defined? Encoding
+  Encoding.default_internal = "UTF-8"
+else
+  if $KCODE!="EUC" then
+    raise RuntimeError,"lib eb requires EUC coding system"
+  end
 end
 
 b=EB::Book.new
