diff options
| author | Lucas Faria Mendes <lucas.oliveira1676@etec.sp.gov.br> | 2025-12-05 08:12:42 +0000 |
|---|---|---|
| committer | Lucas Faria Mendes <lucas.oliveira1676@etec.sp.gov.br> | 2025-12-05 08:12:42 +0000 |
| commit | 1fe2527050761776206110c4da83b57a33b1e18a (patch) | |
| tree | c0f7b51326b478690a5e020657d855e6e5989a6c /src/shell.zig | |
| parent | 6430308cdfd85ebad6819e5c87fe3036b8f21435 (diff) | |
| download | shell-zig-1fe2527050761776206110c4da83b57a33b1e18a.tar.gz shell-zig-1fe2527050761776206110c4da83b57a33b1e18a.zip | |
codecrafters submit [skip ci]
Diffstat (limited to 'src/shell.zig')
| -rw-r--r-- | src/shell.zig | 96 |
1 files changed, 53 insertions, 43 deletions
diff --git a/src/shell.zig b/src/shell.zig index 15046d5..271e3ea 100644 --- a/src/shell.zig +++ b/src/shell.zig @@ -4,6 +4,12 @@ const builtins = @import("builtins.zig"); const path = @import("path.zig"); const executor = @import("executor.zig"); +fn freeArgv(allocator: std.mem.Allocator, argv: []const []const u8) void { + // argv[0] is cmd_name (not allocated), argv[1..] are allocated by parseArgs + for (argv[1..]) |arg| allocator.free(arg); + allocator.free(argv); +} + pub fn executeCommand( allocator: std.mem.Allocator, stdout: anytype, @@ -121,7 +127,10 @@ pub fn executeCommand( defer allocator.free(program_path); const argv = try parser.parseArgs(allocator, cmd_name, args); - defer allocator.free(argv); + defer { + for (argv[1..]) |arg| allocator.free(arg); + allocator.free(argv); + } if (output_redirect != null or error_redirect != null or append_output != null or append_error != null) { try executor.runExternalProgramWithRedirect(allocator, program_path, argv, output_redirect, error_redirect, append_output, append_error); @@ -138,56 +147,57 @@ pub fn executeCommand( pub fn executePipeline( allocator: std.mem.Allocator, stdout: anytype, - left_cmd: []const u8, - right_cmd: []const u8, + commands: []const []const u8, ) !builtins.CommandResult { - const left_parsed = parser.parseCommand(left_cmd); - const right_parsed = parser.parseCommand(right_cmd); + var stages = std.ArrayList(executor.Stage){}; + defer stages.deinit(allocator); - if (left_parsed.name.len == 0) { - try stdout.print("{s}: command not found\n", .{left_cmd}); - return .continue_loop; + var owned_paths = std.ArrayList(?[]const u8){}; + defer { + for (owned_paths.items) |p| if (p) |path_buf| allocator.free(path_buf); + owned_paths.deinit(allocator); } - if (right_parsed.name.len == 0) { - try stdout.print("{s}: command not found\n", .{right_cmd}); - return .continue_loop; + + var owned_argvs = std.ArrayList(?[]const []const u8){}; + defer { + for (owned_argvs.items) |argv_opt| if (argv_opt) |argv| freeArgv(allocator, argv); + owned_argvs.deinit(allocator); } - const left_is_builtin = builtins.isBuiltin(left_parsed.name); - const right_is_builtin = builtins.isBuiltin(right_parsed.name); + for (commands) |cmd_part| { + const parsed = parser.parseCommand(cmd_part); + if (parsed.name.len == 0) { + try stdout.print("{s}: command not found\n", .{cmd_part}); + return .continue_loop; + } + + const is_builtin = builtins.isBuiltin(parsed.name); + var cmd_path: ?[]const u8 = null; + if (!is_builtin) { + cmd_path = try path.findInPath(allocator, parsed.name); + } + if (!is_builtin and cmd_path == null) { + try stdout.print("{s}: command not found\n", .{parsed.name}); + return .continue_loop; + } - const left_path = if (left_is_builtin) null else try path.findInPath(allocator, left_parsed.name); - defer if (left_path) |p| allocator.free(p); - if (!left_is_builtin and left_path == null) { - try stdout.print("{s}: command not found\n", .{left_parsed.name}); - return .continue_loop; - } + try owned_paths.append(allocator, cmd_path); - const right_path = if (right_is_builtin) null else try path.findInPath(allocator, right_parsed.name); - defer if (right_path) |p| allocator.free(p); - if (!right_is_builtin and right_path == null) { - try stdout.print("{s}: command not found\n", .{right_parsed.name}); - return .continue_loop; + var argv: ?[]const []const u8 = null; + if (!is_builtin) { + argv = try parser.parseArgs(allocator, parsed.name, parsed.args); + } + try owned_argvs.append(allocator, argv); + + try stages.append(allocator, .{ + .is_builtin = is_builtin, + .name = parsed.name, + .args = parsed.args, + .path = cmd_path, + .argv = argv, + }); } - const left_argv = if (left_is_builtin) null else try parser.parseArgs(allocator, left_parsed.name, left_parsed.args); - defer if (left_argv) |argv| allocator.free(argv); - - const right_argv = if (right_is_builtin) null else try parser.parseArgs(allocator, right_parsed.name, right_parsed.args); - defer if (right_argv) |argv| allocator.free(argv); - - try executor.runPipeline( - allocator, - left_path, - left_is_builtin, - left_parsed.name, - left_parsed.args, - left_argv, - right_path, - right_is_builtin, - right_parsed.name, - right_parsed.args, - right_argv, - ); + try executor.runPipeline(allocator, stages.items); return .continue_loop; } |