diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/executor.zig | 17 | ||||
| -rw-r--r-- | src/main.zig | 2 | ||||
| -rw-r--r-- | src/parser.zig | 35 | ||||
| -rw-r--r-- | src/shell.zig | 24 |
4 files changed, 69 insertions, 9 deletions
diff --git a/src/executor.zig b/src/executor.zig index 3d3184c..f2db136 100644 --- a/src/executor.zig +++ b/src/executor.zig @@ -28,7 +28,7 @@ pub fn runExternalProgram(allocator: std.mem.Allocator, program_path: []const u8 } } -pub fn runExternalProgramWithRedirect(allocator: std.mem.Allocator, program_path: []const u8, argv: []const []const u8, output_file: ?[]const u8, error_file: ?[]const u8) !void { +pub fn runExternalProgramWithRedirect(allocator: std.mem.Allocator, program_path: []const u8, argv: []const []const u8, output_file: ?[]const u8, error_file: ?[]const u8, append_file: ?[]const u8) !void { const argv_z = try allocator.allocSentinel(?[*:0]const u8, argv.len, null); defer allocator.free(argv_z); @@ -54,6 +54,21 @@ pub fn runExternalProgramWithRedirect(allocator: std.mem.Allocator, program_path }; defer fd.close(); try std.posix.dup2(fd.handle, 1); + } else if (append_file) |file| { + const cwd = std.fs.cwd(); + const fd = cwd.openFile(file, .{ .mode = .write_only }) catch |err| blk: { + if (err == error.FileNotFound) { + break :blk cwd.createFile(file, .{}) catch { + std.posix.exit(1); + }; + } + std.posix.exit(1); + }; + defer fd.close(); + fd.seekFromEnd(0) catch { + std.posix.exit(1); + }; + try std.posix.dup2(fd.handle, 1); } if (error_file) |file| { diff --git a/src/main.zig b/src/main.zig index 29118cf..93a20fe 100644 --- a/src/main.zig +++ b/src/main.zig @@ -20,7 +20,7 @@ pub fn main() !void { const command = try stdin.takeDelimiter('\n'); if (command) |cmd| { const parsed = parser.parseCommand(cmd); - const result = try shell.executeCommand(allocator, stdout, parsed.name, parsed.args, parsed.output_redirect, parsed.error_redirect); + const result = try shell.executeCommand(allocator, stdout, parsed.name, parsed.args, parsed.output_redirect, parsed.error_redirect, parsed.append_output); if (result == .exit_shell) break; } else { diff --git a/src/parser.zig b/src/parser.zig index 33b3c3a..84c8095 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -5,6 +5,7 @@ pub const ParsedCommand = struct { args: ?[]const u8, output_redirect: ?[]const u8, error_redirect: ?[]const u8, + append_output: ?[]const u8, }; pub fn parseCommand(input: []const u8) ParsedCommand { @@ -15,7 +16,7 @@ pub fn parseCommand(input: []const u8) ParsedCommand { while (i < input.len and input[i] == ' ') : (i += 1) {} if (i >= input.len) { - return .{ .name = "", .args = null, .output_redirect = null, .error_redirect = null }; + return .{ .name = "", .args = null, .output_redirect = null, .error_redirect = null, .append_output = null }; } if (input[i] == '\'' or input[i] == '"') { @@ -40,11 +41,18 @@ pub fn parseCommand(input: []const u8) ParsedCommand { var redirect_pos: ?usize = null; var error_redirect_pos: ?usize = null; + var append_pos: ?usize = null; var j = i; while (j < input.len) : (j += 1) { if (j + 1 < input.len and input[j] == '2' and input[j + 1] == '>') { error_redirect_pos = j; j += 1; + } else if (j + 1 < input.len and input[j] == '1' and j + 1 < input.len and input[j + 1] == '>' and j + 2 < input.len and input[j + 2] == '>') { + append_pos = j; + j += 2; + } else if (j + 1 < input.len and input[j] == '>' and input[j + 1] == '>') { + append_pos = j; + j += 1; } else if (input[j] == '1' and j + 1 < input.len and input[j + 1] == '>') { redirect_pos = j; j += 1; @@ -57,6 +65,7 @@ pub fn parseCommand(input: []const u8) ParsedCommand { var args: ?[]const u8 = null; var output_redirect: ?[]const u8 = null; var error_redirect: ?[]const u8 = null; + var append_output: ?[]const u8 = null; var args_end = input.len; if (redirect_pos) |pos| { @@ -65,6 +74,9 @@ pub fn parseCommand(input: []const u8) ParsedCommand { if (error_redirect_pos) |pos| { if (pos < args_end) args_end = pos; } + if (append_pos) |pos| { + if (pos < args_end) args_end = pos; + } while (args_end > i and input[args_end - 1] == ' ') : (args_end -= 1) {} @@ -105,7 +117,26 @@ pub fn parseCommand(input: []const u8) ParsedCommand { } } - return .{ .name = cmd_name, .args = args, .output_redirect = output_redirect, .error_redirect = error_redirect }; + if (append_pos) |pos| { + var k = pos; + if (input[k] == '1') k += 1; + if (k < input.len and input[k] == '>') k += 1; + if (k < input.len and input[k] == '>') k += 1; + + while (k < input.len and input[k] == ' ') : (k += 1) {} + + if (k < input.len) { + var redir_buf = std.ArrayList(u8){}; + defer redir_buf.deinit(std.heap.page_allocator); + + while (k < input.len and input[k] != ' ') : (k += 1) { + _ = redir_buf.append(std.heap.page_allocator, input[k]) catch {}; + } + append_output = redir_buf.toOwnedSlice(std.heap.page_allocator) catch null; + } + } + + return .{ .name = cmd_name, .args = args, .output_redirect = output_redirect, .error_redirect = error_redirect, .append_output = append_output }; } pub fn parseArgs(allocator: std.mem.Allocator, cmd_name: []const u8, args_str: ?[]const u8) ![]const []const u8 { diff --git a/src/shell.zig b/src/shell.zig index ac16cab..23e64d2 100644 --- a/src/shell.zig +++ b/src/shell.zig @@ -11,6 +11,7 @@ pub fn executeCommand( args: ?[]const u8, output_redirect: ?[]const u8, error_redirect: ?[]const u8, + append_output: ?[]const u8, ) !builtins.CommandResult { if (std.mem.eql(u8, cmd_name, "exit")) return builtins.executeExit(); @@ -20,11 +21,24 @@ pub fn executeCommand( fd.close(); } - if (output_redirect != null) { - const file = output_redirect.?; - const fd = try std.fs.cwd().createFile(file, .{}); + if (output_redirect != null or append_output != null) { + const file = if (output_redirect) |f| f else append_output.?; + const is_append = append_output != null; + + const fd = if (is_append) blk: { + break :blk std.fs.cwd().openFile(file, .{ .mode = .write_only }) catch |err| { + if (err == error.FileNotFound) { + break :blk try std.fs.cwd().createFile(file, .{}); + } + return err; + }; + } else try std.fs.cwd().createFile(file, .{}); defer fd.close(); + if (is_append) { + try fd.seekFromEnd(0); + } + if (args) |a| { var i: usize = 0; var in_quote = false; @@ -97,8 +111,8 @@ pub fn executeCommand( const argv = try parser.parseArgs(allocator, cmd_name, args); defer allocator.free(argv); - if (output_redirect != null or error_redirect != null) { - try executor.runExternalProgramWithRedirect(allocator, program_path, argv, output_redirect, error_redirect); + if (output_redirect != null or error_redirect != null or append_output != null) { + try executor.runExternalProgramWithRedirect(allocator, program_path, argv, output_redirect, error_redirect, append_output); } else { try executor.runExternalProgram(allocator, program_path, argv); } |