Compare commits

..

14 commits

Author SHA1 Message Date
Yorhel
2b4c1ca03e Version 2.8 2025-03-05 11:10:31 +01:00
Yorhel
af7163acf6 Revise @branchHint probabilities
Arguably, my previous use of @setCold() was incorrect in some cases, but
it happened to work out better than not providing any hints.  Let's use
the more granular hints now that Zig 0.14 supports them.
2025-03-05 10:56:46 +01:00
Yorhel
5438312440 Fix tests
Broken in 5d5182ede3
2025-03-05 10:44:14 +01:00
Eric Joldasov
0918096301
fix std.Target.isDarwin function replaced with direct version
See https://github.com/ziglang/zig/pull/22589 .

Signed-off-by: Eric Joldasov <bratishkaerik@landless-city.net>
2025-03-03 22:46:51 +05:00
Eric Joldasov
ee1d80da6a
std.fmt.digits now accept u8 instead of usize
See https://github.com/ziglang/zig/pull/22864 .

Signed-off-by: Eric Joldasov <bratishkaerik@landless-city.net>
2025-03-03 22:46:51 +05:00
Eric Joldasov
93a81a3898
ArrayList.pop now returns optional like removed popOrNull
See https://github.com/ziglang/zig/pull/22720 .

Signed-off-by: Eric Joldasov <bratishkaerik@landless-city.net>
2025-03-03 22:46:51 +05:00
Eric Joldasov
cf3a8f3043
update to new allocator interface
See https://github.com/ziglang/zig/pull/20511 .

Signed-off-by: Eric Joldasov <bratishkaerik@landless-city.net>
2025-03-03 22:46:51 +05:00
Eric Joldasov
f7fe61194b
update to new panic interface
See https://github.com/ziglang/zig/pull/22594 .

Signed-off-by: Eric Joldasov <bratishkaerik@landless-city.net>
2025-03-03 22:46:50 +05:00
Eric Joldasov
456cde16df
remove anonymous struct types
See https://github.com/ziglang/zig/pull/21817 .

Signed-off-by: Eric Joldasov <bratishkaerik@landless-city.net>
2025-03-03 22:46:50 +05:00
Eric Joldasov
3c77dc458a
replace deprecated std.Atomic(T).fence with load
See https://github.com/ziglang/zig/pull/21585 .
I went with second option listed in `Conditional Barriers` section.

Signed-off-by: Eric Joldasov <bratishkaerik@landless-city.net>
2025-03-03 22:46:50 +05:00
Eric Joldasov
ce9921846c
update to new names in std.builtin.Type
See https://github.com/ziglang/zig/pull/21225 .

Signed-off-by: Eric Joldasov <bratishkaerik@landless-city.net>
2025-03-03 22:46:49 +05:00
Eric Joldasov
e0ab5d40c7
change deprecated @setCold(true) to @branchHint(.cold)
New `@branchHint` builtin is more expressive than `@setCold`, therefore
latter was removed.
See https://github.com/ziglang/zig/pull/21214 .

Signed-off-by: Eric Joldasov <bratishkaerik@landless-city.net>
2025-03-03 22:46:49 +05:00
Eric Joldasov
607b07a30e
change deprecated timespec.tv_sec to timespec.sec
Part of the reorganization of `std.c` namespace.
See https://github.com/ziglang/zig/pull/20679 .

Signed-off-by: Eric Joldasov <bratishkaerik@landless-city.net>
2025-03-03 22:46:49 +05:00
Eric Joldasov
b4dc9f1d4d
change deprecated std.fs.MAX_PATH_BYTES to max_path_bytes
It was deprecated before, and became hard compile error.
See https://github.com/ziglang/zig/pull/19847 .

Signed-off-by: Eric Joldasov <bratishkaerik@landless-city.net>
2025-03-03 22:46:45 +05:00
14 changed files with 40 additions and 32 deletions

View file

