const std = @import("std");

const DlOpenFn = fn ([*:0]const u8, c_int) callconv(.C) void;
const dlopen_weak = @extern(DlOpenFn, .{
    .name = "dlopen",
    .linkage = .Weak,
});

var general_purpose_allocator = std.heap.GeneralPurposeAllocator(.{}){};

pub fn main() anyerror!void {
    const gpa = &general_purpose_allocator.allocator;
    defer _ = general_purpose_allocator.deinit();

    var arena_instance = std.heap.ArenaAllocator.init(gpa);
    defer arena_instance.deinit();
    const arena = &arena_instance.allocator;

    std.log.debug("detecting whether we are running in the dynamic linker", .{});
    const dlopen = dlopen_weak orelse {
        std.log.debug("we're not. detecting the dynamic linker path", .{});

        const info = try std.zig.system.NativeTargetInfo.detect(arena, .{});
        const dyld_path = info.dynamic_linker.get() orelse @panic("OS has no dynamic linker");
        std.log.debug("dyld_path={}", .{dyld_path});
        const dyld_z = arena.dupeZ(u8, dyld_path) catch @panic("out of memory");

        const argv = arena.allocSentinel(?[*:0]const u8, std.os.argv.len + 1, null) catch @panic("out of memory");
        argv[0] = dyld_z;
        for (std.os.argv) |arg, i| {
            argv[i + 1] = arg;
        }
        // TODO make std.os.environ slice be also null terminated
        const envp = @ptrCast([*:null]const ?[*:0]const u8, std.os.environ.ptr);
        return std.os.execveZ(dyld_z, argv, envp);
    };

    std.log.debug("got the fns", .{});

    // So far our goal is to call these 2 functions.
    //XInitThreads();
    //XrmInitialize();
}