mirror of
https://code.blicky.net/yorhel/ncdu.git
synced 2026-01-12 17:08:39 -09:00
Zig 0.15: Fix support for new IO interface
I've managed to get a single codebase to build with both 0.14 and 0.15 now, but compiling with Zig's native x86_64 backend seems buggy. Need to investigate what's going on there. This is a lazy "just get it to work" migration and avoids the use of 0.15-exclusive APIs. We can probably clean up some code when dropping support for 0.14.
This commit is contained in:
parent
68671a1af1
commit
5129de737e
7 changed files with 78 additions and 54 deletions
|
|
@ -19,7 +19,7 @@ C version (1.x).
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
- Zig 0.14
|
- Zig 0.14 or 0.15
|
||||||
- Some sort of POSIX-like OS
|
- Some sort of POSIX-like OS
|
||||||
- ncurses
|
- ncurses
|
||||||
- libzstd
|
- libzstd
|
||||||
|
|
|
||||||
41
src/main.zig
41
src/main.zig
|
|
@ -118,6 +118,9 @@ pub const config = struct {
|
||||||
|
|
||||||
pub var state: enum { scan, browse, refresh, shell, delete } = .scan;
|
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();
|
||||||
|
|
||||||
// Simple generic argument parser, supports getopt_long() style arguments.
|
// Simple generic argument parser, supports getopt_long() style arguments.
|
||||||
const Args = struct {
|
const Args = struct {
|
||||||
lst: []const [:0]const u8,
|
lst: []const [:0]const u8,
|
||||||
|
|
@ -327,19 +330,13 @@ fn tryReadArgsFile(path: [:0]const u8) void {
|
||||||
};
|
};
|
||||||
defer f.close();
|
defer f.close();
|
||||||
|
|
||||||
var rd_ = std.io.bufferedReader(f.reader());
|
|
||||||
const rd = rd_.reader();
|
|
||||||
|
|
||||||
var line_buf: [4096]u8 = undefined;
|
var line_buf: [4096]u8 = undefined;
|
||||||
var line_fbs = std.io.fixedBufferStream(&line_buf);
|
var line_rd = util.LineReader.init(f, &line_buf);
|
||||||
const line_writer = line_fbs.writer();
|
|
||||||
|
|
||||||
while (true) : (line_fbs.reset()) {
|
while (true) {
|
||||||
rd.streamUntilDelimiter(line_writer, '\n', line_buf.len) catch |err| switch (err) {
|
const line_ = (line_rd.read() catch |e|
|
||||||
error.EndOfStream => if (line_fbs.getPos() catch unreachable == 0) break,
|
ui.die("Error reading from {s}: {s}\nRun with --ignore-config to skip reading config files.\n", .{ path, ui.errorString(e) })
|
||||||
else => |e| ui.die("Error reading from {s}: {s}\nRun with --ignore-config to skip reading config files.\n", .{ path, ui.errorString(e) }),
|
) orelse break;
|
||||||
};
|
|
||||||
const line_ = line_fbs.getWritten();
|
|
||||||
|
|
||||||
var argc: usize = 0;
|
var argc: usize = 0;
|
||||||
var ignerror = false;
|
var ignerror = false;
|
||||||
|
|
@ -374,13 +371,11 @@ fn tryReadArgsFile(path: [:0]const u8) void {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn version() noreturn {
|
fn version() noreturn {
|
||||||
const stdout = std.io.getStdOut();
|
|
||||||
stdout.writeAll("ncdu " ++ program_version ++ "\n") catch {};
|
stdout.writeAll("ncdu " ++ program_version ++ "\n") catch {};
|
||||||
std.process.exit(0);
|
std.process.exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn help() noreturn {
|
fn help() noreturn {
|
||||||
const stdout = std.io.getStdOut();
|
|
||||||
stdout.writeAll(
|
stdout.writeAll(
|
||||||
\\ncdu <options> <directory>
|
\\ncdu <options> <directory>
|
||||||
\\
|
\\
|
||||||
|
|
@ -443,19 +438,9 @@ fn readExcludeFile(path: [:0]const u8) !void {
|
||||||
const f = try std.fs.cwd().openFileZ(path, .{});
|
const f = try std.fs.cwd().openFileZ(path, .{});
|
||||||
defer f.close();
|
defer f.close();
|
||||||
|
|
||||||
var rd_ = std.io.bufferedReader(f.reader());
|
|
||||||
const rd = rd_.reader();
|
|
||||||
|
|
||||||
var line_buf: [4096]u8 = undefined;
|
var line_buf: [4096]u8 = undefined;
|
||||||
var line_fbs = std.io.fixedBufferStream(&line_buf);
|
var line_rd = util.LineReader.init(f, &line_buf);
|
||||||
const line_writer = line_fbs.writer();
|
while (try line_rd.read()) |line| {
|
||||||
|
|
||||||
while (true) : (line_fbs.reset()) {
|
|
||||||
rd.streamUntilDelimiter(line_writer, '\n', line_buf.len) catch |err| switch (err) {
|
|
||||||
error.EndOfStream => if (line_fbs.getPos() catch unreachable == 0) break,
|
|
||||||
else => |e| return e,
|
|
||||||
};
|
|
||||||
const line = line_fbs.getWritten();
|
|
||||||
if (line.len > 0)
|
if (line.len > 0)
|
||||||
exclude.addPattern(line);
|
exclude.addPattern(line);
|
||||||
}
|
}
|
||||||
|
|
@ -463,12 +448,12 @@ fn readExcludeFile(path: [:0]const u8) !void {
|
||||||
|
|
||||||
fn readImport(path: [:0]const u8) !void {
|
fn readImport(path: [:0]const u8) !void {
|
||||||
const fd =
|
const fd =
|
||||||
if (std.mem.eql(u8, "-", path)) std.io.getStdIn()
|
if (std.mem.eql(u8, "-", path)) stdin
|
||||||
else try std.fs.cwd().openFileZ(path, .{});
|
else try std.fs.cwd().openFileZ(path, .{});
|
||||||
errdefer fd.close();
|
errdefer fd.close();
|
||||||
|
|
||||||
var buf: [8]u8 = undefined;
|
var buf: [8]u8 = undefined;
|
||||||
try fd.reader().readNoEof(&buf);
|
if (8 != try fd.readAll(&buf)) return error.EndOfStream;
|
||||||
if (std.mem.eql(u8, &buf, bin_export.SIGNATURE)) {
|
if (std.mem.eql(u8, &buf, bin_export.SIGNATURE)) {
|
||||||
try bin_reader.open(fd);
|
try bin_reader.open(fd);
|
||||||
config.binreader = true;
|
config.binreader = true;
|
||||||
|
|
@ -550,8 +535,6 @@ pub fn main() void {
|
||||||
if (@import("builtin").os.tag != .linux and config.exclude_kernfs)
|
if (@import("builtin").os.tag != .linux and config.exclude_kernfs)
|
||||||
ui.die("The --exclude-kernfs flag is currently only supported on Linux.\n", .{});
|
ui.die("The --exclude-kernfs flag is currently only supported on Linux.\n", .{});
|
||||||
|
|
||||||
const stdin = std.io.getStdIn();
|
|
||||||
const stdout = std.io.getStdOut();
|
|
||||||
const out_tty = stdout.isTty();
|
const out_tty = stdout.isTty();
|
||||||
const in_tty = stdin.isTty();
|
const in_tty = stdin.isTty();
|
||||||
if (config.scan_ui == null) {
|
if (config.scan_ui == null) {
|
||||||
|
|
|
||||||
|
|
@ -109,7 +109,8 @@ pub const Entry = extern struct {
|
||||||
fn alloc(comptime T: type, allocator: std.mem.Allocator, etype: EType, isext: bool, ename: []const u8) *Entry {
|
fn alloc(comptime T: type, allocator: std.mem.Allocator, etype: EType, isext: bool, ename: []const u8) *Entry {
|
||||||
const size = (if (isext) @as(usize, @sizeOf(Ext)) else 0) + @sizeOf(T) + ename.len + 1;
|
const size = (if (isext) @as(usize, @sizeOf(Ext)) else 0) + @sizeOf(T) + ename.len + 1;
|
||||||
var ptr = blk: while (true) {
|
var ptr = blk: while (true) {
|
||||||
if (allocator.allocWithOptions(u8, size, 1, null)) |p| break :blk p
|
const alignment = if (@typeInfo(@TypeOf(std.mem.Allocator.allocWithOptions)).@"fn".params[3].type == ?u29) 1 else std.mem.Alignment.@"1";
|
||||||
|
if (allocator.allocWithOptions(u8, size, alignment, null)) |p| break :blk p
|
||||||
else |_| {}
|
else |_| {}
|
||||||
ui.oom();
|
ui.oom();
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -91,7 +91,7 @@ fn isCacheDir(dir: std.fs.Dir) bool {
|
||||||
const f = dir.openFileZ("CACHEDIR.TAG", .{}) catch return false;
|
const f = dir.openFileZ("CACHEDIR.TAG", .{}) catch return false;
|
||||||
defer f.close();
|
defer f.close();
|
||||||
var buf: [sig.len]u8 = undefined;
|
var buf: [sig.len]u8 = undefined;
|
||||||
const len = f.reader().readAll(&buf) catch return false;
|
const len = f.readAll(&buf) catch return false;
|
||||||
return len == sig.len and std.mem.eql(u8, &buf, sig);
|
return len == sig.len and std.mem.eql(u8, &buf, sig);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -292,7 +292,7 @@ fn drawConsole() void {
|
||||||
var ansi: ?bool = null;
|
var ansi: ?bool = null;
|
||||||
var lines_written: usize = 0;
|
var lines_written: usize = 0;
|
||||||
};
|
};
|
||||||
const stderr = std.io.getStdErr();
|
const stderr = if (@hasDecl(std.io, "getStdErr")) std.io.getStdErr() else std.fs.File.stderr();
|
||||||
const ansi = st.ansi orelse blk: {
|
const ansi = st.ansi orelse blk: {
|
||||||
const t = stderr.supportsAnsiEscapeCodes();
|
const t = stderr.supportsAnsiEscapeCodes();
|
||||||
st.ansi = t;
|
st.ansi = t;
|
||||||
|
|
|
||||||
41
src/ui.zig
41
src/ui.zig
|
|
@ -17,8 +17,7 @@ pub var cols: u32 = undefined;
|
||||||
|
|
||||||
pub fn die(comptime fmt: []const u8, args: anytype) noreturn {
|
pub fn die(comptime fmt: []const u8, args: anytype) noreturn {
|
||||||
deinit();
|
deinit();
|
||||||
const stderr = std.io.getStdErr();
|
std.debug.print(fmt, args);
|
||||||
stderr.writer().print(fmt, args) catch {};
|
|
||||||
std.process.exit(1);
|
std.process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -27,6 +26,8 @@ pub fn quit() noreturn {
|
||||||
std.process.exit(0);
|
std.process.exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const sleep = if (@hasDecl(std.time, "sleep")) std.time.sleep else std.Thread.sleep;
|
||||||
|
|
||||||
// Should be called when malloc fails. Will show a message to the user, wait
|
// Should be called when malloc fails. Will show a message to the user, wait
|
||||||
// for a second and return to give it another try.
|
// for a second and return to give it another try.
|
||||||
// Glitch: this function may be called while we're in the process of drawing
|
// Glitch: this function may be called while we're in the process of drawing
|
||||||
|
|
@ -41,14 +42,13 @@ pub fn oom() void {
|
||||||
if (main_thread == std.Thread.getCurrentId()) {
|
if (main_thread == std.Thread.getCurrentId()) {
|
||||||
const haveui = inited;
|
const haveui = inited;
|
||||||
deinit();
|
deinit();
|
||||||
const stderr = std.io.getStdErr();
|
std.debug.print("\x1b7\x1b[JOut of memory, trying again in 1 second. Hit Ctrl-C to abort.\x1b8", .{});
|
||||||
stderr.writeAll("\x1b7\x1b[JOut of memory, trying again in 1 second. Hit Ctrl-C to abort.\x1b8") catch {};
|
sleep(std.time.ns_per_s);
|
||||||
std.time.sleep(std.time.ns_per_s);
|
|
||||||
if (haveui)
|
if (haveui)
|
||||||
init();
|
init();
|
||||||
} else {
|
} else {
|
||||||
_ = oom_threads.fetchAdd(1, .monotonic);
|
_ = oom_threads.fetchAdd(1, .monotonic);
|
||||||
std.time.sleep(std.time.ns_per_s);
|
sleep(std.time.ns_per_s);
|
||||||
_ = oom_threads.fetchSub(1, .monotonic);
|
_ = oom_threads.fetchSub(1, .monotonic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -335,8 +335,7 @@ fn updateSize() void {
|
||||||
fn clearScr() void {
|
fn clearScr() void {
|
||||||
// Send a "clear from cursor to end of screen" instruction, to clear a
|
// Send a "clear from cursor to end of screen" instruction, to clear a
|
||||||
// potential line left behind from scanning in -1 mode.
|
// potential line left behind from scanning in -1 mode.
|
||||||
const stderr = std.io.getStdErr();
|
std.debug.print("\x1b[J", .{});
|
||||||
stderr.writeAll("\x1b[J") catch {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init() void {
|
pub fn init() void {
|
||||||
|
|
@ -634,7 +633,7 @@ pub fn getch(block: bool) i32 {
|
||||||
}
|
}
|
||||||
if (ch == c.ERR) {
|
if (ch == c.ERR) {
|
||||||
if (!block) return 0;
|
if (!block) return 0;
|
||||||
std.time.sleep(10*std.time.ns_per_ms);
|
sleep(10*std.time.ns_per_ms);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
return ch;
|
return ch;
|
||||||
|
|
@ -643,6 +642,15 @@ pub fn getch(block: bool) i32 {
|
||||||
.{ c.strerror(@intFromEnum(std.posix.errno(-1))) });
|
.{ c.strerror(@intFromEnum(std.posix.errno(-1))) });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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.EnvMap, reporterr: bool) void {
|
||||||
deinit();
|
deinit();
|
||||||
|
|
@ -662,14 +670,9 @@ pub fn runCmd(cmd: []const []const u8, cwd: ?[]const u8, env: *std.process.EnvMa
|
||||||
child.cwd = cwd;
|
child.cwd = cwd;
|
||||||
child.env_map = env;
|
child.env_map = env;
|
||||||
|
|
||||||
const stdin = std.io.getStdIn();
|
|
||||||
const stderr = std.io.getStdErr();
|
|
||||||
const term = child.spawnAndWait() catch |e| blk: {
|
const term = child.spawnAndWait() catch |e| blk: {
|
||||||
stderr.writer().print(
|
std.debug.print("Error running command: {s}\n\nPress enter to continue.\n", .{ ui.errorString(e) });
|
||||||
"Error running command: {s}\n\nPress enter to continue.\n",
|
waitInput();
|
||||||
.{ ui.errorString(e) }
|
|
||||||
) catch {};
|
|
||||||
stdin.reader().skipUntilDelimiterOrEof('\n') catch unreachable;
|
|
||||||
break :blk std.process.Child.Term{ .Exited = 0 };
|
break :blk std.process.Child.Term{ .Exited = 0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -681,9 +684,7 @@ pub fn runCmd(cmd: []const []const u8, cwd: ?[]const u8, env: *std.process.EnvMa
|
||||||
};
|
};
|
||||||
const v = switch (term) { inline else => |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)) {
|
||||||
stderr.writer().print(
|
std.debug.print("\nCommand returned with {s} code {}.\nPress enter to continue.\n", .{ n, v });
|
||||||
"\nCommand returned with {s} code {}.\nPress enter to continue.\n", .{ n, v }
|
waitInput();
|
||||||
) catch {};
|
|
||||||
stdin.reader().skipUntilDelimiterOrEof('\n') catch unreachable;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
41
src/util.zig
41
src/util.zig
|
|
@ -196,5 +196,44 @@ pub fn expanduser(path: []const u8, alloc: std.mem.Allocator) ![:0]u8 {
|
||||||
const home = std.mem.trimRight(u8, home_raw, "/");
|
const home = std.mem.trimRight(u8, home_raw, "/");
|
||||||
|
|
||||||
if (home.len == 0 and path.len == len) return alloc.dupeZ(u8, "/");
|
if (home.len == 0 and path.len == len) return alloc.dupeZ(u8, "/");
|
||||||
return try std.fmt.allocPrintZ(alloc, "{s}{s}", .{ home, path[len..] });
|
return try std.mem.concatWithSentinel(alloc, u8, &.{ home, path[len..] }, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
} else struct {
|
||||||
|
rd: std.fs.File.Reader,
|
||||||
|
|
||||||
|
pub fn init(f: std.fs.File, buf: []u8) @This() {
|
||||||
|
return .{ .rd = f.readerStreaming(buf) };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read(s: *@This()) !?[]u8 {
|
||||||
|
return s.rd.interface.takeDelimiterExclusive('\n') catch |err| switch (err) {
|
||||||
|
error.EndOfStream => null,
|
||||||
|
else => |e| return e,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue