diff --git a/data/luapackages/io.lua b/data/luapackages/io.lua index 6221d2d..0e17cb5 100644 --- a/data/luapackages/io.lua +++ b/data/luapackages/io.lua @@ -8,6 +8,9 @@ local io = {} local file = {} file.__index = file +-- readline buffer size +local bufsize = 512 + local function debugf(...) print("DEBUG:", table.unpack({...})) end @@ -18,6 +21,36 @@ local function not_impl(fnname) end end +local function readline(file, keepnewline) + local result = {} + local buf, baseseek, chr + local dobreak = false + while true do + baseseek = file:seek() + buf = file:read(bufsize) + -- returns nil if nothing was read + if not buf then break end + for i = 1, #buf do + chr = string.sub(buf, i, i) + if chr == '\n' then + table.insert(result, string.sub(buf, 1, i - 1)) + file:seek('set', baseseek + i) + if keepnewline then + table.insert(result, '\n') + end + dobreak = true + break + end + end + if dobreak then break end + table.insert(result, buf) + end + if #result == 0 then + return nil + end + return table.concat(result) +end + -- some errors should return nil, an error string, then an error number -- example: -- > io.open("/nix/abc.txt", "w") @@ -133,9 +166,16 @@ function file:read(...) self:_closed_check() if not self._readable then return file:_bad_desc() end local to_return = {} - for i, v in ipairs({...}) do - if v == "n" or v == "l" or v == "L" then + local args = {...} + if #args == 0 then + args = {"l"} + end + for i, v in ipairs(args) do + if v == "n" then error('mode "'..v..'" is not implemented') + elseif v == "l" or v == "L" then + -- "L" will keep the newline, if present + return readline(self, v == "L") elseif v == "a" then local btr = self._size - self._seek local data = fs.read_file(self._filename, self._seek, btr) @@ -154,6 +194,19 @@ function file:read(...) return table.unpack(to_return) end +function file:lines(...) + local args = {...} + if #args == 0 then + args = {"l"} + end + + local function generator() + return self:read(table.unpack(args)) + end + + return generator +end + function file:seek(whence, offset) if whence == nil then whence = "cur" @@ -198,7 +251,6 @@ function file:write(...) return self end -file.lines = not_impl("file:lines") file.setvbuf = not_impl("file:setvbuf") function io.open(filename, mode) diff --git a/resources/lua-doc.md b/resources/lua-doc.md index 1ce7ef8..c59df4b 100644 --- a/resources/lua-doc.md +++ b/resources/lua-doc.md @@ -139,7 +139,7 @@ These modules are partially available: * [os](https://www.lua.org/manual/5.4/manual.html#6.9) * Only `os.clock`, `os.time`, `os.date`, `os.difftime`, and `os.remove` * [io](https://www.lua.org/manual/5.4/manual.html#6.8) - * Only `io.open`; for open files, all but `file:setvbuf` and `file:lines` + * Only `io.open`; for open files, all but `file:setvbuf` * This is a custom compatibility module that uses `fs` functions. If there are differences compared to the original `io` implementation, please report them as issues. These modules work differently: