From 9482bca1c70c9d6f52b2755d513487a5b36b1ebb Mon Sep 17 00:00:00 2001 From: Emil Renner Berthing Date: Wed, 30 Jan 2013 11:39:32 +0100 Subject: io: add io.streamfile() --- lem/io.lua | 4 +- lem/io/core.c | 126 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ test/lines.lua | 24 ++++++++--- 3 files changed, 146 insertions(+), 8 deletions(-) diff --git a/lem/io.lua b/lem/io.lua index f123d1e..bd24d66 100644 --- a/lem/io.lua +++ b/lem/io.lua @@ -46,11 +46,11 @@ do return stdin:read(...) end - local open, error = io.open, error + local streamfile, error = io.streamfile, error function io.lines(filename, fmt) if not filename then return stdin:lines(fmt) end if not fmt then fmt = '*l' end - local file, err = open(filename) + local file, err = streamfile(filename) if not file then error(err, 2) end return function(s) local line = s:read(fmt) diff --git a/lem/io/core.c b/lem/io/core.c index b5fe4d6..d41c3d0 100644 --- a/lem/io/core.c +++ b/lem/io/core.c @@ -318,6 +318,128 @@ error: return io_strerror(T, err); } +/* + * io.streamfile() + */ +struct streamfile { + struct lem_async a; + const char *filename; + int pipe[2]; + int file; +}; + +static void +io_streamfile_work(struct lem_async *a) +{ + struct streamfile *s = (struct streamfile *)a; + int file = s->file; + int pipe = s->pipe[1]; + +#ifdef __FreeBSD__ + sendfile(file, pipe, 0, 0, NULL, NULL, SF_SYNC); +#else +#ifdef __APPLE__ + off_t len = 0; + sendfile(file, pipe, 0, &len, NULL, 0); +#else + while (sendfile(pipe, file, NULL, 2147483647) > 0); +#endif +#endif + close(file); + close(pipe); +} + +static void +io_streamfile_open(struct lem_async *a) +{ + struct streamfile *s = (struct streamfile *)a; + int file = open(s->filename, +#ifdef O_CLOEXEC + O_CLOEXEC | +#endif + O_RDONLY); + if (file < 0) { + s->file = -errno; + return; + } +#ifndef O_CLOEXEC + if (fcntl(file, F_SETFD, FD_CLOEXEC) == -1) { + s->file = -errno; + goto err1; + } +#endif + + if (socketpair(AF_UNIX, +#ifdef SOCK_CLOEXEC + SOCK_CLOEXEC | +#endif + SOCK_STREAM, 0, s->pipe)) { + s->file = -errno; + goto err1; + } + if ( +#ifndef SOCK_CLOEXEC + fcntl(s->pipe[1], F_SETFD, FD_CLOEXEC) == -1 || + fcntl(s->pipe[0], F_SETFD, FD_CLOEXEC) == -1 || +#endif + shutdown(s->pipe[0], SHUT_WR)) { + s->file = -errno; + goto err2; + } + if (fcntl(s->pipe[0], F_SETFL, O_NONBLOCK) == -1) { + s->file = -errno; + goto err2; + } + s->file = file; + return; +err2: + close(s->pipe[0]); + close(s->pipe[1]); +err1: + close(file); +} + +static void +io_streamfile_reap(struct lem_async *a) +{ + struct streamfile *s = (struct streamfile *)a; + lua_State *T = s->a.T; + int ret; + + if (T == NULL) { + free(s); + return; + } + + ret = s->file; + if (ret < 0) { + free(s); + lem_queue(T, io_strerror(T, -ret)); + return; + } + lem_debug("s->file = %d, s->pipe[0] = %d, s->pipe[1] = %d", + ret, s->pipe[0], s->pipe[1]); + + lem_async_do(&s->a, NULL, io_streamfile_work, io_streamfile_reap); + + stream_new(T, s->pipe[0], 2); + lem_queue(T, 1); +} + +static int +io_streamfile(lua_State *T) +{ + const char *filename = lua_tostring(T, 1); + struct streamfile *s = lem_xmalloc(sizeof(struct streamfile)); + + s->filename = filename; + lem_async_do(&s->a, T, io_streamfile_open, io_streamfile_reap); + + lua_settop(T, 1); + lua_pushvalue(T, lua_upvalueindex(1)); + return lua_yield(T, 2); +} + static void push_stdstream(lua_State *L, int fd) { @@ -455,6 +577,10 @@ luaopen_lem_io_core(lua_State *L) lua_getfield(L, -1, "Stream"); /* upvalue 1 = Stream */ lua_pushcclosure(L, io_popen, 1); lua_setfield(L, -2, "popen"); + /* insert streamfile function */ + lua_getfield(L, -1, "Stream"); /* upvalue 1 = Stream */ + lua_pushcclosure(L, io_streamfile, 1); + lua_setfield(L, -2, "streamfile"); /* create tcp table */ lua_createtable(L, 0, 0); diff --git a/test/lines.lua b/test/lines.lua index 2558184..001ff61 100755 --- a/test/lines.lua +++ b/test/lines.lua @@ -26,19 +26,31 @@ local io = require 'lem.io' local format, write = string.format, io.write local n = 0 + +if not arg[1] then + io.stderr:write("I need a file..\n") + utils.exit(1) +end + ---[[ -local file = assert(io.open('PKGBUILD')) +local file, err = io.streamfile(arg[1]) +--local file, err = io.open(arg[1]) + +if not file then + io.stderr:write(format("Error opening '%s': %s\n", arg[1], err)) + utils.exit(1) +end for line in file:lines() do n = n+1 - write(format("%4d: %s\n", n, line)) end --[=[ --]] -for line in io.lines('PKGBUILD') do - n = n+1 - write(format("%4d: %s\n", n, line)) +for line in io.lines(arg[1]) do + n = n+1 end --]=] --- vim: syntax=lua ts=3 sw=3 et: +write(format('%d lines\n', n)) + +-- vim: syntax=lua ts=2 sw=2 noet: -- cgit v1.2.1