Skip to content

Add error handling, refactor macro name generation, and improve C string escaping in xmake.lua#43

Merged
transicle merged 2 commits intomainfrom
copilot/add-error-handling-file-opening
Mar 27, 2026
Merged

Add error handling, refactor macro name generation, and improve C string escaping in xmake.lua#43
transicle merged 2 commits intomainfrom
copilot/add-error-handling-file-opening

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 27, 2026

The before_build hook in xmake.lua lacked error handling for file I/O failures and used complex inline logic for macro name generation and C string escaping that didn't handle all control characters.

Changes

  • io.open error handling: capture the second return value and assert immediately, surfacing a clear message instead of a cryptic nil-index error downstream
  • io.readfile error handling: explicit raise on nil return before any string operations
  • generate_macro_name() helper: extracted the previously inline path→macro-name logic into a local function, eliminating the duplication and making the loop body easier to read
  • Improved C string escaping: replaced the single newline gsub with a two-pass approach:
    • Pass 1 maps every control character (null, \a\r, and any other byte < 32) to its C escape or \xNN fallback
    • Pass 2 splits any remaining literal newlines across adjacent C string literals for readability
-- Before
local header_file = io.open(header_path, "w")   -- no error check
local content = io.readfile(file)                -- no error check
content = content:gsub("\n", '\\n" \\\n"')       -- only handles newlines

-- After
local header_file, err = io.open(header_path, "w")
assert(header_file, "failed to open header file '" .. header_path .. "': " .. tostring(err))
local content = io.readfile(file)
if not content then raise("failed to read file: %s", file) end
content = content:gsub("[%z\1-\31]", function(c) --[[ per-byte escape ]] end)
content = content:gsub("\n", '\\n"\n"')
Original prompt
Please apply the following diffs and create a pull request.
Once the PR is ready, give it a title based on the messages of the fixes being applied.