@ -1,6 +1,12 @@
# SPDX-FileCopyrightText: Yorhel <projects@yorhel.nl>
# SPDX-License-Identifier: MIT
2.8 - 2025-03-05
- Now requires Zig 0.14
- Add support for @-prefixed lines to ignore errors in config file
- List all supported options in `--help`
- Use `kB` instead of `KB` in `--si` mode
2.7 - 2024-11-19
- Still requires Zig 0.12 or 0.13
- Support transparent reading/writing of zstandard-compressed JSON

View file

@ -19,7 +19,7 @@ C version (1.x).
## Requirements
- Zig 0.12 or 0.13.
- Zig 0.14
- Some sort of POSIX-like OS
- ncurses
- libzstd

View file

@ -22,8 +22,8 @@ pub fn build(b: *std.Build) void {
exe.pie = pie;
exe.root_module.linkSystemLibrary("ncursesw", .{});
exe.root_module.linkSystemLibrary("libzstd", .{});
// https://github.com/ziglang/zig/blob/b52be973dfb7d1408218b8e75800a2da3dc69108/build.zig#L551-L554
if (target.result.isDarwin()) {
// https://github.com/ziglang/zig/blob/faccd79ca5debbe22fe168193b8de54393257604/build.zig#L745-L748
if (target.result.os.tag.isDarwin()) {
// useful for package maintainers
exe.headerpad_max_install_names = true;
}

2
ncdu.1
View file

@ -1,6 +1,6 @@
.\" SPDX-FileCopyrightText: Yorhel <projects@yorhel.nl>
.\" SPDX-License-Identifier: MIT
.Dd November 19, 2024
.Dd March 5, 2025
.Dt NCDU 1
.Os
.Sh NAME

View file

@ -51,7 +51,7 @@ pub const ItemKey = enum(u5) {
// Pessimistic upper bound on the encoded size of an item, excluding the name field.
// 2 bytes for map start/end, 11 per field (2 for the key, 9 for a full u64).
const MAX_ITEM_LEN = 2 + 11 * @typeInfo(ItemKey).Enum.fields.len;
const MAX_ITEM_LEN = 2 + 11 * @typeInfo(ItemKey).@"enum".fields.len;
pub const CborMajor = enum(u3) { pos, neg, bytes, text, array, map, tag, simple };
@ -118,7 +118,7 @@ pub const Thread = struct {
}
fn flush(t: *Thread, expected_len: usize) void {
@setCold(true);
@branchHint(.unlikely);
const block = createBlock(t);
defer block.deinit();

View file

@ -63,7 +63,7 @@ inline fn bigu32(v: [4]u8) u32 { return std.mem.bigToNative(u32, @bitCast(v)); }
inline fn bigu64(v: [8]u8) u64 { return std.mem.bigToNative(u64, @bitCast(v)); }
fn die() noreturn {
@setCold(true);
@branchHint(.cold);
if (global.lastitem) |e| ui.die("Error reading item {x} from file\n", .{e})
else ui.die("Error reading from file\n", .{});
}
@ -338,7 +338,7 @@ const ItemParser = struct {
// Skips over any fields that don't fit into an ItemKey.
fn next(r: *ItemParser) ?Field {
while (r.key()) |k| {
if (k.major == .pos and k.arg <= std.math.maxInt(@typeInfo(ItemKey).Enum.tag_type)) return .{
if (k.major == .pos and k.arg <= std.math.maxInt(@typeInfo(ItemKey).@"enum".tag_type)) return .{
.key = @enumFromInt(k.arg),
.val = r.r.next(),
} else {

View file

@ -73,7 +73,7 @@ pub const Writer = struct {
dir_entry_open: bool = false,
fn flush(ctx: *Writer, bytes: usize) void {
@setCold(true);
@branchHint(.unlikely);
// This can only really happen when the root path exceeds PATH_MAX,
// in which case we would probably have error'ed out earlier anyway.
if (bytes > ctx.buf.len) ui.die("Error writing JSON export: path too long.\n", .{});
@ -126,14 +126,14 @@ pub const Writer = struct {
var index: usize = buf.len;
while (a >= 100) : (a = @divTrunc(a, 100)) {
index -= 2;
buf[index..][0..2].* = std.fmt.digits2(@as(usize, @intCast(a % 100)));
buf[index..][0..2].* = std.fmt.digits2(@as(u8, @intCast(a % 100)));
}
if (a < 10) {
index -= 1;
buf[index] = '0' + @as(u8, @intCast(a));
} else {
index -= 2;
buf[index..][0..2].* = std.fmt.digits2(@as(usize, @intCast(a)));
buf[index..][0..2].* = std.fmt.digits2(@as(u8, @intCast(a)));
}
ctx.write(buf[index..]);
}

View file

@ -83,7 +83,6 @@ const Parser = struct {
}
fn fill(p: *Parser) void {
@setCold(true);
p.rdoff = 0;
p.rdsize = (if (p.zstd) |z| z.read(p.rd, &p.buf) else p.rd.read(&p.buf)) catch |e| switch (e) {
error.IsDir => p.die("not a file"), // should be detected at open() time, but no flag for that...
@ -98,6 +97,7 @@ const Parser = struct {
// (Returning a '?u8' here is nicer but kills performance by about +30%)
fn nextByte(p: *Parser) u8 {
if (p.rdoff == p.rdsize) {
@branchHint(.unlikely);
p.fill();
if (p.rdsize == 0) return 0;
}
@ -133,7 +133,7 @@ const Parser = struct {
}
fn stringContentSlow(p: *Parser, buf: []u8, head: u8, off: usize) []u8 {
@setCold(true);
@branchHint(.unlikely);
var b = head;
var n = off;
while (true) {

View file

@ -1,7 +1,7 @@
// SPDX-FileCopyrightText: Yorhel <projects@yorhel.nl>
// SPDX-License-Identifier: MIT
pub const program_version = "2.7";
pub const program_version = "2.8";
const std = @import("std");
const model = @import("model.zig");
@ -41,7 +41,7 @@ test "imports" {
// This allocator never returns an error, it either succeeds or causes ncdu to quit.
// (Which means you'll find a lot of "catch unreachable" sprinkled through the code,
// they look scarier than they are)
fn wrapAlloc(_: *anyopaque, len: usize, ptr_alignment: u8, return_address: usize) ?[*]u8 {
fn wrapAlloc(_: *anyopaque, len: usize, ptr_alignment: std.mem.Alignment, return_address: usize) ?[*]u8 {
while (true) {
if (std.heap.c_allocator.vtable.alloc(undefined, len, ptr_alignment, return_address)) |r|
return r
@ -56,18 +56,20 @@ pub const allocator = std.mem.Allocator{
.alloc = wrapAlloc,
// AFAIK, all uses of resize() to grow an allocation will fall back to alloc() on failure.
.resize = std.heap.c_allocator.vtable.resize,
.remap = std.heap.c_allocator.vtable.remap,
.free = std.heap.c_allocator.vtable.free,
},
};
// Custom panic impl to reset the terminal before spewing out an error message.
pub fn panic(msg: []const u8, error_return_trace: ?*std.builtin.StackTrace, ret_addr: ?usize) noreturn {
@setCold(true);
ui.deinit();
std.debug.panicImpl(error_return_trace, ret_addr orelse @returnAddress(), msg);
}
pub const panic = std.debug.FullPanic(struct {
pub fn panicFn(msg: []const u8, first_trace_addr: ?usize) noreturn {
@branchHint(.cold);
ui.deinit();
std.debug.defaultPanic(msg, first_trace_addr);
}
}.panicFn);
pub const config = struct {
pub const SortCol = enum { name, blocks, size, items, mtime };
@ -637,7 +639,7 @@ pub fn main() void {
if (config.binreader and (export_json != null or export_bin != null))
bin_reader.import();
} else {
var buf = [_]u8{0} ** (std.fs.MAX_PATH_BYTES+1);
var buf: [std.fs.max_path_bytes+1]u8 = @splat(0);
const path =
if (std.posix.realpathZ(scan_dir orelse ".", buf[0..buf.len-1])) |p| buf[0..p.len:0]
else |_| (scan_dir orelse ".");
@ -725,13 +727,13 @@ test "argument parser" {
const T = struct {
a: Args,
fn opt(self: *@This(), isopt: bool, val: []const u8) !void {
const o = self.a.next().?;
const o = (self.a.next() catch unreachable).?;
try std.testing.expectEqual(isopt, o.opt);
try std.testing.expectEqualStrings(val, o.val);
try std.testing.expectEqual(o.is(val), isopt);
}
fn arg(self: *@This(), val: []const u8) !void {
try std.testing.expectEqualStrings(val, self.a.arg());
try std.testing.expectEqualStrings(val, self.a.arg() catch unreachable);
}
};
var t = T{ .a = Args.init(&lst) };

View file

@ -56,7 +56,7 @@ fn rec(ctx: *Ctx, dir: *sink.Dir, entry: *model.Entry) void {
pub fn run(d: *model.Dir) void {
const sink_threads = sink.createThreads(1);
var ctx = .{
var ctx: Ctx = .{
.sink = &sink_threads[0],
.stat = toStat(&d.entry),
};

View file

@ -67,7 +67,7 @@ fn statAt(parent: std.fs.Dir, name: [:0]const u8, follow: bool, symlink: *bool)
.hasgid = true,
.hasmode = true,
},
.mtime = clamp(model.Ext, .mtime, stat.mtime().tv_sec),
.mtime = clamp(model.Ext, .mtime, stat.mtime().sec),
.uid = truncate(model.Ext, .uid, stat.uid),
.gid = truncate(model.Ext, .gid, stat.gid),
.mode = truncate(model.Ext, .mode, stat.mode),
@ -276,7 +276,7 @@ const Thread = struct {
if (entry) |e| t.scanOne(d, e.name)
else {
t.sink.setDir(null);
t.stack.pop().destroy(t);
t.stack.pop().?.destroy(t);
}
}
}

View file

@ -162,7 +162,7 @@ pub const Dir = struct {
pub fn unref(d: *Dir, t: *Thread) void {
if (d.refcnt.fetchSub(1, .release) != 1) return;
d.refcnt.fence(.acquire);
_ = d.refcnt.load(.acquire);
switch (d.out) {
.mem => |*m| m.final(if (d.parent) |p| &p.out.mem else null),

View file

@ -37,7 +37,7 @@ pub fn quit() noreturn {
// no clue if ncurses will consistently report OOM, but we're not handling that
// right now.
pub fn oom() void {
@setCold(true);
@branchHint(.cold);
if (main_thread == std.Thread.getCurrentId()) {
const haveui = inited;
deinit();
@ -288,7 +288,7 @@ pub const Style = lbl: {
};
}
break :lbl @Type(.{
.Enum = .{
.@"enum" = .{
.tag_type = u8,
.fields = &fields,
.decls = &[_]std.builtin.Type.Declaration{},

View file

@ -18,8 +18,8 @@ pub fn castClamp(comptime T: type, x: anytype) T {
// Cast any integer type to the target type, truncating if necessary.
pub fn castTruncate(comptime T: type, x: anytype) T {
const Ti = @typeInfo(T).Int;
const Xi = @typeInfo(@TypeOf(x)).Int;
const Ti = @typeInfo(T).int;
const Xi = @typeInfo(@TypeOf(x)).int;
const nx: std.meta.Int(Ti.signedness, Xi.bits) = @bitCast(x);
return if (Xi.bits > Ti.bits) @truncate(nx) else nx;
}