const std = @import("std"); const Allocator = std.mem.Allocator; const ArrayList = std.ArrayList; const syntax = @import("../syntax.zig"); const FileSpec = syntax.FileSpec; const types = @import("./lib/types.zig"); const CommandStatus = types.CommandStatus; const CommandContext = types.CommandContext; pub const Type = struct { file: FileSpec, pub fn eval(type_cmd: Type, ctx: CommandContext) !CommandStatus { const file_path = switch (type_cmd.file) { .Con => { const error_msg = "Cannot TYPE from CON\n"; var writer = ctx.output_writer; try writer.write(error_msg); return CommandStatus{ .Code = 1 }; }, .Lpt1, .Lpt2, .Lpt3, .Prn => { const error_msg = "Cannot TYPE from device\n"; var writer = ctx.output_writer; try writer.write(error_msg); return CommandStatus{ .Code = 1 }; }, .Path => |path| path, }; const file = std.fs.cwd().openFile(file_path, .{}) catch |err| { const error_msg = switch (err) { error.FileNotFound => "The system cannot find the file specified.\n", error.IsDir => "Access is denied.\n", error.AccessDenied => "Access is denied.\n", else => "Cannot access file.\n", }; var writer = ctx.output_writer; try writer.write(error_msg); return CommandStatus{ .Code = 1 }; }; defer file.close(); // Read and display file contents var buffer: [4096]u8 = undefined; while (true) { const bytes_read = file.readAll(&buffer) catch |err| { const error_msg = switch (err) { error.AccessDenied => "Access is denied.\n", else => "Error reading file.\n", }; var writer = ctx.output_writer; try writer.write(error_msg); return CommandStatus{ .Code = 1 }; }; if (bytes_read == 0) break; // Process buffer contents for output var processed_output = ArrayList(u8){}; defer processed_output.deinit(ctx.allocator); for (buffer[0..bytes_read]) |byte| { // Convert to printable characters, similar to DOS TYPE behavior if (byte >= 32 and byte <= 126) { try processed_output.append(ctx.allocator, byte); } else if (byte == '\n') { try processed_output.append(ctx.allocator, '\n'); } else if (byte == '\r') { // Skip carriage return in DOS-style line endings continue; } else if (byte == '\t') { try processed_output.append(ctx.allocator, '\t'); } else { // Replace non-printable characters with '?' try processed_output.append(ctx.allocator, '?'); } } var writer = ctx.output_writer; try writer.write(processed_output.items); // If we read less than the buffer size, we're done if (bytes_read < buffer.len) break; } return CommandStatus{ .Code = 0 }; } };