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 sink = @import("sink.zig");
const util = @import("util.zig"); const util = @import("util.zig");
const ui = @import("ui.zig"); const ui = @import("ui.zig");
const c = @import("c.zig").c;
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;
pub const global = struct { pub const global = struct {
var fd: std.fs.File = undefined; 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; } 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. // (Uncompressed) data block size.
// Start with 64k, then use increasingly larger block sizes as the export file // 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 { fn compressZstd(in: []const u8, out: []u8) usize {
while (true) { while (true) {
const r = ZSTD_compress(out.ptr, out.len, in.ptr, in.len, main.config.complevel); const r = c.ZSTD_compress(out.ptr, out.len, in.ptr, in.len, main.config.complevel);
if (ZSTD_isError(r) == 0) return r; if (c.ZSTD_isError(r) == 0) return r;
ui.oom(); // That *ought* to be the only reason the above call can fail. 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); var out = std.ArrayList(u8).init(main.allocator);
if (t.block_num == std.math.maxInt(u32) or t.off == 0) return out; 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; out.items.len = out.capacity;
const bodylen = compressZstd(t.buf[0..t.off], out.items[8..]); const bodylen = compressZstd(t.buf[0..t.off], out.items[8..]);
out.items.len = 12 + bodylen; out.items.len = 12 + bodylen;

View file

@ -8,9 +8,7 @@ const util = @import("util.zig");
const sink = @import("sink.zig"); const sink = @import("sink.zig");
const ui = @import("ui.zig"); const ui = @import("ui.zig");
const bin_export = @import("bin_export.zig"); const bin_export = @import("bin_export.zig");
const c = @import("c.zig").c;
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 CborMajor = bin_export.CborMajor; 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)}); catch |e| ui.die("Error reading from file: {s}\n", .{ui.errorString(e)});
if (rdlen != buf.len) die(); 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(); if (rawlen <= 0 or rawlen >= (1<<24)) die();
block.data = main.allocator.alloc(u8, @intCast(rawlen)) catch unreachable; 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 }); if (res != block.data.len) ui.die("Error decompressing block {} (expected {} got {})\n", .{ num, block.data.len, res });
return block.data; return block.data;

View file

