Compare commits

..

11 commits

Author SHA1 Message Date
Eric Joldasov
8659ebf5a8
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-02-20 21:48:05 +05:00
Eric Joldasov
173f14f8e2
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-02-13 22:53:11 +05:00
Eric Joldasov
1e55747cf7
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-02-13 22:53:00 +05:00
Eric Joldasov
9b98fb4c36
update to new allocator interface
See https://github.com/ziglang/zig/pull/20511 .

Signed-off-by: Eric Joldasov <bratishkaerik@landless-city.net>
2025-02-09 14:33:04 +05:00
Eric Joldasov
e508a61911
update to new panic interface
See https://github.com/ziglang/zig/pull/22594 .

Signed-off-by: Eric Joldasov <bratishkaerik@landless-city.net>
2025-02-09 14:33:02 +05:00
Eric Joldasov
5bbaeb2508
remove anonymous struct types
See https://github.com/ziglang/zig/pull/21817 .

Signed-off-by: Eric Joldasov <bratishkaerik@landless-city.net>
2025-02-09 14:33:01 +05:00
Eric Joldasov
4847a753ad
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-02-09 14:33:00 +05:00
Eric Joldasov
6d67c0f876
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-02-09 14:32:58 +05:00
Eric Joldasov
4ec8153389
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-02-09 14:32:57 +05:00
Eric Joldasov
2249ca2895
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-02-09 14:32:55 +05:00
Eric Joldasov
66de099de4
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-02-09 14:32:53 +05:00
2 changed files with 63 additions and 111 deletions

4
ncdu.1
View file

@ -392,7 +392,6 @@ is given on the command line.
.Pp .Pp
The configuration file format is simply one command line option per line. The configuration file format is simply one command line option per line.
Lines starting with '#' are ignored. Lines starting with '#' are ignored.
A line can be prefixed with '@' to suppress errors while parsing the option.
Example configuration file: Example configuration file:
.Bd -literal -offset indent .Bd -literal -offset indent
# Always enable extended mode # Always enable extended mode
@ -403,9 +402,6 @@ Example configuration file:
# Exclude .git directories # Exclude .git directories
\-\-exclude .git \-\-exclude .git
# Read excludes from ~/.ncduexcludes, ignore error if the file does not exist
@--exclude-from ~/.ncduexcludes
.Ed .Ed
. .
.Sh KEYS .Sh KEYS

View file

