inputor

Evdev remapping utility in lua
git clone https://git.neptards.moe/u3shit/inputor.git
Log | Files | Refs

posix_io.lua (2526B)


      1 local base = string.match(..., "(.-)[^%.]+%.[^%.]+$")
      2 local ffi = require("ffi")
      3 local e_assert = require(base.."helper.errno").assert
      4 
      5 local ffi_string = ffi.string
      6 
      7 ffi.cdef[[
      8 int open(const char* file, int oflag, ...);
      9 int open64(const char* file, int oflag, ...);
     10 
     11 ssize_t read(int fd, void* buf, size_t n);
     12 ssize_t write(int fd, const void* buf, size_t n);
     13 
     14 int close(int fd);
     15 
     16 struct pollfd
     17 {
     18   int fd;
     19   short int events;
     20   short int revents;
     21 };
     22 int poll(struct pollfd* fds, unsigned long int nfds, int timeout);
     23 
     24 // workaround for __gc not working for tables in lua 5.1/luajit
     25 struct posix_io_instance { int fd; };
     26 ]]
     27 
     28 local rdonly = 0
     29 local wronly = 1
     30 local rdwr   = 2
     31 
     32 local ffi_c = ffi.C
     33 local open_func = ffi_c.open
     34 pcall(function() open_func = ffi_c.open64 end)
     35 
     36 local mt = {}
     37 mt.__index = mt
     38 
     39 local char_ary = ffi.typeof("char[?]")
     40 function mt:read(n)
     41   local buf = char_ary(n)
     42   local res = ffi_c.read(self.fd, buf, n)
     43   e_assert("read", res >= 0, 2)
     44   return ffi_string(buf, res)
     45 end
     46 
     47 function mt:write(stuff, len)
     48   if not len then len = #stuff end
     49   local res = ffi_c.write(self.fd, stuff, len)
     50   e_assert("write", res == len, 2)
     51 end
     52 
     53 function mt:close()
     54   if self.fd < 0 then return end
     55   local res = ffi_c.close(self.fd)
     56   self.fd = -1
     57   e_assert("close", res == 0, 2)
     58 end
     59 mt.__gc = mt.close
     60 
     61 -- Very simple poll wrapper, not intended for real-life usage.
     62 local pollfds = ffi.typeof("struct pollfd[?]")
     63 local pollin = 1
     64 local function poll_read(fds, timeout_s)
     65   local arg = pollfds(#fds)
     66   for i,v in ipairs(fds) do
     67     local fd
     68     if type(v) == "number" then fd = v else fd = v.fd end
     69     arg[i-1].fd = fd
     70     arg[i-1].events = pollin
     71   end
     72 
     73   local timeout_ms
     74   if timeout_s then timeout_ms = timeout_s / 1000 else timeout_ms = -1 end
     75   local res = ffi_c.poll(arg, #fds, timeout_ms)
     76   if res == 0 then return end -- timeout
     77   e_assert("poll", res >= 0, 2)
     78 
     79   local ret = {}
     80   for i=0,#fds-1 do
     81     if arg[i].revents == pollin then
     82       ret[fds[i+1]] = true
     83     elseif arg[i].revents ~= 0 then
     84       error("Unhandled revent "..arg[i].revents.." on fd "..fds[i+1].fd)
     85     end
     86   end
     87   return ret
     88 end
     89 
     90 local ct = ffi.typeof("struct posix_io_instance")
     91 ffi.metatype(ct, mt)
     92 
     93 local function new(fname, flags)
     94   local fd = open_func(fname, flags or rdwr)
     95   e_assert("open", fd >= 0, 2)
     96   return ct({fd=fd})
     97 end
     98 mt.new = new
     99 
    100 local module = { rdonly=rdonly, wronly=wronly, rdwr=rdwr, new=new,
    101                  poll_read = poll_read }
    102 return setmetatable(module, {__call=function(_, ...) return new(...) end})