Consolidate @cImports into a single c.zig

Which is, AFAIK, a recommended practice. Reduces the number of times
translate-c is being run and (most likely) simplifies a possible future
transition if/when @cImport is thrown out of the language.

Also uses zstd.h instead of my own definitions, mainly because I plan to
use the streaming API as well and those need more definitions.
This commit is contained in:
Yorhel 2024-10-26 14:33:40 +02:00
parent 28d9eaecab
commit bd442673d2
9 changed files with 52 additions and 50 deletions

View file

@ -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;

View file

@ -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;

View file

@ -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();

17
src/c.zig Normal file
View file

@ -0,0 +1,17 @@
// SPDX-FileCopyrightText: Yorhel <projects@yorhel.nl>
// 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");
});

View file

@ -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,
},

View file

@ -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

View file

@ -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) {

View file

@ -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

View file

@ -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;