From f4998c6abbce862448d68fb2b4c3b17ba16d7b16 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sun, 22 Mar 2026 13:55:38 -0700 Subject: [PATCH] build: fix Windows build failures in helpgen and framegen Use writerStreaming() instead of writer() for stdout in helpgen and main_build_data. The positional writer calls setEndPos/ftruncate in end(), which fails on Windows when stdout is redirected via captureStdOut() because ftruncate maps INVALID_PARAMETER to FileTooBig. Streaming mode skips truncation entirely since stdout is inherently a sequential stream. Replace scandir with opendir/readdir plus qsort in framegen since scandir is a POSIX extension not available on Windows. --- src/build/framegen/main.c | 39 +++++++++++++++++++++++++++++++-------- src/helpgen.zig | 2 +- src/main_build_data.zig | 2 +- 3 files changed, 33 insertions(+), 10 deletions(-) diff --git a/src/build/framegen/main.c b/src/build/framegen/main.c index 647768006..2139b15dd 100644 --- a/src/build/framegen/main.c +++ b/src/build/framegen/main.c @@ -8,15 +8,16 @@ #define SEPARATOR '\x01' #define CHUNK_SIZE 16384 +#define MAX_FRAMES 1024 +#define PATH_SEP '/' -static int filter_frames(const struct dirent *entry) { - const char *name = entry->d_name; +static int is_frame_file(const char *name) { size_t len = strlen(name); return len > 4 && strcmp(name + len - 4, ".txt") == 0; } -static int compare_frames(const struct dirent **a, const struct dirent **b) { - return strcmp((*a)->d_name, (*b)->d_name); +static int compare_names(const void *a, const void *b) { + return strcmp(*(const char **)a, *(const char **)b); } static char *read_file(const char *path, size_t *out_size) { @@ -54,25 +55,47 @@ int main(int argc, char **argv) { const char *frames_dir = argv[1]; const char *output_file = argv[2]; - struct dirent **namelist; - int n = scandir(frames_dir, &namelist, filter_frames, compare_frames); - if (n < 0) { + // Use opendir/readdir instead of scandir for Windows compatibility + DIR *dir = opendir(frames_dir); + if (!dir) { fprintf(stderr, "Failed to scan directory %s: %s\n", frames_dir, strerror(errno)); return 1; } + char *names[MAX_FRAMES]; + int n = 0; + struct dirent *entry; + while ((entry = readdir(dir)) != NULL) { + if (!is_frame_file(entry->d_name)) continue; + if (n >= MAX_FRAMES) { + fprintf(stderr, "Too many frame files (max %d)\n", MAX_FRAMES); + closedir(dir); + return 1; + } + names[n] = strdup(entry->d_name); + if (!names[n]) { + fprintf(stderr, "Failed to allocate memory\n"); + closedir(dir); + return 1; + } + n++; + } + closedir(dir); + if (n == 0) { fprintf(stderr, "No frame files found in %s\n", frames_dir); return 1; } + qsort(names, n, sizeof(char *), compare_names); + size_t total_size = 0; char **frame_contents = calloc(n, sizeof(char*)); size_t *frame_sizes = calloc(n, sizeof(size_t)); for (int i = 0; i < n; i++) { char path[4096]; - snprintf(path, sizeof(path), "%s/%s", frames_dir, namelist[i]->d_name); + snprintf(path, sizeof(path), "%s%c%s", frames_dir, PATH_SEP, names[i]); frame_contents[i] = read_file(path, &frame_sizes[i]); if (!frame_contents[i]) { diff --git a/src/helpgen.zig b/src/helpgen.zig index fe30db10c..49b5f4439 100644 --- a/src/helpgen.zig +++ b/src/helpgen.zig @@ -12,7 +12,7 @@ pub fn main() !void { const alloc = gpa.allocator(); var buf: [4096]u8 = undefined; - var stdout = std.fs.File.stdout().writer(&buf); + var stdout = std.fs.File.stdout().writerStreaming(&buf); const writer = &stdout.interface; try writer.writeAll( \\// THIS FILE IS AUTO GENERATED diff --git a/src/main_build_data.zig b/src/main_build_data.zig index 9dd1da395..4e55f449d 100644 --- a/src/main_build_data.zig +++ b/src/main_build_data.zig @@ -34,7 +34,7 @@ pub fn main() !void { // Our output always goes to stdout. var buffer: [1024]u8 = undefined; - var stdout_writer = std.fs.File.stdout().writer(&buffer); + var stdout_writer = std.fs.File.stdout().writerStreaming(&buffer); const writer = &stdout_writer.interface; switch (action) { .bash => try writer.writeAll(@import("extra/bash.zig").completions),