@ -126,7 +126,6 @@ const Args = struct {
last_arg: ?[:0]const u8 = null, // In the case of --option=<arg> last_arg: ?[:0]const u8 = null, // In the case of --option=<arg>
shortbuf: [2]u8 = undefined, shortbuf: [2]u8 = undefined,
argsep: bool = false, argsep: bool = false,
ignerror: bool = false,
const Self = @This(); const Self = @This();
const Option = struct { const Option = struct {
@ -156,27 +155,22 @@ const Args = struct {
return .{ .opt = true, .val = &self.shortbuf }; return .{ .opt = true, .val = &self.shortbuf };
} }
pub fn die(self: *const Self, comptime msg: []const u8, args: anytype) !noreturn {
if (self.ignerror) return error.InvalidArg;
ui.die(msg, args);
}
/// Return the next option or positional argument. /// Return the next option or positional argument.
/// 'opt' indicates whether it's an option or positional argument, /// 'opt' indicates whether it's an option or positional argument,
/// 'val' will be either -x, --something or the argument. /// 'val' will be either -x, --something or the argument.
pub fn next(self: *Self) !?Option { pub fn next(self: *Self) ?Option {
if (self.last_arg != null) try self.die("Option '{s}' does not expect an argument.\n", .{ self.last.? }); if (self.last_arg != null) ui.die("Option '{s}' does not expect an argument.\n", .{ self.last.? });
if (self.short) |s| return self.shortopt(s); if (self.short) |s| return self.shortopt(s);
const val = self.pop() orelse return null; const val = self.pop() orelse return null;
if (self.argsep or val.len == 0 or val[0] != '-') return Option{ .opt = false, .val = val }; if (self.argsep or val.len == 0 or val[0] != '-') return Option{ .opt = false, .val = val };
if (val.len == 1) try self.die("Invalid option '-'.\n", .{}); if (val.len == 1) ui.die("Invalid option '-'.\n", .{});
if (val.len == 2 and val[1] == '-') { if (val.len == 2 and val[1] == '-') {
self.argsep = true; self.argsep = true;
return self.next(); return self.next();
} }
if (val[1] == '-') { if (val[1] == '-') {
if (std.mem.indexOfScalar(u8, val, '=')) |sep| { if (std.mem.indexOfScalar(u8, val, '=')) |sep| {
if (sep == 2) try self.die("Invalid option '{s}'.\n", .{val}); if (sep == 2) ui.die("Invalid option '{s}'.\n", .{val});
self.last_arg = val[sep+1.. :0]; self.last_arg = val[sep+1.. :0];
self.last = val[0..sep]; self.last = val[0..sep];
return Option{ .opt = true, .val = self.last.? }; return Option{ .opt = true, .val = self.last.? };
@ -188,7 +182,7 @@ const Args = struct {
} }
/// Returns the argument given to the last returned option. Dies with an error if no argument is provided. /// Returns the argument given to the last returned option. Dies with an error if no argument is provided.
pub fn arg(self: *Self) ![:0]const u8 { pub fn arg(self: *Self) [:0]const u8 {
if (self.short) |a| { if (self.short) |a| {
defer self.short = null; defer self.short = null;
return a; return a;
@ -198,11 +192,11 @@ const Args = struct {
return a; return a;
} }
if (self.pop()) |o| return o; if (self.pop()) |o| return o;
try self.die("Option '{s}' requires an argument.\n", .{ self.last.? }); ui.die("Option '{s}' requires an argument.\n", .{ self.last.? });
} }
}; };
fn argConfig(args: *Args, opt: Args.Option, infile: bool) !void { fn argConfig(args: *Args, opt: Args.Option, infile: bool) bool {
if (opt.is("-q") or opt.is("--slow-ui-updates")) config.update_delay = 2*std.time.ns_per_s if (opt.is("-q") or opt.is("--slow-ui-updates")) config.update_delay = 2*std.time.ns_per_s
else if (opt.is("--fast-ui-updates")) config.update_delay = 100*std.time.ns_per_ms else if (opt.is("--fast-ui-updates")) config.update_delay = 100*std.time.ns_per_ms
else if (opt.is("-x") or opt.is("--one-file-system")) config.same_fs = true else if (opt.is("-x") or opt.is("--one-file-system")) config.same_fs = true
@ -232,13 +226,13 @@ fn argConfig(args: *Args, opt: Args.Option, infile: bool) !void {
else if (opt.is("--enable-natsort")) config.sort_natural = true else if (opt.is("--enable-natsort")) config.sort_natural = true
else if (opt.is("--disable-natsort")) config.sort_natural = false else if (opt.is("--disable-natsort")) config.sort_natural = false
else if (opt.is("--graph-style")) { else if (opt.is("--graph-style")) {
const val = try args.arg(); const val = args.arg();
if (std.mem.eql(u8, val, "hash")) config.graph_style = .hash if (std.mem.eql(u8, val, "hash")) config.graph_style = .hash
else if (std.mem.eql(u8, val, "half-block")) config.graph_style = .half else if (std.mem.eql(u8, val, "half-block")) config.graph_style = .half
else if (std.mem.eql(u8, val, "eighth-block") or std.mem.eql(u8, val, "eigth-block")) config.graph_style = .eighth else if (std.mem.eql(u8, val, "eighth-block") or std.mem.eql(u8, val, "eigth-block")) config.graph_style = .eighth
else try args.die("Unknown --graph-style option: {s}.\n", .{val}); else ui.die("Unknown --graph-style option: {s}.\n", .{val});
} else if (opt.is("--sort")) { } else if (opt.is("--sort")) {
var val: []const u8 = try args.arg(); var val: []const u8 = args.arg();
var ord: ?config.SortOrder = null; var ord: ?config.SortOrder = null;
if (std.mem.endsWith(u8, val, "-asc")) { if (std.mem.endsWith(u8, val, "-asc")) {
val = val[0..val.len-4]; val = val[0..val.len-4];
@ -262,13 +256,13 @@ fn argConfig(args: *Args, opt: Args.Option, infile: bool) !void {
} else if (std.mem.eql(u8, val, "mtime")) { } else if (std.mem.eql(u8, val, "mtime")) {
config.sort_col = .mtime; config.sort_col = .mtime;
config.sort_order = ord orelse .asc; config.sort_order = ord orelse .asc;
} else try args.die("Unknown --sort option: {s}.\n", .{val}); } else ui.die("Unknown --sort option: {s}.\n", .{val});
} else if (opt.is("--shared-column")) { } else if (opt.is("--shared-column")) {
const val = try args.arg(); const val = args.arg();
if (std.mem.eql(u8, val, "off")) config.show_shared = .off if (std.mem.eql(u8, val, "off")) config.show_shared = .off
else if (std.mem.eql(u8, val, "shared")) config.show_shared = .shared else if (std.mem.eql(u8, val, "shared")) config.show_shared = .shared
else if (std.mem.eql(u8, val, "unique")) config.show_shared = .unique else if (std.mem.eql(u8, val, "unique")) config.show_shared = .unique
else try args.die("Unknown --shared-column option: {s}.\n", .{val}); else ui.die("Unknown --shared-column option: {s}.\n", .{val});
} else if (opt.is("--apparent-size")) config.show_blocks = false } else if (opt.is("--apparent-size")) config.show_blocks = false
else if (opt.is("--disk-usage")) config.show_blocks = true else if (opt.is("--disk-usage")) config.show_blocks = true
else if (opt.is("-0")) config.scan_ui = .none else if (opt.is("-0")) config.scan_ui = .none
@ -279,13 +273,13 @@ fn argConfig(args: *Args, opt: Args.Option, infile: bool) !void {
else if (opt.is("-L") or opt.is("--follow-symlinks")) config.follow_symlinks = true else if (opt.is("-L") or opt.is("--follow-symlinks")) config.follow_symlinks = true
else if (opt.is("--no-follow-symlinks")) config.follow_symlinks = false else if (opt.is("--no-follow-symlinks")) config.follow_symlinks = false
else if (opt.is("--exclude")) { else if (opt.is("--exclude")) {
const arg = if (infile) (util.expanduser(try args.arg(), allocator) catch unreachable) else try args.arg(); const arg = if (infile) (util.expanduser(args.arg(), allocator) catch unreachable) else args.arg();
defer if (infile) allocator.free(arg); defer if (infile) allocator.free(arg);
exclude.addPattern(arg); exclude.addPattern(arg);
} else if (opt.is("-X") or opt.is("--exclude-from")) { } else if (opt.is("-X") or opt.is("--exclude-from")) {
const arg = if (infile) (util.expanduser(try args.arg(), allocator) catch unreachable) else try args.arg(); const arg = if (infile) (util.expanduser(args.arg(), allocator) catch unreachable) else args.arg();
defer if (infile) allocator.free(arg); defer if (infile) allocator.free(arg);
readExcludeFile(arg) catch |e| try args.die("Error reading excludes from {s}: {s}.\n", .{ arg, ui.errorString(e) }); readExcludeFile(arg) catch |e| ui.die("Error reading excludes from {s}: {s}.\n", .{ arg, ui.errorString(e) });
} else if (opt.is("--exclude-caches")) config.exclude_caches = true } else if (opt.is("--exclude-caches")) config.exclude_caches = true
else if (opt.is("--include-caches")) config.exclude_caches = false else if (opt.is("--include-caches")) config.exclude_caches = false
else if (opt.is("--exclude-kernfs")) config.exclude_kernfs = true else if (opt.is("--exclude-kernfs")) config.exclude_kernfs = true
@ -293,29 +287,29 @@ fn argConfig(args: *Args, opt: Args.Option, infile: bool) !void {
else if (opt.is("-c") or opt.is("--compress")) config.compress = true else if (opt.is("-c") or opt.is("--compress")) config.compress = true
else if (opt.is("--no-compress")) config.compress = false else if (opt.is("--no-compress")) config.compress = false
else if (opt.is("--compress-level")) { else if (opt.is("--compress-level")) {
const val = try args.arg(); const val = args.arg();
const num = std.fmt.parseInt(u8, val, 10) catch try args.die("Invalid number for --compress-level: {s}.\n", .{val}); config.complevel = std.fmt.parseInt(u8, val, 10) catch ui.die("Invalid number for --compress-level: {s}.\n", .{val});
if (num <= 0 or num > 20) try args.die("Invalid number for --compress-level: {s}.\n", .{val}); if (config.complevel <= 0 or config.complevel > 20) ui.die("Invalid number for --compress-level: {s}.\n", .{val});
config.complevel = num;
} else if (opt.is("--export-block-size")) { } else if (opt.is("--export-block-size")) {
const val = try args.arg(); const val = args.arg();
const num = std.fmt.parseInt(u14, val, 10) catch try args.die("Invalid number for --export-block-size: {s}.\n", .{val}); const num = std.fmt.parseInt(u14, val, 10) catch ui.die("Invalid number for --export-block-size: {s}.\n", .{val});
if (num < 4 or num > 16000) try args.die("Invalid number for --export-block-size: {s}.\n", .{val}); if (num < 4 or num > 16000) ui.die("Invalid number for --export-block-size: {s}.\n", .{val});
config.export_block_size = @as(usize, num) * 1024; config.export_block_size = @as(usize, num) * 1024;
} else if (opt.is("--confirm-quit")) config.confirm_quit = true } else if (opt.is("--confirm-quit")) config.confirm_quit = true
else if (opt.is("--no-confirm-quit")) config.confirm_quit = false else if (opt.is("--no-confirm-quit")) config.confirm_quit = false
else if (opt.is("--confirm-delete")) config.confirm_delete = true else if (opt.is("--confirm-delete")) config.confirm_delete = true
else if (opt.is("--no-confirm-delete")) config.confirm_delete = false else if (opt.is("--no-confirm-delete")) config.confirm_delete = false
else if (opt.is("--color")) { else if (opt.is("--color")) {
const val = try args.arg(); const val = args.arg();
if (std.mem.eql(u8, val, "off")) config.ui_color = .off if (std.mem.eql(u8, val, "off")) config.ui_color = .off
else if (std.mem.eql(u8, val, "dark")) config.ui_color = .dark else if (std.mem.eql(u8, val, "dark")) config.ui_color = .dark
else if (std.mem.eql(u8, val, "dark-bg")) config.ui_color = .darkbg else if (std.mem.eql(u8, val, "dark-bg")) config.ui_color = .darkbg
else try args.die("Unknown --color option: {s}.\n", .{val}); else ui.die("Unknown --color option: {s}.\n", .{val});
} else if (opt.is("-t") or opt.is("--threads")) { } else if (opt.is("-t") or opt.is("--threads")) {
const val = try args.arg(); const val = args.arg();
config.threads = std.fmt.parseInt(u8, val, 10) catch try args.die("Invalid number of --threads: {s}.\n", .{val}); config.threads = std.fmt.parseInt(u8, val, 10) catch ui.die("Invalid number of --threads: {s}.\n", .{val});
} else return error.UnknownOption; } else return false;
return true;
} }
fn tryReadArgsFile(path: [:0]const u8) void { fn tryReadArgsFile(path: [:0]const u8) void {
@ -326,6 +320,8 @@ fn tryReadArgsFile(path: [:0]const u8) void {
}; };
defer f.close(); defer f.close();
var arglist = std.ArrayList([:0]const u8).init(allocator);
var rd_ = std.io.bufferedReader(f.reader()); var rd_ = std.io.bufferedReader(f.reader());
const rd = rd_.reader(); const rd = rd_.reader();
@ -340,36 +336,22 @@ fn tryReadArgsFile(path: [:0]const u8) void {
}; };
const line_ = line_fbs.getWritten(); const line_ = line_fbs.getWritten();
var argc: usize = 0;
var ignerror = false;
var arglist: [2][:0]const u8 = .{ "", "" };
var line = std.mem.trim(u8, line_, &std.ascii.whitespace); var line = std.mem.trim(u8, line_, &std.ascii.whitespace);
if (line.len > 0 and line[0] == '@') {
ignerror = true;
line = line[1..];
}
if (line.len == 0 or line[0] == '#') continue; if (line.len == 0 or line[0] == '#') continue;
if (std.mem.indexOfAny(u8, line, " \t=")) |i| { if (std.mem.indexOfAny(u8, line, " \t=")) |i| {
arglist[argc] = allocator.dupeZ(u8, line[0..i]) catch unreachable; arglist.append(allocator.dupeZ(u8, line[0..i]) catch unreachable) catch unreachable;
argc += 1;
line = std.mem.trimLeft(u8, line[i+1..], &std.ascii.whitespace); line = std.mem.trimLeft(u8, line[i+1..], &std.ascii.whitespace);
} }
arglist[argc] = allocator.dupeZ(u8, line) catch unreachable; arglist.append(allocator.dupeZ(u8, line) catch unreachable) catch unreachable;
argc += 1; }
var args = Args.init(arglist[0..argc]); var args = Args.init(arglist.items);
args.ignerror = ignerror; while (args.next()) |opt| {
while (args.next() catch null) |opt| { if (!argConfig(&args, opt, true))
if (argConfig(&args, opt, true)) |_| {}
else |_| {
if (ignerror) break;
ui.die("Unrecognized option in config file '{s}': {s}.\nRun with --ignore-config to skip reading config files.\n", .{path, opt.val}); ui.die("Unrecognized option in config file '{s}': {s}.\nRun with --ignore-config to skip reading config files.\n", .{path, opt.val});
} }
} for (arglist.items) |i| allocator.free(i);
allocator.free(arglist[0]); arglist.deinit();
if (argc == 2) allocator.free(arglist[1]);
}
} }
fn version() noreturn { fn version() noreturn {
@ -383,54 +365,28 @@ fn help() noreturn {
stdout.writeAll( stdout.writeAll(
\\ncdu <options> <directory> \\ncdu <options> <directory>
\\ \\
\\Mode selection: \\Options:
\\ -h, --help This help message \\ -h,--help This help message
\\ -v, -V, --version Print version \\ -q Quiet mode, refresh interval 2 seconds
\\ -v,-V,--version Print version
\\ -x Same filesystem
\\ -e Enable extended information
\\ -t NUM Number of threads to use
\\ -r Read only
\\ -o FILE Export scanned directory to FILE
\\ -f FILE Import scanned directory from FILE \\ -f FILE Import scanned directory from FILE
\\ -o FILE Export scanned directory to FILE in JSON format \\ -0,-1,-2 UI to use when scanning (0=none,2=full ncurses)
\\ -O FILE Export scanned directory to FILE in binary format \\ --si Use base 10 (SI) prefixes instead of base 2
\\ -e, --extended Enable extended information
\\ --ignore-config Don't load config files
\\
\\Scan options:
\\ -x, --one-file-system Stay on the same filesystem
\\ --exclude PATTERN Exclude files that match PATTERN \\ --exclude PATTERN Exclude files that match PATTERN
\\ -X, --exclude-from FILE Exclude files that match any pattern in FILE \\ -X, --exclude-from FILE Exclude files that match any pattern in FILE
\\ --exclude-caches Exclude directories containing CACHEDIR.TAG
\\ -L, --follow-symlinks Follow symbolic links (excluding directories) \\ -L, --follow-symlinks Follow symbolic links (excluding directories)
\\ --exclude-caches Exclude directories containing CACHEDIR.TAG
\\ --exclude-kernfs Exclude Linux pseudo filesystems (procfs,sysfs,cgroup,...) \\ --exclude-kernfs Exclude Linux pseudo filesystems (procfs,sysfs,cgroup,...)
\\ -t NUM Scan with NUM threads \\ --confirm-quit Confirm quitting ncdu
\\ --color SCHEME Set color scheme (off/dark/dark-bg)
\\ --ignore-config Don't load config files
\\ \\
\\Export options: \\Refer to `man ncdu` for the full list of options.
\\ -c, --compress Use Zstandard compression with `-o`
\\ --compress-level NUM Set compression level
\\ --export-block-size KIB Set export block size with `-O`
\\
\\Interface options:
\\ -0, -1, -2 UI to use when scanning (0=none,2=full ncurses)
\\ -q, --slow-ui-updates "Quiet" mode, refresh interval 2 seconds
\\ --enable-shell Enable/disable shell spawning feature
\\ --enable-delete Enable/disable file deletion feature
\\ --enable-refresh Enable/disable directory refresh feature
\\ -r Read only (--disable-delete)
\\ -rr Read only++ (--disable-delete & --disable-shell)
\\ --si Use base 10 (SI) prefixes instead of base 2
\\ --apparent-size Show apparent size instead of disk usage by default
\\ --hide-hidden Hide "hidden" or excluded files by default
\\ --show-itemcount Show item count column by default
\\ --show-mtime Show mtime column by default (requires `-e`)
\\ --show-graph Show graph column by default
\\ --show-percent Show percent column by default
\\ --graph-style STYLE hash / half-block / eighth-block
\\ --shared-column off / shared / unique
\\ --sort COLUMN-(asc/desc) disk-usage / name / apparent-size / itemcount / mtime
\\ --enable-natsort Use natural order when sorting by name
\\ --group-directories-first Sort directories before files
\\ --confirm-quit Ask confirmation before quitting ncdu
\\ --no-confirm-delete Don't ask confirmation before deletion
\\ --color SCHEME off / dark / dark-bg
\\
\\Refer to `man ncdu` for more information.
\\ \\
) catch {}; ) catch {};
std.process.exit(0); std.process.exit(0);
@ -572,8 +528,8 @@ pub fn main() void {
const arglist = std.process.argsAlloc(allocator) catch unreachable; const arglist = std.process.argsAlloc(allocator) catch unreachable;
defer std.process.argsFree(allocator, arglist); defer std.process.argsFree(allocator, arglist);
var args = Args.init(arglist); var args = Args.init(arglist);
_ = args.next() catch unreachable; // program name _ = args.next(); // program name
while (args.next() catch unreachable) |opt| { while (args.next()) |opt| {
if (!opt.opt) { if (!opt.opt) {
// XXX: ncdu 1.x doesn't error, it just silently ignores all but the last argument. // XXX: ncdu 1.x doesn't error, it just silently ignores all but the last argument.
if (scan_dir != null) ui.die("Multiple directories given, see ncdu -h for help.\n", .{}); if (scan_dir != null) ui.die("Multiple directories given, see ncdu -h for help.\n", .{});
@ -583,15 +539,15 @@ pub fn main() void {
if (opt.is("-h") or opt.is("-?") or opt.is("--help")) help() if (opt.is("-h") or opt.is("-?") or opt.is("--help")) help()
else if (opt.is("-v") or opt.is("-V") or opt.is("--version")) version() else if (opt.is("-v") or opt.is("-V") or opt.is("--version")) version()
else if (opt.is("-o") and (export_json != null or export_bin != null)) ui.die("The -o flag can only be given once.\n", .{}) else if (opt.is("-o") and (export_json != null or export_bin != null)) ui.die("The -o flag can only be given once.\n", .{})
else if (opt.is("-o")) export_json = allocator.dupeZ(u8, args.arg() catch unreachable) catch unreachable else if (opt.is("-o")) export_json = allocator.dupeZ(u8, args.arg()) catch unreachable
else if (opt.is("-O") and (export_json != null or export_bin != null)) ui.die("The -O flag can only be given once.\n", .{}) else if (opt.is("-O") and (export_json != null or export_bin != null)) ui.die("The -O flag can only be given once.\n", .{})
else if (opt.is("-O")) export_bin = allocator.dupeZ(u8, args.arg() catch unreachable) catch unreachable else if (opt.is("-O")) export_bin = allocator.dupeZ(u8, args.arg()) catch unreachable
else if (opt.is("-f") and import_file != null) ui.die("The -f flag can only be given once.\n", .{}) else if (opt.is("-f") and import_file != null) ui.die("The -f flag can only be given once.\n", .{})
else if (opt.is("-f")) import_file = allocator.dupeZ(u8, args.arg() catch unreachable) catch unreachable else if (opt.is("-f")) import_file = allocator.dupeZ(u8, args.arg()) catch unreachable
else if (opt.is("--ignore-config")) {} else if (opt.is("--ignore-config")) {}
else if (opt.is("--quit-after-scan")) quit_after_scan = true // undocumented feature to help with benchmarking scan/import else if (opt.is("--quit-after-scan")) quit_after_scan = true // undocumented feature to help with benchmarking scan/import
else if (argConfig(&args, opt, false)) |_| {} else if (argConfig(&args, opt, false)) {}
else |_| ui.die("Unrecognized option '{s}'.\n", .{opt.val}); else ui.die("Unrecognized option '{s}'.\n", .{opt.val});
} }
} }