summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLucas Faria Mendes <lucas.oliveira1676@etec.sp.gov.br>2025-12-05 07:57:40 +0000
committerLucas Faria Mendes <lucas.oliveira1676@etec.sp.gov.br>2025-12-05 07:57:40 +0000
commit16c43f33f8f7302a07778153aff59f565592bad8 (patch)
tree87f27926a1c64bcafa0cfc07c89821ef657e8b35
parenteef2bd90f9549858ab61d0bb697906fa1e41a373 (diff)
downloadshell-zig-16c43f33f8f7302a07778153aff59f565592bad8.tar.gz
shell-zig-16c43f33f8f7302a07778153aff59f565592bad8.zip
codecrafters submit [skip ci]
-rw-r--r--src/executor.zig59
-rw-r--r--src/main.zig25
-rw-r--r--src/shell.zig42
3 files changed, 121 insertions, 5 deletions
diff --git a/src/executor.zig b/src/executor.zig
index cdddb4f..02ec159 100644
--- a/src/executor.zig
+++ b/src/executor.zig
@@ -103,3 +103,62 @@ pub fn runExternalProgramWithRedirect(allocator: std.mem.Allocator, program_path
_ = std.posix.waitpid(pid, 0);
}
}
+
+pub fn runExternalPipeline(allocator: std.mem.Allocator, program1_path: []const u8, argv1: []const []const u8, program2_path: []const u8, argv2: []const []const u8) !void {
+ const argv1_z = try allocator.allocSentinel(?[*:0]const u8, argv1.len, null);
+ defer allocator.free(argv1_z);
+ for (argv1, 0..) |arg, i| {
+ argv1_z[i] = (try allocator.dupeZ(u8, arg)).ptr;
+ }
+ defer {
+ for (argv1_z[0..argv1.len]) |arg_ptr| {
+ if (arg_ptr) |ptr| allocator.free(std.mem.span(ptr));
+ }
+ }
+
+ const argv2_z = try allocator.allocSentinel(?[*:0]const u8, argv2.len, null);
+ defer allocator.free(argv2_z);
+ for (argv2, 0..) |arg, i| {
+ argv2_z[i] = (try allocator.dupeZ(u8, arg)).ptr;
+ }
+ defer {
+ for (argv2_z[0..argv2.len]) |arg_ptr| {
+ if (arg_ptr) |ptr| allocator.free(std.mem.span(ptr));
+ }
+ }
+
+ const program1_path_z = try allocator.dupeZ(u8, program1_path);
+ defer allocator.free(program1_path_z);
+ const program2_path_z = try allocator.dupeZ(u8, program2_path);
+ defer allocator.free(program2_path_z);
+
+ const fds = try std.posix.pipe();
+
+ const pid1 = try std.posix.fork();
+ if (pid1 == 0) {
+ std.posix.close(fds[0]);
+ try std.posix.dup2(fds[1], 1);
+ std.posix.close(fds[1]);
+ _ = std.posix.execveZ(program1_path_z, argv1_z, std.c.environ) catch {
+ std.posix.exit(1);
+ };
+ unreachable;
+ }
+
+ const pid2 = try std.posix.fork();
+ if (pid2 == 0) {
+ std.posix.close(fds[1]);
+ try std.posix.dup2(fds[0], 0);
+ std.posix.close(fds[0]);
+ _ = std.posix.execveZ(program2_path_z, argv2_z, std.c.environ) catch {
+ std.posix.exit(1);
+ };
+ unreachable;
+ }
+
+ std.posix.close(fds[0]);
+ std.posix.close(fds[1]);
+
+ _ = std.posix.waitpid(pid1, 0);
+ _ = std.posix.waitpid(pid2, 0);
+}
diff --git a/src/main.zig b/src/main.zig
index 46bee15..20acf0f 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -294,15 +294,30 @@ pub fn main() !void {
if (command) |cmd| {
defer allocator.free(cmd);
try stdout.writeAll("\n");
-
- const parsed = parser.parseCommand(cmd);
-
var stdout_writer = std.fs.File.stdout().writerStreaming(&.{});
const stdout_iface = &stdout_writer.interface;
- const result = try shell.executeCommand(allocator, stdout_iface, parsed.name, parsed.args, parsed.output_redirect, parsed.error_redirect, parsed.append_output, parsed.append_error);
+ if (std.mem.indexOfScalar(u8, cmd, '|')) |pipe_pos| {
+ var left = cmd[0..pipe_pos];
+ var right = if (pipe_pos + 1 < cmd.len) cmd[pipe_pos + 1 ..] else cmd[pipe_pos..pipe_pos];
+ while (left.len > 0 and left[0] == ' ') left = left[1..];
+ while (left.len > 0 and left[left.len - 1] == ' ') left = left[0 .. left.len - 1];
+ while (right.len > 0 and right[0] == ' ') right = right[1..];
+ while (right.len > 0 and right[right.len - 1] == ' ') right = right[0 .. right.len - 1];
- if (result == .exit_shell) break;
+ if (left.len == 0 or right.len == 0) {
+ try stdout.writeAll("pipe: command not found\n");
+ } else {
+ const result = try shell.executePipeline(allocator, stdout_iface, left, right);
+ if (result == .exit_shell) break;
+ }
+ } else {
+ const parsed = parser.parseCommand(cmd);
+
+ const result = try shell.executeCommand(allocator, stdout_iface, parsed.name, parsed.args, parsed.output_redirect, parsed.error_redirect, parsed.append_output, parsed.append_error);
+
+ if (result == .exit_shell) break;
+ }
} else {
break;
}
diff --git a/src/shell.zig b/src/shell.zig
index b15003e..53aaf3f 100644
--- a/src/shell.zig
+++ b/src/shell.zig
@@ -134,3 +134,45 @@ pub fn executeCommand(
try stdout.print("{s}: command not found\n", .{cmd_name});
return .continue_loop;
}
+
+pub fn executePipeline(
+ allocator: std.mem.Allocator,
+ stdout: anytype,
+ left_cmd: []const u8,
+ right_cmd: []const u8,
+) !builtins.CommandResult {
+ const left_parsed = parser.parseCommand(left_cmd);
+ const right_parsed = parser.parseCommand(right_cmd);
+
+ if (left_parsed.name.len == 0) {
+ try stdout.print("{s}: command not found\n", .{left_cmd});
+ return .continue_loop;
+ }
+ if (right_parsed.name.len == 0) {
+ try stdout.print("{s}: command not found\n", .{right_cmd});
+ return .continue_loop;
+ }
+
+ const left_path = try path.findInPath(allocator, left_parsed.name);
+ defer if (left_path) |p| allocator.free(p);
+ if (left_path == null) {
+ try stdout.print("{s}: command not found\n", .{left_parsed.name});
+ return .continue_loop;
+ }
+
+ const right_path = try path.findInPath(allocator, right_parsed.name);
+ defer if (right_path) |p| allocator.free(p);
+ if (right_path == null) {
+ try stdout.print("{s}: command not found\n", .{right_parsed.name});
+ return .continue_loop;
+ }
+
+ const left_argv = try parser.parseArgs(allocator, left_parsed.name, left_parsed.args);
+ defer allocator.free(left_argv);
+
+ const right_argv = try parser.parseArgs(allocator, right_parsed.name, right_parsed.args);
+ defer allocator.free(right_argv);
+
+ try executor.runExternalPipeline(allocator, left_path.?, left_argv, right_path.?, right_argv);
+ return .continue_loop;
+}