summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMatthias Andreas Benkard <code@mail.matthias.benkard.de>2025-08-14 14:22:03 +0200
committerMatthias Andreas Benkard <code@mail.matthias.benkard.de>2025-08-14 14:22:03 +0200
commitf90db992568e4ef76f3c770f1b38a31e54c94515 (patch)
tree454082ccba1d050028147453cfc76567f03e2eb0 /src
parent0a734819d179f5e89f82cba8917a414ec550e364 (diff)
Add RD, REN, MOVE, PATH (partially).
Diffstat (limited to 'src')
-rw-r--r--src/eval.zig124
-rw-r--r--src/syntax.zig27
2 files changed, 151 insertions, 0 deletions
diff --git a/src/eval.zig b/src/eval.zig
index daf2d38..0fe0fde 100644
--- a/src/eval.zig
+++ b/src/eval.zig
@@ -788,6 +788,130 @@ fn executeCommandWithOutput(command: Command, allocator: Allocator, output_captu
// No output for successful creation (DOS style)
return CommandStatus{ .Code = 0 };
},
+ .Rmdir => |rmdir| {
+ const dir_path = rmdir.path;
+
+ std.fs.cwd().deleteDir(dir_path) catch |err| {
+ const error_msg = switch (err) {
+ error.FileNotFound => "The system cannot find the path specified\n",
+ error.AccessDenied => "Access denied\n",
+ error.DirNotEmpty => "The directory is not empty\n",
+ error.FileBusy => "The directory is in use\n",
+ error.NotDir => "The system cannot find the path specified\n",
+ else => "Unable to remove directory\n",
+ };
+ if (output_capture) |capture| {
+ try capture.write(error_msg);
+ } else {
+ print("{s}", .{error_msg});
+ }
+ return CommandStatus{ .Code = 1 };
+ };
+
+ // No output for successful removal (DOS style)
+ return CommandStatus{ .Code = 0 };
+ },
+ .Rename => |rename| {
+ const from_path = switch (rename.from) {
+ .Con, .Lpt1, .Lpt2, .Lpt3, .Prn => {
+ const error_msg = "Cannot rename device\n";
+ if (output_capture) |capture| {
+ try capture.write(error_msg);
+ } else {
+ print("{s}", .{error_msg});
+ }
+ return CommandStatus{ .Code = 1 };
+ },
+ .Path => |path| path,
+ };
+
+ const to_path = switch (rename.to) {
+ .Con, .Lpt1, .Lpt2, .Lpt3, .Prn => {
+ const error_msg = "Cannot rename to device\n";
+ if (output_capture) |capture| {
+ try capture.write(error_msg);
+ } else {
+ print("{s}", .{error_msg});
+ }
+ return CommandStatus{ .Code = 1 };
+ },
+ .Path => |path| path,
+ };
+
+ std.fs.cwd().rename(from_path, to_path) catch |err| {
+ const error_msg = switch (err) {
+ error.FileNotFound => "The system cannot find the file specified\n",
+ error.AccessDenied => "Access denied\n",
+ error.PathAlreadyExists => "A duplicate file name exists, or the file cannot be found\n",
+ error.RenameAcrossMountPoints => "Cannot rename across different drives\n",
+ else => "Cannot rename file\n",
+ };
+ if (output_capture) |capture| {
+ try capture.write(error_msg);
+ } else {
+ print("{s}", .{error_msg});
+ }
+ return CommandStatus{ .Code = 1 };
+ };
+
+ // No output for successful rename (DOS style)
+ return CommandStatus{ .Code = 0 };
+ },
+ .Move => {
+ const error_msg = "MOVE command not yet implemented\n";
+ if (output_capture) |capture| {
+ try capture.write(error_msg);
+ } else {
+ print("{s}", .{error_msg});
+ }
+ return CommandStatus{ .Code = 1 };
+ },
+ .PathGet => {
+ const current_path = std.process.getEnvVarOwned(allocator, "PATH") catch |err| switch (err) {
+ error.EnvironmentVariableNotFound => {
+ // PATH not set, show empty
+ const output = "PATH=(not set)\n";
+ if (output_capture) |capture| {
+ try capture.write(output);
+ } else {
+ print("{s}", .{output});
+ }
+ return CommandStatus{ .Code = 0 };
+ },
+ else => {
+ const error_msg = "Cannot access PATH environment variable\n";
+ if (output_capture) |capture| {
+ try capture.write(error_msg);
+ } else {
+ print("{s}", .{error_msg});
+ }
+ return CommandStatus{ .Code = 1 };
+ },
+ };
+ defer allocator.free(current_path);
+
+ const output = try std.fmt.allocPrint(allocator, "PATH={s}\n", .{current_path});
+ defer allocator.free(output);
+ if (output_capture) |capture| {
+ try capture.write(output);
+ } else {
+ print("{s}", .{output});
+ }
+ return CommandStatus{ .Code = 0 };
+ },
+ .PathSet => |pathset| {
+ // 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", .{pathset.value});
+ defer allocator.free(output);
+ if (output_capture) |capture| {
+ try capture.write(output);
+ } else {
+ print("{s}", .{output});
+ }
+ return CommandStatus{ .Code = 0 };
+ },
else => {
const error_msg = try std.fmt.allocPrint(allocator, "Command not implemented: {any}\n", .{builtin_cmd});
defer allocator.free(error_msg);
diff --git a/src/syntax.zig b/src/syntax.zig
index af4833c..0725859 100644
--- a/src/syntax.zig
+++ b/src/syntax.zig
@@ -603,6 +603,33 @@ const Parser = struct {
}
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) {
+ return error.ExpectedWord; // Will show "Bad command or file name"
+ }
+ 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) {
+ 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]);
+ 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) {
+ 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 '='
+ else
+ 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);