summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/executor.zig27
-rw-r--r--src/main.zig2
-rw-r--r--src/parser.zig49
-rw-r--r--src/shell.zig13
4 files changed, 69 insertions, 22 deletions
diff --git a/src/executor.zig b/src/executor.zig
index a53ade8..3d3184c 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) !void {
+pub fn runExternalProgramWithRedirect(allocator: std.mem.Allocator, program_path: []const u8, argv: []const []const u8, output_file: ?[]const u8, error_file: ?[]const u8) !void {
const argv_z = try allocator.allocSentinel(?[*:0]const u8, argv.len, null);
defer allocator.free(argv_z);
@@ -44,19 +44,26 @@ pub fn runExternalProgramWithRedirect(allocator: std.mem.Allocator, program_path
const program_path_z = try allocator.dupeZ(u8, program_path);
defer allocator.free(program_path_z);
- const output_file_z = try allocator.dupeZ(u8, output_file);
- defer allocator.free(output_file_z);
-
const pid = try std.posix.fork();
if (pid == 0) {
- const cwd = std.fs.cwd();
- const fd = cwd.createFile(output_file, .{}) catch {
- std.posix.exit(1);
- };
- defer fd.close();
+ if (output_file) |file| {
+ const cwd = std.fs.cwd();
+ const fd = cwd.createFile(file, .{}) catch {
+ std.posix.exit(1);
+ };
+ defer fd.close();
+ try std.posix.dup2(fd.handle, 1);
+ }
- try std.posix.dup2(fd.handle, 1);
+ if (error_file) |file| {
+ const cwd = std.fs.cwd();
+ const fd = cwd.createFile(file, .{}) catch {
+ std.posix.exit(1);
+ };
+ defer fd.close();
+ try std.posix.dup2(fd.handle, 2);
+ }
_ = std.posix.execveZ(program_path_z, argv_z, std.c.environ) catch {
std.posix.exit(1);
diff --git a/src/main.zig b/src/main.zig
index 91ae759..29118cf 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);
+ const result = try shell.executeCommand(allocator, stdout, parsed.name, parsed.args, parsed.output_redirect, parsed.error_redirect);
if (result == .exit_shell) break;
} else {
diff --git a/src/parser.zig b/src/parser.zig
index 680eadb..33b3c3a 100644
--- a/src/parser.zig
+++ b/src/parser.zig
@@ -4,6 +4,7 @@ pub const ParsedCommand = struct {
name: []const u8,
args: ?[]const u8,
output_redirect: ?[]const u8,
+ error_redirect: ?[]const u8,
};
pub fn parseCommand(input: []const u8) ParsedCommand {
@@ -14,7 +15,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 };
+ return .{ .name = "", .args = null, .output_redirect = null, .error_redirect = null };
}
if (input[i] == '\'' or input[i] == '"') {
@@ -38,21 +39,40 @@ pub fn parseCommand(input: []const u8) ParsedCommand {
while (i < input.len and input[i] == ' ') : (i += 1) {}
var redirect_pos: ?usize = null;
+ var error_redirect_pos: ?usize = null;
var j = i;
while (j < input.len) : (j += 1) {
- if (input[j] == '>' or (input[j] == '1' and j + 1 < input.len and input[j + 1] == '>')) {
+ if (j + 1 < input.len and input[j] == '2' and input[j + 1] == '>') {
+ error_redirect_pos = j;
+ j += 1;
+ } else if (input[j] == '1' and j + 1 < input.len and input[j + 1] == '>') {
+ redirect_pos = j;
+ j += 1;
+ } else if (input[j] == '>') {
redirect_pos = j;
- break;
}
}
const cmd_name = cmd_buf.toOwnedSlice(std.heap.page_allocator) catch "";
var args: ?[]const u8 = null;
var output_redirect: ?[]const u8 = null;
+ var error_redirect: ?[]const u8 = null;
+ var args_end = input.len;
if (redirect_pos) |pos| {
- if (pos > i) args = input[i..pos];
+ if (pos < args_end) args_end = pos;
+ }
+ if (error_redirect_pos) |pos| {
+ if (pos < args_end) args_end = pos;
+ }
+
+ while (args_end > i and input[args_end - 1] == ' ') : (args_end -= 1) {}
+
+ if (args_end > i) {
+ args = input[i..args_end];
+ }
+ if (redirect_pos) |pos| {
var k = pos;
if (input[k] == '1') k += 1;
if (k < input.len and input[k] == '>') k += 1;
@@ -63,16 +83,29 @@ pub fn parseCommand(input: []const u8) ParsedCommand {
var redir_buf = std.ArrayList(u8){};
defer redir_buf.deinit(std.heap.page_allocator);
- while (k < input.len and input[k] != ' ') : (k += 1) {
+ while (k < input.len and input[k] != ' ' and !(k + 1 < input.len and input[k] == '2' and input[k + 1] == '>')) : (k += 1) {
_ = redir_buf.append(std.heap.page_allocator, input[k]) catch {};
}
output_redirect = redir_buf.toOwnedSlice(std.heap.page_allocator) catch null;
}
- } else if (i < input.len) {
- args = input[i..];
}
- return .{ .name = cmd_name, .args = args, .output_redirect = output_redirect };
+ if (error_redirect_pos) |pos| {
+ var k = pos + 2;
+ 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 {};
+ }
+ error_redirect = redir_buf.toOwnedSlice(std.heap.page_allocator) catch null;
+ }
+ }
+
+ return .{ .name = cmd_name, .args = args, .output_redirect = output_redirect, .error_redirect = error_redirect };
}
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 c95d9d0..ac16cab 100644
--- a/src/shell.zig
+++ b/src/shell.zig
@@ -10,11 +10,18 @@ pub fn executeCommand(
cmd_name: []const u8,
args: ?[]const u8,
output_redirect: ?[]const u8,
+ error_redirect: ?[]const u8,
) !builtins.CommandResult {
if (std.mem.eql(u8, cmd_name, "exit")) return builtins.executeExit();
if (std.mem.eql(u8, cmd_name, "echo")) {
- if (output_redirect) |file| {
+ if (error_redirect) |file| {
+ const fd = try std.fs.cwd().createFile(file, .{});
+ fd.close();
+ }
+
+ if (output_redirect != null) {
+ const file = output_redirect.?;
const fd = try std.fs.cwd().createFile(file, .{});
defer fd.close();
@@ -90,8 +97,8 @@ pub fn executeCommand(
const argv = try parser.parseArgs(allocator, cmd_name, args);
defer allocator.free(argv);
- if (output_redirect) |file| {
- try executor.runExternalProgramWithRedirect(allocator, program_path, argv, file);
+ if (output_redirect != null or error_redirect != null) {
+ try executor.runExternalProgramWithRedirect(allocator, program_path, argv, output_redirect, error_redirect);
} else {
try executor.runExternalProgram(allocator, program_path, argv);
}