diff options
author | Matthias Andreas Benkard <code@mail.matthias.benkard.de> | 2025-08-13 19:14:55 +0200 |
---|---|---|
committer | Matthias Andreas Benkard <code@mail.matthias.benkard.de> | 2025-08-13 19:14:55 +0200 |
commit | 5f4c1846d7964f70716f2fdf05d4f9ea6e7d74c1 (patch) | |
tree | f9792d0f97acb3eadd93703d377551e8dc1fcfc7 /src | |
parent | c362799fb932b8530c5d949399bf93904b24faf8 (diff) |
Add input redirection.
Diffstat (limited to 'src')
-rw-r--r-- | src/main.zig | 143 |
1 files changed, 136 insertions, 7 deletions
diff --git a/src/main.zig b/src/main.zig index 4cfc581..51ebf3c 100644 --- a/src/main.zig +++ b/src/main.zig @@ -513,6 +513,8 @@ const Parser = struct { } const file_spec = parseFilespec(args.items[0]); return Command{ .Builtin = BuiltinCommand{ .Type = .{ .file = file_spec } } }; + } else if (std.mem.eql(u8, cmd_upper, "SORT")) { + return Command{ .Builtin = BuiltinCommand.Sort }; } else { // External command return Command{ .External = .{ .program = command_name, .args = args } }; @@ -610,7 +612,40 @@ const OutputCapture = struct { } }; -fn executeCommandWithOutput(command: Command, allocator: Allocator, output_capture: ?*OutputCapture) !CommandStatus { +const InputSource = struct { + data: []const u8, + position: usize, + + pub fn init(data: []const u8) InputSource { + return InputSource{ + .data = data, + .position = 0, + }; + } + + pub fn readLine(self: *InputSource, allocator: Allocator) !?[]const u8 { + if (self.position >= self.data.len) { + return null; // EOF + } + + var line_end = self.position; + while (line_end < self.data.len and self.data[line_end] != '\n') { + line_end += 1; + } + + const line = self.data[self.position..line_end]; + self.position = if (line_end < self.data.len) line_end + 1 else self.data.len; + + // Remove trailing \r if present (DOS line endings) + if (line.len > 0 and line[line.len - 1] == '\r') { + return try allocator.dupe(u8, line[0..line.len - 1]); + } else { + return try allocator.dupe(u8, line); + } + } +}; + +fn executeCommandWithOutput(command: Command, allocator: Allocator, output_capture: ?*OutputCapture, input_source: ?*InputSource) !CommandStatus { switch (command) { .Empty => return CommandStatus{ .Code = 0 }, @@ -869,6 +904,55 @@ fn executeCommandWithOutput(command: Command, allocator: Allocator, output_captu return CommandStatus{ .Code = 0 }; }, + .Sort => { + var lines = ArrayList([]const u8).init(allocator); + defer { + for (lines.items) |line| { + allocator.free(line); + } + lines.deinit(); + } + + // Read input lines + if (input_source) |source| { + // Read from input redirection + while (try source.readLine(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| { + try capture.write(msg); + } else { + print("{s}", .{msg}); + } + return CommandStatus{ .Code = 0 }; + } + + // Sort the lines + std.mem.sort([]const u8, lines.items, {}, struct { + fn lessThan(_: void, lhs: []const u8, rhs: []const u8) bool { + return std.mem.order(u8, lhs, rhs) == .lt; + } + }.lessThan); + + // Output sorted lines + var output_buffer = ArrayList(u8).init(allocator); + defer output_buffer.deinit(); + + for (lines.items) |line| { + try output_buffer.writer().print("{s}\n", .{line}); + } + + if (output_capture) |capture| { + try capture.write(output_buffer.items); + } else { + print("{s}", .{output_buffer.items}); + } + + 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); @@ -897,11 +981,56 @@ fn executeCommandWithOutput(command: Command, allocator: Allocator, output_captu var captured_output = OutputCapture.init(allocator); defer captured_output.deinit(); - // Execute the command with output capture - const status = try executeCommandWithOutput(redirect.command.*, allocator, &captured_output); + // Prepare input redirection if needed + var input_data: ?[]const u8 = null; + var redirect_input_source: ?InputSource = null; + defer if (input_data) |data| allocator.free(data); - // Handle redirections + // Process input redirections first for (redirect.redirects.items) |redir| { + if (redir.redirect_type == .InputFrom) { + const file_path = switch (redir.target) { + .Con => { + print("Input redirection from CON not supported\n", .{}); + return CommandStatus{ .Code = 1 }; + }, + .Lpt1, .Lpt2, .Lpt3, .Prn => { + print("Cannot redirect input from device\n", .{}); + return CommandStatus{ .Code = 1 }; + }, + .Path => |path| path, + }; + + // Read input file + const file = std.fs.cwd().openFile(file_path, .{}) catch |err| { + switch (err) { + error.FileNotFound => print("The system cannot find the file specified.\n", .{}), + error.AccessDenied => print("Access is denied.\n", .{}), + else => print("Cannot open input file.\n", .{}), + } + return CommandStatus{ .Code = 1 }; + }; + defer file.close(); + + input_data = file.readToEndAlloc(allocator, std.math.maxInt(usize)) catch |err| { + switch (err) { + error.AccessDenied => print("Access is denied.\n", .{}), + else => print("Cannot read input file.\n", .{}), + } + return CommandStatus{ .Code = 1 }; + }; + + redirect_input_source = InputSource.init(input_data.?); + break; // Only handle first input redirection + } + } + + // Execute the command with input and output capture + const status = try executeCommandWithOutput(redirect.command.*, allocator, &captured_output, if (redirect_input_source) |*source| source else null); + + // Handle output redirections + for (redirect.redirects.items) |redir| { + if (redir.redirect_type == .InputFrom) continue; // Already handled const file_path = switch (redir.target) { .Con => { // Redirect to console - just print normally @@ -984,8 +1113,8 @@ fn executeCommandWithOutput(command: Command, allocator: Allocator, output_captu }; }, .InputFrom => { - print("Input redirection not implemented\n", .{}); - return CommandStatus{ .Code = 1 }; + // Input redirection already handled above + continue; }, } } @@ -1006,7 +1135,7 @@ fn executeCommandWithOutput(command: Command, allocator: Allocator, output_captu } fn executeCommand(command: Command, allocator: Allocator) !CommandStatus { - return executeCommandWithOutput(command, allocator, null); + return executeCommandWithOutput(command, allocator, null, null); } fn readLine(allocator: Allocator, prompt_text: []const u8) !?[]const u8 { |