authorgravatar for manlio.perillo@gmail.comManlio Perillo <manlio.perillo@gmail.com> 2023-01-13 17:24:10+01:00
committergravatar for manlio.perillo@gmail.comManlio Perillo <manlio.perillo@gmail.com> 2023-01-13 17:24:10+01:00
logfde57330fa25ec495e3dbf6d9de50ec07acfe21f
treebbb7bc2ecda5886538534efd07ae9aeeec2ed0c7
parentc5351a8d496edd7d76b3fc505f3e078b9e00982e

docgen: improve command-line argument parsing

Implement a simple command-line argument parser, adapted from the Zig compiler implementation. Promote the zig positional argument to an option.

1 files changed, 51 insertions(+), 12 deletions(-)

doc/docgen.zig+51-12
......@@ -17,6 +17,24 @@ const obj_ext = builtin.object_format.fileExt(builtin.cpu.arch);
1717const tmp_dir_name = "docgen_tmp";
1818const test_out_path = tmp_dir_name ++ fs.path.sep_str ++ "test" ++ exe_ext;
1919
20const usage =
21 \\Usage: docgen [--zig] [--skip-code-test] input output"
22 \\
23 \\ Generates an HTML document from a docgen template.
24 \\
25 \\Options:
26 \\ -h, --help Print this help and exit
27 \\ --skip-code-test Skip the doctests
28 \\
29;
30
31fn errorf(comptime format: []const u8, args: anytype) noreturn {
32 const stderr = io.getStdErr().writer();
33
34 stderr.print("error: " ++ format, args) catch {};
35 process.exit(1);
36}
37
2038pub fn main() !void {
2139 var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
2240 defer arena.deinit();
......@@ -24,33 +42,54 @@ pub fn main() !void {
2442 const allocator = arena.allocator();
2543
2644 var args_it = try process.argsWithAllocator(allocator);
27
2845 if (!args_it.skip()) @panic("expected self arg");
2946
30 const zig_exe = args_it.next() orelse @panic("expected zig exe arg");
31 const in_file_name = args_it.next() orelse @panic("expected input arg");
32 const out_file_name = args_it.next() orelse @panic("expected output arg");
33
47 var zig_exe: []const u8 = "zig";
3448 var do_code_tests = true;
35 if (args_it.next()) |arg| {
36 if (mem.eql(u8, arg, "--skip-code-tests")) {
37 do_code_tests = false;
49 var files = [_][]const u8{ "", "" };
50
51 var i: usize = 0;
52 while (args_it.next()) |arg| {
53 if (mem.startsWith(u8, arg, "-")) {
54 if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
55 const stdout = io.getStdOut().writer();
56 try stdout.writeAll(usage);
57 process.exit(0);
58 } else if (mem.eql(u8, arg, "--zig")) {
59 if (args_it.next()) |param| {
60 zig_exe = param;
61 } else {
62 errorf("expected parameter after --zig\n", .{});
63 }
64 } else if (mem.eql(u8, arg, "--skip-code-tests")) {
65 do_code_tests = false;
66 } else {
67 errorf("unrecognized option: '{s}'\n", .{arg});
68 }
3869 } else {
39 @panic("unrecognized arg");
70 if (i > 1) {
71 errorf("too many arguments\n", .{});
72 }
73 files[i] = arg;
74 i += 1;
4075 }
4176 }
77 if (i < 2) {
78 errorf("not enough arguments\n", .{});
79 process.exit(1);
80 }
4281
43 var in_file = try fs.cwd().openFile(in_file_name, .{ .mode = .read_only });
82 var in_file = try fs.cwd().openFile(files[0], .{ .mode = .read_only });
4483 defer in_file.close();
4584
46 var out_file = try fs.cwd().createFile(out_file_name, .{});
85 var out_file = try fs.cwd().createFile(files[1], .{});
4786 defer out_file.close();
4887
4988 const input_file_bytes = try in_file.reader().readAllAlloc(allocator, max_doc_file_size);
5089
5190 var buffered_writer = io.bufferedWriter(out_file.writer());
5291
53 var tokenizer = Tokenizer.init(in_file_name, input_file_bytes);
92 var tokenizer = Tokenizer.init(files[0], input_file_bytes);
5493 var toc = try genToc(allocator, &tokenizer);
5594
5695 try fs.cwd().makePath(tmp_dir_name);