diff options
author | Martin Ashby <martin@ashbysoft.com> | 2023-10-07 22:23:33 +0100 |
---|---|---|
committer | Martin Ashby <martin@ashbysoft.com> | 2023-10-07 22:23:33 +0100 |
commit | 66c3667bc36a4d6f133dd934fb0166265a1cecd2 (patch) | |
tree | 07942188814c798d1baff1a02f81406cb3293398 /src | |
parent | a28a7c8db679d7a787be035035773abe8dadfff3 (diff) | |
download | zipdl-main.tar.gz zipdl-main.tar.bz2 zipdl-main.tar.xz zipdl-main.zip |
Diffstat (limited to 'src')
-rw-r--r-- | src/main.zig | 82 |
1 files changed, 82 insertions, 0 deletions
diff --git a/src/main.zig b/src/main.zig index ca1fcd8..3e5bd80 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1,6 +1,88 @@ const std = @import("std"); +const Zip = @import("zip"); const SeekableHttpRange = @import("seekable_http_range.zig"); +pub fn main() !void { + var gpa = std.heap.GeneralPurposeAllocator(.{}){}; + defer _ = gpa.deinit(); + const a = gpa.allocator(); + + var args = try std.process.argsAlloc(a); + defer std.process.argsFree(a, args); + if (args.len < 2) { + try printHelpAndExit("No URL specified"); + return; + } + if (args.len < 3) { + try printHelpAndExit("No FILES specified"); + return; + } + const url = args[1]; + const files = args[2..]; + + // TODO general purpose options handling + if (std.mem.eql(u8, url, "-h") or std.mem.eql(u8, url, "--help")) { + try printHelpAndExit(null); + return; + } + + var client = std.http.Client{.allocator = a}; + defer client.deinit(); + + var range = try SeekableHttpRange.init(.{ + .allocator = a, + .client = &client, + .url = url, + .buffer_size = 8192, + }); + defer range.deinit(); + + var zip = try Zip.from(a, &range); + defer zip.deinit(); + + var at_least_one_success = false; + for (files) |file| { + cdhlp: for (zip.central_directory_headers.items, 0..) |cdh, ix| { + if (std.mem.eql(u8, file, cdh.file_name)) { + const cwd = std.fs.cwd(); + if (std.fs.path.dirname(file)) |dirname| { + try cwd.makePath(dirname); + } + var outfile = try cwd.createFile(cdh.file_name, .{}); + defer outfile.close(); + try zip.extract(ix, &range, outfile.writer()); + at_least_one_success = true; + break :cdhlp; + } + } else { + try std.fmt.format(std.io.getStdErr().writer(), "File {s} not found in zip\n", .{file}); + } + } + if (!at_least_one_success) { + try std.io.getStdErr().writeAll("No files successfully downloded\n"); + std.os.exit(1); + } +} + +fn printHelpAndExit(comptime errmsg: ?[]const u8) !void { + const usage = \\Usage: + \\zipdl URL FILES... + \\ URL is the http(s) URL of a ZIP file + \\ FILES are the files to be extracted from the remote ZIP + \\ + ; + if (errmsg) |err| { + try std.io.getStdErr().writeAll(err); + try std.io.getStdErr().writeAll("\n\n"); + try std.io.getStdErr().writeAll(usage); + std.os.exit(2); + } else { + try std.io.getStdErr().writeAll(usage); + std.os.exit(0); + } + unreachable; +} + test { _ = SeekableHttpRange; }
\ No newline at end of file |