From 8a258a2fcb48308f7aa3f1f864aee12e91e1ce3b Mon Sep 17 00:00:00 2001 From: Saikari Date: Mon, 26 Jan 2026 23:32:31 +0300 Subject: enhance shell detection for Linux by checking parent process --- xmake/core/base/tty.lua | 75 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-) diff --git a/xmake/core/base/tty.lua b/xmake/core/base/tty.lua index dd053b3e6..a605a4a9e 100644 --- a/xmake/core/base/tty.lua +++ b/xmake/core/base/tty.lua @@ -23,6 +23,7 @@ local tty = tty or {} -- load modules local io = require("base/io") +local path = require("base/path") -- save metatable and builtin functions tty._term_mode = tty._term_mode or tty.term_mode @@ -256,13 +257,85 @@ function tty.shell() end end end + -- try to find the shell from the parent process (linux) + if not shell and os.host() == "linux" and os.isfile("/proc/self/stat") then + local pid = os.getpid() + for i = 1, 10 do + local stat = io.readfile("/proc/" .. pid .. "/stat") + if not stat or #stat == 0 then + local tmpfile = path.join(os.tmpdir(), "xmake_stat_" .. os.getpid()) + os.execv("cp", {"/proc/" .. pid .. "/stat", tmpfile}) + stat = io.readfile(tmpfile) + os.rm(tmpfile) + end + + -- find last ')' to handle "pid (comm) state ppid" + local start = stat and stat:find(")", 1, true) + while start do + local next_p = stat:find(")", start + 1, true) + if not next_p then break end + start = next_p + end + + if start then + local suffix = stat:sub(start + 1) + local fields = {} + for field in suffix:gmatch("%S+") do + table.insert(fields, field) + if #fields >= 2 then break end + end + + local ppid = tonumber(fields[2]) + if not ppid or ppid == 0 then break end + + local shell_name = nil + local shell_path = nil + if os.isfile("/proc/" .. ppid .. "/exe") then + local ok, link = pcall(os.readlink, "/proc/" .. ppid .. "/exe") + if ok and link then + shell_path = link + end + end + if not shell_path and os.isfile("/proc/" .. ppid .. "/comm") then + shell_name = io.readfile("/proc/" .. ppid .. "/comm") + if not shell_name or #shell_name == 0 then + local tmpfile = path.join(os.tmpdir(), "xmake_comm_" .. os.getpid()) + os.execv("cp", {"/proc/" .. ppid .. "/comm", tmpfile}) + shell_name = io.readfile(tmpfile) + os.rm(tmpfile) + end + if shell_name then + shell_name = shell_name:match("^%s*(.-)%s*$") + end + end + if shell_path then + shell_name = path.filename(shell_path) + end + + if shell_name then + shell_name = shell_name:gsub("^-", "") + for _, name in ipairs({"zsh", "bash", "fish", "nu", "elvish", "sh"}) do + if shell_name == name then + shell = name + break + end + end + if shell then break end + end + pid = ppid + else + break + end + end + end + if not shell then shell = os.getenv("XMAKE_SHELL") end if not shell then shell = os.getenv("SHELL") if shell then - for _, shellname in ipairs({"zsh", "bash", "sh"}) do + for _, shellname in ipairs({"zsh", "bash", "fish", "nu", "elvish", "sh"}) do if shell:find(shellname) then shell = shellname break -- cgit v1.3.1 From 8855fb1173ed118bda8e75ccd75c1b0db26bdcf7 Mon Sep 17 00:00:00 2001 From: Saikari Date: Tue, 27 Jan 2026 00:19:16 +0300 Subject: add support for Alacritty terminal in tty.term function --- xmake/core/base/tty.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/xmake/core/base/tty.lua b/xmake/core/base/tty.lua index a605a4a9e..39c4c0d31 100644 --- a/xmake/core/base/tty.lua +++ b/xmake/core/base/tty.lua @@ -396,6 +396,8 @@ function tty.term() term = "xterm" elseif TERM == "cygwin" then term = "cygwin" + elseif TERM:find("alacritty", 1, true) then + term = "alacritty" end end end -- cgit v1.3.1 From 14b0f24fc76004d1498fa7f85a6c2377b2fbd722 Mon Sep 17 00:00:00 2001 From: Saikari Date: Tue, 27 Jan 2026 00:44:11 +0300 Subject: add support for PowerShell in shell detection --- xmake/core/base/tty.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xmake/core/base/tty.lua b/xmake/core/base/tty.lua index 39c4c0d31..51c301ab4 100644 --- a/xmake/core/base/tty.lua +++ b/xmake/core/base/tty.lua @@ -314,7 +314,7 @@ function tty.shell() if shell_name then shell_name = shell_name:gsub("^-", "") - for _, name in ipairs({"zsh", "bash", "fish", "nu", "elvish", "sh"}) do + for _, name in ipairs({"zsh", "bash", "fish", "nu", "elvish", "pwsh", "sh"}) do if shell_name == name then shell = name break @@ -335,7 +335,7 @@ function tty.shell() if not shell then shell = os.getenv("SHELL") if shell then - for _, shellname in ipairs({"zsh", "bash", "fish", "nu", "elvish", "sh"}) do + for _, shellname in ipairs({"zsh", "bash", "fish", "nu", "elvish", "pwsh", "sh"}) do if shell:find(shellname) then shell = shellname break -- cgit v1.3.1 From 6e6cf755b207fe128e6e8a534d3df15f56d9c8a4 Mon Sep 17 00:00:00 2001 From: Saikari Date: Tue, 27 Jan 2026 05:45:37 +0300 Subject: refactor tty.shell to use os.tmpfile and os.runv for improved file handling --- xmake/core/base/tty.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/xmake/core/base/tty.lua b/xmake/core/base/tty.lua index 51c301ab4..27788419b 100644 --- a/xmake/core/base/tty.lua +++ b/xmake/core/base/tty.lua @@ -263,8 +263,8 @@ function tty.shell() for i = 1, 10 do local stat = io.readfile("/proc/" .. pid .. "/stat") if not stat or #stat == 0 then - local tmpfile = path.join(os.tmpdir(), "xmake_stat_" .. os.getpid()) - os.execv("cp", {"/proc/" .. pid .. "/stat", tmpfile}) + local tmpfile = os.tmpfile() + os.runv("cp", {"/proc/" .. pid .. "/stat", tmpfile}) stat = io.readfile(tmpfile) os.rm(tmpfile) end @@ -299,8 +299,8 @@ function tty.shell() if not shell_path and os.isfile("/proc/" .. ppid .. "/comm") then shell_name = io.readfile("/proc/" .. ppid .. "/comm") if not shell_name or #shell_name == 0 then - local tmpfile = path.join(os.tmpdir(), "xmake_comm_" .. os.getpid()) - os.execv("cp", {"/proc/" .. ppid .. "/comm", tmpfile}) + local tmpfile = os.tmpfile() + os.runv("cp", {"/proc/" .. ppid .. "/comm", tmpfile}) shell_name = io.readfile(tmpfile) os.rm(tmpfile) end -- cgit v1.3.1 From 41e460c869c15699d63f39e4fe433d88225818dc Mon Sep 17 00:00:00 2001 From: Saikari Date: Tue, 27 Jan 2026 05:54:28 +0300 Subject: add function to find shell from parent process in Linux --- xmake/core/base/tty.lua | 149 ++++++++++++++++++++++++++---------------------- 1 file changed, 80 insertions(+), 69 deletions(-) diff --git a/xmake/core/base/tty.lua b/xmake/core/base/tty.lua index 27788419b..788327d20 100644 --- a/xmake/core/base/tty.lua +++ b/xmake/core/base/tty.lua @@ -235,6 +235,84 @@ function tty.flush() return tty end +-- find the shell from the parent process (linux) +function tty._find_shell_from_parent() + if os.host() ~= "linux" or not os.isfile("/proc/self/stat") then + return + end + + local shell + local pid = os.getpid() + for i = 1, 10 do + local stat = io.readfile("/proc/" .. pid .. "/stat") + if not stat or #stat == 0 then + local tmpfile = os.tmpfile() + os.runv("cp", {"/proc/" .. pid .. "/stat", tmpfile}) + stat = io.readfile(tmpfile) + os.rm(tmpfile) + end + + -- find last ')' to handle "pid (comm) state ppid" + local start = stat and stat:find(")", 1, true) + while start do + local next_p = stat:find(")", start + 1, true) + if not next_p then break end + start = next_p + end + + if start then + local suffix = stat:sub(start + 1) + local fields = {} + for field in suffix:gmatch("%S+") do + table.insert(fields, field) + if #fields >= 2 then break end + end + + local ppid = tonumber(fields[2]) + if not ppid or ppid == 0 then break end + + local shell_name = nil + local shell_path = nil + if os.isfile("/proc/" .. ppid .. "/exe") then + local ok, link = pcall(os.readlink, "/proc/" .. ppid .. "/exe") + if ok and link then + shell_path = link + end + end + if not shell_path and os.isfile("/proc/" .. ppid .. "/comm") then + shell_name = io.readfile("/proc/" .. ppid .. "/comm") + if not shell_name or #shell_name == 0 then + local tmpfile = os.tmpfile() + os.runv("cp", {"/proc/" .. ppid .. "/comm", tmpfile}) + shell_name = io.readfile(tmpfile) + os.rm(tmpfile) + end + if shell_name then + shell_name = shell_name:match("^%s*(.-)%s*$") + end + end + if shell_path then + shell_name = path.filename(shell_path) + end + + if shell_name then + shell_name = shell_name:gsub("^-", "") + for _, name in ipairs({"zsh", "bash", "fish", "nu", "elvish", "pwsh", "sh"}) do + if shell_name == name then + shell = name + break + end + end + if shell then break end + end + pid = ppid + else + break + end + end + return shell +end + -- get shell name function tty.shell() local shell = tty._SHELL @@ -258,75 +336,8 @@ function tty.shell() end end -- try to find the shell from the parent process (linux) - if not shell and os.host() == "linux" and os.isfile("/proc/self/stat") then - local pid = os.getpid() - for i = 1, 10 do - local stat = io.readfile("/proc/" .. pid .. "/stat") - if not stat or #stat == 0 then - local tmpfile = os.tmpfile() - os.runv("cp", {"/proc/" .. pid .. "/stat", tmpfile}) - stat = io.readfile(tmpfile) - os.rm(tmpfile) - end - - -- find last ')' to handle "pid (comm) state ppid" - local start = stat and stat:find(")", 1, true) - while start do - local next_p = stat:find(")", start + 1, true) - if not next_p then break end - start = next_p - end - - if start then - local suffix = stat:sub(start + 1) - local fields = {} - for field in suffix:gmatch("%S+") do - table.insert(fields, field) - if #fields >= 2 then break end - end - - local ppid = tonumber(fields[2]) - if not ppid or ppid == 0 then break end - - local shell_name = nil - local shell_path = nil - if os.isfile("/proc/" .. ppid .. "/exe") then - local ok, link = pcall(os.readlink, "/proc/" .. ppid .. "/exe") - if ok and link then - shell_path = link - end - end - if not shell_path and os.isfile("/proc/" .. ppid .. "/comm") then - shell_name = io.readfile("/proc/" .. ppid .. "/comm") - if not shell_name or #shell_name == 0 then - local tmpfile = os.tmpfile() - os.runv("cp", {"/proc/" .. ppid .. "/comm", tmpfile}) - shell_name = io.readfile(tmpfile) - os.rm(tmpfile) - end - if shell_name then - shell_name = shell_name:match("^%s*(.-)%s*$") - end - end - if shell_path then - shell_name = path.filename(shell_path) - end - - if shell_name then - shell_name = shell_name:gsub("^-", "") - for _, name in ipairs({"zsh", "bash", "fish", "nu", "elvish", "pwsh", "sh"}) do - if shell_name == name then - shell = name - break - end - end - if shell then break end - end - pid = ppid - else - break - end - end + if not shell then + shell = tty._find_shell_from_parent() end if not shell then -- cgit v1.3.1 From 666f5c5b7f29beb474b1c12726f8dd39cd1babe9 Mon Sep 17 00:00:00 2001 From: Saikari Date: Tue, 27 Jan 2026 06:04:17 +0300 Subject: refactor _find_shell_from_parent function to simplify error handling for shell path retrieval --- xmake/core/base/tty.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xmake/core/base/tty.lua b/xmake/core/base/tty.lua index 788327d20..5c7f360c2 100644 --- a/xmake/core/base/tty.lua +++ b/xmake/core/base/tty.lua @@ -274,8 +274,8 @@ function tty._find_shell_from_parent() local shell_name = nil local shell_path = nil if os.isfile("/proc/" .. ppid .. "/exe") then - local ok, link = pcall(os.readlink, "/proc/" .. ppid .. "/exe") - if ok and link then + local link = os.readlink("/proc/" .. ppid .. "/exe") + if link then shell_path = link end end -- cgit v1.3.1 From b6578fbe40e03b075c9581895d55d256c0c4205b Mon Sep 17 00:00:00 2001 From: Saikari Date: Tue, 27 Jan 2026 12:17:41 +0300 Subject: refactor _find_shell_from_parent function for improved shell detection and error handling --- xmake/core/base/tty.lua | 96 ++++++++++++++++++++----------------------------- 1 file changed, 38 insertions(+), 58 deletions(-) diff --git a/xmake/core/base/tty.lua b/xmake/core/base/tty.lua index 5c7f360c2..9f339e4f4 100644 --- a/xmake/core/base/tty.lua +++ b/xmake/core/base/tty.lua @@ -243,73 +243,53 @@ function tty._find_shell_from_parent() local shell local pid = os.getpid() - for i = 1, 10 do - local stat = io.readfile("/proc/" .. pid .. "/stat") - if not stat or #stat == 0 then - local tmpfile = os.tmpfile() - os.runv("cp", {"/proc/" .. pid .. "/stat", tmpfile}) - stat = io.readfile(tmpfile) - os.rm(tmpfile) + local tmpfile = os.tmpfile() + while pid ~= 0 do + local shell_name = nil + local shell_path = nil + if os.isfile("/proc/" .. pid .. "/exe") then + local link = os.readlink("/proc/" .. pid .. "/exe") + if link then + shell_path = link + end end - -- find last ')' to handle "pid (comm) state ppid" - local start = stat and stat:find(")", 1, true) - while start do - local next_p = stat:find(")", start + 1, true) - if not next_p then break end - start = next_p + if not shell_path and os.isfile("/proc/" .. pid .. "/comm") then + shell_name = io.readfile("/proc/" .. pid .. "/comm") + if not shell_name or #shell_name == 0 then + os.runv("cp", {"/proc/" .. pid .. "/comm", tmpfile}) + shell_name = io.readfile(tmpfile) + end + if shell_name then + shell_name = shell_name:match("^%s*(.-)%s*$") + end + end + if shell_path then + shell_name = path.filename(shell_path) end - if start then - local suffix = stat:sub(start + 1) - local fields = {} - for field in suffix:gmatch("%S+") do - table.insert(fields, field) - if #fields >= 2 then break end - end - - local ppid = tonumber(fields[2]) - if not ppid or ppid == 0 then break end - - local shell_name = nil - local shell_path = nil - if os.isfile("/proc/" .. ppid .. "/exe") then - local link = os.readlink("/proc/" .. ppid .. "/exe") - if link then - shell_path = link - end - end - if not shell_path and os.isfile("/proc/" .. ppid .. "/comm") then - shell_name = io.readfile("/proc/" .. ppid .. "/comm") - if not shell_name or #shell_name == 0 then - local tmpfile = os.tmpfile() - os.runv("cp", {"/proc/" .. ppid .. "/comm", tmpfile}) - shell_name = io.readfile(tmpfile) - os.rm(tmpfile) - end - if shell_name then - shell_name = shell_name:match("^%s*(.-)%s*$") + if shell_name then + shell_name = shell_name:gsub("^-", "") + for _, name in ipairs({"zsh", "bash", "fish", "nu", "elvish", "pwsh", "sh"}) do + if shell_name == name then + shell = name + break end end - if shell_path then - shell_name = path.filename(shell_path) - end + if shell then break end + end - if shell_name then - shell_name = shell_name:gsub("^-", "") - for _, name in ipairs({"zsh", "bash", "fish", "nu", "elvish", "pwsh", "sh"}) do - if shell_name == name then - shell = name - break - end - end - if shell then break end - end - pid = ppid - else - break + local stat = io.readfile("/proc/" .. pid .. "/stat") + if not stat or #stat == 0 then + os.runv("cp", {"/proc/" .. pid .. "/stat", tmpfile}) + stat = io.readfile(tmpfile) end + + local ppid = stat and tonumber(stat:match(".*%) %S+ (%d+)")) + if not ppid or ppid == 0 then break end + pid = ppid end + os.rm(tmpfile) return shell end -- cgit v1.3.1 From 93b10aae53d6a3fc751894695161b8b472525a4b Mon Sep 17 00:00:00 2001 From: Saikari Date: Tue, 27 Jan 2026 12:35:58 +0300 Subject: limit shell detection loop to prevent infinite iterations --- xmake/core/base/tty.lua | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/xmake/core/base/tty.lua b/xmake/core/base/tty.lua index 9f339e4f4..a162e6341 100644 --- a/xmake/core/base/tty.lua +++ b/xmake/core/base/tty.lua @@ -244,7 +244,10 @@ function tty._find_shell_from_parent() local shell local pid = os.getpid() local tmpfile = os.tmpfile() - while pid ~= 0 do + local count = 0 + while pid ~= 0 and count < 10 do + count = count + 1 + print(count) local shell_name = nil local shell_path = nil if os.isfile("/proc/" .. pid .. "/exe") then -- cgit v1.3.1 From 33ec7a0a2ea8b21b8c896e828ecb80b6da6398d1 Mon Sep 17 00:00:00 2001 From: Saikari Date: Tue, 27 Jan 2026 12:36:23 +0300 Subject: remove debug print statement from _find_shell_from_parent function --- xmake/core/base/tty.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/xmake/core/base/tty.lua b/xmake/core/base/tty.lua index a162e6341..1976a8bb2 100644 --- a/xmake/core/base/tty.lua +++ b/xmake/core/base/tty.lua @@ -247,7 +247,6 @@ function tty._find_shell_from_parent() local count = 0 while pid ~= 0 and count < 10 do count = count + 1 - print(count) local shell_name = nil local shell_path = nil if os.isfile("/proc/" .. pid .. "/exe") then -- cgit v1.3.1 From 9914c5cb87077a289f2ec32e360762e91a4378e4 Mon Sep 17 00:00:00 2001 From: Saikari Date: Tue, 27 Jan 2026 12:39:49 +0300 Subject: limit shell detection loop to prevent excessive iterations --- xmake/core/base/tty.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xmake/core/base/tty.lua b/xmake/core/base/tty.lua index 1976a8bb2..0144795f9 100644 --- a/xmake/core/base/tty.lua +++ b/xmake/core/base/tty.lua @@ -245,7 +245,7 @@ function tty._find_shell_from_parent() local pid = os.getpid() local tmpfile = os.tmpfile() local count = 0 - while pid ~= 0 and count < 10 do + while pid ~= 0 and count < 4 do count = count + 1 local shell_name = nil local shell_path = nil -- cgit v1.3.1 From fe562739ac876196e39cab1dfadaf89294bbc7c6 Mon Sep 17 00:00:00 2001 From: ruki Date: Wed, 28 Jan 2026 22:49:21 +0800 Subject: fix io.read to read /proc files --- core/src/xmake/io/file_read.c | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/core/src/xmake/io/file_read.c b/core/src/xmake/io/file_read.c index 6b7e560ce..b9be64e10 100644 --- a/core/src/xmake/io/file_read.c +++ b/core/src/xmake/io/file_read.c @@ -43,6 +43,27 @@ typedef enum __xm_pushline_state_e { /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ +static tb_bool_t xm_io_file_stream_skip_sequential(tb_stream_ref_t stream, tb_hize_t size) { + tb_byte_t discard[TB_STREAM_BLOCK_MAXN]; + tb_hize_t left = size; + while (left) { + tb_size_t need = left > (tb_hize_t)sizeof(discard) ? (tb_size_t)sizeof(discard) : (tb_size_t)left; + tb_long_t read = tb_stream_read(stream, discard, need); + if (read != (tb_long_t)need) { + return tb_false; + } + left -= need; + } + return tb_true; +} + +static tb_bool_t xm_io_file_stream_skip(tb_stream_ref_t stream, tb_hize_t size, tb_bool_t sequential) { + if (sequential) { + return xm_io_file_stream_skip_sequential(stream, size); + } + return tb_stream_skip(stream, size); +} + static tb_long_t xm_io_file_buffer_readline(tb_stream_ref_t stream, tb_buffer_ref_t line) { tb_assert_and_check_return_val(stream && line, -1); @@ -51,20 +72,21 @@ static tb_long_t xm_io_file_buffer_readline(tb_stream_ref_t stream, tb_buffer_re tb_hize_t offset = 0; tb_byte_t *data = tb_null; tb_hong_t size = tb_stream_size(stream); - while (size < 0 || (offset = tb_stream_offset(stream)) < size) { + tb_bool_t sequential_consume = (size == 0); + while (sequential_consume || (offset = tb_stream_offset(stream)) < size) { tb_long_t real = tb_stream_peek(stream, &data, XM_IO_BLOCK_MAXN); if (real > 0) { tb_char_t const *e = tb_strnchr((tb_char_t const *)data, real, '\n'); if (e) { tb_size_t n = (tb_byte_t const *)e + 1 - data; - if (!tb_stream_skip(stream, n)) - return -1; tb_buffer_memncat(line, data, n); + if (!xm_io_file_stream_skip(stream, n, sequential_consume)) + return -1; break; } else { - if (!tb_stream_skip(stream, real)) - return -1; tb_buffer_memncat(line, data, real); + if (!xm_io_file_stream_skip(stream, (tb_hize_t)real, sequential_consume)) + return -1; } } else if (!real) { real = tb_stream_wait(stream, TB_STREAM_WAIT_READ, -1); @@ -184,7 +206,10 @@ static tb_int_t xm_io_file_read_all_directly(lua_State *lua, xm_io_file_t *file) // read all tb_stream_ref_t stream = file->u.file_ref; - while (!tb_stream_beof(stream)) { + tb_hize_t offset = 0; + tb_hong_t size = tb_stream_size(stream); + tb_bool_t sequential_consume = (size == 0); + while (sequential_consume || (offset = tb_stream_offset(stream)) < size) { tb_long_t real = tb_stream_read(stream, data, XM_IO_BLOCK_MAXN); if (real > 0) { tb_buffer_memncat(&buf, data, real); -- cgit v1.3.1 From 58be018b11ea325940c8e63aa130d04bd972ef45 Mon Sep 17 00:00:00 2001 From: ruki Date: Wed, 28 Jan 2026 22:50:25 +0800 Subject: test read /proc --- tests/modules/io/test.lua | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/modules/io/test.lua b/tests/modules/io/test.lua index 2b8bad8bf..a87151e32 100644 --- a/tests/modules/io/test.lua +++ b/tests/modules/io/test.lua @@ -160,3 +160,17 @@ function test_convert(t) os.tryrm("temp") end + +function test_read_proc_cpuinfo(t) + if not is_host("linux") then + return t:skip("wrong host platform") + end + if not os.isfile("/proc/cpuinfo") then + return t:skip("missing /proc/cpuinfo") + end + local data = io.readfile("/proc/cpuinfo", {encoding = "binary"}) + t:require(data and #data > 0) + + local data2 = io.readfile("/proc/cpuinfo") + t:require(data2 and #data2 > 0) +end -- cgit v1.3.1 From 190df86ff49ed5cf80069ad8ccd34be11d2d948c Mon Sep 17 00:00:00 2001 From: ruki Date: Wed, 28 Jan 2026 22:56:40 +0800 Subject: optimize to read all --- core/src/xmake/io/file_read.c | 146 +++++++++++++++++++++++++++++++++++------- 1 file changed, 124 insertions(+), 22 deletions(-) diff --git a/core/src/xmake/io/file_read.c b/core/src/xmake/io/file_read.c index b9be64e10..e38f7bd0d 100644 --- a/core/src/xmake/io/file_read.c +++ b/core/src/xmake/io/file_read.c @@ -229,6 +229,57 @@ static tb_int_t xm_io_file_read_all_directly(lua_State *lua, xm_io_file_t *file) tb_buffer_exit(&buf); return 1; } + +static tb_bool_t xm_io_file_read_all_to_buffer(xm_io_file_t *file, tb_buffer_ref_t buf) { + tb_assert(file && xm_io_file_is_file(file) && file->u.file_ref && buf); + + tb_byte_t *data = tb_buffer_resize(&file->rcache, XM_IO_BLOCK_MAXN); + tb_assert_and_check_return_val(data, tb_false); + + tb_stream_ref_t stream = file->u.file_ref; + tb_hize_t offset = 0; + tb_hong_t size = tb_stream_size(stream); + tb_bool_t sequential_consume = (size == 0); + while (sequential_consume || (offset = tb_stream_offset(stream)) < size) { + tb_long_t real = tb_stream_read(stream, data, XM_IO_BLOCK_MAXN); + if (real > 0) { + tb_buffer_memncat(buf, data, real); + } else if (!real) { + real = tb_stream_wait(stream, TB_STREAM_WAIT_READ, -1); + tb_check_break(real > 0); + } else { + break; + } + } + return tb_true; +} + +static tb_int_t xm_io_file_read_all_with_continuation(lua_State *lua, xm_io_file_t *file, tb_char_t const *continuation) { + tb_assert(lua && file && continuation && xm_io_file_is_file(file) && file->u.file_ref); + + tb_buffer_t buf; + if (!tb_buffer_init(&buf)) { + xm_io_return_error(lua, "init buffer failed!"); + } + while (1) { + tb_int_t state = xm_io_file_buffer_pushline(&buf, file, continuation, tb_true); + if (state == PL_EOF) { + break; + } + if (state == PL_FAIL) { + tb_buffer_exit(&buf); + xm_io_return_error(lua, "failed to readall"); + } + } + if (tb_buffer_size(&buf)) { + lua_pushlstring(lua, (tb_char_t const *)tb_buffer_data(&buf), tb_buffer_size(&buf)); + } else { + lua_pushliteral(lua, ""); + } + tb_buffer_exit(&buf); + return 1; +} + static tb_int_t xm_io_file_read_all(lua_State *lua, xm_io_file_t *file, tb_char_t const *continuation) { tb_assert(lua && file && continuation && xm_io_file_is_file(file) && file->u.file_ref); @@ -238,35 +289,86 @@ static tb_int_t xm_io_file_read_all(lua_State *lua, xm_io_file_t *file, tb_char_ return xm_io_file_read_all_directly(lua, file); } - // init buffer - tb_buffer_t buf; - if (!tb_buffer_init(&buf)) { - xm_io_return_error(lua, "init buffer failed!"); + if (*continuation != '\0') { + return xm_io_file_read_all_with_continuation(lua, file, continuation); } - // read all - tb_bool_t has_content = tb_false; - while (1) { - switch (xm_io_file_buffer_pushline(&buf, file, continuation, tb_true)) { - case PL_EOF: - if (!has_content) { - lua_pushliteral(lua, ""); + tb_buffer_t raw; + tb_buffer_t out; + tb_bool_t raw_ok = tb_false; + tb_bool_t out_ok = tb_false; + tb_int_t result = 0; + tb_char_t const *errors = tb_null; + do { + if (!tb_buffer_init(&raw)) { + errors = "init buffer failed!"; + result = 2; + break; + } + raw_ok = tb_true; + + if (!xm_io_file_read_all_to_buffer(file, &raw)) { + errors = "failed to read all"; + result = 2; + break; + } + + tb_size_t rawsize = tb_buffer_size(&raw); + + if (!tb_buffer_init(&out)) { + errors = "init buffer failed!"; + result = 2; + break; + } + out_ok = tb_true; + + if (!rawsize) { + lua_pushliteral(lua, ""); + result = 1; + break; + } + + tb_byte_t const *rawdata = (tb_byte_t const *)tb_buffer_data(&raw); + tb_byte_t const *p = rawdata; + tb_byte_t const *b = rawdata; + tb_byte_t const *e = rawdata + rawsize; + while (p < e) { + if (*p == '\r' && p + 1 < e && p[1] == '\n') { + if (p > b) { + tb_buffer_memncat(&out, b, p - b); + } + tb_buffer_memncat(&out, (tb_byte_t const *)"\n", 1); + p += 2; + b = p; } else { - lua_pushlstring(lua, (tb_char_t const *)tb_buffer_data(&buf), tb_buffer_size(&buf)); + p++; } - tb_buffer_exit(&buf); - return 1; - case PL_FIN: - case PL_CONL: - has_content = tb_true; - continue; - case PL_FAIL: - default: - tb_buffer_exit(&buf); - xm_io_return_error(lua, "failed to read all"); + } + if (tb_buffer_size(&out)) { + if (e > b) { + tb_buffer_memncat(&out, b, e - b); + } + lua_pushlstring(lua, (tb_char_t const *)tb_buffer_data(&out), tb_buffer_size(&out)); + result = 1; break; } + + lua_pushlstring(lua, (tb_char_t const *)rawdata, rawsize); + result = 1; + + } while (0); + + if (out_ok) { + tb_buffer_exit(&out); + } + if (raw_ok) { + tb_buffer_exit(&raw); } + if (result == 2) { + lua_pushnil(lua); + lua_pushstring(lua, errors); + } + return result; } static tb_int_t xm_io_file_read_line(lua_State *lua, -- cgit v1.3.1 From 83fd24bc6a601620f827338904eae23effb95099 Mon Sep 17 00:00:00 2001 From: ruki Date: Wed, 28 Jan 2026 23:22:54 +0800 Subject: update tbox --- core/src/tbox/tbox | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/tbox/tbox b/core/src/tbox/tbox index e74624e1b..5fce13a45 160000 --- a/core/src/tbox/tbox +++ b/core/src/tbox/tbox @@ -1 +1 @@ -Subproject commit e74624e1bbe199a1b0ec255e2cb917441dd816ef +Subproject commit 5fce13a458679ba0662f30a5eea32a5380eb8c13 -- cgit v1.3.1 From d0e47424619d453a1c74a7b248c26bab82bdd876 Mon Sep 17 00:00:00 2001 From: ruki Date: Wed, 28 Jan 2026 23:40:27 +0800 Subject: fix read --- core/src/xmake/io/file_read.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/core/src/xmake/io/file_read.c b/core/src/xmake/io/file_read.c index e38f7bd0d..1d0ae7368 100644 --- a/core/src/xmake/io/file_read.c +++ b/core/src/xmake/io/file_read.c @@ -49,10 +49,14 @@ static tb_bool_t xm_io_file_stream_skip_sequential(tb_stream_ref_t stream, tb_hi while (left) { tb_size_t need = left > (tb_hize_t)sizeof(discard) ? (tb_size_t)sizeof(discard) : (tb_size_t)left; tb_long_t read = tb_stream_read(stream, discard, need); - if (read != (tb_long_t)need) { + if (read > 0) { + left -= read; + } else if (!read) { + read = tb_stream_wait(stream, TB_STREAM_WAIT_READ, -1); + tb_check_return_val(read > 0, tb_false); + } else { return tb_false; } - left -= need; } return tb_true; } -- cgit v1.3.1 From 5c99e2d9e452e08de4fd7595f4429790ce8efed7 Mon Sep 17 00:00:00 2001 From: ruki Date: Wed, 28 Jan 2026 22:00:56 +0800 Subject: Update tty.lua --- xmake/core/base/tty.lua | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/xmake/core/base/tty.lua b/xmake/core/base/tty.lua index 0144795f9..b3ac35b2b 100644 --- a/xmake/core/base/tty.lua +++ b/xmake/core/base/tty.lua @@ -243,7 +243,6 @@ function tty._find_shell_from_parent() local shell local pid = os.getpid() - local tmpfile = os.tmpfile() local count = 0 while pid ~= 0 and count < 4 do count = count + 1 @@ -258,12 +257,8 @@ function tty._find_shell_from_parent() if not shell_path and os.isfile("/proc/" .. pid .. "/comm") then shell_name = io.readfile("/proc/" .. pid .. "/comm") - if not shell_name or #shell_name == 0 then - os.runv("cp", {"/proc/" .. pid .. "/comm", tmpfile}) - shell_name = io.readfile(tmpfile) - end if shell_name then - shell_name = shell_name:match("^%s*(.-)%s*$") + shell_name = shell_name:trim() end end if shell_path then @@ -271,27 +266,25 @@ function tty._find_shell_from_parent() end if shell_name then - shell_name = shell_name:gsub("^-", "") + shell_name = shell_name:ltrim("-") for _, name in ipairs({"zsh", "bash", "fish", "nu", "elvish", "pwsh", "sh"}) do if shell_name == name then shell = name break end end - if shell then break end + if shell then + break + end end local stat = io.readfile("/proc/" .. pid .. "/stat") - if not stat or #stat == 0 then - os.runv("cp", {"/proc/" .. pid .. "/stat", tmpfile}) - stat = io.readfile(tmpfile) - end - local ppid = stat and tonumber(stat:match(".*%) %S+ (%d+)")) - if not ppid or ppid == 0 then break end + if not ppid or ppid == 0 then + break + end pid = ppid end - os.rm(tmpfile) return shell end @@ -628,4 +621,3 @@ end -- return module return tty - -- cgit v1.3.1