From 16c43f33f8f7302a07778153aff59f565592bad8 Mon Sep 17 00:00:00 2001 From: Lucas Faria Mendes Date: Fri, 5 Dec 2025 04:57:40 -0300 Subject: codecrafters submit [skip ci] --- src/executor.zig | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.zig | 25 +++++++++++++++++++----- src/shell.zig | 42 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 121 insertions(+), 5 deletions(-) (limited to 'src') 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; +} -- cgit v1.2.3