From 6190d75c3793fa6fbf0440edc88e2edb5d99ace3 Mon Sep 17 00:00:00 2001 From: payonel Date: Tue, 12 Sep 2017 15:26:25 -0700 Subject: [PATCH 1/4] more cats improve cat io by directly feeding stream data to output and optimize more to not use line parsing --- .../opencomputers/loot/openos/bin/cat.lua | 2 +- .../opencomputers/loot/openos/bin/more.lua | 94 +++++++++---------- 2 files changed, 43 insertions(+), 53 deletions(-) diff --git a/src/main/resources/assets/opencomputers/loot/openos/bin/cat.lua b/src/main/resources/assets/opencomputers/loot/openos/bin/cat.lua index fafe5f0e9..fcaeb88e8 100644 --- a/src/main/resources/assets/opencomputers/loot/openos/bin/cat.lua +++ b/src/main/resources/assets/opencomputers/loot/openos/bin/cat.lua @@ -7,7 +7,7 @@ if #args == 0 then args = {"-"} end -local input_method, input_param = "read", 2048 +local input_method, input_param = "read", require("tty").window.width for i = 1, #args do local arg = shell.resolve(args[i]) diff --git a/src/main/resources/assets/opencomputers/loot/openos/bin/more.lua b/src/main/resources/assets/opencomputers/loot/openos/bin/more.lua index dfc3d55f6..687a5ed17 100644 --- a/src/main/resources/assets/opencomputers/loot/openos/bin/more.lua +++ b/src/main/resources/assets/opencomputers/loot/openos/bin/more.lua @@ -1,11 +1,7 @@ +local buffer = require("buffer") local keyboard = require("keyboard") local shell = require("shell") -local term = require("term") -- TODO use tty and cursor position instead of global area and gpu -local text = require("text") - -if not io.output().tty then - return loadfile(shell.resolve("cat", "lua"), "bt", _G)(...) -end +local tty = require("tty") local args = shell.parse(...) if #args > 1 then @@ -13,55 +9,49 @@ if #args > 1 then io.write("- or no args reads stdin\n") return 1 end -local arg = args[1] or "-" -local file, reason -if arg == "-" then - file, reason = io.stdin, "this process has no stdin" -else - file, reason = io.open(shell.resolve(arg)) -end -if not file then - io.stderr:write(reason,'\n') - return 1 + +local function clear_line() + tty.window.x = 1 -- move cursor to start of line + io.write("\27[2K") -- clear line end -local line = nil -local function readlines(num) - local _, _, w, h = term.getGlobalArea() - num = num or (h - 1) - for _ = 1, num do - if not line then - line = file:read("*l") - if not line then -- eof - return nil +if io.output().tty then + io.write("\27[2J\27[H") + + local intercept_active = true + local original_stream = io.stdout.stream + local custom_stream = setmetatable({ + scroll = function(...) + local _, height, _, _, _, y = tty.getViewport() + local lines_below = height - y + if intercept_active and lines_below < 1 then + intercept_active = false + original_stream.scroll(-lines_below) -- if zero no scroll action is made [good] + tty.setCursor(1, height) -- move to end + clear_line() + io.write(":") -- status + local _, _, _, code = original_stream:pull(nil, "key_down") -- nil timeout is math.huge + if code == keyboard.keys.q then + clear_line() + os.exit(1) -- abort + elseif code == keyboard.keys["end"] then + io.stdout.stream.scroll = nil -- remove handler + elseif code == keyboard.keys.space or code == keyboard.keys.pageDown then + io.write("\27[2J\27[H") -- clear whole screen, get new page drawn; move cursor to 1,1 + elseif code == keyboard.keys.enter or code == keyboard.keys.down then + clear_line() -- remove status bar + original_stream.scroll(1) -- move everything up one + tty.setCursor(1, height - 1) + end + intercept_active = true end + return original_stream.scroll(...) end - local wrapped - wrapped, line = text.wrap(text.detab(line), w, w) - io.write(wrapped,"\n") - end - term.setCursor(1, h) - term.write(":") - return true + }, {__index=original_stream}) + + local custom_output_buffer = buffer.new("w", custom_stream) + custom_output_buffer:setvbuf("no") + io.output(custom_output_buffer) end -while true do - term.clear() - if not readlines() then - return - end - while true do - local _, _, _, code = term.pull("key_down") - if code == keyboard.keys.q then - term.clearLine() - return - elseif code == keyboard.keys.space or code == keyboard.keys.pageDown then - break - elseif code == keyboard.keys.enter or code == keyboard.keys.down then - term.clearLine() - if not readlines(1) then - return - end - end - end -end +return loadfile(shell.resolve("cat", "lua"))(...) From 5c9760cf77abcd1750abdb7e92888af6e8203c50 Mon Sep 17 00:00:00 2001 From: payonel Date: Wed, 13 Sep 2017 10:46:17 -0700 Subject: [PATCH 2/4] thread code cleanup for clarity, no api change --- .../opencomputers/loot/openos/lib/thread.lua | 35 ++++++++++--------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/src/main/resources/assets/opencomputers/loot/openos/lib/thread.lua b/src/main/resources/assets/opencomputers/loot/openos/lib/thread.lua index 5c62cee07..2e155a423 100644 --- a/src/main/resources/assets/opencomputers/loot/openos/lib/thread.lua +++ b/src/main/resources/assets/opencomputers/loot/openos/lib/thread.lua @@ -60,17 +60,18 @@ function thread.waitForAll(threads, timeout) end local box_thread = {} -local box_thread_handle = {close = thread.waitForAll} +local box_thread_list = {close = thread.waitForAll} -local function get_box_thread_handle(handles, bCreate) +local function get_process_threads(proc, bCreate) + local handles = proc.data.handles for _,next_handle in ipairs(handles) do - local btm_mt = getmetatable(next_handle) - if btm_mt and btm_mt.__index == box_thread_handle then + local handle_mt = getmetatable(next_handle) + if handle_mt and handle_mt.__index == box_thread_list then return next_handle end end if bCreate then - local btm = setmetatable({}, {__index = box_thread_handle}) + local btm = setmetatable({}, {__index = box_thread_list}) table.insert(handles, btm) return btm end @@ -126,10 +127,10 @@ function box_thread:attach(parent) if mt.attached == proc then return self end -- already attached if mt.attached then - local prev_btHandle = assert(get_box_thread_handle(mt.attached.data.handles), "thread panic: no thread handle") - for i,h in ipairs(prev_btHandle) do - if h == self then - table.remove(prev_btHandle, i) + local prev_threads = assert(get_process_threads(mt.attached), "thread panic: no thread handle") + for index,t_in_list in ipairs(prev_threads) do + if t_in_list == self then + table.remove(prev_threads, index) break end end @@ -141,9 +142,9 @@ function box_thread:attach(parent) -- attach to parent or the current process mt.attached = proc - -- this process may not have a box_thread manager handle - local btHandle = get_box_thread_handle(proc.data.handles, true) - table.insert(btHandle, self) + -- this process may not have a box_thread list + local threads = get_process_threads(proc, true) + table.insert(threads, self) -- register on the new parent if waiting_handler then -- event-waiting @@ -158,7 +159,7 @@ function thread.current() local thread_root while proc do if thread_root then - for _,bt in ipairs(get_box_thread_handle(proc.data.handles) or {}) do + for _,bt in ipairs(get_process_threads(proc) or {}) do if bt.pco.root == thread_root then return bt end @@ -287,10 +288,10 @@ function thread.create(fp, ...) if t:status() == "dead" then return end - local htm = get_box_thread_handle(mt.attached.data.handles) - for _,ht in ipairs(htm) do - if ht == t then - table.remove(htm, _) + local threads = get_process_threads(mt.attached) + for index,t_in_list in ipairs(threads) do + if t_in_list == t then + table.remove(threads, index) break end end From 47c67a119ff1971276b4e8bee41f0cd631b05871 Mon Sep 17 00:00:00 2001 From: payonel Date: Sat, 16 Sep 2017 08:19:49 +0200 Subject: [PATCH 3/4] term fixes, scroll methods was moved --- .../assets/opencomputers/loot/openos/lib/term.lua | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/resources/assets/opencomputers/loot/openos/lib/term.lua b/src/main/resources/assets/opencomputers/loot/openos/lib/term.lua index 3dd0b3642..77e63253b 100644 --- a/src/main/resources/assets/opencomputers/loot/openos/lib/term.lua +++ b/src/main/resources/assets/opencomputers/loot/openos/lib/term.lua @@ -248,5 +248,12 @@ function term.bind(gpu, window) return as_window(window, tty.bind, gpu) end -return term +function term.scroll(...) + if io.stdout.tty then + return io.stdout.stream.scroll(...) + end +end +term.internal.run_in_window = as_window + +return term From 2abd8b3134bf578e42b064159d42430b87dd9352 Mon Sep 17 00:00:00 2001 From: payonel Date: Sat, 16 Sep 2017 08:40:48 +0200 Subject: [PATCH 4/4] closes #2507 /bin/less and /bin/more were able to lock up the system if they call string.gsub(string, function) on a very large string (~144k chars long). The machine layer intercepts expensive strings calls by checking the length of the string, but it does not intercept gsub calls when the replace action is a function The fix is to intercept all long string actions, not just non-function replacement gsub calls Note that /bin/more is now more efficient and doesn't call string.gsub, but this is still the right fix to keep the sandbox from being able to lock up the system with string methods --- src/main/resources/assets/opencomputers/lua/machine.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/assets/opencomputers/lua/machine.lua b/src/main/resources/assets/opencomputers/lua/machine.lua index cb0069831..06f07a70f 100644 --- a/src/main/resources/assets/opencomputers/lua/machine.lua +++ b/src/main/resources/assets/opencomputers/lua/machine.lua @@ -577,7 +577,7 @@ do checkArg(3, repl, "number", "string", "function", "table") checkArg(4, n, "number", "nil") - if #s < SHORT_STRING or type(repl) == "function" then + if #s < SHORT_STRING then return string_gsub(s, pattern, repl, n) end