diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 01f73a0aae7ef9e298e3f541d3450a43061104bd..8ab09e968b5b8e32e89ef3d59fdcec578048963c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -234,6 +234,12 @@ if (TARGET_OS_FREEBSD AND NOT TARGET_OS_DEBIAN_FREEBSD) else() set (common_libraries ${common_libraries} ${INTL}) endif() + find_library (ICONV iconv) + if (NOT ICONV) + message(FATAL_ERROR "iconv library not found") + else() + set (common_libraries ${common_libraries} ${ICONV}) + endif() endif() set (common_libraries ${common_libraries} ${LIBUUID_LIBRARIES}) diff --git a/src/lua/iconv.lua b/src/lua/iconv.lua index 304768d8fafaa1e2b152cb7c1d5bde1f2ab959bb..6a6bfeb761e1a30075287a49bde4a00b90fc6f73 100644 --- a/src/lua/iconv.lua +++ b/src/lua/iconv.lua @@ -8,6 +8,13 @@ iconv_t iconv_open(const char *tocode, const char *fromcode); void iconv_close(iconv_t cd); size_t iconv(iconv_t cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft); +/* + * add prefix 'lib' under FreeBSD + */ +iconv_t libiconv_open(const char *tocode, const char *fromcode); +void libiconv_close(iconv_t cd); +size_t libiconv(iconv_t cd, const char **inbuf, size_t *inbytesleft, + char **outbuf, size_t *outbytesleft); ]] local iconv_t = ffi.typeof('struct iconv') @@ -16,6 +23,22 @@ local cchar_ptr_arr_t = ffi.typeof('const char *[1]') local cchar_ptr_t = ffi.typeof('const char *') local size_t_arr_t = ffi.typeof('size_t [1]') +local _iconv_open +local _iconv_close +local _iconv + +-- To fix #3073, BSD iconv implementation is not fully +-- compatible with iconv, so use external iconv.so lib +if jit.os == 'BSD' then + _iconv_open = ffi.C.libiconv_open + _iconv_close = ffi.C.libiconv_close + _iconv = ffi.C.libiconv +else + _iconv_open = ffi.C.iconv_open + _iconv_close = ffi.C.iconv_close + _iconv = ffi.C.iconv +end + local E2BIG = errno['E2BIG'] local EINVAL = errno['EINVAL'] local EILSEQ = errno['EILSEQ'] @@ -41,10 +64,10 @@ local function iconv_convert(iconv, data) while data_left[0] > 0 do buf_ptr[0] = buf:reserve(output_len) buf_left[0] = buf:unused() - local res = ffi.C.iconv(iconv, data_ptr, data_left, + local res = _iconv(iconv, data_ptr, data_left, buf_ptr, buf_left) if res == ffi.cast('size_t', -1) and errno() ~= E2BIG then - ffi.C.iconv(iconv, nil, nil, nil, nil) + _iconv(iconv, nil, nil, nil, nil) if errno() == EINVAL then error('Invalid multibyte sequence') end @@ -57,7 +80,7 @@ local function iconv_convert(iconv, data) end -- iconv function sets cd's conversion state to the initial state - ffi.C.iconv(iconv, nil, nil, nil, nil) + _iconv(iconv, nil, nil, nil, nil) local result = ffi.string(buf.rpos, buf:size()) buf:reset() return result @@ -65,7 +88,7 @@ end local iconv_mt = { __call = iconv_convert, - __gc = ffi.C.iconv_close, + __gc = _iconv_close, __tostring = function(iconv) return string.format("iconv: %p", iconv) end } @@ -75,7 +98,7 @@ local function iconv_new(to, from) if type(to) ~= 'string' or type(from) ~= 'string' then error('Usage: iconv.new("CP1251", "KOI8-R")') end - local iconv = ffi.C.iconv_open(to, from) + local iconv = _iconv_open(to, from) if iconv == conv_rv_error then error('iconv: '..errno.strerror()) end