summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/executor.zig17
-rw-r--r--src/main.zig2
-rw-r--r--src/parser.zig35
-rw-r--r--src/shell.zig24
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);
}