lib/ffi-icu/lib.rb in ffi-icu-0.0.7 vs lib/ffi-icu/lib.rb in ffi-icu-0.0.8

- old
+ new

@@ -6,64 +6,73 @@ end module Lib extend FFI::Library - VERSIONS = { - "48" => "_48", - "46" => "_46", - "45" => "_45", - "44" => "_44", - "42" => "_4_2", - } - - # FIXME: this is incredibly ugly, figure out some better way - def self.find_icu - suffix = '' - - # let the user tell us where the lib is - if ENV['FFI_ICU_LIB'] - libs = ENV['FFI_ICU_LIB'].split(",") - ffi_lib(*libs) - - if ENV['FFI_ICU_VERSION_SUFFIX'] - return ENV['FFI_ICU_VERSION_SUFFIX'] - elsif num = libs.first[/\d+$/] - return num.split(//).join("_") + def self.search_paths + @search_paths ||= begin + if ENV['FFI_ICU_LIB'] + [ ENV['FFI_ICU_LIB'] ] + elsif FFI::Platform::IS_WINDOWS + ENV['PATH'].split(File::PATH_SEPARATOR) else - return suffix + [ '/usr/local/{lib64,lib}', '/opt/local/{lib64,lib}', '/usr/{lib64,lib}' ] end end + end - libs = nil - versions = VERSIONS.keys + def self.find_lib(lib) + Dir.glob(search_paths.map { |path| + File.expand_path(File.join(path, lib)) + }).first + end - # ok, try to find it - case ICU.platform - when :osx - ffi_lib "icucore" - when :linux - libs = ffi_lib versions.map { |v| "libicui18n.so.#{v}" }, - versions.map { |v| "libicutu.so.#{v}" } + def self.load_icu + # First find the library + lib_names = case ICU.platform + when :osx + [find_lib("libicucore.#{FFI::Platform::LIBSUFFIX}")] + when :linux + [find_lib("libicui18n.#{FFI::Platform::LIBSUFFIX}.??"), + find_lib("libicutu.#{FFI::Platform::LIBSUFFIX}.??")] + when :windows + [find_lib("icuuc??.#{FFI::Platform::LIBSUFFIX}"), + find_lib("icuin??.#{FFI::Platform::LIBSUFFIX}")] + end - when :windows - libs = ffi_lib versions.map { |v| "icuin#{v}.dll" } - else - raise LoadError + lib_names.compact! if lib_names + + if not lib_names or lib_names.length == 0 + raise LoadError, "Could not find ICU on #{ICU.platform.inspect}, patches appreciated!" end - if libs - lib_name = libs.first.name - version = VERSIONS.find { |object, func| lib_name =~ /#{object}(\.dll)?$/ } + # And now try to load the library + begin + libs = ffi_lib(*lib_names) + rescue LoadError => ex + raise LoadError, "no idea how to load ICU on #{ICU.platform.inspect}, patches appreciated! (#{ex.message})" + end - version or raise "unable to find suffix in #{lib_name}" - suffix = version.last + # And last figure out the version we just loaded + icu_version(libs) + end + + def self.icu_version(libs) + version = nil + + libs.find do |lib| + # Get the version - sure would be nice if libicu exported this in a function + # we could just call cause this is super fugly! + match = lib.name.match(/(\d\d)\.#{FFI::Platform::LIBSUFFIX}/) || + lib.name.match(/#{FFI::Platform::LIBSUFFIX}\.(\d\d)/) + if match + version = match[1] + end end - suffix - rescue LoadError => ex - raise LoadError, "no idea how to load ICU on #{ICU.platform.inspect}, patches appreciated! (#{ex.message})" + # Note this may return nil, like on OSX + version end def self.check_error ptr = FFI::MemoryPointer.new(:int) ret = yield(ptr) @@ -99,13 +108,13 @@ self.class.send :define_method, func_name do |*args| raise Error, "#{func_name} not available on platform #{ICU.platform.inspect}" end end + version = load_icu + suffix = version ? "_#{version}" : "" - suffix = find_icu() - attach_function :u_errorName, "u_errorName#{suffix}", [:int], :string attach_function :uenum_count, "uenum_count#{suffix}", [:pointer, :pointer], :int attach_function :uenum_close, "uenum_close#{suffix}", [:pointer], :void attach_function :uenum_next, "uenum_next#{suffix}", [:pointer, :pointer, :pointer], :string attach_function :u_charsToUChars, "u_charsToUChars#{suffix}", [:string, :pointer, :int32_t], :void @@ -188,11 +197,11 @@ :nfkd, 3, :nfc, 4, :default, 4, :nfkc, 5, :fcd, 6 - ] + ] attach_function :unorm_normalize, "unorm_normalize#{suffix}", [:pointer, :int32_t, :normalization_mode, :int32_t, :pointer, :int32_t, :pointer], :int32_t # # Text Boundary Analysis @@ -209,10 +218,10 @@ :letter_limit, 300, :kana, 300, :kana_limit, 400, :ideo, 400, :ideo_limit, 400 - ] + ] attach_function :ubrk_countAvailable, "ubrk_countAvailable#{suffix}", [], :int32_t attach_function :ubrk_getAvailable, "ubrk_getAvailable#{suffix}", [:int32_t], :string attach_function :ubrk_open, "ubrk_open#{suffix}", [:iterator_type, :string, :pointer, :int32_t, :pointer], :pointer