Skip to content

Commit 229f48d

Browse files
committed
split up CLI handler
1 parent ac7f268 commit 229f48d

File tree

2 files changed

+76
-52
lines changed

2 files changed

+76
-52
lines changed

src/cli.zig

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
const std = @import("std");
2+
3+
// ========================= //
4+
// = Copyright (c) NullDev = //
5+
// ========================= //
6+
7+
pub const CliOptions = struct {
8+
exe_path: ?[]const u8,
9+
out_dir_path: ?[]const u8,
10+
};
11+
12+
pub fn printUsage(writer: anytype) !void {
13+
try writer.writeAll(
14+
\\SimSymSrv is a tool to download PDB files from Microsoft's Symbol Server.
15+
\\Copyright (c) 2025 NullDev
16+
\\
17+
\\Usage: SimSymSrv [options]
18+
\\
19+
\\Options:
20+
\\ -i, --input <PATH> Path to EXE/DLL/SYS file
21+
\\ -o, --output <PATH> Path to output folder
22+
\\ -h, --help Print this help message
23+
\\
24+
\\If options are not provided, you will be prompted for the missing input.
25+
\\
26+
);
27+
}
28+
29+
pub fn parseArgs(allocator: std.mem.Allocator) !CliOptions {
30+
var args = try std.process.argsWithAllocator(allocator);
31+
defer args.deinit();
32+
33+
var options = CliOptions{
34+
.exe_path = null,
35+
.out_dir_path = null,
36+
};
37+
38+
// Skip the program name argv[0]
39+
_ = args.skip();
40+
41+
while (args.next()) |arg| {
42+
if (std.mem.eql(u8, arg, "-h") or std.mem.eql(u8, arg, "--help")) {
43+
try printUsage(std.io.getStdOut().writer());
44+
std.process.exit(0);
45+
} else if (std.mem.eql(u8, arg, "-i") or std.mem.eql(u8, arg, "--input")) {
46+
const path = args.next() orelse {
47+
try std.io.getStdErr().writer().writeAll("Error: -i/--input requires a path argument\n");
48+
try printUsage(std.io.getStdErr().writer());
49+
return error.InvalidArgument;
50+
};
51+
options.exe_path = try allocator.dupe(u8, path);
52+
} else if (std.mem.eql(u8, arg, "-o") or std.mem.eql(u8, arg, "--output")) {
53+
const path = args.next() orelse {
54+
try std.io.getStdErr().writer().writeAll("Error: -o/--output requires a path argument\n");
55+
try printUsage(std.io.getStdErr().writer());
56+
return error.InvalidArgument;
57+
};
58+
options.out_dir_path = try allocator.dupe(u8, path);
59+
} else {
60+
try std.io.getStdErr().writer().print("Error: Unknown argument '{s}'\n", .{arg});
61+
try printUsage(std.io.getStdErr().writer());
62+
return error.InvalidArgument;
63+
}
64+
}
65+
66+
return options;
67+
}

src/main.zig

Lines changed: 9 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ const std = @import("std");
22
const pe = @import("pe.zig");
33
const downloader = @import("downloader/downloader.zig");
44
const h = @import("headers.zig");
5+
const cli = @import("cli.zig");
56

67
// ========================= //
78
// = Copyright (c) NullDev = //
@@ -13,78 +14,34 @@ fn readLineAlloc(alloc: std.mem.Allocator, r: anytype) ![]u8 {
1314
return alloc.dupe(u8, std.mem.trim(u8, bytes, " \r\n"));
1415
}
1516

16-
fn printUsage(writer: anytype) !void {
17-
try writer.writeAll(
18-
\\SimSymSrv is a tool to download PDB files from Microsoft's Symbol Server.
19-
\\Copyright (c) 2025 NullDev
20-
\\
21-
\\Usage: SimSymSrv [options]
22-
\\
23-
\\Options:
24-
\\ -i, --input <PATH> Path to EXE/DLL/SYS file
25-
\\ -o, --output <PATH> Path to output folder
26-
\\ -h, --help Print this help message
27-
\\
28-
\\If options are not provided, you will be prompted for the missing input.
29-
\\
30-
);
31-
}
32-
3317
pub fn main() !void {
3418
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
3519
defer std.debug.assert(gpa.deinit() == .ok);
3620
// abort if the leak checker reports anything but ".ok"
3721
const alloc = gpa.allocator();
3822

3923
const stdout = std.io.getStdOut().writer();
40-
const stderr = std.io.getStdErr().writer();
41-
var args = try std.process.argsWithAllocator(alloc);
42-
defer args.deinit();
4324

44-
var exe_path: ?[]const u8 = null;
45-
var out_dir_path: ?[]const u8 = null;
46-
47-
// Skip the program name
48-
_ = args.skip();
49-
50-
// Parse arguments
51-
while (args.next()) |arg| {
52-
if (std.mem.eql(u8, arg, "-h") or std.mem.eql(u8, arg, "--help")) {
53-
try printUsage(stdout);
54-
return;
55-
} else if (std.mem.eql(u8, arg, "-i") or std.mem.eql(u8, arg, "--input")) {
56-
exe_path = args.next() orelse {
57-
try stderr.writeAll("Error: -i/--input requires a path argument\n");
58-
try printUsage(stderr);
59-
return error.InvalidArgument;
60-
};
61-
} else if (std.mem.eql(u8, arg, "-o") or std.mem.eql(u8, arg, "--output")) {
62-
out_dir_path = args.next() orelse {
63-
try stderr.writeAll("Error: -o/--output requires a path argument\n");
64-
try printUsage(stderr);
65-
return error.InvalidArgument;
66-
};
67-
} else {
68-
try stderr.print("Error: Unknown argument '{s}'\n", .{arg});
69-
try printUsage(stderr);
70-
return error.InvalidArgument;
71-
}
25+
const options = try cli.parseArgs(alloc);
26+
defer {
27+
if (options.exe_path) |path| alloc.free(path);
28+
if (options.out_dir_path) |path| alloc.free(path);
7229
}
7330

7431
const stdin = std.io.getStdIn().reader();
7532

7633
// If arguments weren't provided, prompt for them
77-
const final_exe_path = if (exe_path) |path| path else blk: {
34+
const final_exe_path = if (options.exe_path) |path| path else blk: {
7835
try stdout.print("Path to EXE/DLL/SYS: ", .{});
7936
break :blk try readLineAlloc(alloc, stdin);
8037
};
81-
defer if (exe_path == null) alloc.free(final_exe_path);
38+
defer if (options.exe_path == null) alloc.free(final_exe_path);
8239

83-
const final_out_dir = if (out_dir_path) |path| path else blk: {
40+
const final_out_dir = if (options.out_dir_path) |path| path else blk: {
8441
try stdout.print("Path to Output Folder: ", .{});
8542
break :blk try readLineAlloc(alloc, stdin);
8643
};
87-
defer if (out_dir_path == null) alloc.free(final_out_dir);
44+
defer if (options.out_dir_path == null) alloc.free(final_out_dir);
8845

8946
// open and load the PE
9047
const pe_file = try std.fs.openFileAbsolute(final_exe_path, .{});

0 commit comments

Comments
 (0)