diff options
-rw-r--r-- | build.zig | 16 | ||||
-rw-r--r-- | src/cmd.zig | 4 | ||||
-rw-r--r-- | src/cmd/dir.zig | 28 | ||||
-rw-r--r-- | src/cmd/external.zig | 13 | ||||
-rw-r--r-- | src/cmd/lib/flags.zig | 30 | ||||
-rw-r--r-- | src/cmd/lib/types.zig | 63 | ||||
-rw-r--r-- | src/cmd/redirect.zig | 8 | ||||
-rw-r--r-- | src/cmd/sort.zig | 12 | ||||
-rw-r--r-- | src/cmd/type.zig | 12 | ||||
-rw-r--r-- | src/main.zig | 83 | ||||
-rw-r--r-- | src/parser.zig | 110 | ||||
-rw-r--r-- | src/paths.zig | 62 |
12 files changed, 234 insertions, 207 deletions
@@ -6,9 +6,11 @@ pub fn build(b: *std.Build) void { const exe = b.addExecutable(.{ .name = "dose", - .root_source_file = b.path("src/main.zig"), - .target = target, - .optimize = optimize, + .root_module = b.createModule(.{ + .root_source_file = b.path("src/main.zig"), + .target = target, + .optimize = optimize, + }), }); // Add cross-platform terminal support @@ -33,9 +35,11 @@ pub fn build(b: *std.Build) void { run_step.dependOn(&run_cmd.step); const unit_tests = b.addTest(.{ - .root_source_file = b.path("src/main.zig"), - .target = target, - .optimize = optimize, + .root_module = b.createModule(.{ + .root_source_file = b.path("src/main.zig"), + .target = target, + .optimize = optimize, + }), }); const run_unit_tests = b.addRunArtifact(unit_tests); diff --git a/src/cmd.zig b/src/cmd.zig index 755e659..2766a8c 100644 --- a/src/cmd.zig +++ b/src/cmd.zig @@ -174,14 +174,14 @@ pub const Command = union(enum) { else => {}, } } - redirect.redirects.deinit(); + redirect.redirects.deinit(allocator); }, .External => |*external| { allocator.free(external.program); for (external.args.items) |arg| { allocator.free(arg); } - external.args.deinit(); + external.args.deinit(allocator); }, .Builtin => |builtin| { switch (builtin) { diff --git a/src/cmd/dir.zig b/src/cmd/dir.zig index 04f74dc..96c6319 100644 --- a/src/cmd/dir.zig +++ b/src/cmd/dir.zig @@ -120,8 +120,8 @@ pub const Dir = struct { subdirs: bool = false, // /s flag pub fn eval(dir: Dir, ctx: CommandContext) !CommandStatus { - var output_buffer = ArrayList(u8).init(ctx.allocator); - defer output_buffer.deinit(); + var output_buffer = ArrayList(u8){}; + defer output_buffer.deinit(ctx.allocator); // Format path in DOS style with backslashes and uppercase drive letter const formatted_path = try formatDosPath(ctx.allocator, dir.path); @@ -134,9 +134,9 @@ pub const Dir = struct { formatted_path[0] else 'C'; - try output_buffer.writer().print(" Volume in drive {c} has no label\n", .{drive_letter}); - try output_buffer.writer().print(" Volume Serial Number is 1234-5678\n", .{}); - try output_buffer.writer().print("\n Directory of {s}\n\n", .{formatted_path}); + try output_buffer.writer(ctx.allocator).print(" Volume in drive {c} has no label\n", .{drive_letter}); + try output_buffer.writer(ctx.allocator).print(" Volume Serial Number is 1234-5678\n", .{}); + try output_buffer.writer(ctx.allocator).print("\n Directory of {s}\n\n", .{formatted_path}); } var dir_iterator = std.fs.cwd().openDir(dir.path, .{ .iterate = true }) catch { @@ -172,23 +172,23 @@ pub const Dir = struct { switch (entry.kind) { .directory => { if (dir.bare_format) { - try output_buffer.writer().print("{s}\n", .{entry.name}); + try output_buffer.writer(ctx.allocator).print("{s}\n", .{entry.name}); } else if (dir.wide_format) { - try output_buffer.writer().print("{s:<12} ", .{entry.name}); + try output_buffer.writer(ctx.allocator).print("{s:<12} ", .{entry.name}); } else { - try output_buffer.writer().print("{s:<8} {s:<3} <DIR> {s}\n", .{ name, ext, date_time }); + try output_buffer.writer(ctx.allocator).print("{s:<8} {s:<3} <DIR> {s}\n", .{ name, ext, date_time }); } dir_count += 1; }, .file => { if (dir.bare_format) { - try output_buffer.writer().print("{s}\n", .{entry.name}); + try output_buffer.writer(ctx.allocator).print("{s}\n", .{entry.name}); } else if (dir.wide_format) { - try output_buffer.writer().print("{s:<12} ", .{entry.name}); + try output_buffer.writer(ctx.allocator).print("{s:<12} ", .{entry.name}); } else { const formatted_size = try formatWithCommas(ctx.allocator, stat.size); defer ctx.allocator.free(formatted_size); - try output_buffer.writer().print("{s:<8} {s:<3} {s:>14} {s}\n", .{ name, ext, formatted_size, date_time }); + try output_buffer.writer(ctx.allocator).print("{s:<8} {s:<3} {s:>14} {s}\n", .{ name, ext, formatted_size, date_time }); } file_count += 1; total_file_bytes += stat.size; @@ -199,7 +199,7 @@ pub const Dir = struct { // Add newline after wide format listing if (dir.wide_format and !dir.bare_format) { - try output_buffer.writer().print("\n", .{}); + try output_buffer.writer(ctx.allocator).print("\n", .{}); } // Only show footer for non-bare format @@ -218,8 +218,8 @@ pub const Dir = struct { const formatted_free_bytes = try formatWithCommas(ctx.allocator, bytes_free); defer ctx.allocator.free(formatted_free_bytes); - try output_buffer.writer().print(" {d} File(s) {s:>14} bytes\n", .{ file_count, formatted_total_bytes }); - try output_buffer.writer().print(" {d} Dir(s) {s:>14} bytes free\n", .{ dir_count, formatted_free_bytes }); + try output_buffer.writer(ctx.allocator).print(" {d} File(s) {s:>14} bytes\n", .{ file_count, formatted_total_bytes }); + try output_buffer.writer(ctx.allocator).print(" {d} Dir(s) {s:>14} bytes free\n", .{ dir_count, formatted_free_bytes }); } var writer = ctx.output_writer; diff --git a/src/cmd/external.zig b/src/cmd/external.zig index 3aaa7af..befd746 100644 --- a/src/cmd/external.zig +++ b/src/cmd/external.zig @@ -26,12 +26,12 @@ pub const External = struct { .capture => true, }; // Try to execute external command - var child_args = ArrayList([]const u8).init(allocator); - defer child_args.deinit(); + var child_args = ArrayList([]const u8){}; + defer child_args.deinit(allocator); - try child_args.append(external.program); + try child_args.append(allocator, external.program); for (external.args.items) |arg| { - try child_args.append(arg); + try child_args.append(allocator, arg); } var child = std.process.Child.init(child_args.items, allocator); @@ -72,7 +72,9 @@ pub const External = struct { // Handle input redirection if (input_source) |source| { if (child.stdin) |stdin| { - const writer = stdin.writer(); + var writer_buffer: [1024]u8 = undefined; + var file_writer = stdin.writer(&writer_buffer); + const writer = &file_writer.interface; // Reset source position for reading var temp_source = source.*; @@ -82,6 +84,7 @@ pub const External = struct { defer allocator.free(line); try writer.print("{s}\n", .{line}); } + try writer.flush(); child.stdin.?.close(); child.stdin = null; } diff --git a/src/cmd/lib/flags.zig b/src/cmd/lib/flags.zig index 637ea83..266ddfe 100644 --- a/src/cmd/lib/flags.zig +++ b/src/cmd/lib/flags.zig @@ -155,34 +155,34 @@ pub const CommandFlags = struct { } pub fn getHelp(self: *const CommandFlags, command_name: []const u8, allocator: Allocator) ![]const u8 { - var help = ArrayList(u8).init(allocator); - defer help.deinit(); + var help = ArrayList(u8){}; + defer help.deinit(allocator); - try help.appendSlice(command_name); - try help.appendSlice(" - Available flags:\n\n"); + try help.appendSlice(allocator, command_name); + try help.appendSlice(allocator, " - Available flags:\n\n"); for (self.flags) |flag_def| { - try help.appendSlice(" /"); - try help.appendSlice(flag_def.name); + try help.appendSlice(allocator, " /"); + try help.appendSlice(allocator, flag_def.name); if (flag_def.aliases.len > 0) { - try help.appendSlice(" ("); + try help.appendSlice(allocator, " ("); for (flag_def.aliases, 0..) |alias, i| { - if (i > 0) try help.appendSlice(", "); - try help.appendSlice(alias); + if (i > 0) try help.appendSlice(allocator, ", "); + try help.appendSlice(allocator, alias); } - try help.appendSlice(")"); + try help.appendSlice(allocator, ")"); } switch (flag_def.flag_type) { - .String => try help.appendSlice(":value"), - .Number => try help.appendSlice(":number"), + .String => try help.appendSlice(allocator, ":value"), + .Number => try help.appendSlice(allocator, ":number"), .Boolean => {}, } - try help.appendSlice(" - "); - try help.appendSlice(flag_def.description); - try help.appendSlice("\n"); + try help.appendSlice(allocator, " - "); + try help.appendSlice(allocator, flag_def.description); + try help.appendSlice(allocator, "\n"); } return help.toOwnedSlice(); diff --git a/src/cmd/lib/types.zig b/src/cmd/lib/types.zig index 57d370d..2dfb0fa 100644 --- a/src/cmd/lib/types.zig +++ b/src/cmd/lib/types.zig @@ -12,19 +12,21 @@ pub const CommandStatus = union(enum) { pub const OutputCapture = struct { buffer: ArrayList(u8), + allocator: Allocator, pub fn init(allocator: Allocator) OutputCapture { return OutputCapture{ - .buffer = ArrayList(u8).init(allocator), + .buffer = ArrayList(u8){}, + .allocator = allocator, }; } pub fn deinit(self: *OutputCapture) void { - self.buffer.deinit(); + self.buffer.deinit(self.allocator); } pub fn write(self: *OutputCapture, data: []const u8) !void { - try self.buffer.appendSlice(data); + try self.buffer.appendSlice(self.allocator, data); } pub fn getContents(self: *const OutputCapture) []const u8 { @@ -35,7 +37,11 @@ pub const OutputCapture = struct { pub const StdoutOutputCapture = struct { pub fn write(self: *StdoutOutputCapture, data: []const u8) !void { _ = self; - try std.io.getStdOut().writeAll(data); + var stdout_buffer: [1024]u8 = undefined; + var stdout_writer = std.fs.File.stdout().writer(&stdout_buffer); + const stdout = &stdout_writer.interface; + try stdout.writeAll(data); + try stdout.flush(); } }; @@ -73,41 +79,32 @@ pub const InputSource = struct { }; pub const StdinInputReader = struct { - pub fn readLine(self: *StdinInputReader, allocator: Allocator) !?[]const u8 { + pub fn readLine(self: *StdinInputReader, buf: []u8) !?[]const u8 { _ = self; - const stdin = std.io.getStdIn().reader(); + const stdin = std.fs.File.stdin(); // Read line from stdin with proper DOS handling - const line = stdin.readUntilDelimiterOrEofAlloc(allocator, '\n', 4096) catch |err| switch (err) { + var reader = stdin.readerStreaming(buf); + const input = std.io.Reader.takeDelimiterExclusive(&reader.interface, '\n') catch |err| switch (err) { + error.EndOfStream => return null, error.StreamTooLong => { - // Line too long, skip to next line - while (true) { - const ch = stdin.readByte() catch return null; - if (ch == '\n') break; - } - return try allocator.dupe(u8, ""); + // Line too long - return empty string + return ""; }, else => return null, }; - if (line) |input| { - // Check for Ctrl+Z (EOF marker) - ASCII 26 - if (input.len == 1 and input[0] == 26) { - allocator.free(input); - return null; // EOF - } - - // Remove trailing \r if present (DOS line endings) - if (input.len > 0 and input[input.len - 1] == '\r') { - const trimmed = try allocator.dupe(u8, input[0 .. input.len - 1]); - allocator.free(input); - return trimmed; - } else { - return input; - } - } else { + // Check for Ctrl+Z (EOF marker) - ASCII 26 + if (input.len == 1 and input[0] == 26) { return null; // EOF } + + // Remove trailing \r if present (DOS line endings) + if (input.len > 0 and input[input.len - 1] == '\r') { + return input[0 .. input.len - 1]; + } else { + return input; + } } }; @@ -118,7 +115,13 @@ pub const InputReader = union(enum) { pub fn readLine(self: *InputReader, allocator: Allocator) !?[]const u8 { switch (self.*) { .source => |source| return source.readLine(allocator), - .stdin => |stdin| return stdin.readLine(allocator), + .stdin => |stdin| { + var buf: [4096]u8 = undefined; + if (try stdin.readLine(&buf)) |line| { + return try allocator.dupe(u8, line); + } + return null; + }, } } }; diff --git a/src/cmd/redirect.zig b/src/cmd/redirect.zig index ef37c3e..3921ef0 100644 --- a/src/cmd/redirect.zig +++ b/src/cmd/redirect.zig @@ -21,8 +21,12 @@ pub const RedirectCommand = struct { pub fn eval(redirect: RedirectCommand, ctx: CommandContext) !CommandStatus { const allocator = ctx.allocator; - const stdout = std.io.getStdOut(); - const stderr = std.io.getStdErr(); + var stdout_buffer: [1024]u8 = undefined; + var stdout_writer = std.fs.File.stdout().writer(&stdout_buffer); + const stdout = &stdout_writer.interface; + var stderr_buffer: [1024]u8 = undefined; + var stderr_writer = std.fs.File.stderr().writer(&stderr_buffer); + const stderr = &stderr_writer.interface; // Extract output_capture from the output_writer for redirection logic const output_capture = switch (ctx.output_writer) { .capture => |capture| capture, diff --git a/src/cmd/sort.zig b/src/cmd/sort.zig index 79616e9..5f75734 100644 --- a/src/cmd/sort.zig +++ b/src/cmd/sort.zig @@ -10,12 +10,12 @@ pub const Sort = struct { pub fn eval(sort: Sort, ctx: CommandContext) !CommandStatus { _ = sort; - var lines = ArrayList([]const u8).init(ctx.allocator); + var lines = ArrayList([]const u8){}; defer { for (lines.items) |line| { ctx.allocator.free(line); } - lines.deinit(); + lines.deinit(ctx.allocator); } // Read input lines from unified input reader @@ -33,7 +33,7 @@ pub const Sort = struct { .source => { // Read from input redirection while (try reader.readLine(ctx.allocator)) |line| { - try lines.append(line); + try lines.append(ctx.allocator, line); } }, } @@ -46,11 +46,11 @@ pub const Sort = struct { }.lessThan); // Output sorted lines - var output_buffer = ArrayList(u8).init(ctx.allocator); - defer output_buffer.deinit(); + var output_buffer = ArrayList(u8){}; + defer output_buffer.deinit(ctx.allocator); for (lines.items) |line| { - try output_buffer.writer().print("{s}\n", .{line}); + try output_buffer.writer(ctx.allocator).print("{s}\n", .{line}); } var writer = ctx.output_writer; diff --git a/src/cmd/type.zig b/src/cmd/type.zig index 147c2a9..5909f4a 100644 --- a/src/cmd/type.zig +++ b/src/cmd/type.zig @@ -58,23 +58,23 @@ pub const Type = struct { if (bytes_read == 0) break; // Process buffer contents for output - var processed_output = ArrayList(u8).init(ctx.allocator); - defer processed_output.deinit(); + var processed_output = ArrayList(u8){}; + defer processed_output.deinit(ctx.allocator); for (buffer[0..bytes_read]) |byte| { // Convert to printable characters, similar to DOS TYPE behavior if (byte >= 32 and byte <= 126) { - try processed_output.append(byte); + try processed_output.append(ctx.allocator, byte); } else if (byte == '\n') { - try processed_output.append('\n'); + try processed_output.append(ctx.allocator, '\n'); } else if (byte == '\r') { // Skip carriage return in DOS-style line endings continue; } else if (byte == '\t') { - try processed_output.append('\t'); + try processed_output.append(ctx.allocator, '\t'); } else { // Replace non-printable characters with '?' - try processed_output.append('?'); + try processed_output.append(ctx.allocator, '?'); } } diff --git a/src/main.zig b/src/main.zig index 7c2ffd7..f8bd7b5 100644 --- a/src/main.zig +++ b/src/main.zig @@ -18,14 +18,14 @@ const STDERR_BUFFER_SIZE: usize = 1024; fn formatPath(allocator: Allocator, path: []const u8) ![]const u8 { // Normalize separators and case first - var normalized = ArrayList(u8).init(allocator); - defer normalized.deinit(); + var normalized = ArrayList(u8){}; + defer normalized.deinit(allocator); for (path) |ch| { if (ch == '/') { - try normalized.append('\\'); + try normalized.append(allocator, '\\'); } else { - try normalized.append(std.ascii.toUpper(ch)); + try normalized.append(allocator, std.ascii.toUpper(ch)); } } @@ -48,12 +48,12 @@ fn formatPath(allocator: Allocator, path: []const u8) ![]const u8 { } // Build result with components converted to 8.3 - var result = ArrayList(u8).init(allocator); - defer result.deinit(); + var result = ArrayList(u8){}; + defer result.deinit(allocator); // If absolute, start with a backslash (after potential drive prefix) if (starts_with_backslash) { - try result.append('\\'); + try result.append(allocator, '\\'); } var it = std.mem.splitScalar(u8, normalized.items[idx..], '\\'); @@ -62,38 +62,38 @@ fn formatPath(allocator: Allocator, path: []const u8) ![]const u8 { if (component.len == 0) continue; if (!first_component and result.items.len > 0 and result.items[result.items.len - 1] != '\\') { - try result.append('\\'); + try result.append(allocator, '\\'); } first_component = false; const short_name = try convertTo83(allocator, component); defer allocator.free(short_name.name); defer allocator.free(short_name.ext); - try result.appendSlice(short_name.name); + try result.appendSlice(allocator, short_name.name); if (short_name.ext.len > 0) { - try result.append('.'); - try result.appendSlice(short_name.ext); + try result.append(allocator, '.'); + try result.appendSlice(allocator, short_name.ext); } } // Prepend drive if present or add default C: - var final_buf = ArrayList(u8).init(allocator); - defer final_buf.deinit(); + var final_buf = ArrayList(u8){}; + defer final_buf.deinit(allocator); if (has_drive) { - try final_buf.append(drive_letter); - try final_buf.append(':'); + try final_buf.append(allocator, drive_letter); + try final_buf.append(allocator, ':'); if (result.items.len > 0 and result.items[0] != '\\') { - try final_buf.append('\\'); + try final_buf.append(allocator, '\\'); } - try final_buf.appendSlice(result.items); + try final_buf.appendSlice(allocator, result.items); } else { // No drive: default to C: - try final_buf.appendSlice("C:"); + try final_buf.appendSlice(allocator, "C:"); if (result.items.len > 0 and result.items[0] != '\\') { - try final_buf.append('\\'); + try final_buf.append(allocator, '\\'); } - try final_buf.appendSlice(result.items); + try final_buf.appendSlice(allocator, result.items); } return allocator.dupe(u8, final_buf.items); @@ -113,19 +113,25 @@ fn parseAndExecute(input: []const u8, allocator: Allocator) !CommandStatus { return try eval.executeCommand(command, allocator); } -fn readLine(allocator: Allocator, prompt_text: []const u8) !?[]const u8 { - const stdin = std.io.getStdIn().reader(); - const stdout = std.io.getStdOut(); +fn readLine(buf: []u8, prompt_text: []const u8) !?[]const u8 { + const stdin = std.fs.File.stdin(); + var stdout_buffer: [1024]u8 = undefined; + var stdout_writer = std.fs.File.stdout().writer(&stdout_buffer); + const stdout = &stdout_writer.interface; try stdout.writeAll(prompt_text); + try stdout.flush(); - if (try stdin.readUntilDelimiterOrEofAlloc(allocator, '\n', 4096)) |input| { - // Remove trailing \r on Windows - if (input.len > 0 and input[input.len - 1] == '\r') { - return input[0 .. input.len - 1]; + var reader = stdin.readerStreaming(buf); + const input = std.io.Reader.takeDelimiterExclusive(&reader.interface, '\n') catch |err| { + switch (err) { + error.EndOfStream => return null, + else => return err, } - return input; + }; + if (input.len > 0 and input[input.len - 1] == '\r') { + return input[0 .. input.len - 1]; } - return null; + return input; } pub fn main() !void { @@ -153,14 +159,16 @@ pub fn main() !void { const final_prompt = try std.mem.replaceOwned(u8, allocator, interpolated_prompt, "$g", ">"); defer allocator.free(final_prompt); - if (try readLine(allocator, final_prompt)) |line| { - defer allocator.free(line); - + var buf: [4096]u8 = undefined; + if (try readLine(&buf, final_prompt)) |line| { const command_result = parseAndExecute(line, allocator) catch |err| { switch (err) { error.ExpectedWord, error.UnexpectedToken => { - const stdout = std.io.getStdOut(); + var stdout_buffer: [1024]u8 = undefined; + var stdout_writer = std.fs.File.stdout().writer(&stdout_buffer); + const stdout = &stdout_writer.interface; try stdout.writeAll("Bad command or file name\n"); + try stdout.flush(); continue; }, else => return err, @@ -178,8 +186,12 @@ pub fn main() !void { } fn printWelcomeMessage() !void { - const stdout = std.io.getStdOut(); - if (!stdout.isTty()) return; + const stdout_file = std.fs.File.stdout(); + if (!stdout_file.isTty()) return; + + var stdout_buffer: [1024]u8 = undefined; + var stdout_writer = stdout_file.writer(&stdout_buffer); + const stdout = &stdout_writer.interface; try stdout.writeAll( \\Starting MB-DOS... @@ -193,4 +205,5 @@ fn printWelcomeMessage() !void { \\ \\ ); + try stdout.flush(); } diff --git a/src/parser.zig b/src/parser.zig index 7bbfdab..af465f8 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -46,8 +46,8 @@ const Lexer = struct { } fn readWord(self: *Lexer, allocator: Allocator) ![]const u8 { - var word = ArrayList(u8).init(allocator); - defer word.deinit(); + var word = ArrayList(u8){}; + defer word.deinit(allocator); var in_quotes = false; var quote_char: u8 = '"'; @@ -63,18 +63,18 @@ const Lexer = struct { in_quotes = false; self.advance(); } else { - try word.append(ch); + try word.append(allocator, ch); self.advance(); } }, '|', '>', '<', '\n' => { if (!in_quotes) break; - try word.append(ch); + try word.append(allocator, ch); self.advance(); }, else => { if (!in_quotes and std.ascii.isWhitespace(ch)) break; - try word.append(ch); + try word.append(allocator, ch); self.advance(); }, } @@ -127,7 +127,7 @@ const Lexer = struct { } pub fn tokenize(self: *Lexer, allocator: Allocator) !ArrayList(Token) { - var tokens = ArrayList(Token).init(allocator); + var tokens = ArrayList(Token){}; while (true) { const token = try self.nextToken(allocator); @@ -135,7 +135,7 @@ const Lexer = struct { .Eof => true, else => false, }; - try tokens.append(token); + try tokens.append(allocator, token); if (is_eof) break; } @@ -206,7 +206,7 @@ const Parser = struct { fn parseRedirectedCommand(self: *Parser) !Command { const command = try self.parseSimpleCommand(); - var redirects = ArrayList(Redirect).init(self.allocator); + var redirects = ArrayList(Redirect){}; while (true) { const redirect_type = switch (self.currentToken()) { @@ -221,14 +221,14 @@ const Parser = struct { const target_str = try self.expectWord(); const target = try parseFilespec(self.allocator, target_str); - try redirects.append(Redirect{ + try redirects.append(self.allocator, Redirect{ .redirect_type = redirect_type, .target = target, }); } if (redirects.items.len == 0) { - redirects.deinit(); + redirects.deinit(self.allocator); return command; } else { const command_ptr = try self.allocator.create(Command); @@ -242,23 +242,23 @@ const Parser = struct { .Eof, .Newline => return Command.Empty, .Word => |command_name| { self.advance(); - var args = ArrayList([]const u8).init(self.allocator); + var args = ArrayList([]const u8){}; // Collect arguments while (true) { switch (self.currentToken()) { .Word => |arg| { - try args.append(arg); + try args.append(self.allocator, arg); self.advance(); }, else => break, } } - const result = try self.parseBuiltinCommand(command_name, args); + const result = try self.parseBuiltinCommand(command_name, &args); // For builtin commands, free the args ArrayList (the strings inside belong to tokens and will be freed later) if (result == .Builtin) { - args.deinit(); + args.deinit(self.allocator); } return result; }, @@ -266,35 +266,35 @@ const Parser = struct { } } - fn parseBuiltinCommand(self: *Parser, command_name: []const u8, args: ArrayList([]const u8)) !Command { + fn parseBuiltinCommand(self: *Parser, command_name: []const u8, args: *ArrayList([]const u8)) !Command { const cmd_upper = try std.ascii.allocUpperString(self.allocator, command_name); defer self.allocator.free(cmd_upper); // Check for /? help flag first - if (hasHelpFlag(args.items)) { + if (hasHelpFlag(args.*.items)) { const cmd_copy = try self.allocator.dupe(u8, cmd_upper); return Command{ .Builtin = BuiltinCommand{ .Help = .{ .command = cmd_copy } } }; } if (std.mem.eql(u8, cmd_upper, "HELP")) { - const help_command = if (args.items.len > 0) - try self.allocator.dupe(u8, args.items[0]) + const help_command = if (args.*.items.len > 0) + try self.allocator.dupe(u8, args.*.items[0]) else null; return Command{ .Builtin = BuiltinCommand{ .Help = .{ .command = help_command } } }; } else if (std.mem.eql(u8, cmd_upper, "ECHO")) { - if (args.items.len == 0) { + if (args.*.items.len == 0) { return Command{ .Builtin = BuiltinCommand.EchoPlain }; } else { - const first_arg_upper = try std.ascii.allocUpperString(self.allocator, args.items[0]); + const first_arg_upper = try std.ascii.allocUpperString(self.allocator, args.*.items[0]); defer self.allocator.free(first_arg_upper); - if (std.mem.eql(u8, first_arg_upper, "ON") and args.items.len == 1) { + if (std.mem.eql(u8, first_arg_upper, "ON") and args.*.items.len == 1) { return Command{ .Builtin = BuiltinCommand.EchoOn }; - } else if (std.mem.eql(u8, first_arg_upper, "OFF") and args.items.len == 1) { + } else if (std.mem.eql(u8, first_arg_upper, "OFF") and args.*.items.len == 1) { return Command{ .Builtin = BuiltinCommand.EchoOff }; } else { - const message = try std.mem.join(self.allocator, " ", args.items); + const message = try std.mem.join(self.allocator, " ", args.*.items); return Command{ .Builtin = BuiltinCommand{ .EchoText = .{ .message = message } } }; } } @@ -307,9 +307,9 @@ const Parser = struct { } else if (std.mem.eql(u8, cmd_upper, "VERIFY")) { return Command{ .Builtin = BuiltinCommand.Verify }; } else if (std.mem.eql(u8, cmd_upper, "DIR")) { - const separated = try self.separateFlagsFromArgs(args.items); - defer separated.flags.deinit(); - defer separated.positional.deinit(); + var separated = try self.separateFlagsFromArgs(args.*.items); + defer separated.flags.deinit(self.allocator); + defer separated.positional.deinit(self.allocator); const path = if (separated.positional.items.len == 0) try self.allocator.dupe(u8, ".") @@ -338,74 +338,74 @@ const Parser = struct { } else if (std.mem.eql(u8, cmd_upper, "TIME")) { return Command{ .Builtin = BuiltinCommand.Time }; } else if (std.mem.eql(u8, cmd_upper, "TYPE")) { - if (args.items.len == 0) { + if (args.*.items.len == 0) { return error.ExpectedWord; // Will be caught and show "Bad command or file name" } - const file_spec = try parseFilespec(self.allocator, args.items[0]); + const file_spec = try parseFilespec(self.allocator, args.*.items[0]); return Command{ .Builtin = BuiltinCommand{ .Type = .{ .file = file_spec } } }; } else if (std.mem.eql(u8, cmd_upper, "SORT")) { return Command{ .Builtin = BuiltinCommand.Sort }; } else if (std.mem.eql(u8, cmd_upper, "CD") or std.mem.eql(u8, cmd_upper, "CHDIR")) { - const path = if (args.items.len == 0) + const path = if (args.*.items.len == 0) try self.allocator.dupe(u8, "") else - try self.allocator.dupe(u8, args.items[0]); + try self.allocator.dupe(u8, args.*.items[0]); return Command{ .Builtin = BuiltinCommand{ .Chdir = .{ .path = path } } }; } else if (std.mem.eql(u8, cmd_upper, "COPY")) { - if (args.items.len < 2) { + if (args.*.items.len < 2) { return error.ExpectedWord; // Will show "Bad command or file name" } - const from_spec = try parseFilespec(self.allocator, args.items[0]); - const to_spec = try parseFilespec(self.allocator, args.items[1]); + const from_spec = try parseFilespec(self.allocator, args.*.items[0]); + const to_spec = try parseFilespec(self.allocator, args.*.items[1]); return Command{ .Builtin = BuiltinCommand{ .Copy = .{ .from = from_spec, .to = to_spec } } }; } else if (std.mem.eql(u8, cmd_upper, "DEL") or std.mem.eql(u8, cmd_upper, "ERASE")) { - if (args.items.len == 0) { + if (args.*.items.len == 0) { return error.ExpectedWord; // Will show "Bad command or file name" } - const path = try self.allocator.dupe(u8, args.items[0]); + const path = try self.allocator.dupe(u8, args.*.items[0]); return Command{ .Builtin = BuiltinCommand{ .Remove = .{ .path = path } } }; } else if (std.mem.eql(u8, cmd_upper, "MD") or std.mem.eql(u8, cmd_upper, "MKDIR")) { - if (args.items.len == 0) { + if (args.*.items.len == 0) { return error.ExpectedWord; // Will show "Bad command or file name" } - const path = try self.allocator.dupe(u8, args.items[0]); + const path = try self.allocator.dupe(u8, args.*.items[0]); return Command{ .Builtin = BuiltinCommand{ .Mkdir = .{ .path = path } } }; } else if (std.mem.eql(u8, cmd_upper, "RD") or std.mem.eql(u8, cmd_upper, "RMDIR")) { - if (args.items.len == 0) { + if (args.*.items.len == 0) { return error.ExpectedWord; // Will show "Bad command or file name" } - const path = try self.allocator.dupe(u8, args.items[0]); + const path = try self.allocator.dupe(u8, args.*.items[0]); return Command{ .Builtin = BuiltinCommand{ .Rmdir = .{ .path = path } } }; } else if (std.mem.eql(u8, cmd_upper, "REN") or std.mem.eql(u8, cmd_upper, "RENAME")) { - if (args.items.len < 2) { + if (args.*.items.len < 2) { return error.ExpectedWord; // Will show "Bad command or file name" } - const from_spec = try parseFilespec(self.allocator, args.items[0]); - const to_spec = try parseFilespec(self.allocator, args.items[1]); + const from_spec = try parseFilespec(self.allocator, args.*.items[0]); + const to_spec = try parseFilespec(self.allocator, args.*.items[1]); return Command{ .Builtin = BuiltinCommand{ .Rename = .{ .from = from_spec, .to = to_spec } } }; } else if (std.mem.eql(u8, cmd_upper, "MOVE")) { // MOVE command is more complex - for now just show not implemented return Command{ .Builtin = BuiltinCommand.Move }; } else if (std.mem.eql(u8, cmd_upper, "PATH")) { - if (args.items.len == 0) { + if (args.*.items.len == 0) { return Command{ .Builtin = BuiltinCommand.PathGet }; } else { // PATH=value or PATH value - const value = if (std.mem.startsWith(u8, args.items[0], "=")) - try self.allocator.dupe(u8, args.items[0][1..]) // Skip the '=' + const value = if (std.mem.startsWith(u8, args.*.items[0], "=")) + try self.allocator.dupe(u8, args.*.items[0][1..]) // Skip the '=' else - try self.allocator.dupe(u8, args.items[0]); + try self.allocator.dupe(u8, args.*.items[0]); return Command{ .Builtin = BuiltinCommand{ .PathSet = .{ .value = value } } }; } } else { // External command - need to duplicate all strings const program_copy = try self.allocator.dupe(u8, command_name); - var args_copy = ArrayList([]const u8).init(self.allocator); - for (args.items) |arg| { + var args_copy = ArrayList([]const u8){}; + for (args.*.items) |arg| { const arg_copy = try self.allocator.dupe(u8, arg); - try args_copy.append(arg_copy); + try args_copy.append(self.allocator, arg_copy); } - args.deinit(); // Free the original args list (but not the strings, as they belong to tokens) + args.*.deinit(self.allocator); // Free the original args list (but not the strings, as they belong to tokens) return Command{ .External = .{ .program = program_copy, .args = args_copy } }; } } @@ -420,14 +420,14 @@ const Parser = struct { } fn separateFlagsFromArgs(self: *Parser, args: []const []const u8) !struct { flags: ArrayList([]const u8), positional: ArrayList([]const u8) } { - var flags = ArrayList([]const u8).init(self.allocator); - var positional = ArrayList([]const u8).init(self.allocator); + var flags = ArrayList([]const u8){}; + var positional = ArrayList([]const u8){}; for (args) |arg| { if (arg.len > 0 and arg[0] == '/') { - try flags.append(arg); + try flags.append(self.allocator, arg); } else { - try positional.append(arg); + try positional.append(self.allocator, arg); } } @@ -463,7 +463,7 @@ pub fn parse(input: []const u8, allocator: Allocator) !Command { else => {}, } } - tokens.deinit(); + tokens.deinit(allocator); } var parser = Parser.init(tokens, allocator); diff --git a/src/paths.zig b/src/paths.zig index dd3ace2..abda053 100644 --- a/src/paths.zig +++ b/src/paths.zig @@ -3,18 +3,18 @@ const Allocator = std.mem.Allocator; const ArrayList = std.ArrayList; pub fn formatDosPath(allocator: Allocator, path: []const u8) ![]const u8 { - var result = ArrayList(u8).init(allocator); - defer result.deinit(); + var result = ArrayList(u8){}; + defer result.deinit(allocator); // Convert path to DOS format with uppercase drive letter and backslashes - var converted_path = ArrayList(u8).init(allocator); - defer converted_path.deinit(); + var converted_path = ArrayList(u8){}; + defer converted_path.deinit(allocator); for (path) |ch| { if (ch == '/') { - try converted_path.append('\\'); + try converted_path.append(allocator, '\\'); } else { - try converted_path.append(std.ascii.toUpper(ch)); + try converted_path.append(allocator, std.ascii.toUpper(ch)); } } @@ -26,7 +26,7 @@ pub fn formatDosPath(allocator: Allocator, path: []const u8) ![]const u8 { if (component.len == 0) continue; if (!first) { - try result.append('\\'); + try result.append(allocator, '\\'); } first = false; @@ -34,22 +34,22 @@ pub fn formatDosPath(allocator: Allocator, path: []const u8) ![]const u8 { const short_name = try convertTo83(allocator, component); defer allocator.free(short_name.name); defer allocator.free(short_name.ext); - try result.appendSlice(short_name.name); + try result.appendSlice(allocator, short_name.name); if (short_name.ext.len > 0) { - try result.append('.'); - try result.appendSlice(short_name.ext); + try result.append(allocator, '.'); + try result.appendSlice(allocator, short_name.ext); } } // Ensure it starts with a drive letter if it's an absolute path if (result.items.len == 0 or (result.items.len >= 1 and result.items[0] == '\\')) { - var prefixed = ArrayList(u8).init(allocator); - defer prefixed.deinit(); - try prefixed.appendSlice("C:"); + var prefixed = ArrayList(u8){}; + defer prefixed.deinit(allocator); + try prefixed.appendSlice(allocator, "C:"); if (result.items.len > 0 and result.items[0] != '\\') { - try prefixed.append('\\'); + try prefixed.append(allocator, '\\'); } - try prefixed.appendSlice(result.items); + try prefixed.appendSlice(allocator, result.items); return allocator.dupe(u8, prefixed.items); } @@ -79,48 +79,48 @@ pub fn convertTo83(allocator: Allocator, filename: []const u8) !struct { name: [ } // Clean name part (remove spaces and invalid chars, convert to uppercase) - var clean_name = ArrayList(u8).init(allocator); - defer clean_name.deinit(); + var clean_name = ArrayList(u8){}; + defer clean_name.deinit(allocator); for (name_part) |ch| { if (std.ascii.isAlphanumeric(ch)) { - try clean_name.append(std.ascii.toUpper(ch)); + try clean_name.append(allocator, std.ascii.toUpper(ch)); } else if (ch == '-' or ch == '_') { - try clean_name.append(ch); + try clean_name.append(allocator, ch); } // Skip spaces and other invalid characters } // Clean extension part (max 3 chars, uppercase) - var clean_ext = ArrayList(u8).init(allocator); - defer clean_ext.deinit(); + var clean_ext = ArrayList(u8){}; + defer clean_ext.deinit(allocator); for (ext_part) |ch| { if (clean_ext.items.len >= 3) break; if (std.ascii.isAlphanumeric(ch)) { - try clean_ext.append(std.ascii.toUpper(ch)); + try clean_ext.append(allocator, std.ascii.toUpper(ch)); } } - var name_result = ArrayList(u8).init(allocator); - defer name_result.deinit(); - var ext_result = ArrayList(u8).init(allocator); - defer ext_result.deinit(); + var name_result = ArrayList(u8){}; + defer name_result.deinit(allocator); + var ext_result = ArrayList(u8){}; + defer ext_result.deinit(allocator); // Build 8.3 filename if (clean_name.items.len <= 8 and clean_ext.items.len <= 3) { // Name fits in 8.3, use as-is - try name_result.appendSlice(clean_name.items); - try ext_result.appendSlice(clean_ext.items); + try name_result.appendSlice(allocator, clean_name.items); + try ext_result.appendSlice(allocator, clean_ext.items); } else { // Need to abbreviate with ~1 const max_name_len = if (clean_name.items.len > 6) 6 else clean_name.items.len; - try name_result.appendSlice(clean_name.items[0..max_name_len]); - try name_result.appendSlice("~1"); + try name_result.appendSlice(allocator, clean_name.items[0..max_name_len]); + try name_result.appendSlice(allocator, "~1"); if (clean_ext.items.len > 0) { const max_ext_len = if (clean_ext.items.len > 3) 3 else clean_ext.items.len; - try ext_result.appendSlice(clean_ext.items[0..max_ext_len]); + try ext_result.appendSlice(allocator, clean_ext.items[0..max_ext_len]); } } |