From 1ad4b4b0e8e0f4f4f2a0a6c531f424189255586c Mon Sep 17 00:00:00 2001 From: Arnau478 Date: Wed, 15 May 2024 22:54:15 +0200 Subject: [PATCH] Unified error reporting --- src/argparse.zig | 26 +++++++++++--------------- src/hevi.zig | 3 +-- src/main.zig | 29 +++++++++++++++++++++++------ 3 files changed, 35 insertions(+), 23 deletions(-) diff --git a/src/argparse.zig b/src/argparse.zig index 989a6c1..95717a2 100644 --- a/src/argparse.zig +++ b/src/argparse.zig @@ -1,6 +1,7 @@ const std = @import("std"); const build_options = @import("build_options"); const hevi = @import("hevi"); +const main = @import("main.zig"); pub const ParseResult = struct { filename: []const u8, @@ -32,11 +33,6 @@ const Flag = union(enum) { }, }; -fn printError(comptime fmt: []const u8, args: anytype) noreturn { - std.debug.print("Error: " ++ fmt ++ "\nTip: use `--help` for help\n", args); - std.process.exit(1); -} - fn printHelp() noreturn { std.debug.print( \\hevi - hex viewer @@ -124,7 +120,7 @@ pub fn parse(args: [][]const u8) ParseResult { var string_ptr: *?[]const u8 = undefined; for (args) |arg| { if (take_string) { - if (arg[0] == '-') printError("expected arg string!", .{}); + if (arg[0] == '-') main.fail("expected arg string", .{}); string_ptr.* = arg; take_string = false; @@ -133,7 +129,7 @@ pub fn parse(args: [][]const u8) ParseResult { if (arg[0] == '-') { if (arg.len <= 1) { - printError("expected flag", .{}); + main.fail("expected flag", .{}); } switch (arg[1]) { 'h' => { @@ -144,7 +140,7 @@ pub fn parse(args: [][]const u8) ParseResult { }, '-' => { const name = arg[2..]; - if (name.len == 0) printError("expected flag", .{}); + if (name.len == 0) main.fail("expected flag", .{}); const flags: []const Flag = &.{ .{ .action = .{ .flag = "help", .action = .help } }, @@ -181,8 +177,8 @@ pub fn parse(args: [][]const u8) ParseResult { if (set) |s| { if (toggle.boolean.* != null) { if (toggle.boolean.*.? != s) { - printError("`--{s}` and `--{s}` are mutually exclusive", .{ toggle.enable, toggle.disable }); - } else printError("`--{s}` specified multiple times", .{if (s) toggle.enable else toggle.disable}); + main.fail("`--{s}` and `--{s}` are mutually exclusive", .{ toggle.enable, toggle.disable }); + } else main.fail("`--{s}` specified multiple times", .{if (s) toggle.enable else toggle.disable}); } else toggle.boolean.* = s; break :blk true; @@ -199,19 +195,19 @@ pub fn parse(args: [][]const u8) ParseResult { break :blk false; }; - if (!found) printError("invalid flag `{s}`", .{arg}); + if (!found) main.fail("invalid flag `{s}`", .{arg}); }, - else => printError("invalid flag `{s}`", .{arg}), + else => main.fail("invalid flag `{s}`", .{arg}), } } else { if (filename) |_| { - printError("multiple files specified", .{}); + main.fail("multiple files specified", .{}); } else filename = arg; } } return .{ - .filename = filename orelse printError("no file specified", .{}), + .filename = filename orelse main.fail("no file specified", .{}), .color = color, .uppercase = uppercase, .show_size = show_size, @@ -219,7 +215,7 @@ pub fn parse(args: [][]const u8) ParseResult { .show_ascii = show_ascii, .skip_lines = skip_lines, .parser = if (parser) |p| - std.meta.stringToEnum(hevi.Parser, p) orelse printError("no parser named {s}", .{p}) + std.meta.stringToEnum(hevi.Parser, p) orelse main.fail("no parser named {s}", .{p}) else null, }; diff --git a/src/hevi.zig b/src/hevi.zig index 9cc3dcd..4025c2f 100644 --- a/src/hevi.zig +++ b/src/hevi.zig @@ -124,8 +124,7 @@ fn getColors(allocator: std.mem.Allocator, reader: std.io.AnyReader, options: Di parser.getColors(colors, data); return colors; } else { - std.debug.print("Error: the specified parser doesn't match the file format!\n", .{}); - std.process.exit(1); + return error.NonMatchingParser; } } } else if (parser.matches(data)) { diff --git a/src/main.zig b/src/main.zig index 11ead78..dad5a56 100644 --- a/src/main.zig +++ b/src/main.zig @@ -3,24 +3,41 @@ const hevi = @import("hevi"); const argparse = @import("argparse.zig"); const options = @import("options.zig"); -pub fn main() !void { +pub fn fail(comptime fmt: []const u8, args: anytype) noreturn { + std.log.err(fmt, args); + std.process.exit(1); +} + +pub fn main() void { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; - defer if (gpa.deinit() == .leak) std.debug.print("Error: MEMORY LEAK!\n", .{}); + defer if (gpa.deinit() == .leak) fail("Memory leak detected", .{}); const allocator = gpa.allocator(); - const args = try std.process.argsAlloc(allocator); + const args = std.process.argsAlloc(allocator) catch fail("Out of memory", .{}); defer std.process.argsFree(allocator, args); const parsed_args = argparse.parse(args[1..]); - const file = try std.fs.cwd().openFile(parsed_args.filename, .{}); + const file = std.fs.cwd().openFile(parsed_args.filename, .{}) catch |err| switch (err) { + error.FileNotFound => fail("{s} not found", .{parsed_args.filename}), + error.IsDir => fail("{s} is a directory", .{parsed_args.filename}), + else => fail("{s} could not be opened", .{parsed_args.filename}), + }; defer file.close(); - const data = try file.readToEndAlloc(allocator, std.math.maxInt(usize)); + const data = file.readToEndAlloc(allocator, std.math.maxInt(usize)) catch fail("Out of memory", .{}); defer allocator.free(data); const stdout = std.io.getStdOut(); - try hevi.dump(allocator, data, stdout.writer().any(), try options.getOptions(allocator, parsed_args, stdout)); + const opts = options.getOptions(allocator, parsed_args, stdout) catch |err| switch (err) { + error.InvalidConfig => fail("Invalid config found", .{}), + else => fail("Error getting options and config file", .{}), + }; + + hevi.dump(allocator, data, stdout.writer().any(), opts) catch |err| switch (err) { + error.NonMatchingParser => fail("{s} does not match parser {s}", .{ parsed_args.filename, @tagName(opts.parser.?) }), + else => fail("{s}", .{@errorName(err)}), + }; }