const std = @import("std"); const ArrayList = std.ArrayList; const Allocator = std.mem.Allocator; const Thread = std.Thread; const Mutex = std.Thread.Mutex; const c = @cImport({ @cInclude("errno.h"); @cInclude("stdio.h"); if (@import("builtin").os.tag != .windows) { @cInclude("sys/statvfs.h"); } }); const cmd = @import("cmd.zig"); const Command = cmd.Command; const BuiltinCommand = cmd.BuiltinCommand; const syntax = @import("syntax.zig"); const FileSpec = syntax.FileSpec; const RedirectType = syntax.RedirectType; const Redirect = syntax.Redirect; const cmdTypes = @import("cmd/lib/types.zig"); pub const CommandStatus = cmdTypes.CommandStatus; const OutputCapture = cmdTypes.OutputCapture; const StdoutOutputCapture = cmdTypes.StdoutOutputCapture; const OutputWriter = cmdTypes.OutputWriter; const InputSource = cmdTypes.InputSource; const StdinInputReader = cmdTypes.StdinInputReader; const InputReader = cmdTypes.InputReader; const CommandContext = cmdTypes.CommandContext; const STDOUT_BUFFER_SIZE: usize = 1024; const STDERR_BUFFER_SIZE: usize = 1024; pub fn executeCommand(command: Command, allocator: Allocator) !CommandStatus { return executeCommandWithOutput(command, allocator, null, null); } pub fn executeCommandWithOutput(command: Command, allocator: Allocator, output_capture: ?*OutputCapture, input_source: ?*InputSource) !CommandStatus { var stdout_capture = StdoutOutputCapture{}; const output_writer = if (output_capture) |capture| OutputWriter{ .capture = capture } else OutputWriter{ .stdout = &stdout_capture }; var stdin_reader = StdinInputReader{}; const input_reader = if (input_source) |source| InputReader{ .source = source } else InputReader{ .stdin = &stdin_reader }; const ctx = CommandContext.init(allocator, output_writer, input_reader, executeCommandWithOutput); switch (command) { .Empty => return CommandStatus{ .Code = 0 }, .Builtin => |builtin_cmd| { switch (builtin_cmd) { .EchoText => |echo_text| { return echo_text.eval(ctx); }, .Cls => |cls| { return cls.eval(ctx); }, .Exit => { return CommandStatus.ExitShell; }, .EchoPlain => |echo_plain| { return echo_plain.eval(ctx); }, .EchoOn => |echo_on| { return echo_on.eval(ctx); }, .EchoOff => |echo_off| { return echo_off.eval(ctx); }, .Ver => |ver| { return ver.eval(ctx); }, .Date => |date| { return date.eval(ctx); }, .Time => |time| { return time.eval(ctx); }, .Dir => |dir| { return dir.eval(ctx); }, .Type => |type_cmd| { return type_cmd.eval(ctx); }, .Sort => |sort| { return sort.eval(ctx); }, .Chdir => |chdir| { return chdir.eval(ctx); }, .Copy => |copy| { return copy.eval(ctx); }, .Remove => |remove| { return remove.eval(ctx); }, .Mkdir => |mkdir| { return mkdir.eval(ctx); }, .Rmdir => |rmdir| { return rmdir.eval(ctx); }, .Rename => |rename| { return rename.eval(ctx); }, .Move => |move| { return move.eval(ctx); }, .PathGet => |path_get| { return path_get.eval(ctx); }, .PathSet => |path_set| { return path_set.eval(ctx); }, .Help => |help| { return help.eval(ctx); }, else => { const error_msg = try std.fmt.allocPrint(ctx.allocator, "Command not implemented: {any}\n", .{builtin_cmd}); defer ctx.allocator.free(error_msg); var writer = ctx.output_writer; try writer.write(error_msg); return CommandStatus{ .Code = 1 }; }, } }, .External => |external| { return external.eval(ctx); }, .Redirect => |redirect| { return redirect.eval(ctx); }, .Pipe => |pipe| { return pipe.eval(ctx); }, } }