From d303b53f2ced75703bf022a5d337ee3ba530b288 Mon Sep 17 00:00:00 2001 From: Uko Kokņevičs Date: Mon, 25 Apr 2022 05:09:55 +0300 Subject: Initial commit --- libs/clap | 1 + libs/curl/curl.zig | 103 +++++++++++++++++++++++++++++++ libs/libarchive/libarchive.zig | 135 +++++++++++++++++++++++++++++++++++++++++ libs/xdg/xdg.zig | 36 +++++++++++ 4 files changed, 275 insertions(+) create mode 160000 libs/clap create mode 100644 libs/curl/curl.zig create mode 100644 libs/libarchive/libarchive.zig create mode 100644 libs/xdg/xdg.zig (limited to 'libs') diff --git a/libs/clap b/libs/clap new file mode 160000 index 0000000..ac5f465 --- /dev/null +++ b/libs/clap @@ -0,0 +1 @@ +Subproject commit ac5f46541ca47d3db9df0fcef3cc61731adaefab diff --git a/libs/curl/curl.zig b/libs/curl/curl.zig new file mode 100644 index 0000000..4a26eed --- /dev/null +++ b/libs/curl/curl.zig @@ -0,0 +1,103 @@ +pub const c = @cImport(@cInclude("curl/curl.h")); + +const std = @import("std"); + +const Allocator = std.mem.Allocator; +const ArrayList = std.ArrayList; +const File = std.fs.File; + +pub fn easyDownload(allocator: Allocator, url: [:0]const u8) ![]u8 { + var handle = try Easy.init(); + defer handle.deinit(); + + var buf = ArrayList(u8).init(allocator); + defer buf.deinit(); + + try handle.setopt(.url, url.ptr); + try handle.setopt(.follow_location, true); + try handle.setopt(.write_function, easyDownloadCb); + try handle.setopt(.write_data, &buf); + + try handle.perform(); + + return buf.toOwnedSlice(); +} + +fn easyDownloadCb(ptr: [*]const u8, size: usize, nmemb: usize, buf: *ArrayList(u8)) usize { + std.debug.assert(size == 1); + + const slice = ptr[0..nmemb]; + buf.appendSlice(slice) catch |err| { + std.log.err("in easyDownloadCb: {}", .{err}); + return 0; + }; + + return nmemb; +} + +pub fn easyDownloadToFile(file: *File, url: [:0]const u8) !void { + var handle = try Easy.init(); + defer handle.deinit(); + + const writer = file.writer(); + + try handle.setopt(.url, url.ptr); + try handle.setopt(.follow_location, true); + try handle.setopt(.write_function, easyDownloadToFileCb); + try handle.setopt(.write_data, &writer); + + try handle.perform(); +} + +fn easyDownloadToFileCb(ptr: [*]const u8, size: usize, nmemb: usize, writer: *const File.Writer) usize { + std.debug.assert(size == 1); + + const slice = ptr[0..nmemb]; + writer.writeAll(slice) catch |err| { + std.log.err("in easyDownloadToFileCb: {}", .{err}); + return 0; + }; + + return nmemb; +} + +pub const Easy = struct { + raw: *c.CURL, + + pub const Option = enum(c.CURLoption) { + follow_location = c.CURLOPT_FOLLOWLOCATION, + url = c.CURLOPT_URL, + write_data = c.CURLOPT_WRITEDATA, + write_function = c.CURLOPT_WRITEFUNCTION, + }; + + pub fn init() !Easy { + if (c.curl_easy_init()) |raw| { + return Easy{ .raw = raw }; + } else { + return error.CurlError; + } + } + + pub fn deinit(self: *Easy) void { + c.curl_easy_cleanup(self.raw); + self.* = undefined; + } + + pub fn perform(self: *Easy) !void { + const errc = c.curl_easy_perform(self.raw); + if (errc != c.CURLE_OK) { + std.log.err("Curl: {s}", .{c.curl_easy_strerror(errc)}); + return error.CurlError; + } + } + + pub fn setopt(self: *Easy, option: Option, param: anytype) !void { + const option_raw = @enumToInt(option); + const errc = c.curl_easy_setopt(self.raw, option_raw, param); + if (errc != c.CURLE_OK) { + std.log.err("Curl: {s}", .{c.curl_easy_strerror(errc)}); + return error.CurlError; + } + } +}; diff --git a/libs/libarchive/libarchive.zig b/libs/libarchive/libarchive.zig new file mode 100644 index 0000000..dab205e --- /dev/null +++ b/libs/libarchive/libarchive.zig @@ -0,0 +1,135 @@ +pub const c = @cImport({ + @cInclude("archive.h"); + @cInclude("archive_entry.h"); +}); + +const std = @import("std"); + +pub const Entry = struct { + raw: *c.archive_entry, + + pub fn pathname(self: Entry) [:0]const u8 { + return std.mem.span(c.archive_entry_pathname(self.raw)); + } + + pub fn setPathname(self: *Entry, new_pathname: [:0]const u8) void { + c.archive_entry_set_pathname(self.raw, new_pathname.ptr); + } +}; + +pub const Read = struct { + raw: *c.archive, + + pub fn init() !Read { + if (c.archive_read_new()) |raw| { + return Read{ .raw = raw }; + } else { + std.log.err("archive_read_new failed", .{}); + return error.LibArchiveError; + } + } + + pub fn deinit(self: *Read) void { + if (c.archive_read_free(self.raw) != c.ARCHIVE_OK) { + std.log.warn("archive_read_free failed", .{}); + } + } + + pub const Filter = enum { + all, + bzip2, + compress, + grzip, + gzip, + lrzip, + lz4, + lzma, + lzop, + none, + rpm, + uu, + xz, + zstd, + }; + + pub fn supportFilter(self: *Read, comptime filter: Filter) !void { + const fn_name = comptime "archive_read_support_filter_" ++ @tagName(filter); + const f = comptime @field(c, fn_name); + if (f(self.raw) != c.ARCHIVE_OK) { + std.log.err(fn_name ++ ": {s}", .{c.archive_error_string(self.raw)}); + return error.LibArchiveError; + } + } + + pub const Format = enum { + @"7zip", + all, + ar, + cab, + cpio, + empty, + iso9660, + lha, + mtree, + rar, + raw, + tar, + xar, + zip, + }; + + pub fn supportFormat(self: *Read, comptime format: Format) !void { + const fn_name = comptime "archive_read_support_format_" ++ @tagName(format); + const f = comptime @field(c, fn_name); + if (f(self.raw) != c.ARCHIVE_OK) { + std.log.err(fn_name ++ ": {s}", .{c.archive_error_string(self.raw)}); + return error.LibArchiveError; + } + } + + pub fn openFilename(self: *Read, filename: [:0]const u8, block_size: usize) !void { + if (c.archive_read_open_filename(self.raw, filename.ptr, block_size) != c.ARCHIVE_OK) { + std.log.err("archive_read_open_filename: {s}", .{c.archive_error_string(self.raw)}); + return error.LibArchiveError; + } + } + + pub fn nextHeader(self: *Read) !?Entry { + var header_raw: ?*c.archive_entry = undefined; + var r = c.ARCHIVE_RETRY; + while (r == c.ARCHIVE_RETRY) { + r = c.archive_read_next_header(self.raw, &header_raw); + } + + if (r == c.ARCHIVE_WARN) { + std.log.warn("archive_read_next_header: {s}", .{c.archive_error_string(self.raw)}); + r = c.ARCHIVE_OK; + } + + if (r == c.ARCHIVE_EOF) { + return null; + } + + if (r != c.ARCHIVE_OK or header_raw == null) { + std.log.err("archive_read_next_header: {s}", .{c.archive_error_string(self.raw)}); + return error.LibArchiveError; + } + + return Entry{ .raw = header_raw.? }; + } + + // TODO: Replace flags with enum + pub fn extract(self: *Read, entry: Entry, flags: c_int) !void { + var r = c.ARCHIVE_RETRY; + while (r == c.ARCHIVE_RETRY) { + r = c.archive_read_extract(self.raw, entry.raw, flags); + } + + if (r == c.ARCHIVE_WARN) { + std.log.warn("archive_read_extract: {s}", .{c.archive_error_string(self.raw)}); + } else if (r != c.ARCHIVE_OK) { + std.log.err("archive_read_extract: {s}", .{c.archive_error_string(self.raw)}); + return error.LibArchiveError; + } + } +}; diff --git a/libs/xdg/xdg.zig b/libs/xdg/xdg.zig new file mode 100644 index 0000000..8466066 --- /dev/null +++ b/libs/xdg/xdg.zig @@ -0,0 +1,36 @@ +const std = @import("std"); + +const Allocator = std.mem.Allocator; +const Dir = std.fs.Dir; + +pub fn getDataHome(allocator: Allocator, app_name: []const u8) ![]u8 { + if (std.os.getenv("XDG_DATA_HOME")) |data_home| { + return std.fs.path.join(allocator, &.{ data_home, app_name }); + } + + if (std.os.getenv("HOME")) |home| { + return std.fs.path.join(allocator, &.{ home, ".local", "share", app_name }); + } + + return error.HomeNotFound; +} + +pub fn getBinHome(allocator: Allocator) ![]u8 { + if (std.os.getenv("HOME")) |home| { + return std.fs.path.join(allocator, &.{ home, ".local", "bin" }); + } + + return error.HomeNotFound; +} + +pub fn openDataHome(allocator: Allocator, app_name: []const u8) !Dir { + var data_home = try getDataHome(allocator, app_name); + defer allocator.free(data_home); + return try std.fs.cwd().makeOpenPath(data_home, .{}); +} + +pub fn openBinHome(allocator: Allocator) !Dir { + var bin_home = try getBinHome(allocator); + defer allocator.free(bin_home); + return try std.fs.cwd().makeOpenPath(bin_home, .{}); +} -- cgit v1.2.3