Onran aae642a13e
Streaming I/O and support of named pipes (#570)
* added streaming i/o for scripting, and a byteutil.get_size function

* added i/o stream class, also added named pipes support on lua side via ffi

* added constant file.named_pipes_prefix

* added buffered and yield modes for io_stream

* added new time function for work with UTC - utc_time, utc_offset, local_time

* docs updated

* constant pid moved to os.pid

* now gmtime_s and localtime_s used only in windows
2025-08-01 20:26:43 +03:00

104 lines
2.0 KiB
Lua

local path_validate = require "core:internal/stream_providers/named_pipe_path_validate"
local io_stream = require "core:io_stream"
local FFI = ffi
FFI.cdef[[
int open(const char *pathname, int flags);
int close(int fd);
ssize_t read(int fd, void *buf, size_t count);
ssize_t write(int fd, const void *buf, size_t count);
int fcntl(int fd, int cmd, ...);
const char *strerror(int errnum);
]]
local C = FFI.C
local O_RDONLY = 0x0
local O_WRONLY = 0x1
local O_RDWR = 0x2
local O_NONBLOCK = 0x800
local F_GETFL = 3
local function getError()
local err = ffi.errno()
return ffi.string(C.strerror(err)).." ("..err..")"
end
local lib = {}
function lib.read(fd, len)
local buffer = FFI.new("uint8_t[?]", len)
local result = C.read(fd, buffer, len)
local out = Bytearray()
if result <= 0 then
return out
end
for i = 0, result - 1 do
out[i+1] = buffer[i]
end
return out
end
function lib.write(fd, bytearray)
local len = #bytearray
local buffer = FFI.new("uint8_t[?]", len)
for i = 1, len do
buffer[i-1] = bytearray[i]
end
if C.write(fd, buffer, len) == -1 then
error("failed to write to named pipe: "..getError())
end
end
function lib.flush(fd)
-- no flush on unix
end
function lib.is_alive(fd)
if fd == nil or fd < 0 then return false end
return C.fcntl(fd, F_GETFL) ~= -1
end
function lib.close(fd)
C.close(fd)
end
return function(path, mode)
path_validate(path)
path = "/tmp/"..path
local read = mode:find('r') ~= nil
local write = mode:find('w') ~= nil
local flags
if read and write then
flags = O_RDWR
elseif read then
flags = O_RDONLY
elseif write then
flags = O_WRONLY
else
error "mode must contain read or write flag"
end
flags = bit.bor(flags, O_NONBLOCK)
local fd = C.open(path, flags)
if fd == -1 then
error("failed to open named pipe: "..getError())
end
return io_stream.new(fd, mode:find('b') ~= nil, lib)
end