const std = @import("std"); const c = @cImport({ @cInclude("archive.h"); @cInclude("archive_entry.h"); }); const W = *std.Io.Writer; fn writeRustType(w: W, comptime T: type) std.Io.Writer.Error!void { if (T == c_int) return w.writeAll("c_int"); if (T == c_uint) return w.writeAll("c_uint"); if (T == c_long) return w.writeAll("c_long"); if (T == c_ulong) return w.writeAll("c_ulong"); if (T == usize) return w.writeAll("usize"); if (T == isize) return w.writeAll("isize"); if (T == i64) return w.writeAll("i64"); if (T == u64) return w.writeAll("u64"); if (T == i32) return w.writeAll("i32"); if (T == u32) return w.writeAll("u32"); if (T == c.struct_archive) return w.writeAll("archive"); if (T == c.struct_archive_entry) return w.writeAll("archive_entry"); if (T == anyopaque) return w.writeAll("c_void"); if (T == u8) return w.writeAll("c_char"); switch (@typeInfo(T)) { .optional => |o| return writeRustType(w, o.child), .pointer => |p| { try w.writeAll(if (p.is_const) "*const " else "*mut "); return writeRustType(w, p.child); }, else => @compileError("unhandled type: " ++ @typeName(T)), } } fn FnInfo(comptime name: []const u8) type { const F = @TypeOf(@field(c, name)); const raw = @typeInfo(F); return switch (raw) { .@"fn" => F, .pointer => |p| p.child, else => @compileError("expected fn for " ++ name), }; } fn writeFn(w: W, comptime name: []const u8) std.Io.Writer.Error!void { const fi = @typeInfo(FnInfo(name)).@"fn"; try w.writeAll(" pub fn " ++ name ++ "("); inline for (fi.params, 0..) |param, i| { if (i > 0) try w.writeAll(", "); try w.print("_{d}: ", .{i}); try writeRustType(w, param.type.?); } try w.writeAll(")"); if (fi.return_type) |ret| { if (ret != void) { try w.writeAll(" -> "); try writeRustType(w, ret); } } try w.writeAll(";\n"); } pub fn main() !void { var buf: [4096]u8 = undefined; var fw = std.fs.File.stdout().writerStreaming(&buf); const w: W = &fw.interface; try w.writeAll( \\#![allow(non_camel_case_types, dead_code, unused_imports)] \\ \\use std::os::raw::{c_char, c_int, c_long, c_uint, c_void}; \\ \\// Opaque types \\#[repr(C)] \\pub struct archive { \\ _opaque: [u8; 0], \\} \\ \\#[repr(C)] \\pub struct archive_entry { \\ _opaque: [u8; 0], \\} \\ \\ ); // Return codes try w.writeAll("// Return codes\n"); inline for (.{ "ARCHIVE_EOF", "ARCHIVE_OK", "ARCHIVE_WARN" }) |name| { try w.print("pub const {s}: c_int = {d};\n", .{ name, @as(c_int, @field(c, name)) }); } // Format codes try w.writeAll("\n// Format codes\n"); inline for (.{ "ARCHIVE_FORMAT_BASE_MASK", "ARCHIVE_FORMAT_CPIO", "ARCHIVE_FORMAT_TAR", "ARCHIVE_FORMAT_ISO9660", "ARCHIVE_FORMAT_ZIP", "ARCHIVE_FORMAT_EMPTY", "ARCHIVE_FORMAT_AR", "ARCHIVE_FORMAT_MTREE", "ARCHIVE_FORMAT_RAW", "ARCHIVE_FORMAT_XAR", "ARCHIVE_FORMAT_LHA", "ARCHIVE_FORMAT_CAB", "ARCHIVE_FORMAT_RAR", "ARCHIVE_FORMAT_7ZIP", "ARCHIVE_FORMAT_WARC", "ARCHIVE_FORMAT_RAR_V5", }) |name| { try w.print("pub const {s}: u32 = 0x{x};\n", .{ name, @as(c_uint, @field(c, name)) }); } // Filter codes try w.writeAll("\n// Filter codes\n"); inline for (.{ "ARCHIVE_FILTER_NONE", "ARCHIVE_FILTER_GZIP", "ARCHIVE_FILTER_BZIP2", "ARCHIVE_FILTER_COMPRESS", "ARCHIVE_FILTER_LZMA", "ARCHIVE_FILTER_XZ", "ARCHIVE_FILTER_UU", "ARCHIVE_FILTER_RPM", "ARCHIVE_FILTER_LZIP", "ARCHIVE_FILTER_LRZIP", "ARCHIVE_FILTER_LZOP", "ARCHIVE_FILTER_GRZIP", "ARCHIVE_FILTER_LZ4", "ARCHIVE_FILTER_ZSTD", }) |name| { try w.print("pub const {s}: u32 = {d};\n", .{ name, @as(c_uint, @field(c, name)) }); } // Extract flags try w.writeAll("\n// Extract flags\n"); inline for (.{ "ARCHIVE_EXTRACT_TIME", "ARCHIVE_EXTRACT_PERM", "ARCHIVE_EXTRACT_ACL", "ARCHIVE_EXTRACT_FFLAGS", "ARCHIVE_EXTRACT_SECURE_SYMLINKS", "ARCHIVE_EXTRACT_SECURE_NODOTDOT", "ARCHIVE_EXTRACT_SECURE_NOABSOLUTEPATHS", }) |name| { try w.print("pub const {s}: u32 = 0x{x:0>4};\n", .{ name, @as(c_uint, @field(c, name)) }); } // File type constants (from POSIX stat) — hardcoded, zig cImport can't translate octal macros try w.writeAll("\n// File type constants (from POSIX stat)\n"); try w.writeAll("pub const AE_IFREG: u32 = 0o100000;\n"); try w.writeAll("pub const AE_IFDIR: u32 = 0o040000;\n"); try w.writeAll("pub const AE_IFLNK: u32 = 0o120000;\n"); // Functions try w.writeAll( \\ \\unsafe extern "C" { \\ ); // Reader try w.writeAll(" // Reader\n"); inline for (.{ "archive_read_new", "archive_read_free", "archive_read_support_format_all", "archive_read_support_format_raw", "archive_read_support_filter_all", "archive_read_open_filename", "archive_read_open_memory", "archive_read_next_header", "archive_read_next_header2", "archive_read_data", "archive_read_data_block", }) |name| { try writeFn(w, name); } // Writer try w.writeAll("\n // Writer\n"); inline for (.{ "archive_write_new", "archive_write_free", "archive_write_set_format", "archive_write_set_format_raw", "archive_write_set_format_pax_restricted", "archive_write_set_format_zip", "archive_write_set_format_7zip", "archive_write_set_format_ar_svr4", "archive_write_set_format_cpio_newc", "archive_write_add_filter", "archive_write_add_filter_none", "archive_write_open_filename", "archive_write_open_fd", "archive_write_header", "archive_write_data", "archive_write_finish_entry", "archive_write_close", }) |name| { try writeFn(w, name); } // Disk reader try w.writeAll("\n // Disk reader\n"); inline for (.{ "archive_read_disk_new", "archive_read_disk_set_standard_lookup", "archive_read_disk_open", "archive_read_disk_descend", }) |name| { try writeFn(w, name); } // Disk writer try w.writeAll("\n // Disk writer\n"); inline for (.{ "archive_write_disk_new", "archive_write_disk_set_options", "archive_write_disk_set_standard_lookup", }) |name| { try writeFn(w, name); } // Entry try w.writeAll("\n // Entry\n"); inline for (.{ "archive_entry_new", "archive_entry_free", "archive_entry_clear", "archive_entry_pathname", "archive_entry_pathname_utf8", "archive_entry_set_pathname_utf8", "archive_entry_size", "archive_entry_set_size", "archive_entry_filetype", "archive_entry_set_filetype", "archive_entry_perm", "archive_entry_set_perm", "archive_entry_set_mtime", "archive_entry_set_atime", "archive_entry_set_ctime", "archive_entry_set_uid", "archive_entry_set_gid", "archive_entry_set_uname_utf8", "archive_entry_set_gname_utf8", "archive_entry_hardlink_utf8", "archive_entry_symlink_utf8", }) |name| { try writeFn(w, name); } // Metadata try w.writeAll("\n // Metadata\n"); inline for (.{ "archive_format", "archive_filter_count", "archive_filter_code", "archive_filter_name", "archive_format_name", "archive_error_string", }) |name| { try writeFn(w, name); } try w.writeAll("}\n"); try w.flush(); }