diff --git a/src/bin_export.zig b/src/bin_export.zig index 08be2c6..2e0223b 100644 --- a/src/bin_export.zig +++ b/src/bin_export.zig @@ -7,9 +7,7 @@ const model = @import("model.zig"); const sink = @import("sink.zig"); const util = @import("util.zig"); const ui = @import("ui.zig"); - -extern fn ZSTD_compress(dst: ?*anyopaque, dstCapacity: usize, src: ?*const anyopaque, srcSize: usize, compressionLevel: c_int) usize; -extern fn ZSTD_isError(code: usize) c_uint; +const c = @import("c.zig").c; pub const global = struct { var fd: std.fs.File = undefined; @@ -65,9 +63,6 @@ inline fn blockHeader(id: u4, len: u28) [4]u8 { return bigu32((@as(u32, id) << 2 inline fn cborByte(major: CborMajor, arg: u5) u8 { return (@as(u8, @intFromEnum(major)) << 5) | arg; } -// ZSTD_COMPRESSBOUND(), assuming input does not exceed ZSTD_MAX_INPUT_SIZE -fn compressBound(size: usize) usize { return size + (size>>8) + (if (size < (128<<10)) ((128<<10) - size) >> 11 else 0); } - // (Uncompressed) data block size. // Start with 64k, then use increasingly larger block sizes as the export file @@ -100,8 +95,8 @@ pub const Thread = struct { fn compressZstd(in: []const u8, out: []u8) usize { while (true) { - const r = ZSTD_compress(out.ptr, out.len, in.ptr, in.len, main.config.complevel); - if (ZSTD_isError(r) == 0) return r; + const r = c.ZSTD_compress(out.ptr, out.len, in.ptr, in.len, main.config.complevel); + if (c.ZSTD_isError(r) == 0) return r; ui.oom(); // That *ought* to be the only reason the above call can fail. } } @@ -110,7 +105,7 @@ pub const Thread = struct { var out = std.ArrayList(u8).init(main.allocator); if (t.block_num == std.math.maxInt(u32) or t.off == 0) return out; - out.ensureTotalCapacityPrecise(12 + compressBound(t.off)) catch unreachable; + out.ensureTotalCapacityPrecise(12 + c.ZSTD_COMPRESSBOUND(t.off)) catch unreachable; out.items.len = out.capacity; const bodylen = compressZstd(t.buf[0..t.off], out.items[8..]); out.items.len = 12 + bodylen; diff --git a/src/bin_reader.zig b/src/bin_reader.zig index 6e2301f..7d1b55d 100644 --- a/src/bin_reader.zig +++ b/src/bin_reader.zig @@ -8,9 +8,7 @@ const util = @import("util.zig"); const sink = @import("sink.zig"); const ui = @import("ui.zig"); const bin_export = @import("bin_export.zig"); - -extern fn ZSTD_decompress(dst: ?*anyopaque, dstCapacity: usize, src: ?*const anyopaque, compressedSize: usize) usize; -extern fn ZSTD_getFrameContentSize(src: ?*const anyopaque, srcSize: usize) c_ulonglong; +const c = @import("c.zig").c; const CborMajor = bin_export.CborMajor; @@ -103,11 +101,11 @@ fn readBlock(num: u32) []const u8 { catch |e| ui.die("Error reading from file: {s}\n", .{ui.errorString(e)}); if (rdlen != buf.len) die(); - const rawlen = ZSTD_getFrameContentSize(buf.ptr, buf.len); + const rawlen = c.ZSTD_getFrameContentSize(buf.ptr, buf.len); if (rawlen <= 0 or rawlen >= (1<<24)) die(); block.data = main.allocator.alloc(u8, @intCast(rawlen)) catch unreachable; - const res = ZSTD_decompress(block.data.ptr, block.data.len, buf.ptr, buf.len); + const res = c.ZSTD_decompress(block.data.ptr, block.data.len, buf.ptr, buf.len); if (res != block.data.len) ui.die("Error decompressing block {} (expected {} got {})\n", .{ num, block.data.len, res }); return block.data; diff --git a/src/browser.zig b/src/browser.zig index 2e0cb58..4d49663 100644 --- a/src/browser.zig +++ b/src/browser.zig @@ -9,7 +9,7 @@ const mem_sink = @import("mem_sink.zig"); const bin_reader = @import("bin_reader.zig"); const delete = @import("delete.zig"); const ui = @import("ui.zig"); -const c = @cImport(@cInclude("time.h")); +const c = @import("c.zig").c; const util = @import("util.zig"); // Currently opened directory. @@ -644,8 +644,8 @@ const info = struct { fn keyInput(ch: i32) bool { if (entry.?.pack.etype == .link) { switch (ch) { - '1', 'h', ui.c.KEY_LEFT => { set(entry, .info); return true; }, - '2', 'l', ui.c.KEY_RIGHT => { set(entry, .links); return true; }, + '1', 'h', c.KEY_LEFT => { set(entry, .info); return true; }, + '2', 'l', c.KEY_RIGHT => { set(entry, .links); return true; }, else => {}, } } @@ -802,9 +802,9 @@ const help = struct { '1' => tab = .keys, '2' => tab = .flags, '3' => tab = .about, - 'h', ui.c.KEY_LEFT => tab = if (tab == .about) .flags else .keys, - 'l', ui.c.KEY_RIGHT => tab = if (tab == .keys) .flags else .about, - 'j', ' ', ui.c.KEY_DOWN, ui.c.KEY_NPAGE => { + 'h', c.KEY_LEFT => tab = if (tab == .about) .flags else .keys, + 'l', c.KEY_RIGHT => tab = if (tab == .keys) .flags else .about, + 'j', ' ', c.KEY_DOWN, c.KEY_NPAGE => { const max = switch (tab) { .keys => keys.len/2 - keylines, else => @as(u32, 0), @@ -812,7 +812,7 @@ const help = struct { if (offset < max) offset += 1; }, - 'k', ui.c.KEY_UP, ui.c.KEY_PPAGE => { if (offset > 0) offset -= 1; }, + 'k', c.KEY_UP, c.KEY_PPAGE => { if (offset > 0) offset -= 1; }, else => state = .main, } } @@ -917,16 +917,16 @@ fn sortToggle(col: main.config.SortCol, default_order: main.config.SortOrder) vo fn keyInputSelection(ch: i32, idx: *usize, len: usize, page: u32) bool { switch (ch) { - 'j', ui.c.KEY_DOWN => { + 'j', c.KEY_DOWN => { if (idx.*+1 < len) idx.* += 1; }, - 'k', ui.c.KEY_UP => { + 'k', c.KEY_UP => { if (idx.* > 0) idx.* -= 1; }, - ui.c.KEY_HOME => idx.* = 0, - ui.c.KEY_END, ui.c.KEY_LL => idx.* = len -| 1, - ui.c.KEY_PPAGE => idx.* = idx.* -| page, - ui.c.KEY_NPAGE => idx.* = @min(len -| 1, idx.* + page), + c.KEY_HOME => idx.* = 0, + c.KEY_END, c.KEY_LL => idx.* = len -| 1, + c.KEY_PPAGE => idx.* = idx.* -| page, + c.KEY_NPAGE => idx.* = @min(len -| 1, idx.* + page), else => return false, } return true; @@ -1017,7 +1017,7 @@ pub fn keyInput(ch: i32) void { }, // Navigation - 10, 'l', ui.c.KEY_RIGHT => { + 10, 'l', c.KEY_RIGHT => { if (dir_items.items.len == 0) { } else if (dir_items.items[cursor_idx]) |e| { if (e.dir()) |d| { @@ -1032,7 +1032,7 @@ pub fn keyInput(ch: i32) void { state = .main; } }, - 'h', '<', ui.c.KEY_BACKSPACE, ui.c.KEY_LEFT => { + 'h', '<', c.KEY_BACKSPACE, c.KEY_LEFT => { if (dir_parents.items.len > 1) { //const h = dir_parent.entry.nameHash(); enterParent(); diff --git a/src/c.zig b/src/c.zig new file mode 100644 index 0000000..9f5e1e5 --- /dev/null +++ b/src/c.zig @@ -0,0 +1,17 @@ +// SPDX-FileCopyrightText: Yorhel +// SPDX-License-Identifier: MIT + +pub const c = @cImport({ + @cDefine("_XOPEN_SOURCE", "1"); // for wcwidth() + @cInclude("stdio.h"); // fopen(), used to initialize ncurses + @cInclude("string.h"); // strerror() + @cInclude("time.h"); // strftime() + @cInclude("wchar.h"); // wcwidth() + @cInclude("locale.h"); // setlocale() and localeconv() + @cInclude("fnmatch.h"); // fnmatch() + if (@import("builtin").os.tag == .linux) { + @cInclude("sys/vfs.h"); // statfs() + } + @cInclude("curses.h"); + @cInclude("zstd.h"); +}); diff --git a/src/delete.zig b/src/delete.zig index e692b5c..ad76c2f 100644 --- a/src/delete.zig +++ b/src/delete.zig @@ -7,6 +7,7 @@ const model = @import("model.zig"); const ui = @import("ui.zig"); const browser = @import("browser.zig"); const util = @import("util.zig"); +const c = @import("c.zig").c; var parent: *model.Dir = undefined; var entry: *model.Entry = undefined; @@ -178,11 +179,11 @@ pub fn draw() void { pub fn keyInput(ch: i32) void { switch (state) { .confirm => switch (ch) { - 'h', ui.c.KEY_LEFT => confirm = switch (confirm) { + 'h', c.KEY_LEFT => confirm = switch (confirm) { .ignore => .no, else => .yes, }, - 'l', ui.c.KEY_RIGHT => confirm = switch (confirm) { + 'l', c.KEY_RIGHT => confirm = switch (confirm) { .yes => .no, else => .ignore, }, @@ -202,11 +203,11 @@ pub fn keyInput(ch: i32) void { main.state = .browse; }, .err => switch (ch) { - 'h', ui.c.KEY_LEFT => error_option = switch (error_option) { + 'h', c.KEY_LEFT => error_option = switch (error_option) { .all => .ignore, else => .abort, }, - 'l', ui.c.KEY_RIGHT => error_option = switch (error_option) { + 'l', c.KEY_RIGHT => error_option = switch (error_option) { .abort => .ignore, else => .all, }, diff --git a/src/exclude.zig b/src/exclude.zig index 391426b..d90611d 100644 --- a/src/exclude.zig +++ b/src/exclude.zig @@ -3,7 +3,7 @@ const std = @import("std"); const main = @import("main.zig"); -const c = @cImport(@cInclude("fnmatch.h")); +const c = @import("c.zig").c; // Reference: // https://manned.org/glob.7 diff --git a/src/main.zig b/src/main.zig index bdf98ef..e5cb866 100644 --- a/src/main.zig +++ b/src/main.zig @@ -18,7 +18,7 @@ const browser = @import("browser.zig"); const delete = @import("delete.zig"); const util = @import("util.zig"); const exclude = @import("exclude.zig"); -const c = @cImport(@cInclude("locale.h")); +const c = @import("c.zig").c; test "imports" { _ = model; @@ -634,14 +634,14 @@ pub fn handleEvent(block: bool, force_draw: bool) void { while (ui.oom_threads.load(.monotonic) > 0) ui.oom(); if (block or force_draw or event_delay_timer.read() > config.update_delay) { - if (ui.inited) _ = ui.c.erase(); + if (ui.inited) _ = c.erase(); switch (state) { .scan, .refresh => sink.draw(), .browse => browser.draw(), .delete => delete.draw(), .shell => unreachable, } - if (ui.inited) _ = ui.c.refresh(); + if (ui.inited) _ = c.refresh(); event_delay_timer.reset(); } if (!ui.inited) { diff --git a/src/scan.zig b/src/scan.zig index a62555c..96ec5c1 100644 --- a/src/scan.zig +++ b/src/scan.zig @@ -8,13 +8,13 @@ const model = @import("model.zig"); const sink = @import("sink.zig"); const ui = @import("ui.zig"); const exclude = @import("exclude.zig"); -const c_statfs = @cImport(@cInclude("sys/vfs.h")); +const c = @import("c.zig").c; // This function only works on Linux fn isKernfs(dir: std.fs.Dir) bool { - var buf: c_statfs.struct_statfs = undefined; - if (c_statfs.fstatfs(dir.fd, &buf) != 0) return false; // silently ignoring errors isn't too nice. + var buf: c.struct_statfs = undefined; + if (c.fstatfs(dir.fd, &buf) != 0) return false; // silently ignoring errors isn't too nice. const iskern = switch (util.castTruncate(u32, buf.f_type)) { // These numbers are documented in the Linux 'statfs(2)' man page, so I assume they're stable. 0x42494e4d, // BINFMTFS_MAGIC diff --git a/src/ui.zig b/src/ui.zig index 3d3eb90..9aab964 100644 --- a/src/ui.zig +++ b/src/ui.zig @@ -6,16 +6,7 @@ const std = @import("std"); const main = @import("main.zig"); const util = @import("util.zig"); - -pub const c = @cImport({ - @cDefine("_XOPEN_SOURCE", "1"); - @cInclude("stdio.h"); - @cInclude("string.h"); - @cInclude("curses.h"); - @cInclude("time.h"); - @cInclude("wchar.h"); - @cInclude("locale.h"); -}); +const c = @import("c.zig").c; pub var inited: bool = false; pub var main_thread: std.Thread.Id = undefined;