diff --git a/.vscode/launch.json b/.vscode/launch.json index be3d58d..4c87ee2 100755 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -10,15 +10,7 @@ "valuesFormatting": "parseText", "preLaunchTask": "Build Debug", }, - { - "name": "Oar", - "type": "gdb", - "request": "launch", - "target": "${workspaceFolder}/zig-out/bin/oar", - "cwd": "${workspaceRoot}", - "valuesFormatting": "parseText", - "preLaunchTask": "Build Debug", - }, + { "name": "Test", "type": "gdb", diff --git a/src/oar/main.zig b/src/oar/main.zig deleted file mode 100644 index bc1d5ea..0000000 --- a/src/oar/main.zig +++ /dev/null @@ -1,253 +0,0 @@ -const core = @import("core"); -const std = @import("std"); - -/// -/// -/// -pub const Archive = struct { - pub fn deinit(archive: *Archive) { - - } - - pub fn init(file_system: *const sys.FileSystem, file_path: sys.Path) { - - } -}; - -/// -/// An entry block of an Oar archive file. -/// -/// Typically, following the block in memory is the file data it holds the meta-information for. -/// -pub const Entry = extern struct { - signature: [signature_magic.len]u8 = signature_magic, - revision: u8, - path: Path, - file_size: u64, - absolute_offset: u64, - padding: [232]u8 = std.mem.zeroes([232]u8), - - comptime { - const entry_size = @sizeOf(Entry); - - if (entry_size != 512) - @compileError("Entry is " ++ - std.fmt.comptimePrint("{d}", .{entry_size}) ++ " bytes"); - } - - /// - /// Attempts to read the next [Entry] from `file_access`. - /// - /// Returns the read [Entry], `null` if there is no more to read, or a - /// [core.io.FileAccess.Error] if it failed. - /// - pub fn next(file_access: core.io.FileAccess) core.io.FileAccess.Error!?Entry { - const mem = std.mem; - var entry = mem.zeroes(Entry); - const origin = try file_access.queryCursor(); - - if (((try file_access.read(mem.asBytes(&entry))) != @sizeOf(Entry)) and - core.io.equals(u8, &entry.signature, &signature_magic)) { - - try file_access.seek(origin); - - return null; - } - - return entry; - } - - /// - /// Magic identifier used to validate [Entry] data. - /// - pub const signature_magic = [3]u8{'o', 'a', 'r'}; -}; - -/// -/// Unique identifier pointing to an entry within an archive. -/// -/// A path does not do any verification that the given entry pointed to actually exists. -/// -pub const Path = extern struct { - buffer: [255]u8, - length: u8, - - /// - /// [Error.TooLong] occurs when creating a path that is greater than the maximum path size **in - /// bytes**. - /// - pub const Error = error { - TooLong, - }; - - /// - /// An empty [Path] with a length of `0`. - /// - pub const empty = std.mem.zeroes(Path); - - /// - /// Returns `true` if `this_path` is equal to `that_path, otherwise `false`. - /// - pub fn equals(this_path: Path, that_path: Path) bool { - return core.io.equals(u8, this_path.buffer[0 ..this_path. - length], that_path.buffer[0 .. that_path.length]); - } - - /// - /// Returns the hash of the text in `path`. - /// - pub fn hash(path: Path) usize { - return core.io.hashBytes(path.buffer[0 .. path.length]); - } - - /// - /// Attempts to create a [Path] with the path components in `sequences` as a fully qualified - /// path from root. - /// - /// A [Path] value is returned containing the fully qualified path from the file-system root or - /// a [Error] if it could not be created. - /// - pub fn joined(sequences: []const []const u8) Error!Path { - var path = empty; - - if (sequences.len != 0) { - const last_sequence_index = sequences.len - 1; - - for (sequences) |sequence, index| if (sequence.len != 0) { - var components = core.io.Spliterator(u8){ - .source = sequence, - .delimiter = "/", - }; - - while (components.next()) |component| if (component.len != 0) { - for (component) |byte| { - if (path.length == max) return error.TooLong; - - path.buffer[path.length] = byte; - path.length += 1; - } - - if (components.hasNext()) { - if (path.length == max) return error.TooLong; - - path.buffer[path.length] = '/'; - path.length += 1; - } - }; - - if (index < last_sequence_index) { - if (path.length == max) return error.TooLong; - - path.buffer[path.length] = '/'; - path.length += 1; - } - }; - } - - return path; - } - - /// - /// Maximum number of **bytes** in a [Path]. - /// - pub const max = 255; - - /// - /// Textual separator between components of a [Path]. - /// - pub const seperator = '/'; -}; - -test "Path" { - const testing = std.testing; - const empty_path = Path.empty; - - try testing.expectEqual(empty_path.length, 0); - try testing.expect(empty_path.equals(Path.empty)); - - const joined_component_path = try Path.joined(&.{"path", "to/my", "/file"}); - const joined_normalized_path = try Path.joined(&.{"path/to/my/file"}); - - try testing.expectEqual(joined_component_path.length, joined_normalized_path.length); - try testing.expect(joined_component_path.equals(joined_normalized_path)); -} - -/// -/// Starts the **O**na **Ar**chive packer utility. -/// -pub fn main() u8 { - var gpa = std.heap.GeneralPurposeAllocator(.{}){}; - - defer std.debug.assert(!gpa.deinit()); - - const allocator = gpa.allocator(); - const out_writer = std.io.getStdOut().writer(); - const process = std.process; - - const args = process.argsAlloc(allocator) catch { - out_writer.print("Failed to allocate args memory\n", .{}) catch undefined; - - return 1; - }; - - defer process.argsFree(allocator, args); - - if (args.len < 2) { - out_writer.print("Usage: oar [OPTION]... [FILE]...\n", .{}) catch undefined; - out_writer.print("Options and arguments\n", .{}) catch undefined; - - return 0; - } - - const arg = std.mem.sliceTo(args[1], 0); - - if (core.io.equals(u8, arg, "--create")) { - if (args.len < 3) { - out_writer.print("Expected output file specified after `--create`\n", .{}) catch undefined; - - return 1; - } - - var archive = Archive.init(allocator, Path.joined(&.{args[2]})) catch { - out_writer.print("Failed to initialize archive for create\n", .{}) catch undefined; - - return 1; - }; - - defer archive.deinit(); - - for (args[3 .. ]) |input_file_path| { - const file = std.fs.cwd().openFile(input_file_path) catch { - out_writer.print("Failed to open {s}\n", .{input_file_path}) catch undefined; - - return 1; - }; - - defer file.close(); - - var entry = archive.open(Path.joined(&.{input_file_path})) catch { - out_writer.print("Failed to open {s}\n", .{input_file_path}) catch undefined; - - return 1; - }; - - defer archive.close(entry); - - var copy_buffer = std.mem.zeroes([4096]u8); - - while (true) { - const read = try file.read(©_buffer); - - if (read == 0) break; - - try entry.write(copy_buffer[read ..]); - } - } - - return 0; - } - - out_writer.print("Unrecognized command-line option `{s}`\n", .{arg}) catch undefined; - - return 0; -}