@ -9,7 +9,7 @@ const mem_sink = @import("mem_sink.zig");
const bin_reader = @import("bin_reader.zig"); const bin_reader = @import("bin_reader.zig");
const delete = @import("delete.zig"); const delete = @import("delete.zig");
const ui = @import("ui.zig"); const ui = @import("ui.zig");
const c = @cImport(@cInclude("time.h")); const c = @import("c.zig").c;
const util = @import("util.zig"); const util = @import("util.zig");
// Currently opened directory. // Currently opened directory.
@ -644,8 +644,8 @@ const info = struct {
fn keyInput(ch: i32) bool { fn keyInput(ch: i32) bool {
if (entry.?.pack.etype == .link) { if (entry.?.pack.etype == .link) {
switch (ch) { switch (ch) {
'1', 'h', ui.c.KEY_LEFT => { set(entry, .info); return true; }, '1', 'h', c.KEY_LEFT => { set(entry, .info); return true; },
'2', 'l', ui.c.KEY_RIGHT => { set(entry, .links); return true; }, '2', 'l', c.KEY_RIGHT => { set(entry, .links); return true; },
else => {}, else => {},
} }
} }
@ -802,9 +802,9 @@ const help = struct {
'1' => tab = .keys, '1' => tab = .keys,
'2' => tab = .flags, '2' => tab = .flags,
'3' => tab = .about, '3' => tab = .about,
'h', ui.c.KEY_LEFT => tab = if (tab == .about) .flags else .keys, 'h', c.KEY_LEFT => tab = if (tab == .about) .flags else .keys,
'l', ui.c.KEY_RIGHT => tab = if (tab == .keys) .flags else .about, 'l', c.KEY_RIGHT => tab = if (tab == .keys) .flags else .about,
'j', ' ', ui.c.KEY_DOWN, ui.c.KEY_NPAGE => { 'j', ' ', c.KEY_DOWN, c.KEY_NPAGE => {
const max = switch (tab) { const max = switch (tab) {
.keys => keys.len/2 - keylines, .keys => keys.len/2 - keylines,
else => @as(u32, 0), else => @as(u32, 0),
@ -812,7 +812,7 @@ const help = struct {
if (offset < max) if (offset < max)
offset += 1; 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, 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 { fn keyInputSelection(ch: i32, idx: *usize, len: usize, page: u32) bool {
switch (ch) { switch (ch) {
'j', ui.c.KEY_DOWN => { 'j', c.KEY_DOWN => {
if (idx.*+1 < len) idx.* += 1; if (idx.*+1 < len) idx.* += 1;
}, },
'k', ui.c.KEY_UP => { 'k', c.KEY_UP => {
if (idx.* > 0) idx.* -= 1; if (idx.* > 0) idx.* -= 1;
}, },
ui.c.KEY_HOME => idx.* = 0, c.KEY_HOME => idx.* = 0,
ui.c.KEY_END, ui.c.KEY_LL => idx.* = len -| 1, c.KEY_END, c.KEY_LL => idx.* = len -| 1,
ui.c.KEY_PPAGE => idx.* = idx.* -| page, c.KEY_PPAGE => idx.* = idx.* -| page,
ui.c.KEY_NPAGE => idx.* = @min(len -| 1, idx.* + page), c.KEY_NPAGE => idx.* = @min(len -| 1, idx.* + page),
else => return false, else => return false,
} }
return true; return true;
@ -1017,7 +1017,7 @@ pub fn keyInput(ch: i32) void {
}, },
// Navigation // Navigation
10, 'l', ui.c.KEY_RIGHT => { 10, 'l', c.KEY_RIGHT => {
if (dir_items.items.len == 0) { if (dir_items.items.len == 0) {
} else if (dir_items.items[cursor_idx]) |e| { } else if (dir_items.items[cursor_idx]) |e| {
if (e.dir()) |d| { if (e.dir()) |d| {
@ -1032,7 +1032,7 @@ pub fn keyInput(ch: i32) void {
state = .main; state = .main;
} }
}, },
'h', '<', ui.c.KEY_BACKSPACE, ui.c.KEY_LEFT => { 'h', '<', c.KEY_BACKSPACE, c.KEY_LEFT => {
if (dir_parents.items.len > 1) { if (dir_parents.items.len > 1) {
//const h = dir_parent.entry.nameHash(); //const h = dir_parent.entry.nameHash();
enterParent(); 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 ui = @import("ui.zig");
const browser = @import("browser.zig"); const browser = @import("browser.zig");
const util = @import("util.zig"); const util = @import("util.zig");
const c = @import("c.zig").c;
var parent: *model.Dir = undefined; var parent: *model.Dir = undefined;
var entry: *model.Entry = undefined; var entry: *model.Entry = undefined;
@ -178,11 +179,11 @@ pub fn draw() void {
pub fn keyInput(ch: i32) void { pub fn keyInput(ch: i32) void {
switch (state) { switch (state) {
.confirm => switch (ch) { .confirm => switch (ch) {
'h', ui.c.KEY_LEFT => confirm = switch (confirm) { 'h', c.KEY_LEFT => confirm = switch (confirm) {
.ignore => .no, .ignore => .no,
else => .yes, else => .yes,
}, },
'l', ui.c.KEY_RIGHT => confirm = switch (confirm) { 'l', c.KEY_RIGHT => confirm = switch (confirm) {
.yes => .no, .yes => .no,
else => .ignore, else => .ignore,
}, },
@ -202,11 +203,11 @@ pub fn keyInput(ch: i32) void {
main.state = .browse; main.state = .browse;
}, },
.err => switch (ch) { .err => switch (ch) {
'h', ui.c.KEY_LEFT => error_option = switch (error_option) { 'h', c.KEY_LEFT => error_option = switch (error_option) {
.all => .ignore, .all => .ignore,
else => .abort, else => .abort,
}, },
'l', ui.c.KEY_RIGHT => error_option = switch (error_option) { 'l', c.KEY_RIGHT => error_option = switch (error_option) {
.abort => .ignore, .abort => .ignore,
else => .all, else => .all,
}, },

View file

@ -3,7 +3,7 @@
const std = @import("std"); const std = @import("std");
const main = @import("main.zig"); const main = @import("main.zig");
const c = @cImport(@cInclude("fnmatch.h")); const c = @import("c.zig").c;
// Reference: // Reference:
// https://manned.org/glob.7 // https://manned.org/glob.7

View file

@ -18,7 +18,7 @@ const browser = @import("browser.zig");
const delete = @import("delete.zig"); const delete = @import("delete.zig");
const util = @import("util.zig"); const util = @import("util.zig");
const exclude = @import("exclude.zig"); const exclude = @import("exclude.zig");
const c = @cImport(@cInclude("locale.h")); const c = @import("c.zig").c;
test "imports" { test "imports" {
_ = model; _ = model;
@ -634,14 +634,14 @@ pub fn handleEvent(block: bool, force_draw: bool) void {
while (ui.oom_threads.load(.monotonic) > 0) ui.oom(); while (ui.oom_threads.load(.monotonic) > 0) ui.oom();
if (block or force_draw or event_delay_timer.read() > config.update_delay) { 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) { switch (state) {
.scan, .refresh => sink.draw(), .scan, .refresh => sink.draw(),
.browse => browser.draw(), .browse => browser.draw(),
.delete => delete.draw(), .delete => delete.draw(),
.shell => unreachable, .shell => unreachable,
} }
if (ui.inited) _ = ui.c.refresh(); if (ui.inited) _ = c.refresh();
event_delay_timer.reset(); event_delay_timer.reset();
} }
if (!ui.inited) { if (!ui.inited) {

View file

@ -8,13 +8,13 @@ const model = @import("model.zig");
const sink = @import("sink.zig"); const sink = @import("sink.zig");
const ui = @import("ui.zig"); const ui = @import("ui.zig");
const exclude = @import("exclude.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 // This function only works on Linux
fn isKernfs(dir: std.fs.Dir) bool { fn isKernfs(dir: std.fs.Dir) bool {
var buf: c_statfs.struct_statfs = undefined; var buf: c.struct_statfs = undefined;
if (c_statfs.fstatfs(dir.fd, &buf) != 0) return false; // silently ignoring errors isn't too nice. 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)) { 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. // These numbers are documented in the Linux 'statfs(2)' man page, so I assume they're stable.
0x42494e4d, // BINFMTFS_MAGIC 0x42494e4d, // BINFMTFS_MAGIC

View file

@ -6,16 +6,7 @@
const std = @import("std"); const std = @import("std");
const main = @import("main.zig"); const main = @import("main.zig");
const util = @import("util.zig"); const util = @import("util.zig");
const c = @import("c.zig").c;
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");
});
pub var inited: bool = false; pub var inited: bool = false;
pub var main_thread: std.Thread.Id = undefined; pub var main_thread: std.Thread.Id = undefined;