1const std = @import("std");
2const Io = std.Io;
3const Dir = std.Io.Dir;
4const assert = std.debug.assert;
5const info = std.log.info;
6const fatal = std.process.fatal;
7const Allocator = std.mem.Allocator;
8
9const usage =
10 \\gen_macos_headers_c [dir]
11 \\
12 \\General Options:
13 \\-h, --help Print this help and exit
14;
15
16pub fn main(init: std.process.Init) !void {
17 const arena = init.arena.allocator();
18 const io = init.io;
19 const args = try init.minimal.args.toSlice(arena);
20
21 if (args.len == 1) fatal("no command or option specified", .{});
22
23 var positionals = std.array_list.Managed([]const u8).init(arena);
24
25 for (args[1..]) |arg| {
26 if (std.mem.eql(u8, arg, "--help") or std.mem.eql(u8, arg, "-h")) {
27 return info(usage, .{});
28 } else try positionals.append(arg);
29 }
30
31 if (positionals.items.len != 1) fatal("expected one positional argument: [dir]", .{});
32
33 var dir = try Io.Dir.cwd().openDir(io, positionals.items[0], .{ .follow_symlinks = false });
34 defer dir.close(io);
35 var paths = std.array_list.Managed([]const u8).init(arena);
36 try findHeaders(arena, io, dir, "", &paths);
37
38 const SortFn = struct {
39 pub fn lessThan(ctx: void, lhs: []const u8, rhs: []const u8) bool {
40 _ = ctx;
41 return std.mem.lessThan(u8, lhs, rhs);
42 }
43 };
44
45 std.mem.sort([]const u8, paths.items, {}, SortFn.lessThan);
46
47 var buffer: [2000]u8 = undefined;
48 var stdout_writer = Io.File.stdout().writerStreaming(io, &buffer);
49 const w = &stdout_writer.interface;
50 try w.writeAll("#define _XOPEN_SOURCE\n");
51 for (paths.items) |path| {
52 try w.print("#include <{s}>\n", .{path});
53 }
54 try w.writeAll(
55 \\int main(int argc, char **argv) {
56 \\ return 0;
57 \\}
58 );
59 try w.flush();
60}
61
62fn findHeaders(
63 arena: Allocator,
64 io: Io,
65 dir: Dir,
66 prefix: []const u8,
67 paths: *std.array_list.Managed([]const u8),
68) anyerror!void {
69 var it = dir.iterate();
70 while (try it.next(io)) |entry| {
71 switch (entry.kind) {
72 .directory => {
73 const path = try Io.Dir.path.join(arena, &.{ prefix, entry.name });
74 var subdir = try dir.openDir(io, entry.name, .{ .follow_symlinks = false });
75 defer subdir.close(io);
76 try findHeaders(arena, io, subdir, path, paths);
77 },
78 .file, .sym_link => {
79 const ext = Io.Dir.path.extension(entry.name);
80 if (!std.mem.eql(u8, ext, ".h")) continue;
81 const path = try Io.Dir.path.join(arena, &.{ prefix, entry.name });
82 try paths.append(path);
83 },
84 else => {},
85 }
86 }
87}