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