summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEmil Renner Berthing <esmil@mailme.dk>2013-01-30 11:39:32 +0100
committerEmil Renner Berthing <esmil@mailme.dk>2013-01-30 22:11:14 +0100
commit9482bca1c70c9d6f52b2755d513487a5b36b1ebb (patch)
tree5588d0d55fb8762257f24691ba0aa014a01baf46
parent501d84381c8603e5680b86d65afeb633279116f9 (diff)
downloadlem-9482bca1c70c9d6f52b2755d513487a5b36b1ebb.tar.gz
lem-9482bca1c70c9d6f52b2755d513487a5b36b1ebb.tar.xz
lem-9482bca1c70c9d6f52b2755d513487a5b36b1ebb.zip
io: add io.streamfile()
-rw-r--r--lem/io.lua4
-rw-r--r--lem/io/core.c126
-rwxr-xr-xtest/lines.lua24
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: