aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Ashby <martin@ashbysoft.com>2023-10-07 22:23:33 +0100
committerMartin Ashby <martin@ashbysoft.com>2023-10-07 22:23:33 +0100
commit66c3667bc36a4d6f133dd934fb0166265a1cecd2 (patch)
tree07942188814c798d1baff1a02f81406cb3293398
parenta28a7c8db679d7a787be035035773abe8dadfff3 (diff)
downloadzipdl-66c3667bc36a4d6f133dd934fb0166265a1cecd2.tar.gz
zipdl-66c3667bc36a4d6f133dd934fb0166265a1cecd2.tar.bz2
zipdl-66c3667bc36a4d6f133dd934fb0166265a1cecd2.tar.xz
zipdl-66c3667bc36a4d6f133dd934fb0166265a1cecd2.zip
Implement main applicationHEAD0.0.1main
-rw-r--r--src/main.zig82
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