diff options
-rw-r--r-- | src/cmd/chdir.zig | 31 | ||||
-rw-r--r-- | src/cmd/cls.zig | 9 | ||||
-rw-r--r-- | src/cmd/copy.zig | 41 | ||||
-rw-r--r-- | src/cmd/date.zig | 12 | ||||
-rw-r--r-- | src/cmd/dir.zig | 27 | ||||
-rw-r--r-- | src/cmd/echo.zig | 31 | ||||
-rw-r--r-- | src/cmd/external.zig | 6 | ||||
-rw-r--r-- | src/cmd/lib/types.zig | 31 | ||||
-rw-r--r-- | src/cmd/mkdir.zig | 11 | ||||
-rw-r--r-- | src/cmd/move.zig | 11 | ||||
-rw-r--r-- | src/cmd/path.zig | 31 | ||||
-rw-r--r-- | src/cmd/pipe.zig | 8 | ||||
-rw-r--r-- | src/cmd/redirect.zig | 10 | ||||
-rw-r--r-- | src/cmd/remove.zig | 13 | ||||
-rw-r--r-- | src/cmd/rename.zig | 15 | ||||
-rw-r--r-- | src/cmd/rmdir.zig | 11 | ||||
-rw-r--r-- | src/cmd/sort.zig | 19 | ||||
-rw-r--r-- | src/cmd/time.zig | 12 | ||||
-rw-r--r-- | src/cmd/type.zig | 19 | ||||
-rw-r--r-- | src/cmd/ver.zig | 9 | ||||
-rw-r--r-- | src/eval.zig | 57 |
21 files changed, 216 insertions, 198 deletions
diff --git a/src/cmd/chdir.zig b/src/cmd/chdir.zig index 5c2c618..c9413ff 100644 --- a/src/cmd/chdir.zig +++ b/src/cmd/chdir.zig @@ -7,35 +7,34 @@ const formatDosPath = paths.formatDosPath; const types = @import("./lib/types.zig"); const CommandStatus = types.CommandStatus; -const OutputCapture = types.OutputCapture; -const InputSource = types.InputSource; +const CommandContext = types.CommandContext; pub const Chdir = struct { path: []const u8, - pub fn eval(chdir: Chdir, allocator: Allocator, output_capture: ?*OutputCapture, input_source: ?*InputSource) !CommandStatus { - _ = input_source; + pub fn eval(chdir: Chdir, ctx: CommandContext) !CommandStatus { + _ = ctx.input_source; if (chdir.path.len == 0) { // No arguments - display current directory - const cwd = std.fs.cwd().realpathAlloc(allocator, ".") catch { + const cwd = std.fs.cwd().realpathAlloc(ctx.allocator, ".") catch { const error_msg = "Unable to determine current directory\n"; - if (output_capture) |capture| { + if (ctx.output_capture) |capture| { try capture.write(error_msg); } else { print("{s}", .{error_msg}); } return CommandStatus{ .Code = 1 }; }; - defer allocator.free(cwd); + defer ctx.allocator.free(cwd); - const formatted_path = try formatDosPath(allocator, cwd); - defer allocator.free(formatted_path); + const formatted_path = try formatDosPath(ctx.allocator, cwd); + defer ctx.allocator.free(formatted_path); - const output = try std.fmt.allocPrint(allocator, "{s}\n", .{formatted_path}); - defer allocator.free(output); + const output = try std.fmt.allocPrint(ctx.allocator, "{s}\n", .{formatted_path}); + defer ctx.allocator.free(output); - if (output_capture) |capture| { + if (ctx.output_capture) |capture| { try capture.write(output); } else { print("{s}", .{output}); @@ -50,7 +49,7 @@ pub const Chdir = struct { // Go to parent directory std.process.changeCurDir("..") catch { const error_msg = "The system cannot find the path specified.\n"; - if (output_capture) |capture| { + if (ctx.output_capture) |capture| { try capture.write(error_msg); } else { print("{s}", .{error_msg}); @@ -61,7 +60,7 @@ pub const Chdir = struct { // Go to root directory - simplified to just go to "/" std.process.changeCurDir("/") catch { const error_msg = "The system cannot find the path specified.\n"; - if (output_capture) |capture| { + if (ctx.output_capture) |capture| { try capture.write(error_msg); } else { print("{s}", .{error_msg}); @@ -74,7 +73,7 @@ pub const Chdir = struct { for (target_path) |ch| { if (ch == 0) { const error_msg = "Invalid path: contains null character\n"; - if (output_capture) |capture| { + if (ctx.output_capture) |capture| { try capture.write(error_msg); } else { print("{s}", .{error_msg}); @@ -85,7 +84,7 @@ pub const Chdir = struct { std.process.changeCurDir(target_path) catch { const error_msg = "The system cannot find the path specified.\n"; - if (output_capture) |capture| { + if (ctx.output_capture) |capture| { try capture.write(error_msg); } else { print("{s}", .{error_msg}); diff --git a/src/cmd/cls.zig b/src/cmd/cls.zig index 70c1fc4..4e7b8c6 100644 --- a/src/cmd/cls.zig +++ b/src/cmd/cls.zig @@ -4,16 +4,13 @@ const print = std.debug.print; const types = @import("./lib/types.zig"); const CommandStatus = types.CommandStatus; -const OutputCapture = types.OutputCapture; -const InputSource = types.InputSource; +const CommandContext = types.CommandContext; pub const Cls = struct { - pub fn eval(cls: Cls, allocator: Allocator, output_capture: ?*OutputCapture, input_source: ?*InputSource) !CommandStatus { + pub fn eval(cls: Cls, ctx: CommandContext) !CommandStatus { _ = cls; - _ = allocator; - _ = input_source; - if (output_capture == null) { + if (ctx.output_capture == null) { // Clear screen - only works when not redirected print("\x1B[2J\x1B[H", .{}); } diff --git a/src/cmd/copy.zig b/src/cmd/copy.zig index c99560f..9f9d4bf 100644 --- a/src/cmd/copy.zig +++ b/src/cmd/copy.zig @@ -7,15 +7,14 @@ const FileSpec = syntax.FileSpec; const types = @import("./lib/types.zig"); const CommandStatus = types.CommandStatus; -const OutputCapture = types.OutputCapture; -const InputSource = types.InputSource; +const CommandContext = types.CommandContext; pub const Copy = struct { from: FileSpec, to: FileSpec, - pub fn eval(copy: Copy, allocator: Allocator, output_capture: ?*OutputCapture, input_source: ?*InputSource) !CommandStatus { - _ = input_source; + pub fn eval(copy: Copy, ctx: CommandContext) !CommandStatus { + _ = ctx.input_source; // Handle source file const source_path = switch (copy.from) { @@ -24,7 +23,7 @@ pub const Copy = struct { const dest_path = switch (copy.to) { .Con => { const error_msg = "Cannot copy from CON to CON\n"; - if (output_capture) |capture| { + if (ctx.output_capture) |capture| { try capture.write(error_msg); } else { print("{s}", .{error_msg}); @@ -33,7 +32,7 @@ pub const Copy = struct { }, .Lpt1, .Lpt2, .Lpt3, .Prn => { const error_msg = "Cannot copy to device\n"; - if (output_capture) |capture| { + if (ctx.output_capture) |capture| { try capture.write(error_msg); } else { print("{s}", .{error_msg}); @@ -50,7 +49,7 @@ pub const Copy = struct { error.PathAlreadyExists => "File already exists - use different name\n", else => "Cannot create file\n", }; - if (output_capture) |capture| { + if (ctx.output_capture) |capture| { try capture.write(error_msg); } else { print("{s}", .{error_msg}); @@ -64,14 +63,14 @@ pub const Copy = struct { var line_count: u32 = 0; // Skip output redirection since we're doing interactive input - if (output_capture == null) { + if (ctx.output_capture == null) { // In interactive mode, show no prompt (DOS behavior) } while (true) { - if (stdin.readUntilDelimiterOrEofAlloc(allocator, '\n', 4096)) |maybe_line| { + if (stdin.readUntilDelimiterOrEofAlloc(ctx.allocator, '\n', 4096)) |maybe_line| { if (maybe_line) |line| { - defer allocator.free(line); + defer ctx.allocator.free(line); // Check for Ctrl+Z (EOF marker) if (line.len == 1 and line[0] == 26) { // ASCII 26 = Ctrl+Z @@ -98,9 +97,9 @@ pub const Copy = struct { } } - const msg = try std.fmt.allocPrint(allocator, " 1 File(s) copied\n", .{}); - defer allocator.free(msg); - if (output_capture) |capture| { + const msg = try std.fmt.allocPrint(ctx.allocator, " 1 File(s) copied\n", .{}); + defer ctx.allocator.free(msg); + if (ctx.output_capture) |capture| { try capture.write(msg); } else { print("{s}", .{msg}); @@ -109,7 +108,7 @@ pub const Copy = struct { }, .Lpt1, .Lpt2, .Lpt3, .Prn => { const error_msg = "Cannot copy from device\n"; - if (output_capture) |capture| { + if (ctx.output_capture) |capture| { try capture.write(error_msg); } else { print("{s}", .{error_msg}); @@ -129,7 +128,7 @@ pub const Copy = struct { error.AccessDenied => "Access denied\n", else => "Cannot access source file\n", }; - if (output_capture) |capture| { + if (ctx.output_capture) |capture| { try capture.write(error_msg); } else { print("{s}", .{error_msg}); @@ -143,7 +142,7 @@ pub const Copy = struct { while (true) { const bytes_read = source_file.readAll(&buffer) catch { const error_msg = "Error reading file\n"; - if (output_capture) |capture| { + if (ctx.output_capture) |capture| { try capture.write(error_msg); } else { print("{s}", .{error_msg}); @@ -152,7 +151,7 @@ pub const Copy = struct { }; if (bytes_read == 0) break; - if (output_capture) |capture| { + if (ctx.output_capture) |capture| { try capture.write(buffer[0..bytes_read]); } else { print("{s}", .{buffer[0..bytes_read]}); @@ -162,7 +161,7 @@ pub const Copy = struct { } const msg = " 1 File(s) copied\n"; - if (output_capture) |capture| { + if (ctx.output_capture) |capture| { try capture.write(msg); } else { print("{s}", .{msg}); @@ -171,7 +170,7 @@ pub const Copy = struct { }, .Lpt1, .Lpt2, .Lpt3, .Prn => { const error_msg = "Cannot copy to device\n"; - if (output_capture) |capture| { + if (ctx.output_capture) |capture| { try capture.write(error_msg); } else { print("{s}", .{error_msg}); @@ -189,7 +188,7 @@ pub const Copy = struct { error.PathAlreadyExists => "File already exists\n", else => "Cannot copy file\n", }; - if (output_capture) |capture| { + if (ctx.output_capture) |capture| { try capture.write(error_msg); } else { print("{s}", .{error_msg}); @@ -198,7 +197,7 @@ pub const Copy = struct { }; const msg = " 1 File(s) copied\n"; - if (output_capture) |capture| { + if (ctx.output_capture) |capture| { try capture.write(msg); } else { print("{s}", .{msg}); diff --git a/src/cmd/date.zig b/src/cmd/date.zig index a299667..3a7d72b 100644 --- a/src/cmd/date.zig +++ b/src/cmd/date.zig @@ -4,17 +4,15 @@ const print = std.debug.print; const types = @import("./lib/types.zig"); const CommandStatus = types.CommandStatus; -const OutputCapture = types.OutputCapture; -const InputSource = types.InputSource; +const CommandContext = types.CommandContext; fn isLeapYear(year: u32) bool { return (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0); } pub const Date = struct { - pub fn eval(date: Date, allocator: Allocator, output_capture: ?*OutputCapture, input_source: ?*InputSource) !CommandStatus { + pub fn eval(date: Date, ctx: CommandContext) !CommandStatus { _ = date; - _ = input_source; const timestamp = std.time.timestamp(); const epoch_seconds = @as(u64, @intCast(timestamp)); @@ -56,9 +54,9 @@ pub const Date = struct { const day = remaining_days + 1; // Days are 1-indexed - const output = try std.fmt.allocPrint(allocator, "Current date is {d:0>2}/{d:0>2}/{d}\n", .{ month, day, year }); - defer allocator.free(output); - if (output_capture) |capture| { + const output = try std.fmt.allocPrint(ctx.allocator, "Current date is {d:0>2}/{d:0>2}/{d}\n", .{ month, day, year }); + defer ctx.allocator.free(output); + if (ctx.output_capture) |capture| { try capture.write(output); } else { print("{s}", .{output}); diff --git a/src/cmd/dir.zig b/src/cmd/dir.zig index a3b8279..5aff48b 100644 --- a/src/cmd/dir.zig +++ b/src/cmd/dir.zig @@ -17,6 +17,7 @@ const convertTo83 = paths.convertTo83; const types = @import("./lib/types.zig"); const CommandStatus = types.CommandStatus; +const CommandContext = types.CommandContext; const OutputCapture = types.OutputCapture; const InputSource = types.InputSource; @@ -75,15 +76,13 @@ fn getFreeDiskSpace(path: []const u8) GetFreeDiskSpaceError!u64 { pub const Dir = struct { path: []const u8, - pub fn eval(dir: Dir, allocator: Allocator, output_capture: ?*OutputCapture, input_source: ?*InputSource) !CommandStatus { - _ = input_source; - - var output_buffer = ArrayList(u8).init(allocator); + pub fn eval(dir: Dir, ctx: CommandContext) !CommandStatus { + var output_buffer = ArrayList(u8).init(ctx.allocator); defer output_buffer.deinit(); // Format path in DOS style with backslashes and uppercase drive letter - const formatted_path = try formatDosPath(allocator, dir.path); - defer allocator.free(formatted_path); + const formatted_path = try formatDosPath(ctx.allocator, dir.path); + defer ctx.allocator.free(formatted_path); // Get volume label (simplified - just show drive) const drive_letter = if (formatted_path.len >= 2 and formatted_path[1] == ':') @@ -96,7 +95,7 @@ pub const Dir = struct { var dir_iterator = std.fs.cwd().openDir(dir.path, .{ .iterate = true }) catch { const error_msg = "File not found\n"; - if (output_capture) |capture| { + if (ctx.output_capture) |capture| { try capture.write(error_msg); } else { print("{s}", .{error_msg}); @@ -115,12 +114,12 @@ pub const Dir = struct { // Convert timestamp to DOS date/time format const mtime_secs = @divFloor(stat.mtime, std.time.ns_per_s); - const date_time = try formatDosDateTime(allocator, @intCast(mtime_secs)); - defer allocator.free(date_time); + const date_time = try formatDosDateTime(ctx.allocator, @intCast(mtime_secs)); + defer ctx.allocator.free(date_time); // Convert filename to 8.3 format - const short_name = try convertTo83(allocator, entry.name); - defer allocator.free(short_name); + const short_name = try convertTo83(ctx.allocator, entry.name); + defer ctx.allocator.free(short_name); switch (entry.kind) { .directory => { @@ -137,8 +136,8 @@ pub const Dir = struct { } // Get free disk space using statvfs - const path = try std.fs.cwd().realpathAlloc(allocator, dir.path); - defer allocator.free(path); + const path = try std.fs.cwd().realpathAlloc(ctx.allocator, dir.path); + defer ctx.allocator.free(path); const bytes_free = getFreeDiskSpace(path) catch |err| switch (err) { error.AccessDenied => 0, error.NotImplemented => 0, @@ -147,7 +146,7 @@ pub const Dir = struct { try output_buffer.writer().print(" {d} File(s) {d:>14} bytes\n", .{ file_count, total_file_bytes }); try output_buffer.writer().print(" {d} Dir(s) {d:>14} bytes free\n", .{ dir_count, bytes_free }); - if (output_capture) |capture| { + if (ctx.output_capture) |capture| { try capture.write(output_buffer.items); } else { print("{s}", .{output_buffer.items}); diff --git a/src/cmd/echo.zig b/src/cmd/echo.zig index d3ef8b1..4f2731b 100644 --- a/src/cmd/echo.zig +++ b/src/cmd/echo.zig @@ -4,28 +4,23 @@ const print = std.debug.print; const types = @import("./lib/types.zig"); const CommandStatus = types.CommandStatus; -const OutputCapture = types.OutputCapture; -const InputSource = types.InputSource; +const CommandContext = types.CommandContext; pub const EchoOff = struct { - pub fn eval(echo_off: EchoOff, allocator: Allocator, output_capture: ?*OutputCapture, input_source: ?*InputSource) !CommandStatus { + pub fn eval(echo_off: EchoOff, ctx: CommandContext) !CommandStatus { _ = echo_off; - _ = allocator; - _ = output_capture; - _ = input_source; + _ = ctx; return CommandStatus{ .Code = 0 }; } }; pub const EchoOn = struct { - pub fn eval(echo_on: EchoOn, allocator: Allocator, output_capture: ?*OutputCapture, input_source: ?*InputSource) !CommandStatus { + pub fn eval(echo_on: EchoOn, ctx: CommandContext) !CommandStatus { _ = echo_on; - _ = allocator; - _ = input_source; const output = "ECHO is on\n"; - if (output_capture) |capture| { + if (ctx.output_capture) |capture| { try capture.write(output); } else { print("{s}", .{output}); @@ -35,13 +30,11 @@ pub const EchoOn = struct { }; pub const EchoPlain = struct { - pub fn eval(echo_plain: EchoPlain, allocator: Allocator, output_capture: ?*OutputCapture, input_source: ?*InputSource) !CommandStatus { + pub fn eval(echo_plain: EchoPlain, ctx: CommandContext) !CommandStatus { _ = echo_plain; - _ = allocator; - _ = input_source; const output = "ECHO is on\n"; - if (output_capture) |capture| { + if (ctx.output_capture) |capture| { try capture.write(output); } else { print("{s}", .{output}); @@ -53,12 +46,10 @@ pub const EchoPlain = struct { pub const EchoText = struct { message: []const u8, - pub fn eval(echo_text: EchoText, allocator: Allocator, output_capture: ?*OutputCapture, input_source: ?*InputSource) !CommandStatus { - _ = input_source; - - const output = try std.fmt.allocPrint(allocator, "{s}\n", .{echo_text.message}); - defer allocator.free(output); - if (output_capture) |capture| { + pub fn eval(echo_text: EchoText, ctx: CommandContext) !CommandStatus { + const output = try std.fmt.allocPrint(ctx.allocator, "{s}\n", .{echo_text.message}); + defer ctx.allocator.free(output); + if (ctx.output_capture) |capture| { try capture.write(output); } else { print("{s}", .{output}); diff --git a/src/cmd/external.zig b/src/cmd/external.zig index 92bfba6..68fc758 100644 --- a/src/cmd/external.zig +++ b/src/cmd/external.zig @@ -5,6 +5,7 @@ const print = std.debug.print; const types = @import("./lib/types.zig"); const CommandStatus = types.CommandStatus; +const CommandContext = types.CommandContext; const OutputCapture = types.OutputCapture; const InputSource = types.InputSource; @@ -12,7 +13,10 @@ pub const External = struct { program: []const u8, args: ArrayList([]const u8), - pub fn eval(external: External, allocator: Allocator, output_capture: ?*OutputCapture, input_source: ?*InputSource) !CommandStatus { + pub fn eval(external: External, ctx: CommandContext) !CommandStatus { + const allocator = ctx.allocator; + const output_capture = ctx.output_capture; + const input_source = ctx.input_source; // Try to execute external command var child_args = ArrayList([]const u8).init(allocator); defer child_args.deinit(); diff --git a/src/cmd/lib/types.zig b/src/cmd/lib/types.zig index 1f0e162..2d96295 100644 --- a/src/cmd/lib/types.zig +++ b/src/cmd/lib/types.zig @@ -61,3 +61,34 @@ pub const InputSource = struct { } } }; + +pub const CommandContext = struct { + allocator: Allocator, + output_capture: ?*OutputCapture, + input_source: ?*InputSource, + + // The real type is: + // + // const ExecuteCommandFn = *const fn (Command, Allocator, ?*OutputCapture, ?*InputSource) anyerror!CommandStatus; + // + // But Command is defined in ../cmd.zig, so we can't write it. + execute_command: ?*const anyopaque, // Will be cast to the appropriate function type when used + + pub fn init(allocator: Allocator, output_capture: ?*OutputCapture, input_source: ?*InputSource) CommandContext { + return CommandContext{ + .allocator = allocator, + .output_capture = output_capture, + .input_source = input_source, + .execute_command = null, + }; + } + + pub fn with_executor(allocator: Allocator, output_capture: ?*OutputCapture, input_source: ?*InputSource, execute_command: anytype) CommandContext { + return CommandContext{ + .allocator = allocator, + .output_capture = output_capture, + .input_source = input_source, + .execute_command = @ptrCast(&execute_command), + }; + } +}; diff --git a/src/cmd/mkdir.zig b/src/cmd/mkdir.zig index 7009fbc..59ed431 100644 --- a/src/cmd/mkdir.zig +++ b/src/cmd/mkdir.zig @@ -4,15 +4,14 @@ const print = std.debug.print; const types = @import("./lib/types.zig"); const CommandStatus = types.CommandStatus; -const OutputCapture = types.OutputCapture; -const InputSource = types.InputSource; +const CommandContext = types.CommandContext; pub const Mkdir = struct { path: []const u8, - pub fn eval(mkdir: Mkdir, allocator: Allocator, output_capture: ?*OutputCapture, input_source: ?*InputSource) !CommandStatus { - _ = allocator; - _ = input_source; + pub fn eval(mkdir: Mkdir, ctx: CommandContext) !CommandStatus { + _ = ctx.allocator; + _ = ctx.input_source; const dir_path = mkdir.path; @@ -24,7 +23,7 @@ pub const Mkdir = struct { error.NotDir => "The system cannot find the path specified\n", else => "Unable to create directory\n", }; - if (output_capture) |capture| { + if (ctx.output_capture) |capture| { try capture.write(error_msg); } else { print("{s}", .{error_msg}); diff --git a/src/cmd/move.zig b/src/cmd/move.zig index 9ae47b7..9787673 100644 --- a/src/cmd/move.zig +++ b/src/cmd/move.zig @@ -4,17 +4,16 @@ const print = std.debug.print; const types = @import("./lib/types.zig"); const CommandStatus = types.CommandStatus; -const OutputCapture = types.OutputCapture; -const InputSource = types.InputSource; +const CommandContext = types.CommandContext; pub const Move = struct { - pub fn eval(move: Move, allocator: Allocator, output_capture: ?*OutputCapture, input_source: ?*InputSource) !CommandStatus { + pub fn eval(move: Move, ctx: CommandContext) !CommandStatus { _ = move; - _ = allocator; - _ = input_source; + _ = ctx.allocator; + _ = ctx.input_source; const error_msg = "MOVE command not yet implemented\n"; - if (output_capture) |capture| { + if (ctx.output_capture) |capture| { try capture.write(error_msg); } else { print("{s}", .{error_msg}); diff --git a/src/cmd/path.zig b/src/cmd/path.zig index f8d5939..baf1c2e 100644 --- a/src/cmd/path.zig +++ b/src/cmd/path.zig @@ -4,19 +4,18 @@ const print = std.debug.print; const types = @import("./lib/types.zig"); const CommandStatus = types.CommandStatus; -const OutputCapture = types.OutputCapture; -const InputSource = types.InputSource; +const CommandContext = types.CommandContext; pub const PathGet = struct { - pub fn eval(path_get: PathGet, allocator: Allocator, output_capture: ?*OutputCapture, input_source: ?*InputSource) !CommandStatus { + pub fn eval(path_get: PathGet, ctx: CommandContext) !CommandStatus { _ = path_get; - _ = input_source; + _ = ctx.input_source; - const current_path = std.process.getEnvVarOwned(allocator, "PATH") catch |err| switch (err) { + const current_path = std.process.getEnvVarOwned(ctx.allocator, "PATH") catch |err| switch (err) { error.EnvironmentVariableNotFound => { // PATH not set, show empty const output = "PATH=(not set)\n"; - if (output_capture) |capture| { + if (ctx.output_capture) |capture| { try capture.write(output); } else { print("{s}", .{output}); @@ -25,7 +24,7 @@ pub const PathGet = struct { }, else => { const error_msg = "Cannot access PATH environment variable\n"; - if (output_capture) |capture| { + if (ctx.output_capture) |capture| { try capture.write(error_msg); } else { print("{s}", .{error_msg}); @@ -33,11 +32,11 @@ pub const PathGet = struct { return CommandStatus{ .Code = 1 }; }, }; - defer allocator.free(current_path); + defer ctx.allocator.free(current_path); - const output = try std.fmt.allocPrint(allocator, "PATH={s}\n", .{current_path}); - defer allocator.free(output); - if (output_capture) |capture| { + const output = try std.fmt.allocPrint(ctx.allocator, "PATH={s}\n", .{current_path}); + defer ctx.allocator.free(output); + if (ctx.output_capture) |capture| { try capture.write(output); } else { print("{s}", .{output}); @@ -49,15 +48,15 @@ pub const PathGet = struct { pub const PathSet = struct { value: []const u8, - pub fn eval(path_set: PathSet, allocator: Allocator, output_capture: ?*OutputCapture, input_source: ?*InputSource) !CommandStatus { - _ = input_source; + pub fn eval(path_set: PathSet, ctx: CommandContext) !CommandStatus { + _ = ctx.input_source; // Note: In a real DOS system, this would persist for the session // Here we just show what would be set but don't actually set it // since Zig's std.process doesn't provide a simple way to set env vars - const output = try std.fmt.allocPrint(allocator, "PATH would be set to: {s}\n(Note: Environment variable setting not implemented in this shell)\n", .{path_set.value}); - defer allocator.free(output); - if (output_capture) |capture| { + const output = try std.fmt.allocPrint(ctx.allocator, "PATH would be set to: {s}\n(Note: Environment variable setting not implemented in this shell)\n", .{path_set.value}); + defer ctx.allocator.free(output); + if (ctx.output_capture) |capture| { try capture.write(output); } else { print("{s}", .{output}); diff --git a/src/cmd/pipe.zig b/src/cmd/pipe.zig index 4f079cb..f97561a 100644 --- a/src/cmd/pipe.zig +++ b/src/cmd/pipe.zig @@ -4,6 +4,7 @@ const print = std.debug.print; const types = @import("./lib/types.zig"); const CommandStatus = types.CommandStatus; +const CommandContext = types.CommandContext; const OutputCapture = types.OutputCapture; const InputSource = types.InputSource; @@ -17,8 +18,11 @@ pub const PipeCommand = struct { left: *Command, right: *Command, - pub fn eval(pipe: PipeCommand, allocator: Allocator, output_capture: ?*OutputCapture, input_source: ?*InputSource, executeCommandWithOutput: ExecuteCommandFn) !CommandStatus { - _ = input_source; // Pipe handles its own input flow + pub fn eval(pipe: PipeCommand, ctx: CommandContext) !CommandStatus { + // Cast the execute function back to its proper type + const executeCommandWithOutput: ExecuteCommandFn = @ptrCast(@alignCast(ctx.execute_command.?)); + const allocator = ctx.allocator; + const output_capture = ctx.output_capture; // Create output capture for the left command var left_output = OutputCapture.init(allocator); diff --git a/src/cmd/redirect.zig b/src/cmd/redirect.zig index dbdeafe..4cba259 100644 --- a/src/cmd/redirect.zig +++ b/src/cmd/redirect.zig @@ -5,6 +5,7 @@ const print = std.debug.print; const types = @import("./lib/types.zig"); const CommandStatus = types.CommandStatus; +const CommandContext = types.CommandContext; const OutputCapture = types.OutputCapture; const InputSource = types.InputSource; @@ -22,8 +23,13 @@ pub const RedirectCommand = struct { command: *Command, redirects: ArrayList(Redirect), - pub fn eval(redirect: RedirectCommand, allocator: Allocator, output_capture: ?*OutputCapture, input_source: ?*InputSource, executeCommandWithOutput: ExecuteCommandFn) !CommandStatus { - _ = input_source; // Redirect handles its own input source + pub fn eval(redirect: RedirectCommand, ctx: CommandContext) !CommandStatus { + _ = ctx.input_source; // Redirect handles its own input source + + // Cast the execute function back to its proper type + const executeCommandWithOutput: ExecuteCommandFn = @ptrCast(@alignCast(ctx.execute_command.?)); + const allocator = ctx.allocator; + const output_capture = ctx.output_capture; // Check if we have any output redirections var has_output_redirect = false; diff --git a/src/cmd/remove.zig b/src/cmd/remove.zig index 7b85f1d..e7d2688 100644 --- a/src/cmd/remove.zig +++ b/src/cmd/remove.zig @@ -4,15 +4,14 @@ const print = std.debug.print; const types = @import("./lib/types.zig"); const CommandStatus = types.CommandStatus; -const OutputCapture = types.OutputCapture; -const InputSource = types.InputSource; +const CommandContext = types.CommandContext; pub const Remove = struct { path: []const u8, - pub fn eval(remove: Remove, allocator: Allocator, output_capture: ?*OutputCapture, input_source: ?*InputSource) !CommandStatus { - _ = allocator; - _ = input_source; + pub fn eval(remove: Remove, ctx: CommandContext) !CommandStatus { + _ = ctx.allocator; + _ = ctx.input_source; const file_path = remove.path; @@ -20,7 +19,7 @@ pub const Remove = struct { if (std.mem.indexOf(u8, file_path, "*") != null or std.mem.indexOf(u8, file_path, "?") != null) { // Simple wildcard deletion - just show error for now const error_msg = "Wildcard deletion not yet implemented\n"; - if (output_capture) |capture| { + if (ctx.output_capture) |capture| { try capture.write(error_msg); } else { print("{s}", .{error_msg}); @@ -36,7 +35,7 @@ pub const Remove = struct { error.IsDir => "Access denied - cannot delete directory\n", else => "Cannot delete file\n", }; - if (output_capture) |capture| { + if (ctx.output_capture) |capture| { try capture.write(error_msg); } else { print("{s}", .{error_msg}); diff --git a/src/cmd/rename.zig b/src/cmd/rename.zig index 9942f4c..baca001 100644 --- a/src/cmd/rename.zig +++ b/src/cmd/rename.zig @@ -7,21 +7,20 @@ const FileSpec = syntax.FileSpec; const types = @import("./lib/types.zig"); const CommandStatus = types.CommandStatus; -const OutputCapture = types.OutputCapture; -const InputSource = types.InputSource; +const CommandContext = types.CommandContext; pub const Rename = struct { from: FileSpec, to: FileSpec, - pub fn eval(rename: Rename, allocator: Allocator, output_capture: ?*OutputCapture, input_source: ?*InputSource) !CommandStatus { - _ = allocator; - _ = input_source; + pub fn eval(rename: Rename, ctx: CommandContext) !CommandStatus { + _ = ctx.allocator; + _ = ctx.input_source; const from_path = switch (rename.from) { .Con, .Lpt1, .Lpt2, .Lpt3, .Prn => { const error_msg = "Cannot rename device\n"; - if (output_capture) |capture| { + if (ctx.output_capture) |capture| { try capture.write(error_msg); } else { print("{s}", .{error_msg}); @@ -34,7 +33,7 @@ pub const Rename = struct { const to_path = switch (rename.to) { .Con, .Lpt1, .Lpt2, .Lpt3, .Prn => { const error_msg = "Cannot rename to device\n"; - if (output_capture) |capture| { + if (ctx.output_capture) |capture| { try capture.write(error_msg); } else { print("{s}", .{error_msg}); @@ -52,7 +51,7 @@ pub const Rename = struct { error.RenameAcrossMountPoints => "Cannot rename across different drives\n", else => "Cannot rename file\n", }; - if (output_capture) |capture| { + if (ctx.output_capture) |capture| { try capture.write(error_msg); } else { print("{s}", .{error_msg}); diff --git a/src/cmd/rmdir.zig b/src/cmd/rmdir.zig index cbb0b92..db41fab 100644 --- a/src/cmd/rmdir.zig +++ b/src/cmd/rmdir.zig @@ -4,15 +4,14 @@ const print = std.debug.print; const types = @import("./lib/types.zig"); const CommandStatus = types.CommandStatus; -const OutputCapture = types.OutputCapture; -const InputSource = types.InputSource; +const CommandContext = types.CommandContext; pub const Rmdir = struct { path: []const u8, - pub fn eval(rmdir: Rmdir, allocator: Allocator, output_capture: ?*OutputCapture, input_source: ?*InputSource) !CommandStatus { - _ = allocator; - _ = input_source; + pub fn eval(rmdir: Rmdir, ctx: CommandContext) !CommandStatus { + _ = ctx.allocator; + _ = ctx.input_source; const dir_path = rmdir.path; @@ -25,7 +24,7 @@ pub const Rmdir = struct { error.NotDir => "The system cannot find the path specified\n", else => "Unable to remove directory\n", }; - if (output_capture) |capture| { + if (ctx.output_capture) |capture| { try capture.write(error_msg); } else { print("{s}", .{error_msg}); diff --git a/src/cmd/sort.zig b/src/cmd/sort.zig index 9c04c1e..8b797d1 100644 --- a/src/cmd/sort.zig +++ b/src/cmd/sort.zig @@ -5,31 +5,30 @@ const print = std.debug.print; const types = @import("./lib/types.zig"); const CommandStatus = types.CommandStatus; -const OutputCapture = types.OutputCapture; -const InputSource = types.InputSource; +const CommandContext = types.CommandContext; pub const Sort = struct { - pub fn eval(sort: Sort, allocator: Allocator, output_capture: ?*OutputCapture, input_source: ?*InputSource) !CommandStatus { + pub fn eval(sort: Sort, ctx: CommandContext) !CommandStatus { _ = sort; - var lines = ArrayList([]const u8).init(allocator); + var lines = ArrayList([]const u8).init(ctx.allocator); defer { for (lines.items) |line| { - allocator.free(line); + ctx.allocator.free(line); } lines.deinit(); } // Read input lines - if (input_source) |source| { + if (ctx.input_source) |source| { // Read from input redirection - while (try source.readLine(allocator)) |line| { + while (try source.readLine(ctx.allocator)) |line| { try lines.append(line); } } else { // Read from stdin (simplified - just show message) const msg = "SORT: Use input redirection (< file.txt) to sort file contents\n"; - if (output_capture) |capture| { + if (ctx.output_capture) |capture| { try capture.write(msg); } else { print("{s}", .{msg}); @@ -45,14 +44,14 @@ pub const Sort = struct { }.lessThan); // Output sorted lines - var output_buffer = ArrayList(u8).init(allocator); + var output_buffer = ArrayList(u8).init(ctx.allocator); defer output_buffer.deinit(); for (lines.items) |line| { try output_buffer.writer().print("{s}\n", .{line}); } - if (output_capture) |capture| { + if (ctx.output_capture) |capture| { try capture.write(output_buffer.items); } else { print("{s}", .{output_buffer.items}); diff --git a/src/cmd/time.zig b/src/cmd/time.zig index bd03cfa..c30ca47 100644 --- a/src/cmd/time.zig +++ b/src/cmd/time.zig @@ -4,13 +4,11 @@ const print = std.debug.print; const types = @import("./lib/types.zig"); const CommandStatus = types.CommandStatus; -const OutputCapture = types.OutputCapture; -const InputSource = types.InputSource; +const CommandContext = types.CommandContext; pub const Time = struct { - pub fn eval(time: Time, allocator: Allocator, output_capture: ?*OutputCapture, input_source: ?*InputSource) !CommandStatus { + pub fn eval(time: Time, ctx: CommandContext) !CommandStatus { _ = time; - _ = input_source; const timestamp = std.time.timestamp(); const epoch_seconds = @as(u64, @intCast(timestamp)); @@ -19,9 +17,9 @@ pub const Time = struct { const minutes = (day_seconds % std.time.s_per_hour) / std.time.s_per_min; const seconds = day_seconds % std.time.s_per_min; - const output = try std.fmt.allocPrint(allocator, "Current time is {d:0>2}:{d:0>2}:{d:0>2}\n", .{ hours, minutes, seconds }); - defer allocator.free(output); - if (output_capture) |capture| { + const output = try std.fmt.allocPrint(ctx.allocator, "Current time is {d:0>2}:{d:0>2}:{d:0>2}\n", .{ hours, minutes, seconds }); + defer ctx.allocator.free(output); + if (ctx.output_capture) |capture| { try capture.write(output); } else { print("{s}", .{output}); diff --git a/src/cmd/type.zig b/src/cmd/type.zig index 9270e7b..86ccfda 100644 --- a/src/cmd/type.zig +++ b/src/cmd/type.zig @@ -8,19 +8,16 @@ const FileSpec = syntax.FileSpec; const types = @import("./lib/types.zig"); const CommandStatus = types.CommandStatus; -const OutputCapture = types.OutputCapture; -const InputSource = types.InputSource; +const CommandContext = types.CommandContext; pub const Type = struct { file: FileSpec, - pub fn eval(type_cmd: Type, allocator: Allocator, output_capture: ?*OutputCapture, input_source: ?*InputSource) !CommandStatus { - _ = input_source; - + pub fn eval(type_cmd: Type, ctx: CommandContext) !CommandStatus { const file_path = switch (type_cmd.file) { .Con => { const error_msg = "Cannot TYPE from CON\n"; - if (output_capture) |capture| { + if (ctx.output_capture) |capture| { try capture.write(error_msg); } else { print("{s}", .{error_msg}); @@ -29,7 +26,7 @@ pub const Type = struct { }, .Lpt1, .Lpt2, .Lpt3, .Prn => { const error_msg = "Cannot TYPE from device\n"; - if (output_capture) |capture| { + if (ctx.output_capture) |capture| { try capture.write(error_msg); } else { print("{s}", .{error_msg}); @@ -46,7 +43,7 @@ pub const Type = struct { error.AccessDenied => "Access is denied.\n", else => "Cannot access file.\n", }; - if (output_capture) |capture| { + if (ctx.output_capture) |capture| { try capture.write(error_msg); } else { print("{s}", .{error_msg}); @@ -63,7 +60,7 @@ pub const Type = struct { error.AccessDenied => "Access is denied.\n", else => "Error reading file.\n", }; - if (output_capture) |capture| { + if (ctx.output_capture) |capture| { try capture.write(error_msg); } else { print("{s}", .{error_msg}); @@ -74,7 +71,7 @@ pub const Type = struct { if (bytes_read == 0) break; // Process buffer contents for output - var processed_output = ArrayList(u8).init(allocator); + var processed_output = ArrayList(u8).init(ctx.allocator); defer processed_output.deinit(); for (buffer[0..bytes_read]) |byte| { @@ -94,7 +91,7 @@ pub const Type = struct { } } - if (output_capture) |capture| { + if (ctx.output_capture) |capture| { try capture.write(processed_output.items); } else { print("{s}", .{processed_output.items}); diff --git a/src/cmd/ver.zig b/src/cmd/ver.zig index 2d8d56b..5e99c03 100644 --- a/src/cmd/ver.zig +++ b/src/cmd/ver.zig @@ -4,17 +4,14 @@ const print = std.debug.print; const types = @import("./lib/types.zig"); const CommandStatus = types.CommandStatus; -const OutputCapture = types.OutputCapture; -const InputSource = types.InputSource; +const CommandContext = types.CommandContext; pub const Ver = struct { - pub fn eval(ver: Ver, allocator: Allocator, output_capture: ?*OutputCapture, input_source: ?*InputSource) !CommandStatus { + pub fn eval(ver: Ver, ctx: CommandContext) !CommandStatus { _ = ver; - _ = allocator; - _ = input_source; const output = "MB-DOSE Version 6.22\n"; - if (output_capture) |capture| { + if (ctx.output_capture) |capture| { try capture.write(output); } else { print("{s}", .{output}); diff --git a/src/eval.zig b/src/eval.zig index a689837..7aaae4b 100644 --- a/src/eval.zig +++ b/src/eval.zig @@ -30,6 +30,7 @@ const cmdTypes = @import("cmd/lib/types.zig"); pub const CommandStatus = cmdTypes.CommandStatus; const OutputCapture = cmdTypes.OutputCapture; const InputSource = cmdTypes.InputSource; +const CommandContext = cmdTypes.CommandContext; const STDOUT_BUFFER_SIZE: usize = 1024; const STDERR_BUFFER_SIZE: usize = 1024; @@ -39,78 +40,80 @@ pub fn executeCommand(command: Command, allocator: Allocator) !CommandStatus { } pub fn executeCommandWithOutput(command: Command, allocator: Allocator, output_capture: ?*OutputCapture, input_source: ?*InputSource) !CommandStatus { + const ctx = CommandContext.init(allocator, output_capture, input_source); + switch (command) { .Empty => return CommandStatus{ .Code = 0 }, .Builtin => |builtin_cmd| { switch (builtin_cmd) { .EchoText => |echo_text| { - return echo_text.eval(allocator, output_capture, input_source); + return echo_text.eval(ctx); }, .Cls => |cls| { - return cls.eval(allocator, output_capture, input_source); + return cls.eval(ctx); }, .Exit => { return CommandStatus.ExitShell; }, .EchoPlain => |echo_plain| { - return echo_plain.eval(allocator, output_capture, input_source); + return echo_plain.eval(ctx); }, .EchoOn => |echo_on| { - return echo_on.eval(allocator, output_capture, input_source); + return echo_on.eval(ctx); }, .EchoOff => |echo_off| { - return echo_off.eval(allocator, output_capture, input_source); + return echo_off.eval(ctx); }, .Ver => |ver| { - return ver.eval(allocator, output_capture, input_source); + return ver.eval(ctx); }, .Date => |date| { - return date.eval(allocator, output_capture, input_source); + return date.eval(ctx); }, .Time => |time| { - return time.eval(allocator, output_capture, input_source); + return time.eval(ctx); }, .Dir => |dir| { - return dir.eval(allocator, output_capture, input_source); + return dir.eval(ctx); }, .Type => |type_cmd| { - return type_cmd.eval(allocator, output_capture, input_source); + return type_cmd.eval(ctx); }, .Sort => |sort| { - return sort.eval(allocator, output_capture, input_source); + return sort.eval(ctx); }, .Chdir => |chdir| { - return chdir.eval(allocator, output_capture, input_source); + return chdir.eval(ctx); }, .Copy => |copy| { - return copy.eval(allocator, output_capture, input_source); + return copy.eval(ctx); }, .Remove => |remove| { - return remove.eval(allocator, output_capture, input_source); + return remove.eval(ctx); }, .Mkdir => |mkdir| { - return mkdir.eval(allocator, output_capture, input_source); + return mkdir.eval(ctx); }, .Rmdir => |rmdir| { - return rmdir.eval(allocator, output_capture, input_source); + return rmdir.eval(ctx); }, .Rename => |rename| { - return rename.eval(allocator, output_capture, input_source); + return rename.eval(ctx); }, .Move => |move| { - return move.eval(allocator, output_capture, input_source); + return move.eval(ctx); }, .PathGet => |path_get| { - return path_get.eval(allocator, output_capture, input_source); + return path_get.eval(ctx); }, .PathSet => |path_set| { - return path_set.eval(allocator, output_capture, input_source); + return path_set.eval(ctx); }, else => { - const error_msg = try std.fmt.allocPrint(allocator, "Command not implemented: {any}\n", .{builtin_cmd}); - defer allocator.free(error_msg); - if (output_capture) |capture| { + const error_msg = try std.fmt.allocPrint(ctx.allocator, "Command not implemented: {any}\n", .{builtin_cmd}); + defer ctx.allocator.free(error_msg); + if (ctx.output_capture) |capture| { try capture.write(error_msg); } else { print("{s}", .{error_msg}); @@ -121,15 +124,17 @@ pub fn executeCommandWithOutput(command: Command, allocator: Allocator, output_c }, .External => |external| { - return external.eval(allocator, output_capture, input_source); + return external.eval(ctx); }, .Redirect => |redirect| { - return redirect.eval(allocator, output_capture, input_source, executeCommandWithOutput); + const ctx_with_executor = CommandContext.with_executor(allocator, output_capture, input_source, executeCommandWithOutput); + return redirect.eval(ctx_with_executor); }, .Pipe => |pipe| { - return pipe.eval(allocator, output_capture, input_source, executeCommandWithOutput); + const ctx_with_executor = CommandContext.with_executor(allocator, output_capture, input_source, executeCommandWithOutput); + return pipe.eval(ctx_with_executor); }, } } |