[{"message":"Missing error handling for file opening operation. If io.open fails, it returns nil and subsequent write operations will cause a runtime error. Add a check to ensure header_file is not nil before proceeding.","fixFiles":[{"filePath":"xmake.lua","diff":"diff --git a/xmake.lua b/xmake.lua\n--- a/xmake.lua\n+++ b/xmake.lua\n@@ -28,7 +28,8 @@\n \tlocal header_path = path.join(os.projectdir(), build_dir, \".gens\", target:name(), \"embedded_libs_data.h\")\n \n \tos.mkdir(path.directory(header_path))\n-\tlocal header_file = io.open(header_path, \"w\")\n+\tlocal header_file, err = io.open(header_path, \"w\")\n+\tassert(header_file, \"failed to open header file '\" .. header_path .. \"': \" .. tostring(err))\n \theader_file:write(\"// Auto-generated embedded libs\\n\\n\")\n \n \tlocal embed_dirs = {\n"}]},{"message":"The macro name generation logic is complex and duplicated. Consider extracting this into a separate function like generate_macro_name(rel_path) to improve readability and maintainability.","fixFiles":[{"filePath":"xmake.lua","diff":"diff --git a/xmake.lua b/xmake.lua\n--- a/xmake.lua\n+++ b/xmake.lua\n@@ -24,6 +24,30 @@\n add_includedirs(\"build/.gens/adan\", { public = true })\n \n before_build(function(target)\n+\tlocal function generate_macro_name(rel_path)\n+\t\tlocal parts = rel_path:split(\"[/\\\\]\")\n+\t\tlocal macro_name = \"\"\n+\t\tif #parts > 1 then\n+\t\t\tlocal dir_name = parts[1]\n+\t\t\tlocal file_parts = {}\n+\t\t\tfor i = 2, #parts do\n+\t\t\t\ttable.insert(file_parts, parts[i])\n+\t\t\tend\n+\t\t\tlocal file_part = table.concat(file_parts, \"_\")\n+\t\t\tlocal file_id = file_part:gsub(\"%.\", \"_\")\n+\t\t\tlocal dir_up = dir_name:upper()\n+\t\t\tlocal file_up = file_id:upper()\n+\t\t\tif file_up:find(\"^\" .. dir_up .. \"_\") then\n+\t\t\t\tmacro_name = file_up\n+\t\t\telse\n+\t\t\t\tmacro_name = dir_up .. \"_\" .. file_up\n+\t\t\tend\n+\t\telse\n+\t\t\tmacro_name = rel_path:gsub(\"%.\", \"_\"):upper()\n+\t\tend\n+\t\treturn macro_name\n+\tend\n+\n \tlocal build_dir = \"build\"\n \tlocal header_path = path.join(os.projectdir(), build_dir, \".gens\", target:name(), \"embedded_libs_data.h\")\n \n@@ -45,26 +69,7 @@\n \n \t\t\tfor _, file in ipairs(files) do\n \t\t\t\tlocal rel_path = path.relative(file, dir)\n-\t\t\t\tlocal parts = rel_path:split(\"[/\\\\]\")\n-\t\t\t\tlocal macro_name = \"\"\n-\t\t\t\tif #parts > 1 then\n-\t\t\t\t\tlocal dir_name = parts[1]\n-\t\t\t\t\tlocal file_parts = {}\n-\t\t\t\t\tfor i = 2, #parts do\n-\t\t\t\t\t\ttable.insert(file_parts, parts[i])\n-\t\t\t\t\tend\n-\t\t\t\t\tlocal file_part = table.concat(file_parts, \"_\")\n-\t\t\t\t\tlocal file_id = file_part:gsub(\"%.\", \"_\")\n-\t\t\t\t\tlocal dir_up = dir_name:upper()\n-\t\t\t\t\tlocal file_up = file_id:upper()\n-\t\t\t\t\tif file_up:find(\"^\" .. dir_up .. \"_\") then\n-\t\t\t\t\t\tmacro_name = file_up\n-\t\t\t\t\telse\n-\t\t\t\t\t\tmacro_name = dir_up .. \"_\" .. file_up\n-\t\t\t\t\tend\n-\t\t\t\telse\n-\t\t\t\t\tmacro_name = rel_path:gsub(\"%.\", \"_\"):upper()\n-\t\t\t\tend\n+\t\t\t\tlocal macro_name = generate_macro_name(rel_path)\n \n \t\t\t\tlocal content = io.readfile(file)\n \t\t\t\t-- Escape content for inclusion as a C string literal in a header:\n"}]},{"message":"Missing error handling for file read operation. If io.readfile fails, it may return nil and subsequent string operations will cause a runtime error. Add a check to ensure content is not nil before proceeding with string transformations.","fixFiles":[{"filePath":"xmake.lua","diff":"diff --git a/xmake.lua b/xmake.lua\n--- a/xmake.lua\n+++ b/xmake.lua\n@@ -67,6 +67,9 @@\n \t\t\t\tend\n \n \t\t\t\tlocal content = io.readfile(file)\n+\t\t\t\tif not content then\n+\t\t\t\t\traise(\"failed to read file: %s\", file)\n+\t\t\t\tend\n \t\t\t\t-- Escape content for inclusion as a C string literal in a header:\n \t\t\t\t-- 1) escape backslashes, 2) escape double quotes, 3) convert newlines\n \t\t\t\t--    to '\\n' and split the C string across multiple lines.\n"}]},{"message":"The content escaping logic may not handle all edge cases for C string literals. Consider additional escaping for characters like carriage returns (\\r), tabs (\\t), and null bytes that could cause issues in generated C code.","fixFiles":[{"filePath":"xmake.lua","diff":"diff --git a/xmake.lua b/xmake.lua\n--- a/xmake.lua\n+++ b/xmake.lua\n@@ -68,11 +68,40 @@\n \n \t\t\t\tlocal content = io.readfile(file)\n \t\t\t\t-- Escape content for inclusion as a C string literal in a header:\n-\t\t\t\t-- 1) escape backslashes, 2) escape double quotes, 3) convert newlines\n-\t\t\t\t--    to '\\n' and split the C string across multiple lines.\n+\t\t\t\t-- 1) escape backslashes and double quotes\n+\t\t\t\t-- 2) escape control characters (including null bytes) using C-style escapes\n+\t\t\t\t-- 3) convert remaining n...

⌨️ Start Copilot coding agent tasks without leaving your editor — available in VS Code, Visual Studio, JetBrains IDEs and Eclipse.

…ing escaping in xmake.lua

Agent-Logs-Url: https://github.com/Cappucina/ADAN/sessions/bf51f094-74e4-4f08-a0bf-00bbbc585565

Co-authored-by: transicle <173532449+transicle@users.noreply.github.com>
@transicle transicle marked this pull request as ready for review March 27, 2026 20:17
Copilot AI changed the title [WIP] Add error handling for file opening operation Add error handling, refactor macro name generation, and improve C string escaping in xmake.lua Mar 27, 2026
Copilot AI requested a review from transicle March 27, 2026 20:18
@transicle transicle merged commit f9d0bf6 into main Mar 27, 2026
3 of 4 checks passed
@transicle transicle deleted the copilot/add-error-handling-file-opening branch March 27, 2026 20:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants