mirror of
https://github.com/macports/macports-ports.git
synced 2026-07-12 18:20:25 -07:00
1208 lines
48 KiB
Diff
1208 lines
48 KiB
Diff
diff --git a/src/bin_export.zig b/src/bin_export.zig
|
|
index a10128b..0972ddd 100644
|
|
--- a/src/bin_export.zig
|
|
+++ b/src/bin_export.zig
|
|
@@ -10,10 +10,10 @@ const ui = @import("ui.zig");
|
|
const c = @import("c.zig").c;
|
|
|
|
pub const global = struct {
|
|
- var fd: std.fs.File = undefined;
|
|
+ var fd: std.Io.File = undefined;
|
|
var index: std.ArrayListUnmanaged(u8) = .empty;
|
|
var file_off: u64 = 0;
|
|
- var lock: std.Thread.Mutex = .{};
|
|
+ var lock: std.Io.Mutex = .init;
|
|
var root_itemref: u64 = 0;
|
|
};
|
|
|
|
@@ -125,8 +125,8 @@ pub const Thread = struct {
|
|
var block = createBlock(t);
|
|
defer block.deinit(main.allocator);
|
|
|
|
- global.lock.lock();
|
|
- defer global.lock.unlock();
|
|
+ global.lock.lockUncancelable(main.io);
|
|
+ defer global.lock.unlock(main.io);
|
|
// This can only really happen when the root path exceeds our block size,
|
|
// in which case we would probably have error'ed out earlier anyway.
|
|
if (expected_len > t.buf.len) ui.die("Error writing data: path too long.\n", .{});
|
|
@@ -135,7 +135,7 @@ pub const Thread = struct {
|
|
if (global.file_off >= (1<<40)) ui.die("Export data file has grown too large, please report a bug.\n", .{});
|
|
global.index.items[4..][t.block_num*8..][0..8].* = bigu64((global.file_off << 24) + block.items.len);
|
|
global.file_off += block.items.len;
|
|
- global.fd.writeAll(block.items) catch |e|
|
|
+ global.fd.writeStreamingAll(main.io, block.items) catch |e|
|
|
ui.die("Error writing to file: {s}.\n", .{ ui.errorString(e) });
|
|
}
|
|
|
|
@@ -246,7 +246,7 @@ pub const Dir = struct {
|
|
// I'm not expecting much lock contention, but it's possible to turn
|
|
// last_item into an atomic integer and other fields could be split up for
|
|
// subdir use.
|
|
- lock: std.Thread.Mutex = .{},
|
|
+ lock: std.Io.Mutex = .init,
|
|
last_sub: ?u64 = null,
|
|
stat: sink.Stat,
|
|
items: u64 = 0,
|
|
@@ -268,8 +268,8 @@ pub const Dir = struct {
|
|
|
|
|
|
pub fn addSpecial(d: *Dir, t: *Thread, name: []const u8, sp: model.EType) void {
|
|
- d.lock.lock();
|
|
- defer d.lock.unlock();
|
|
+ d.lock.lockUncancelable(main.io);
|
|
+ defer d.lock.unlock(main.io);
|
|
d.items += 1;
|
|
if (sp == .err) d.suberr = true;
|
|
d.last_sub = t.itemStart(sp, d.last_sub, name);
|
|
@@ -277,8 +277,8 @@ pub const Dir = struct {
|
|
}
|
|
|
|
pub fn addStat(d: *Dir, t: *Thread, name: []const u8, stat: *const sink.Stat) void {
|
|
- d.lock.lock();
|
|
- defer d.lock.unlock();
|
|
+ d.lock.lockUncancelable(main.io);
|
|
+ defer d.lock.unlock(main.io);
|
|
d.items += 1;
|
|
if (stat.etype != .link) {
|
|
d.size +|= stat.size;
|
|
@@ -309,8 +309,8 @@ pub const Dir = struct {
|
|
}
|
|
|
|
pub fn addDir(d: *Dir, stat: *const sink.Stat) Dir {
|
|
- d.lock.lock();
|
|
- defer d.lock.unlock();
|
|
+ d.lock.lockUncancelable(main.io);
|
|
+ defer d.lock.unlock(main.io);
|
|
d.items += 1;
|
|
d.size +|= stat.size;
|
|
d.blocks +|= stat.blocks;
|
|
@@ -318,8 +318,8 @@ pub const Dir = struct {
|
|
}
|
|
|
|
pub fn setReadError(d: *Dir) void {
|
|
- d.lock.lock();
|
|
- defer d.lock.unlock();
|
|
+ d.lock.lockUncancelable(main.io);
|
|
+ defer d.lock.unlock(main.io);
|
|
d.err = true;
|
|
}
|
|
|
|
@@ -375,8 +375,8 @@ pub const Dir = struct {
|
|
}
|
|
|
|
pub fn final(d: *Dir, t: *Thread, name: []const u8, parent: ?*Dir) void {
|
|
- if (parent) |p| p.lock.lock();
|
|
- defer if (parent) |p| p.lock.unlock();
|
|
+ if (parent) |p| p.lock.lockUncancelable(main.io);
|
|
+ defer if (parent) |p| p.lock.unlock(main.io);
|
|
|
|
if (parent) |p| {
|
|
// Different dev? Don't merge the 'inodes' sets, just count the
|
|
@@ -450,16 +450,16 @@ pub fn done(threads: []sink.Thread) void {
|
|
global.index.appendSlice(main.allocator, &bigu64(global.root_itemref)) catch unreachable;
|
|
global.index.appendSlice(main.allocator, &blockHeader(1, @intCast(global.index.items.len + 4))) catch unreachable;
|
|
global.index.items[0..4].* = blockHeader(1, @intCast(global.index.items.len));
|
|
- global.fd.writeAll(global.index.items) catch |e|
|
|
+ global.fd.writeStreamingAll(main.io, global.index.items) catch |e|
|
|
ui.die("Error writing to file: {s}.\n", .{ ui.errorString(e) });
|
|
global.index.clearAndFree(main.allocator);
|
|
|
|
- global.fd.close();
|
|
+ global.fd.close(main.io);
|
|
}
|
|
|
|
-pub fn setupOutput(fd: std.fs.File) void {
|
|
+pub fn setupOutput(fd: std.Io.File) void {
|
|
global.fd = fd;
|
|
- fd.writeAll(SIGNATURE) catch |e|
|
|
+ fd.writeStreamingAll(main.io, SIGNATURE) catch |e|
|
|
ui.die("Error writing to file: {s}.\n", .{ ui.errorString(e) });
|
|
global.file_off = 8;
|
|
|
|
diff --git a/src/bin_reader.zig b/src/bin_reader.zig
|
|
index cdbe117..31b989a 100644
|
|
--- a/src/bin_reader.zig
|
|
+++ b/src/bin_reader.zig
|
|
@@ -39,7 +39,7 @@ const ItemKey = bin_export.ItemKey;
|
|
// This file only implements (2) at the moment.
|
|
|
|
pub const global = struct {
|
|
- var fd: std.fs.File = undefined;
|
|
+ var fd: std.Io.File = undefined;
|
|
var index: []u8 = undefined;
|
|
var blocks: [8]Block = [1]Block{.{}}**8;
|
|
var counter: u64 = 0;
|
|
@@ -97,7 +97,7 @@ fn readBlock(num: u32) []const u8 {
|
|
// Only read the compressed data part, assume block header, number and footer are correct.
|
|
const buf = main.allocator.alloc(u8, @intCast(len - 12)) catch unreachable;
|
|
defer main.allocator.free(buf);
|
|
- const rdlen = global.fd.preadAll(buf, off + 8)
|
|
+ const rdlen = global.fd.readPositionalAll(main.io, buf, off + 8)
|
|
catch |e| ui.die("Error reading from file: {s}\n", .{ui.errorString(e)});
|
|
if (rdlen != buf.len) die();
|
|
|
|
@@ -233,8 +233,8 @@ const CborVal = struct {
|
|
|
|
fn etype(v: *const CborVal) model.EType {
|
|
const n = v.int(i32);
|
|
- return std.meta.intToEnum(model.EType, n)
|
|
- catch if (n < 0) .pattern else .nonreg;
|
|
+ return std.enums.fromInt(model.EType, n)
|
|
+ orelse if (n < 0) .pattern else .nonreg;
|
|
}
|
|
|
|
fn itemref(v: *const CborVal, cur: u64) u64 {
|
|
@@ -501,21 +501,19 @@ pub fn import() void {
|
|
}
|
|
|
|
// Assumes that the file signature has already been read and validated.
|
|
-pub fn open(fd: std.fs.File) !void {
|
|
+pub fn open(fd: std.Io.File) !void {
|
|
global.fd = fd;
|
|
|
|
- // Do not use fd.getEndPos() because that requires newer kernels supporting statx() #261.
|
|
- try fd.seekFromEnd(0);
|
|
- const size = try fd.getPos();
|
|
+ const size = try fd.length(main.io);
|
|
if (size < 16) return error.EndOfStream;
|
|
|
|
// Read index block
|
|
var buf: [4]u8 = undefined;
|
|
- if (try fd.preadAll(&buf, size - 4) != 4) return error.EndOfStream;
|
|
+ if (try fd.readPositionalAll(main.io, &buf, size - 4) != 4) return error.EndOfStream;
|
|
const index_header = bigu32(buf);
|
|
if ((index_header >> 28) != 1 or (index_header & 7) != 0) die();
|
|
const len = (index_header & 0x0fffffff) - 8; // excluding block header & footer
|
|
if (len >= size) die();
|
|
global.index = main.allocator.alloc(u8, len) catch unreachable;
|
|
- if (try fd.preadAll(global.index, size - len - 4) != global.index.len) return error.EndOfStream;
|
|
+ if (try fd.readPositionalAll(main.io, global.index, size - len - 4) != global.index.len) return error.EndOfStream;
|
|
}
|
|
diff --git a/src/browser.zig b/src/browser.zig
|
|
index c664baf..e380296 100644
|
|
--- a/src/browser.zig
|
|
+++ b/src/browser.zig
|
|
@@ -137,7 +137,7 @@ pub fn loadDir(next_sel: u64) void {
|
|
// XXX: The current dir listing is wiped before loading the new one, which
|
|
// causes the screen to flicker a bit when the loading indicator is drawn.
|
|
// Should we keep the old listing around?
|
|
- main.event_delay_timer.reset();
|
|
+ main.event_delay_timer = std.Io.Timestamp.now(main.io, .awake);
|
|
_ = dir_alloc.reset(.free_all);
|
|
dir_items.shrinkRetainingCapacity(0);
|
|
dir_refs.shrinkRetainingCapacity(0);
|
|
diff --git a/src/delete.zig b/src/delete.zig
|
|
index 5d4d4af..595503c 100644
|
|
--- a/src/delete.zig
|
|
+++ b/src/delete.zig
|
|
@@ -42,30 +42,30 @@ fn err(e: anyerror) bool {
|
|
return main.state != .delete;
|
|
}
|
|
|
|
-fn deleteItem(dir: std.fs.Dir, path: [:0]const u8, ptr: *align(1) ?*model.Entry) bool {
|
|
+fn deleteItem(dir: std.Io.Dir, path: [:0]const u8, ptr: *align(1) ?*model.Entry) bool {
|
|
entry = ptr.*.?;
|
|
main.handleEvent(false, false);
|
|
if (main.state != .delete)
|
|
return true;
|
|
|
|
if (entry.dir()) |d| {
|
|
- var fd = dir.openDirZ(path, .{ .no_follow = true, .iterate = false }) catch |e| return err(e);
|
|
+ var fd = dir.openDir(main.io, path, .{ .follow_symlinks = false, .iterate = false }) catch |e| return err(e);
|
|
var it = &d.sub.ptr;
|
|
parent = d;
|
|
defer parent = parent.parent.?;
|
|
while (it.*) |n| {
|
|
if (deleteItem(fd, n.name(), it)) {
|
|
- fd.close();
|
|
+ fd.close(main.io);
|
|
return true;
|
|
}
|
|
if (it.* == n) // item deletion failed, make sure to still advance to next
|
|
it = &n.next.ptr;
|
|
}
|
|
- fd.close();
|
|
- dir.deleteDirZ(path) catch |e|
|
|
+ fd.close(main.io);
|
|
+ dir.deleteDir(main.io, path) catch |e|
|
|
return if (e != error.DirNotEmpty or d.sub.ptr == null) err(e) else false;
|
|
} else
|
|
- dir.deleteFileZ(path) catch |e| return err(e);
|
|
+ dir.deleteFile(main.io, path) catch |e| return err(e);
|
|
ptr.*.?.zeroStats(parent);
|
|
ptr.* = ptr.*.?.next.ptr;
|
|
return false;
|
|
@@ -74,7 +74,7 @@ fn deleteItem(dir: std.fs.Dir, path: [:0]const u8, ptr: *align(1) ?*model.Entry)
|
|
// Returns true if the item has been deleted successfully.
|
|
fn deleteCmd(path: [:0]const u8, ptr: *align(1) ?*model.Entry) bool {
|
|
{
|
|
- var env = std.process.getEnvMap(main.allocator) catch unreachable;
|
|
+ var env = main.environ.createMap(main.allocator) catch unreachable;
|
|
defer env.deinit();
|
|
env.put("NCDU_DELETE_PATH", path) catch unreachable;
|
|
|
|
@@ -86,7 +86,7 @@ fn deleteCmd(path: [:0]const u8, ptr: *align(1) ?*model.Entry) bool {
|
|
ui.runCmd(&.{"/bin/sh", "-c", cmd}, null, &env, true);
|
|
}
|
|
|
|
- const stat = scan.statAt(std.fs.cwd(), path, false, null) catch {
|
|
+ const stat = scan.statAt(std.Io.Dir.cwd(), path, false, null) catch {
|
|
// Stat failed. Would be nice to display an error if it's not
|
|
// 'FileNotFound', but w/e, let's just assume the item has been
|
|
// deleted as expected.
|
|
@@ -144,7 +144,7 @@ pub fn delete() ?*model.Entry {
|
|
path.appendSlice(main.allocator, entry.name()) catch unreachable;
|
|
|
|
if (main.config.delete_command.len == 0) {
|
|
- _ = deleteItem(std.fs.cwd(), util.arrayListBufZ(&path, main.allocator), it);
|
|
+ _ = deleteItem(std.Io.Dir.cwd(), util.arrayListBufZ(&path, main.allocator), it);
|
|
model.inodes.addAllStats();
|
|
return if (it.* == e) e else next_sel;
|
|
} else {
|
|
diff --git a/src/exclude.zig b/src/exclude.zig
|
|
index 2376640..f3b094f 100644
|
|
--- a/src/exclude.zig
|
|
+++ b/src/exclude.zig
|
|
@@ -55,7 +55,7 @@ const Pattern = struct {
|
|
}
|
|
|
|
fn parse(pat_: []const u8) *const Pattern {
|
|
- var pat = std.mem.trimLeft(u8, pat_, "/");
|
|
+ var pat = std.mem.trimStart(u8, pat_, "/");
|
|
const top = main.allocator.create(Pattern) catch unreachable;
|
|
var tail = top;
|
|
tail.sub = null;
|
|
@@ -150,7 +150,7 @@ fn PatternList(comptime withsub: bool) type {
|
|
const e = self.literals.getOrPut(main.allocator, pat) catch unreachable;
|
|
if (!e.found_existing) {
|
|
e.key_ptr.* = pat;
|
|
- e.value_ptr.* = if (withsub) .{} else {};
|
|
+ e.value_ptr.* = if (withsub) .empty else {};
|
|
}
|
|
if (!withsub and !pat.isdir and e.key_ptr.*.isdir) e.key_ptr.* = pat;
|
|
if (withsub) {
|
|
diff --git a/src/json_export.zig b/src/json_export.zig
|
|
index 3937b3f..8d2a7e9 100644
|
|
--- a/src/json_export.zig
|
|
+++ b/src/json_export.zig
|
|
@@ -42,7 +42,7 @@ const ZstdWriter = struct {
|
|
main.allocator.destroy(w);
|
|
}
|
|
|
|
- fn write(w: *ZstdWriter, f: std.fs.File, in: []const u8, flush: bool) !void {
|
|
+ fn write(w: *ZstdWriter, f: std.Io.File, in: []const u8, flush: bool) !void {
|
|
var arg = c.ZSTD_inBuffer{
|
|
.src = in.ptr,
|
|
.size = in.len,
|
|
@@ -52,7 +52,7 @@ const ZstdWriter = struct {
|
|
const v = c.ZSTD_compressStream2(w.ctx, &w.out, &arg, if (flush) c.ZSTD_e_end else c.ZSTD_e_continue);
|
|
if (c.ZSTD_isError(v) != 0) return error.ZstdCompressError;
|
|
if (flush or w.out.pos > w.outbuf.len / 2) {
|
|
- try f.writeAll(w.outbuf[0..w.out.pos]);
|
|
+ try f.writeStreamingAll(main.io, w.outbuf[0..w.out.pos]);
|
|
w.out.pos = 0;
|
|
}
|
|
if (!flush and arg.pos == arg.size) break;
|
|
@@ -62,7 +62,7 @@ const ZstdWriter = struct {
|
|
};
|
|
|
|
pub const Writer = struct {
|
|
- fd: std.fs.File,
|
|
+ fd: std.Io.File,
|
|
zstd: ?*ZstdWriter = null,
|
|
// Must be large enough to hold PATH_MAX*6 plus some overhead.
|
|
// (The 6 is because, in the worst case, every byte expands to a "\u####"
|
|
@@ -78,7 +78,7 @@ pub const Writer = struct {
|
|
// 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", .{});
|
|
const buf = ctx.buf[0..ctx.off];
|
|
- (if (ctx.zstd) |z| z.write(ctx.fd, buf, bytes == 0) else ctx.fd.writeAll(buf)) catch |e|
|
|
+ (if (ctx.zstd) |z| z.write(ctx.fd, buf, bytes == 0) else ctx.fd.writeStreamingAll(main.io, buf)) catch |e|
|
|
ui.die("Error writing to file: {s}.\n", .{ ui.errorString(e) });
|
|
ctx.off = 0;
|
|
}
|
|
@@ -138,12 +138,13 @@ pub const Writer = struct {
|
|
ctx.write(buf[index..]);
|
|
}
|
|
|
|
- fn init(out: std.fs.File) *Writer {
|
|
+ fn init(out: std.Io.File) *Writer {
|
|
var ctx = main.allocator.create(Writer) catch unreachable;
|
|
ctx.* = .{ .fd = out };
|
|
if (main.config.compress) ctx.zstd = ZstdWriter.create();
|
|
ctx.write("[1,2,{\"progname\":\"ncdu\",\"progver\":\"" ++ main.program_version ++ "\",\"timestamp\":");
|
|
- ctx.writeUint(@intCast(@max(0, std.time.timestamp())));
|
|
+ const now = std.Io.Timestamp.now(main.io, .real).toSeconds();
|
|
+ ctx.writeUint(@intCast(@max(0, now)));
|
|
ctx.writeByte('}');
|
|
return ctx;
|
|
}
|
|
@@ -261,10 +262,10 @@ pub fn done() void {
|
|
global.writer.write("]\n");
|
|
global.writer.flush(0);
|
|
if (global.writer.zstd) |z| z.destroy();
|
|
- global.writer.fd.close();
|
|
+ global.writer.fd.close(main.io);
|
|
main.allocator.destroy(global.writer);
|
|
}
|
|
|
|
-pub fn setupOutput(out: std.fs.File) void {
|
|
+pub fn setupOutput(out: std.Io.File) void {
|
|
global.writer = Writer.init(out);
|
|
}
|
|
diff --git a/src/json_import.zig b/src/json_import.zig
|
|
index 28224e6..d496ac9 100644
|
|
--- a/src/json_import.zig
|
|
+++ b/src/json_import.zig
|
|
@@ -37,11 +37,11 @@ const ZstdReader = struct {
|
|
main.allocator.destroy(r);
|
|
}
|
|
|
|
- fn read(r: *ZstdReader, f: std.fs.File, out: []u8) !usize {
|
|
+ fn read(r: *ZstdReader, f: std.Io.File, out: []u8) !usize {
|
|
while (true) {
|
|
if (r.in.size == r.in.pos) {
|
|
r.in.pos = 0;
|
|
- r.in.size = try f.read(&r.inbuf);
|
|
+ r.in.size = try f.readStreaming(main.io, &.{&r.inbuf});
|
|
if (r.in.size == 0) {
|
|
if (r.lastret == 0) return 0;
|
|
return error.ZstdDecompressError; // Early EOF
|
|
@@ -63,7 +63,7 @@ const ZstdReader = struct {
|
|
// strings.
|
|
|
|
const Parser = struct {
|
|
- rd: std.fs.File,
|
|
+ rd: std.Io.File,
|
|
zstd: ?*ZstdReader = null,
|
|
rdoff: usize = 0,
|
|
rdsize: usize = 0,
|
|
@@ -84,7 +84,7 @@ const Parser = struct {
|
|
|
|
fn fill(p: *Parser) void {
|
|
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) {
|
|
+ p.rdsize = (if (p.zstd) |z| z.read(p.rd, &p.buf) else p.rd.readStreaming(main.io, &.{&p.buf})) catch |e| switch (e) {
|
|
error.IsDir => p.die("not a file"), // should be detected at open() time, but no flag for that...
|
|
error.SystemResources => p.die("out of memory"),
|
|
error.ZstdDecompressError => p.die("decompression error"),
|
|
@@ -528,7 +528,7 @@ fn item(ctx: *Ctx, parent: ?*sink.Dir, dev: u64) void {
|
|
}
|
|
|
|
|
|
-pub fn import(fd: std.fs.File, head: []const u8) void {
|
|
+pub fn import(fd: std.Io.File, head: []const u8) void {
|
|
const sink_threads = sink.createThreads(1);
|
|
defer sink.done();
|
|
|
|
diff --git a/src/main.zig b/src/main.zig
|
|
index 7301586..067570e 100644
|
|
--- a/src/main.zig
|
|
+++ b/src/main.zig
|
|
@@ -118,8 +118,14 @@ pub const config = struct {
|
|
|
|
pub var state: enum { scan, browse, refresh, shell, delete } = .scan;
|
|
|
|
-const stdin = if (@hasDecl(std.io, "getStdIn")) std.io.getStdIn() else std.fs.File.stdin();
|
|
-const stdout = if (@hasDecl(std.io, "getStdOut")) std.io.getStdOut() else std.fs.File.stdout();
|
|
+const stdin = std.Io.File.stdin();
|
|
+const stdout = std.Io.File.stdout();
|
|
+pub var io: std.Io = undefined;
|
|
+pub var environ: std.process.Environ = .empty;
|
|
+
|
|
+pub fn getenvZ(key: []const u8) ?[:0]const u8 {
|
|
+ return environ.getPosix(key);
|
|
+}
|
|
|
|
// Simple generic argument parser, supports getopt_long() style arguments.
|
|
const Args = struct {
|
|
@@ -323,15 +329,15 @@ fn argConfig(args: *Args, opt: Args.Option, infile: bool) !void {
|
|
}
|
|
|
|
fn tryReadArgsFile(path: [:0]const u8) void {
|
|
- var f = std.fs.cwd().openFileZ(path, .{}) catch |e| switch (e) {
|
|
+ var f = std.Io.Dir.cwd().openFile(io, path, .{}) catch |e| switch (e) {
|
|
error.FileNotFound => return,
|
|
error.NotDir => return,
|
|
else => ui.die("Error opening {s}: {s}\nRun with --ignore-config to skip reading config files.\n", .{ path, ui.errorString(e) }),
|
|
};
|
|
- defer f.close();
|
|
+ defer f.close(io);
|
|
|
|
var line_buf: [4096]u8 = undefined;
|
|
- var line_rd = util.LineReader.init(f, &line_buf);
|
|
+ var line_rd = util.LineReader.init(f, io, &line_buf);
|
|
|
|
while (true) {
|
|
const line_ = (line_rd.read() catch |e|
|
|
@@ -351,7 +357,7 @@ fn tryReadArgsFile(path: [:0]const u8) void {
|
|
if (std.mem.indexOfAny(u8, line, " \t=")) |i| {
|
|
arglist[argc] = allocator.dupeZ(u8, line[0..i]) catch unreachable;
|
|
argc += 1;
|
|
- line = std.mem.trimLeft(u8, line[i+1..], &std.ascii.whitespace);
|
|
+ line = std.mem.trimStart(u8, line[i+1..], &std.ascii.whitespace);
|
|
}
|
|
arglist[argc] = allocator.dupeZ(u8, line) catch unreachable;
|
|
argc += 1;
|
|
@@ -371,12 +377,12 @@ fn tryReadArgsFile(path: [:0]const u8) void {
|
|
}
|
|
|
|
fn version() noreturn {
|
|
- stdout.writeAll("ncdu " ++ program_version ++ "\n") catch {};
|
|
+ stdout.writeStreamingAll(io, "ncdu " ++ program_version ++ "\n") catch {};
|
|
std.process.exit(0);
|
|
}
|
|
|
|
fn help() noreturn {
|
|
- stdout.writeAll(
|
|
+ stdout.writeStreamingAll(io,
|
|
\\ncdu <options> <directory>
|
|
\\
|
|
\\Mode selection:
|
|
@@ -435,11 +441,11 @@ fn help() noreturn {
|
|
|
|
|
|
fn readExcludeFile(path: [:0]const u8) !void {
|
|
- const f = try std.fs.cwd().openFileZ(path, .{});
|
|
- defer f.close();
|
|
+ const f = try std.Io.Dir.cwd().openFile(io, path, .{});
|
|
+ defer f.close(io);
|
|
|
|
var line_buf: [4096]u8 = undefined;
|
|
- var line_rd = util.LineReader.init(f, &line_buf);
|
|
+ var line_rd = util.LineReader.init(f, io, &line_buf);
|
|
while (try line_rd.read()) |line| {
|
|
if (line.len > 0)
|
|
exclude.addPattern(line);
|
|
@@ -449,21 +455,24 @@ fn readExcludeFile(path: [:0]const u8) !void {
|
|
fn readImport(path: [:0]const u8) !void {
|
|
const fd =
|
|
if (std.mem.eql(u8, "-", path)) stdin
|
|
- else try std.fs.cwd().openFileZ(path, .{});
|
|
- errdefer fd.close();
|
|
+ else try std.Io.Dir.cwd().openFile(io, path, .{});
|
|
+ errdefer fd.close(io);
|
|
|
|
var buf: [8]u8 = undefined;
|
|
- if (8 != try fd.readAll(&buf)) return error.EndOfStream;
|
|
+ if (8 != try fd.readStreaming(io, &.{&buf})) return error.EndOfStream;
|
|
if (std.mem.eql(u8, &buf, bin_export.SIGNATURE)) {
|
|
try bin_reader.open(fd);
|
|
config.binreader = true;
|
|
} else {
|
|
json_import.import(fd, &buf);
|
|
- fd.close();
|
|
+ fd.close(io);
|
|
}
|
|
}
|
|
|
|
-pub fn main() void {
|
|
+pub fn main(init: std.process.Init) void {
|
|
+ io = init.io;
|
|
+ environ = init.minimal.environ;
|
|
+
|
|
ui.main_thread = std.Thread.getCurrentId();
|
|
|
|
// Grab thousands_sep from the current C locale.
|
|
@@ -477,7 +486,7 @@ pub fn main() void {
|
|
}
|
|
|
|
const loadConf = blk: {
|
|
- var args = std.process.ArgIteratorPosix.init();
|
|
+ var args = std.process.Args.Iterator.init(init.minimal.args);
|
|
while (args.next()) |a|
|
|
if (std.mem.eql(u8, a, "--ignore-config"))
|
|
break :blk false;
|
|
@@ -487,11 +496,11 @@ pub fn main() void {
|
|
if (loadConf) {
|
|
tryReadArgsFile("/etc/ncdu.conf");
|
|
|
|
- if (std.posix.getenvZ("XDG_CONFIG_HOME")) |p| {
|
|
+ if (getenvZ("XDG_CONFIG_HOME")) |p| {
|
|
const path = std.fs.path.joinZ(allocator, &.{p, "ncdu", "config"}) catch unreachable;
|
|
defer allocator.free(path);
|
|
tryReadArgsFile(path);
|
|
- } else if (std.posix.getenvZ("HOME")) |p| {
|
|
+ } else if (getenvZ("HOME")) |p| {
|
|
const path = std.fs.path.joinZ(allocator, &.{p, ".config", "ncdu", "config"}) catch unreachable;
|
|
defer allocator.free(path);
|
|
tryReadArgsFile(path);
|
|
@@ -504,8 +513,10 @@ pub fn main() void {
|
|
var export_bin: ?[:0]const u8 = null;
|
|
var quit_after_scan = false;
|
|
{
|
|
- const arglist = std.process.argsAlloc(allocator) catch unreachable;
|
|
- defer std.process.argsFree(allocator, arglist);
|
|
+ const raw_args = init.minimal.args.vector;
|
|
+ const arglist = allocator.alloc([:0]const u8, raw_args.len) catch unreachable;
|
|
+ defer allocator.free(arglist);
|
|
+ for (arglist, raw_args) |*arg, raw_arg| arg.* = std.mem.sliceTo(raw_arg, 0);
|
|
var args = Args.init(arglist);
|
|
_ = args.next() catch unreachable; // program name
|
|
while (args.next() catch unreachable) |opt| {
|
|
@@ -535,8 +546,8 @@ pub fn main() void {
|
|
if (@import("builtin").os.tag != .linux and config.exclude_kernfs)
|
|
ui.die("The --exclude-kernfs flag is currently only supported on Linux.\n", .{});
|
|
|
|
- const out_tty = stdout.isTty();
|
|
- const in_tty = stdin.isTty();
|
|
+ const out_tty = stdout.isTty(io) catch false;
|
|
+ const in_tty = stdin.isTty(io) catch false;
|
|
if (config.scan_ui == null) {
|
|
if (export_json orelse export_bin) |f| {
|
|
if (!out_tty or std.mem.eql(u8, f, "-")) config.scan_ui = .none
|
|
@@ -547,20 +558,20 @@ pub fn main() void {
|
|
ui.die("Standard input is not a TTY. Did you mean to import a file using '-f -'?\n", .{});
|
|
config.nc_tty = !in_tty or (if (export_json orelse export_bin) |f| std.mem.eql(u8, f, "-") else false);
|
|
|
|
- event_delay_timer = std.time.Timer.start() catch unreachable;
|
|
+ event_delay_timer = std.Io.Timestamp.now(io, .awake);
|
|
defer ui.deinit();
|
|
|
|
if (export_json) |f| {
|
|
const file =
|
|
if (std.mem.eql(u8, f, "-")) stdout
|
|
- else std.fs.cwd().createFileZ(f, .{})
|
|
+ else std.Io.Dir.cwd().createFile(io, f, .{})
|
|
catch |e| ui.die("Error opening export file: {s}.\n", .{ui.errorString(e)});
|
|
json_export.setupOutput(file);
|
|
sink.global.sink = .json;
|
|
} else if (export_bin) |f| {
|
|
const file =
|
|
if (std.mem.eql(u8, f, "-")) stdout
|
|
- else std.fs.cwd().createFileZ(f, .{})
|
|
+ else std.Io.Dir.cwd().createFile(io, f, .{})
|
|
catch |e| ui.die("Error opening export file: {s}.\n", .{ui.errorString(e)});
|
|
bin_export.setupOutput(file);
|
|
sink.global.sink = .bin;
|
|
@@ -572,10 +583,13 @@ pub fn main() void {
|
|
if (config.binreader and (export_json != null or export_bin != null))
|
|
bin_reader.import();
|
|
} else {
|
|
- 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 ".");
|
|
+ var buf: [std.Io.Dir.max_path_bytes+1]u8 = @splat(0);
|
|
+ const path = blk: {
|
|
+ const len = std.Io.Dir.cwd().realPathFile(io, scan_dir orelse ".", buf[0..buf.len-1]) catch
|
|
+ break :blk scan_dir orelse ".";
|
|
+ buf[len] = 0;
|
|
+ break :blk buf[0..len:0];
|
|
+ };
|
|
scan.scan(path) catch |e| ui.die("Error opening directory: {s}.\n", .{ui.errorString(e)});
|
|
}
|
|
if (quit_after_scan or export_json != null or export_bin != null) return;
|
|
@@ -604,8 +618,8 @@ pub fn main() void {
|
|
browser.loadDir(0);
|
|
},
|
|
.shell => {
|
|
- const shell = std.posix.getenvZ("NCDU_SHELL") orelse std.posix.getenvZ("SHELL") orelse "/bin/sh";
|
|
- var env = std.process.getEnvMap(allocator) catch unreachable;
|
|
+ const shell = getenvZ("NCDU_SHELL") orelse getenvZ("SHELL") orelse "/bin/sh";
|
|
+ var env = environ.createMap(allocator) catch unreachable;
|
|
defer env.deinit();
|
|
ui.runCmd(&.{shell}, browser.dir_path, &env, false);
|
|
state = .browse;
|
|
@@ -622,14 +636,15 @@ pub fn main() void {
|
|
}
|
|
}
|
|
|
|
-pub var event_delay_timer: std.time.Timer = undefined;
|
|
+pub var event_delay_timer: std.Io.Timestamp = .zero;
|
|
|
|
// Draw the screen and handle the next input event.
|
|
// In non-blocking mode, screen drawing is rate-limited to keep this function fast.
|
|
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) {
|
|
+ const elapsed = event_delay_timer.durationTo(std.Io.Timestamp.now(io, .awake)).toNanoseconds();
|
|
+ if (block or force_draw or elapsed > config.update_delay) {
|
|
if (ui.inited) _ = c.erase();
|
|
switch (state) {
|
|
.scan, .refresh => sink.draw(),
|
|
@@ -638,7 +653,7 @@ pub fn handleEvent(block: bool, force_draw: bool) void {
|
|
.shell => unreachable,
|
|
}
|
|
if (ui.inited) _ = c.refresh();
|
|
- event_delay_timer.reset();
|
|
+ event_delay_timer = std.Io.Timestamp.now(io, .awake);
|
|
}
|
|
if (!ui.inited) {
|
|
std.debug.assert(!block);
|
|
diff --git a/src/mem_sink.zig b/src/mem_sink.zig
|
|
index 37b0ece..9973fb7 100644
|
|
--- a/src/mem_sink.zig
|
|
+++ b/src/mem_sink.zig
|
|
@@ -28,8 +28,8 @@ pub fn statToEntry(stat: *const sink.Stat, e: *model.Entry, parent: *model.Dir)
|
|
l.parent = parent;
|
|
l.ino = stat.ino;
|
|
l.pack.nlink = stat.nlink;
|
|
- model.inodes.lock.lock();
|
|
- defer model.inodes.lock.unlock();
|
|
+ model.inodes.lock.lockUncancelable(main.io);
|
|
+ defer model.inodes.lock.unlock(main.io);
|
|
l.addLink();
|
|
}
|
|
if (e.ext()) |ext| ext.* = stat.ext;
|
|
@@ -49,7 +49,7 @@ pub const Dir = struct {
|
|
items: u32 = 0,
|
|
mtime: u64 = 0,
|
|
suberr: bool = false,
|
|
- lock: std.Thread.Mutex = .{},
|
|
+ lock: std.Io.Mutex = .init,
|
|
|
|
const Map = std.HashMap(*model.Entry, void, HashContext, 80);
|
|
|
|
@@ -161,8 +161,8 @@ pub const Dir = struct {
|
|
|
|
// Add own counts to parent
|
|
if (parent) |p| {
|
|
- p.lock.lock();
|
|
- defer p.lock.unlock();
|
|
+ p.lock.lockUncancelable(main.io);
|
|
+ defer p.lock.unlock(main.io);
|
|
p.blocks +|= self.dir.entry.pack.blocks - self.own_blocks;
|
|
p.bytes +|= self.dir.entry.size - self.own_bytes;
|
|
p.items +|= self.dir.items;
|
|
diff --git a/src/model.zig b/src/model.zig
|
|
index b428d24..87c94a1 100644
|
|
--- a/src/model.zig
|
|
+++ b/src/model.zig
|
|
@@ -211,7 +211,7 @@ pub const Dir = extern struct {
|
|
// (Old C habits die hard)
|
|
name: [0]u8 = undefined,
|
|
|
|
- pub const Packed = packed struct {
|
|
+ pub const Packed = packed struct(u32) {
|
|
// Indexes into the global 'devices.list' array
|
|
dev: DevId = 0,
|
|
err: bool = false,
|
|
@@ -350,15 +350,15 @@ pub const Ext = extern struct {
|
|
// List of st_dev entries. Those are typically 64bits, but that's quite a waste
|
|
// of space when a typical scan won't cover many unique devices.
|
|
pub const devices = struct {
|
|
- var lock = std.Thread.Mutex{};
|
|
+ var lock = std.Io.Mutex.init;
|
|
// id -> dev
|
|
pub var list: std.ArrayListUnmanaged(u64) = .empty;
|
|
// dev -> id
|
|
var lookup = std.AutoHashMap(u64, DevId).init(main.allocator);
|
|
|
|
pub fn getId(dev: u64) DevId {
|
|
- lock.lock();
|
|
- defer lock.unlock();
|
|
+ lock.lockUncancelable(main.io);
|
|
+ defer lock.unlock(main.io);
|
|
const d = lookup.getOrPut(dev) catch unreachable;
|
|
if (!d.found_existing) {
|
|
if (list.items.len >= std.math.maxInt(DevId)) ui.die("Maximum number of device identifiers exceeded.\n", .{});
|
|
@@ -386,7 +386,7 @@ pub const inodes = struct {
|
|
var uncounted = std.HashMap(*Link, void, HashContext, 80).init(main.allocator);
|
|
var uncounted_full = true; // start with true for the initial scan
|
|
|
|
- pub var lock = std.Thread.Mutex{};
|
|
+ pub var lock = std.Io.Mutex.init;
|
|
|
|
const HashContext = struct {
|
|
pub fn hash(_: @This(), l: *Link) u64 {
|
|
diff --git a/src/scan.zig b/src/scan.zig
|
|
index d98bf73..f61d4bf 100644
|
|
--- a/src/scan.zig
|
|
+++ b/src/scan.zig
|
|
@@ -12,9 +12,9 @@ const c = @import("c.zig").c;
|
|
|
|
|
|
// This function only works on Linux
|
|
-fn isKernfs(dir: std.fs.Dir) bool {
|
|
+fn isKernfs(dir: std.Io.Dir) bool {
|
|
var buf: c.struct_statfs = undefined;
|
|
- if (c.fstatfs(dir.fd, &buf) != 0) return false; // silently ignoring errors isn't too nice.
|
|
+ if (c.fstatfs(dir.handle, &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
|
|
@@ -46,10 +46,10 @@ fn truncate(comptime T: type, comptime field: anytype, x: anytype) std.meta.fiel
|
|
}
|
|
|
|
|
|
-pub fn statAt(parent: std.fs.Dir, name: [:0]const u8, follow: bool, symlink: ?*bool) !sink.Stat {
|
|
+pub fn statAt(parent: std.Io.Dir, name: [:0]const u8, follow: bool, symlink: ?*bool) !sink.Stat {
|
|
// std.posix.fstatatZ() in Zig 0.14 is not suitable due to https://github.com/ziglang/zig/issues/23463
|
|
var stat: std.c.Stat = undefined;
|
|
- if (std.c.fstatat(parent.fd, name, &stat, if (follow) 0 else std.c.AT.SYMLINK_NOFOLLOW) != 0) {
|
|
+ if (std.c.fstatat(parent.handle, name, &stat, if (follow) 0 else std.c.AT.SYMLINK_NOFOLLOW) != 0) {
|
|
return switch (std.c._errno().*) {
|
|
@intFromEnum(std.c.E.NOENT) => error.FileNotFound,
|
|
@intFromEnum(std.c.E.NAMETOOLONG) => error.NameTooLong,
|
|
@@ -86,12 +86,12 @@ pub fn statAt(parent: std.fs.Dir, name: [:0]const u8, follow: bool, symlink: ?*b
|
|
}
|
|
|
|
|
|
-fn isCacheDir(dir: std.fs.Dir) bool {
|
|
+fn isCacheDir(dir: std.Io.Dir) bool {
|
|
const sig = "Signature: 8a477f597d28d172789f06886806bc55";
|
|
- const f = dir.openFileZ("CACHEDIR.TAG", .{}) catch return false;
|
|
- defer f.close();
|
|
+ const f = dir.openFile(main.io, "CACHEDIR.TAG", .{}) catch return false;
|
|
+ defer f.close(main.io);
|
|
var buf: [sig.len]u8 = undefined;
|
|
- const len = f.readAll(&buf) catch return false;
|
|
+ const len = f.readStreaming(main.io, &.{&buf}) catch return false;
|
|
return len == sig.len and std.mem.eql(u8, &buf, sig);
|
|
}
|
|
|
|
@@ -107,8 +107,8 @@ const State = struct {
|
|
// impossible for me to predict how that ends up affecting performance.
|
|
queue: [QUEUE_SIZE]*Dir = undefined,
|
|
queue_len: std.atomic.Value(usize) = std.atomic.Value(usize).init(0),
|
|
- queue_lock: std.Thread.Mutex = .{},
|
|
- queue_cond: std.Thread.Condition = .{},
|
|
+ queue_lock: std.Io.Mutex = .init,
|
|
+ queue_cond: std.Io.Condition = .init,
|
|
|
|
threads: []Thread,
|
|
waiting: usize = 0,
|
|
@@ -121,28 +121,28 @@ const State = struct {
|
|
fn tryPush(self: *State, d: *Dir) bool {
|
|
if (self.queue_len.load(.acquire) == QUEUE_SIZE) return false;
|
|
{
|
|
- self.queue_lock.lock();
|
|
- defer self.queue_lock.unlock();
|
|
+ self.queue_lock.lockUncancelable(main.io);
|
|
+ defer self.queue_lock.unlock(main.io);
|
|
if (self.queue_len.load(.monotonic) == QUEUE_SIZE) return false;
|
|
const slot = self.queue_len.fetchAdd(1, .monotonic);
|
|
self.queue[slot] = d;
|
|
}
|
|
- self.queue_cond.signal();
|
|
+ self.queue_cond.signal(main.io);
|
|
return true;
|
|
}
|
|
|
|
// Blocks while the queue is empty, returns null when all threads are blocking.
|
|
fn waitPop(self: *State) ?*Dir {
|
|
- self.queue_lock.lock();
|
|
- defer self.queue_lock.unlock();
|
|
+ self.queue_lock.lockUncancelable(main.io);
|
|
+ defer self.queue_lock.unlock(main.io);
|
|
|
|
self.waiting += 1;
|
|
while (self.queue_len.load(.monotonic) == 0) {
|
|
if (self.waiting == self.threads.len) {
|
|
- self.queue_cond.broadcast();
|
|
+ self.queue_cond.broadcast(main.io);
|
|
return null;
|
|
}
|
|
- self.queue_cond.wait(&self.queue_lock);
|
|
+ self.queue_cond.waitUncancelable(main.io, &self.queue_lock);
|
|
}
|
|
self.waiting -= 1;
|
|
|
|
@@ -154,13 +154,13 @@ const State = struct {
|
|
|
|
|
|
const Dir = struct {
|
|
- fd: std.fs.Dir,
|
|
+ fd: std.Io.Dir,
|
|
dev: u64,
|
|
pat: exclude.Patterns,
|
|
- it: std.fs.Dir.Iterator,
|
|
+ it: std.Io.Dir.Iterator,
|
|
sink: *sink.Dir,
|
|
|
|
- fn create(fd: std.fs.Dir, dev: u64, pat: exclude.Patterns, s: *sink.Dir) *Dir {
|
|
+ fn create(fd: std.Io.Dir, dev: u64, pat: exclude.Patterns, s: *sink.Dir) *Dir {
|
|
const d = main.allocator.create(Dir) catch unreachable;
|
|
d.* = .{
|
|
.fd = fd,
|
|
@@ -174,7 +174,7 @@ const Dir = struct {
|
|
|
|
fn destroy(d: *Dir, t: *Thread) void {
|
|
d.pat.deinit();
|
|
- d.fd.close();
|
|
+ d.fd.close(main.io);
|
|
d.sink.unref(t.sink);
|
|
main.allocator.destroy(d);
|
|
}
|
|
@@ -239,7 +239,7 @@ const Thread = struct {
|
|
return;
|
|
}
|
|
|
|
- var edir = dir.fd.openDirZ(name, .{ .no_follow = true, .iterate = true }) catch {
|
|
+ var edir = dir.fd.openDir(main.io, name, .{ .follow_symlinks = false, .iterate = true }) catch {
|
|
const s = dir.sink.addDir(t.sink, name, &stat);
|
|
s.setReadError(t.sink);
|
|
s.unref(t.sink);
|
|
@@ -251,14 +251,14 @@ const Thread = struct {
|
|
and stat.dev != dir.dev
|
|
and isKernfs(edir)
|
|
) {
|
|
- edir.close();
|
|
+ edir.close(main.io);
|
|
dir.sink.addSpecial(t.sink, name, .kernfs);
|
|
return;
|
|
}
|
|
|
|
if (main.config.exclude_caches and isCacheDir(edir)) {
|
|
dir.sink.addSpecial(t.sink, name, .pattern);
|
|
- edir.close();
|
|
+ edir.close(main.io);
|
|
return;
|
|
}
|
|
|
|
@@ -279,7 +279,7 @@ const Thread = struct {
|
|
t.sink.setDir(d.sink);
|
|
if (t.thread_num == 0) main.handleEvent(false, false);
|
|
|
|
- const entry = d.it.next() catch blk: {
|
|
+ const entry = d.it.next(main.io) catch blk: {
|
|
dir.sink.setReadError(t.sink);
|
|
break :blk null;
|
|
};
|
|
@@ -299,8 +299,8 @@ pub fn scan(path: [:0]const u8) !void {
|
|
defer sink.done();
|
|
|
|
var symlink: bool = undefined;
|
|
- const stat = try statAt(std.fs.cwd(), path, true, &symlink);
|
|
- const fd = try std.fs.cwd().openDirZ(path, .{ .iterate = true });
|
|
+ const stat = try statAt(std.Io.Dir.cwd(), path, true, &symlink);
|
|
+ const fd = try std.Io.Dir.cwd().openDir(main.io, path, .{ .iterate = true });
|
|
|
|
var state = State{
|
|
.threads = main.allocator.alloc(Thread, main.config.threads) catch unreachable,
|
|
diff --git a/src/sink.zig b/src/sink.zig
|
|
index 71e95cd..ca0f595 100644
|
|
--- a/src/sink.zig
|
|
+++ b/src/sink.zig
|
|
@@ -86,8 +86,8 @@ pub const Dir = struct {
|
|
.bin => |*b| b.addSpecial(&t.sink.bin, name, sp),
|
|
}
|
|
if (sp == .err) {
|
|
- global.last_error_lock.lock();
|
|
- defer global.last_error_lock.unlock();
|
|
+ global.last_error_lock.lockUncancelable(main.io);
|
|
+ defer global.last_error_lock.unlock(main.io);
|
|
if (global.last_error) |p| main.allocator.free(p);
|
|
const p = d.path();
|
|
global.last_error = std.fs.path.joinZ(main.allocator, &.{ p, name }) catch unreachable;
|
|
@@ -133,8 +133,8 @@ pub const Dir = struct {
|
|
.json => |*j| j.setReadError(),
|
|
.bin => |*b| b.setReadError(),
|
|
}
|
|
- global.last_error_lock.lock();
|
|
- defer global.last_error_lock.unlock();
|
|
+ global.last_error_lock.lockUncancelable(main.io);
|
|
+ defer global.last_error_lock.unlock(main.io);
|
|
if (global.last_error) |p| main.allocator.free(p);
|
|
global.last_error = d.path();
|
|
}
|
|
@@ -180,7 +180,7 @@ pub const Dir = struct {
|
|
|
|
pub const Thread = struct {
|
|
current_dir: ?*Dir = null,
|
|
- lock: std.Thread.Mutex = .{},
|
|
+ lock: std.Io.Mutex = .init,
|
|
// On 32-bit architectures, bytes_seen is protected by the above mutex instead.
|
|
bytes_seen: std.atomic.Value(u64) = std.atomic.Value(u64).init(0),
|
|
files_seen: std.atomic.Value(u32) = std.atomic.Value(u32).init(0),
|
|
@@ -194,8 +194,8 @@ pub const Thread = struct {
|
|
fn addBytes(t: *Thread, bytes: u64) void {
|
|
if (@bitSizeOf(usize) >= 64) _ = t.bytes_seen.fetchAdd(bytes, .monotonic)
|
|
else {
|
|
- t.lock.lock();
|
|
- defer t.lock.unlock();
|
|
+ t.lock.lockUncancelable(main.io);
|
|
+ defer t.lock.unlock(main.io);
|
|
t.bytes_seen.raw += bytes;
|
|
}
|
|
}
|
|
@@ -203,15 +203,15 @@ pub const Thread = struct {
|
|
fn getBytes(t: *Thread) u64 {
|
|
if (@bitSizeOf(usize) >= 64) return t.bytes_seen.load(.monotonic)
|
|
else {
|
|
- t.lock.lock();
|
|
- defer t.lock.unlock();
|
|
+ t.lock.lockUncancelable(main.io);
|
|
+ defer t.lock.unlock(main.io);
|
|
return t.bytes_seen.raw;
|
|
}
|
|
}
|
|
|
|
pub fn setDir(t: *Thread, d: ?*Dir) void {
|
|
- t.lock.lock();
|
|
- defer t.lock.unlock();
|
|
+ t.lock.lockUncancelable(main.io);
|
|
+ defer t.lock.unlock(main.io);
|
|
t.current_dir = d;
|
|
}
|
|
};
|
|
@@ -223,7 +223,7 @@ pub const global = struct {
|
|
pub var sink: enum { json, mem, bin } = .mem;
|
|
|
|
pub var last_error: ?[:0]u8 = null;
|
|
- var last_error_lock = std.Thread.Mutex{};
|
|
+ var last_error_lock = std.Io.Mutex.init;
|
|
var need_confirm_quit = false;
|
|
};
|
|
|
|
@@ -292,16 +292,15 @@ fn drawConsole() void {
|
|
var ansi: ?bool = null;
|
|
var lines_written: usize = 0;
|
|
};
|
|
- const stderr = if (@hasDecl(std.io, "getStdErr")) std.io.getStdErr() else std.fs.File.stderr();
|
|
+ const stderr = std.Io.File.stderr();
|
|
const ansi = st.ansi orelse blk: {
|
|
- const t = stderr.supportsAnsiEscapeCodes();
|
|
+ const t = stderr.supportsAnsiEscapeCodes(main.io) catch false;
|
|
st.ansi = t;
|
|
break :blk t;
|
|
};
|
|
|
|
var buf: [4096]u8 = undefined;
|
|
- var strm = std.io.fixedBufferStream(buf[0..]);
|
|
- var wr = strm.writer();
|
|
+ var wr = std.Io.Writer.fixed(&buf);
|
|
while (ansi and st.lines_written > 0) {
|
|
wr.writeAll("\x1b[1F\x1b[2K") catch {};
|
|
st.lines_written -= 1;
|
|
@@ -327,8 +326,8 @@ fn drawConsole() void {
|
|
|
|
for (global.threads, 0..) |*t, i| {
|
|
const dir = blk: {
|
|
- t.lock.lock();
|
|
- defer t.lock.unlock();
|
|
+ t.lock.lockUncancelable(main.io);
|
|
+ defer t.lock.unlock(main.io);
|
|
break :blk if (t.current_dir) |d| d.path() else null;
|
|
};
|
|
wr.print(" #{}: {s}\n", .{i+1, ui.shorten(ui.toUtf8(dir orelse "(waiting)"), 73)}) catch {};
|
|
@@ -337,7 +336,7 @@ fn drawConsole() void {
|
|
}
|
|
}
|
|
|
|
- stderr.writeAll(strm.getWritten()) catch {};
|
|
+ stderr.writeStreamingAll(main.io, wr.buffered()) catch {};
|
|
}
|
|
|
|
|
|
@@ -369,8 +368,8 @@ fn drawProgress() void {
|
|
box.move(3+@as(u32, @intCast(i)), 4);
|
|
const dir = blk: {
|
|
const t = &global.threads[i];
|
|
- t.lock.lock();
|
|
- defer t.lock.unlock();
|
|
+ t.lock.lockUncancelable(main.io);
|
|
+ defer t.lock.unlock(main.io);
|
|
break :blk if (t.current_dir) |d| d.path() else null;
|
|
};
|
|
ui.addstr(ui.shorten(ui.toUtf8(dir orelse "(waiting)"), width -| 6));
|
|
@@ -378,8 +377,8 @@ fn drawProgress() void {
|
|
}
|
|
|
|
blk: {
|
|
- global.last_error_lock.lock();
|
|
- defer global.last_error_lock.unlock();
|
|
+ global.last_error_lock.lockUncancelable(main.io);
|
|
+ defer global.last_error_lock.unlock(main.io);
|
|
const err = global.last_error orelse break :blk;
|
|
box.move(4 + numthreads, 2);
|
|
ui.style(.bold);
|
|
diff --git a/src/ui.zig b/src/ui.zig
|
|
index 1436b6e..c7e5e30 100644
|
|
--- a/src/ui.zig
|
|
+++ b/src/ui.zig
|
|
@@ -26,7 +26,9 @@ pub fn quit() noreturn {
|
|
std.process.exit(0);
|
|
}
|
|
|
|
-const sleep = if (@hasDecl(std.time, "sleep")) std.time.sleep else std.Thread.sleep;
|
|
+fn sleep(ns: u64) void {
|
|
+ main.io.sleep(.fromNanoseconds(@intCast(ns)), .awake) catch {};
|
|
+}
|
|
|
|
// Should be called when malloc fails. Will show a message to the user, wait
|
|
// for a second and return to give it another try.
|
|
@@ -113,7 +115,8 @@ pub fn toUtf8(in: [:0]const u8) [:0]const u8 {
|
|
} else |_| {}
|
|
}
|
|
} else |_| {}
|
|
- to_utf8_buf.writer(main.allocator).print("\\x{X:0>2}", .{in[i]}) catch unreachable;
|
|
+ var buf: [4]u8 = undefined;
|
|
+ to_utf8_buf.appendSlice(main.allocator, std.fmt.bufPrint(&buf, "\\x{X:0>2}", .{in[i]}) catch unreachable) catch unreachable;
|
|
i += 1;
|
|
}
|
|
return util.arrayListBufZ(&to_utf8_buf, main.allocator);
|
|
@@ -280,21 +283,13 @@ const styles = [_]StyleDef{
|
|
};
|
|
|
|
pub const Style = lbl: {
|
|
- var fields: [styles.len]std.builtin.Type.EnumField = undefined;
|
|
- for (&fields, styles, 0..) |*field, s, i| {
|
|
- field.* = .{
|
|
- .name = s.name,
|
|
- .value = i,
|
|
- };
|
|
+ var field_names: [styles.len][]const u8 = undefined;
|
|
+ var field_values: [styles.len]u8 = undefined;
|
|
+ for (&field_names, &field_values, styles, 0..) |*name, *value, s, i| {
|
|
+ name.* = s.name;
|
|
+ value.* = i;
|
|
}
|
|
- break :lbl @Type(.{
|
|
- .@"enum" = .{
|
|
- .tag_type = u8,
|
|
- .fields = &fields,
|
|
- .decls = &[_]std.builtin.Type.Declaration{},
|
|
- .is_exhaustive = true,
|
|
- }
|
|
- });
|
|
+ break :lbl @Enum(u8, .exhaustive, &field_names, &field_values);
|
|
};
|
|
|
|
const ui = @This();
|
|
@@ -643,16 +638,12 @@ pub fn getch(block: bool) i32 {
|
|
}
|
|
|
|
fn waitInput() void {
|
|
- if (@hasDecl(std.io, "getStdIn")) {
|
|
- std.io.getStdIn().reader().skipUntilDelimiterOrEof('\n') catch unreachable;
|
|
- } else {
|
|
- var buf: [512]u8 = undefined;
|
|
- var rd = std.fs.File.stdin().reader(&buf);
|
|
- _ = rd.interface.discardDelimiterExclusive('\n') catch unreachable;
|
|
- }
|
|
+ var buf: [512]u8 = undefined;
|
|
+ var rd = std.Io.File.stdin().reader(main.io, &buf);
|
|
+ _ = rd.interface.discardDelimiterExclusive('\n') catch unreachable;
|
|
}
|
|
|
|
-pub fn runCmd(cmd: []const []const u8, cwd: ?[]const u8, env: *std.process.EnvMap, reporterr: bool) void {
|
|
+pub fn runCmd(cmd: []const []const u8, cwd: ?[]const u8, env: *std.process.Environ.Map, reporterr: bool) void {
|
|
deinit();
|
|
defer init();
|
|
|
|
@@ -666,24 +657,33 @@ pub fn runCmd(cmd: []const []const u8, cwd: ?[]const u8, env: *std.process.EnvMa
|
|
else
|
|
env.put("NCDU_LEVEL", "1") catch unreachable;
|
|
|
|
- var child = std.process.Child.init(cmd, main.allocator);
|
|
- child.cwd = cwd;
|
|
- child.env_map = env;
|
|
-
|
|
- const term = child.spawnAndWait() catch |e| blk: {
|
|
+ var child = std.process.spawn(main.io, .{
|
|
+ .argv = cmd,
|
|
+ .cwd = if (cwd) |p| .{ .path = p } else .inherit,
|
|
+ .environ_map = env,
|
|
+ }) catch |e| blk: {
|
|
std.debug.print("Error running command: {s}\n\nPress enter to continue.\n", .{ ui.errorString(e) });
|
|
waitInput();
|
|
- break :blk std.process.Child.Term{ .Exited = 0 };
|
|
+ break :blk null;
|
|
};
|
|
+ const term = if (child) |*c_| c_.wait(main.io) catch |e| blk: {
|
|
+ std.debug.print("Error running command: {s}\n\nPress enter to continue.\n", .{ ui.errorString(e) });
|
|
+ waitInput();
|
|
+ break :blk std.process.Child.Term{ .exited = 0 };
|
|
+ } else std.process.Child.Term{ .exited = 0 };
|
|
|
|
const n = switch (term) {
|
|
- .Exited => "error",
|
|
- .Signal => "signal",
|
|
- .Stopped => "stopped",
|
|
- .Unknown => "unknown",
|
|
+ .exited => "error",
|
|
+ .signal => "signal",
|
|
+ .stopped => "stopped",
|
|
+ .unknown => "unknown",
|
|
+ };
|
|
+ const v: u32 = switch (term) {
|
|
+ .exited => |v_| v_,
|
|
+ .signal, .stopped => |v_| @intFromEnum(v_),
|
|
+ .unknown => |v_| v_,
|
|
};
|
|
- const v = switch (term) { inline else => |v| v };
|
|
- if (term != .Exited or (reporterr and v != 0)) {
|
|
+ if (term != .exited or (reporterr and v != 0)) {
|
|
std.debug.print("\nCommand returned with {s} code {}.\nPress enter to continue.\n", .{ n, v });
|
|
waitInput();
|
|
}
|
|
diff --git a/src/util.zig b/src/util.zig
|
|
index 607dfb5..1d41b05 100644
|
|
--- a/src/util.zig
|
|
+++ b/src/util.zig
|
|
@@ -180,7 +180,7 @@ pub fn expanduser(path: []const u8, alloc: std.mem.Allocator) ![:0]u8 {
|
|
const home_raw = blk: {
|
|
const pwd = pwd: {
|
|
if (len == 1) {
|
|
- if (std.posix.getenvZ("HOME")) |p| break :blk p;
|
|
+ if (std.c.getenv("HOME")) |p| break :blk std.mem.sliceTo(p, 0);
|
|
break :pwd c.getpwuid(c.getuid());
|
|
} else {
|
|
const name = try alloc.dupeZ(u8, path[1..len]);
|
|
@@ -193,7 +193,7 @@ pub fn expanduser(path: []const u8, alloc: std.mem.Allocator) ![:0]u8 {
|
|
break :blk std.mem.span(p);
|
|
return alloc.dupeZ(u8, path);
|
|
};
|
|
- const home = std.mem.trimRight(u8, home_raw, "/");
|
|
+ const home = std.mem.trimEnd(u8, home_raw, "/");
|
|
|
|
if (home.len == 0 and path.len == len) return alloc.dupeZ(u8, "/");
|
|
return try std.mem.concatWithSentinel(alloc, u8, &.{ home, path[len..] }, 0);
|
|
@@ -203,47 +203,14 @@ pub fn expanduser(path: []const u8, alloc: std.mem.Allocator) ![:0]u8 {
|
|
// Silly abstraction to read a file one line at a time. Only exists to help
|
|
// with supporting both Zig 0.14 and 0.15, can be removed once 0.14 support is
|
|
// dropped.
|
|
-pub const LineReader = if (@hasDecl(std.io, "bufferedReader")) struct {
|
|
- rd: std.io.BufferedReader(4096, std.fs.File.Reader),
|
|
- fbs: std.io.FixedBufferStream([]u8),
|
|
-
|
|
- pub fn init(f: std.fs.File, buf: []u8) @This() {
|
|
- return .{
|
|
- .rd = std.io.bufferedReader(f.reader()),
|
|
- .fbs = std.io.fixedBufferStream(buf),
|
|
- };
|
|
- }
|
|
-
|
|
- pub fn read(s: *@This()) !?[]u8 {
|
|
- s.fbs.reset();
|
|
- s.rd.reader().streamUntilDelimiter(s.fbs.writer(), '\n', s.fbs.buffer.len) catch |err| switch (err) {
|
|
- error.EndOfStream => if (s.fbs.getPos() catch unreachable == 0) return null,
|
|
- else => |e| return e,
|
|
- };
|
|
- return s.fbs.getWritten();
|
|
- }
|
|
+pub const LineReader = struct {
|
|
+ rd: std.Io.File.Reader,
|
|
|
|
-} else struct {
|
|
- rd: std.fs.File.Reader,
|
|
-
|
|
- pub fn init(f: std.fs.File, buf: []u8) @This() {
|
|
- return .{ .rd = f.readerStreaming(buf) };
|
|
+ pub fn init(f: std.Io.File, io: std.Io, buf: []u8) @This() {
|
|
+ return .{ .rd = f.readerStreaming(io, buf) };
|
|
}
|
|
|
|
pub fn read(s: *@This()) !?[]u8 {
|
|
- // Can't use takeDelimiter() because that's not available in 0.15.1,
|
|
- // Can't use takeDelimiterExclusive() because that changed behavior in 0.15.2.
|
|
- const r = &s.rd.interface;
|
|
- const result = r.peekDelimiterInclusive('\n') catch |err| switch (err) {
|
|
- error.EndOfStream => {
|
|
- const remaining = r.buffer[r.seek..r.end];
|
|
- if (remaining.len == 0) return null;
|
|
- r.toss(remaining.len);
|
|
- return remaining;
|
|
- },
|
|
- else => |e| return e,
|
|
- };
|
|
- r.toss(result.len);
|
|
- return result[0 .. result.len - 1];
|
|
+ return s.rd.interface.takeDelimiter('\n');
|
|
}
|
|
};
|