diff options
author | Daniel Silverstone <dsilvers@digital-scurf.org> | 2016-09-05 22:15:51 +0100 |
---|---|---|
committer | Daniel Silverstone <dsilvers@digital-scurf.org> | 2016-09-05 22:15:51 +0100 |
commit | d6e186bad3aa0641091dd37d361be02ce7001a3c (patch) | |
tree | f356f4c9aa95ced5fed3aa02f2133273d8c6539a | |
parent | 64c2eac157d1f60f759b1976c9df084e197e6877 (diff) | |
download | luxio-d6e186bad3aa0641091dd37d361be02ce7001a3c.tar.gz |
Ensure iconv contexts get cleaned up, also test it
-rw-r--r-- | luxio.c | 65 | ||||
-rw-r--r-- | tests/test-iconv.lua | 5 |
2 files changed, 63 insertions, 7 deletions
@@ -3703,6 +3703,51 @@ luxio_LOG_MASK(lua_State *L) return 1; } +/*** Character set conversion. +@section iconv +*/ + +#define LUXIO_ICONV_METATABLE "luxio.iconv" + +static int +luxio__iconv_gc(lua_State *L) +{ + iconv_t *ic = (iconv_t*)(lua_touserdata(L, 1)); + if (*ic != NULL && *ic != (iconv_t)(-1)) { + iconv_close(*ic); + *ic = NULL; + } + return 0; +} + +static int +luxio__iconv_tostring(lua_State *L) +{ + iconv_t *ic = (iconv_t*)(lua_touserdata(L, 1)); + lua_pushfstring(L, "<iconv %p>", *ic); + return 1; +} + +static iconv_t* +luxio__create_iconv(lua_State *L) +{ + iconv_t *r = lua_newuserdata(L, sizeof(iconv_t)); + int create = luaL_newmetatable(L, LUXIO_ICONV_METATABLE); + + if (create != 0) { + lua_pushcfunction(L, luxio__iconv_gc); + lua_setfield(L, -2, "__gc"); + lua_pushcfunction(L, luxio__iconv_tostring); + lua_setfield(L, -2, "__tostring"); + } + + *r = NULL; + + lua_setmetatable(L, -2); + + return r; +} + /*** Allocate descriptor for character set conversion. @tparam string tocode @tparam string fromcode @@ -3715,16 +3760,18 @@ luxio_iconv_open(lua_State *L) { const char *tocode = luaL_checkstring(L, 1); const char *fromcode = luaL_checkstring(L, 2); - iconv_t r = iconv_open(tocode, fromcode); + iconv_t *r = luxio__create_iconv(L); - if (r == (iconv_t)-1) { + *r = iconv_open(tocode, fromcode); + + if (*r == (iconv_t)-1) { lua_pushnumber(L, -1); lua_pushnumber(L, errno); return 2; - } else { - lua_pushlightuserdata(L, (void *)r); - return 1; } + + /* On the top of the stack is the iconv userdata */ + return 1; } /*** Close a previously-allocated iconv descriptor. @@ -3736,7 +3783,10 @@ luxio_iconv_open(lua_State *L) static int luxio_iconv_close(lua_State *L) { - iconv_t c = (iconv_t)lua_touserdata(L, 1); + iconv_t *_c = (iconv_t*)lua_touserdata(L, 1); + iconv_t c = *_c; + + *_c = NULL; if (iconv_close(c) == -1) { lua_pushnumber(L, -1); @@ -3763,7 +3813,8 @@ luxio_iconv(lua_State *L) { /* based on Alexandre Erwin Ittner <alexandre@ittner.com.br>'s code */ /* either returns completed string, or -1, errno, partial result */ - iconv_t cd = (iconv_t)lua_touserdata(L, 1); + iconv_t *_cd = (iconv_t*)lua_touserdata(L, 1); + iconv_t cd = *_cd; size_t ibleft; char *inbuf = (char* )luaL_checklstring(L, 2, &ibleft); char outbufs[ICONV_BUF_SIZE]; diff --git a/tests/test-iconv.lua b/tests/test-iconv.lua new file mode 100644 index 0000000..6a14ac1 --- /dev/null +++ b/tests/test-iconv.lua @@ -0,0 +1,5 @@ +luxio = require 'luxio' + +cd = luxio.iconv_open("UTF-8", "ISO-8859-1") +assert(luxio.iconv(cd, "\163") == "£") +luxio.iconv_close(cd) |