brimworks / lua-ev

Lua integration with libev.
MIT License
225 stars 55 forks source link

Interoperability with lua file objects #5

Open daurnimator opened 13 years ago

daurnimator commented 13 years ago

Could you add a way to use normal lua file descriptors? See: http://www.lua.org/source/5.1/liolib.c.html#getiofile

For usabilitiy; it might be nice if there was a tolibevio(x) funtion that would take a lua file object, socket object or other io types and convert them to an io object for libev.

brimworks commented 13 years ago

This sounds like a neat idea. Do you want to try implementing this in a fork?

daurnimator commented 13 years ago

I'm rather compiler-poor at the moment; but I can point you to the code at https://github.com/rrthomas/luaposix/blob/master/lposix.c#L583 this will transform a lua file object into a fd for you.

Otherwise for sockets, as you know you have getfd.

So, as a C function, I'd check if the metatable is the file metatable; if so use the above routine; otherwise just try and call the getfd method..... Other libraries can then be made to work by adding getfd functions to their methods.

blitmap commented 11 years ago

On Linux you use fileno() to fetch the fd from the FILE* within the lua_Stream (Lua's file handle type). On Windows you use _fileno() :-)

So it would involve a function like this:

static int
standard_error(lua_State * L, int err, char * (*errfunc)(int), char * fname)
{
    char * msg = errfunc(err);

    lua_pushnil(L);

    if (NULL == fname)
        lua_pushstring(L, msg);
    else
        lua_pushfstring(L, "%s: %s", fname, msg);

    lua_pushinteger(L, err);

    return 3;
}

static int
file_to_fd(lua_State * L, FILE * stream)
{
    int fd = -1;

#ifdef _WIN32
    fd = _fileno(stream);
#else
    fd = fileno(stream);
#endif

    if (-1 == fd)
#ifdef _WIN32
        return standard_error(L, fd, &str_error, "_fileno()");
#else
        return standard_error(L, fd, &str_error, "fileno()");
#endif

    return fd;
}

First you would:

luaL_testudata(L, index, LUA_FILEHANDLE)

If the result is non-NULL you pass that pointer to file_to_fd(), if not, you treat the first arg as an immediate fd in lua_Number form. ;-) file_to_fd() would be called by io_new() in io_lua_ev.c

Maybe I'll work on this at the weekend...\

PS: Yes standard_error() is a bit over-engineered but in another project I swap out str_error() with gai_error() sometimes. :>

Trendyne commented 2 years ago

What worked for me. Adapt it to win32 like Blitmap does if you need that

typedef struct myluaL_Stream {
    FILE *f;
    lua_CFunction closef;
} myluaL_Stream;

//* int fd getFD(file file) Returns the file descriptor associated with a Lua file
static int l_getFD(lua_State* L){
    lua_pushinteger(L, fileno(((myluaL_Stream*)luaL_checkudata(L, 1, "FILE*"))->f));
    return 1;
}

I had to copy the struct because it wasn't public in 5.1 but still works with the latest revisions of Lua 5.1 and/or LuaJIT and doesn't change in future versions. https://www.lua.org/source/5.2/lauxlib.h.html#luaL_Stream https://www.lua.org/source/5.3/lauxlib.h.html#luaL_Stream https://www.lua.org/source/5.4/lauxlib.h.html#luaL_Stream

Since it's the first member it is also possible to do something like

    FILE** file = luaL_checkudata(L, 1, "FILE*");
    lua_pushinteger(L, fileno(*file));

But doesn't really gain you anything and makes it harder to get what's actually going on, IMHO