const std = @import("std"); const print = std.debug.print; const ArrayList = std.ArrayList; const Allocator = std.mem.Allocator; const Thread = std.Thread; const Mutex = std.Thread.Mutex; const parser = @import("syntax.zig"); const Command = parser.Command; const eval = @import("eval.zig"); const CommandStatus = eval.CommandStatus; const STDOUT_BUFFER_SIZE: usize = 1024; const STDERR_BUFFER_SIZE: usize = 1024; fn formatPath(allocator: Allocator, path: []const u8) ![]const u8 { var result = ArrayList(u8).init(allocator); defer result.deinit(); // Simple DOS-style path formatting // Convert to uppercase and replace / with \ for (path) |ch| { if (ch == '/') { try result.append('\\'); } else { try result.append(std.ascii.toUpper(ch)); } } // Add C: prefix if no drive letter if (result.items.len == 0 or result.items[1] != ':') { var prefixed = ArrayList(u8).init(allocator); defer prefixed.deinit(); try prefixed.appendSlice("C:"); try prefixed.appendSlice(result.items); return allocator.dupe(u8, prefixed.items); } return allocator.dupe(u8, result.items); } fn parseAndExecute(input: []const u8, allocator: Allocator) !CommandStatus { var command = parser.parse(input, allocator) catch |err| { switch (err) { error.ExpectedWord, error.UnexpectedToken => { return CommandStatus{ .Code = 1 }; }, else => return err, } }; defer command.deinit(allocator); return try eval.executeCommand(command, allocator); } fn readLine(allocator: Allocator, prompt_text: []const u8) !?[]const u8 { const stdin = std.io.getStdIn().reader(); print("{s}", .{prompt_text}); if (try stdin.readUntilDelimiterOrEofAlloc(allocator, '\n', 4096)) |input| { // Remove trailing \r on Windows if (input.len > 0 and input[input.len - 1] == '\r') { return input[0 .. input.len - 1]; } return input; } return null; } pub fn main() !void { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; defer _ = gpa.deinit(); const allocator = gpa.allocator(); const prompt_spec = "$p$g "; while (true) { const cwd = std.fs.cwd().realpathAlloc(allocator, ".") catch |err| switch (err) { error.FileNotFound => "C:\\", else => return err, }; defer allocator.free(cwd); const full_cwd = try formatPath(allocator, cwd); defer allocator.free(full_cwd); const interpolated_prompt = try std.mem.replaceOwned(u8, allocator, prompt_spec, "$p", full_cwd); defer allocator.free(interpolated_prompt); const final_prompt = try std.mem.replaceOwned(u8, allocator, interpolated_prompt, "$g", ">"); defer allocator.free(final_prompt); if (try readLine(allocator, final_prompt)) |line| { defer allocator.free(line); const command_result = parseAndExecute(line, allocator) catch |err| { switch (err) { error.ExpectedWord, error.UnexpectedToken => { print("Bad command or file name\n", .{}); continue; }, else => return err, } }; switch (command_result) { .ExitShell => break, .Code => |_| {}, } } else { break; // EOF } } }