diff options
author | Matthias Andreas Benkard <code@mail.matthias.benkard.de> | 2025-08-13 20:10:42 +0200 |
---|---|---|
committer | Matthias Andreas Benkard <code@mail.matthias.benkard.de> | 2025-08-13 20:10:42 +0200 |
commit | cdaecb2a0e4f5c25338cd7f11f3b881194068ac9 (patch) | |
tree | 95f0c7fca34507e36fd726370113d4297945896c | |
parent | 51a9d99310bff6df8f92963613595a69ec778991 (diff) |
DIR: More DOS-like output.
-rw-r--r-- | src/eval.zig | 94 |
1 files changed, 88 insertions, 6 deletions
diff --git a/src/eval.zig b/src/eval.zig index 472d896..ba7cff0 100644 --- a/src/eval.zig +++ b/src/eval.zig @@ -75,6 +75,66 @@ const InputSource = struct { } }; +fn formatDosPath(allocator: Allocator, path: []const u8) ![]const u8 { + var result = ArrayList(u8).init(allocator); + defer result.deinit(); + + // Convert path to DOS format with uppercase drive letter and backslashes + for (path) |ch| { + if (ch == '/') { + try result.append('\\'); + } else { + try result.append(std.ascii.toUpper(ch)); + } + } + + // Ensure it starts with a drive letter if it's an absolute path + if (result.items.len == 0 or (result.items.len >= 1 and result.items[0] == '\\')) { + var prefixed = ArrayList(u8).init(allocator); + defer prefixed.deinit(); + try prefixed.appendSlice("C:"); + if (result.items.len > 0 and result.items[0] != '\\') { + try prefixed.append('\\'); + } + try prefixed.appendSlice(result.items); + return allocator.dupe(u8, prefixed.items); + } + + return allocator.dupe(u8, result.items); +} + +fn formatDosDateTime(allocator: Allocator, timestamp_secs: i64) ![]const u8 { + const epoch_seconds = @as(u64, @intCast(@max(timestamp_secs, 0))); + const epoch_day = @divFloor(epoch_seconds, std.time.s_per_day); + const day_seconds = epoch_seconds % std.time.s_per_day; + + // Calculate date (simplified) + var year: u32 = 1970; // Start from Unix epoch year + var remaining_days = epoch_day; + + // Simple year calculation + while (remaining_days >= 365) { + const days_in_year: u64 = if (isLeapYear(year)) 366 else 365; + if (remaining_days < days_in_year) break; + remaining_days -= days_in_year; + year += 1; + } + + // Simple month/day calculation (approximate) + const month = @min(@divFloor(remaining_days, 30) + 1, 12); + const day = @min(remaining_days % 30 + 1, 31); + + // Calculate time + const hours = day_seconds / std.time.s_per_hour; + const minutes = (day_seconds % std.time.s_per_hour) / std.time.s_per_min; + + // Format as MM-DD-YY HH:MMa (DOS style) + const am_pm = if (hours < 12) "a" else "p"; + const display_hour = if (hours == 0) 12 else if (hours > 12) hours - 12 else hours; + + return try std.fmt.allocPrint(allocator, "{d:0>2}-{d:0>2}-{d:0>2} {d:>2}:{d:0>2}{s}", .{ @as(u32, @intCast(month)), @as(u32, @intCast(day)), @as(u32, @intCast(year % 100)), @as(u32, @intCast(display_hour)), @as(u32, @intCast(minutes)), am_pm }); +} + pub fn executeCommand(command: Command, allocator: Allocator) !CommandStatus { return executeCommandWithOutput(command, allocator, null, null); } @@ -206,7 +266,18 @@ fn executeCommandWithOutput(command: Command, allocator: Allocator, output_captu var output_buffer = ArrayList(u8).init(allocator); defer output_buffer.deinit(); - try output_buffer.writer().print("Directory of {s}\n\n", .{dir.path}); + // Format path in DOS style with backslashes and uppercase drive letter + const formatted_path = try formatDosPath(allocator, dir.path); + defer allocator.free(formatted_path); + + // Get volume label (simplified - just show drive) + const drive_letter = if (formatted_path.len >= 2 and formatted_path[1] == ':') + formatted_path[0] + else + 'C'; + try output_buffer.writer().print(" Volume in drive {c} has no label\n", .{drive_letter}); + try output_buffer.writer().print(" Volume Serial Number is 1234-5678\n", .{}); + try output_buffer.writer().print("\n Directory of {s}\n\n", .{formatted_path}); var dir_iterator = std.fs.cwd().openDir(dir.path, .{ .iterate = true }) catch { const error_msg = "File not found\n"; @@ -222,24 +293,35 @@ fn executeCommandWithOutput(command: Command, allocator: Allocator, output_captu var iterator = dir_iterator.iterate(); var file_count: u32 = 0; var dir_count: u32 = 0; + var total_file_bytes: u64 = 0; while (try iterator.next()) |entry| { + const stat = dir_iterator.statFile(entry.name) catch continue; + + // Convert timestamp to DOS date/time format + const mtime_secs = @divFloor(stat.mtime, std.time.ns_per_s); + const date_time = try formatDosDateTime(allocator, @intCast(mtime_secs)); + defer allocator.free(date_time); + switch (entry.kind) { .directory => { - try output_buffer.writer().print("<DIR> {s}\n", .{entry.name}); + try output_buffer.writer().print("{s} <DIR> {s}\n", .{ date_time, entry.name }); dir_count += 1; }, .file => { - const stat = dir_iterator.statFile(entry.name) catch continue; - try output_buffer.writer().print("{d:>14} {s}\n", .{ stat.size, entry.name }); + try output_buffer.writer().print("{s} {d:>14} {s}\n", .{ date_time, stat.size, entry.name }); file_count += 1; + total_file_bytes += stat.size; }, else => {}, } } - try output_buffer.writer().print("\n{d} File(s)\n", .{file_count}); - try output_buffer.writer().print("{d} Dir(s)\n", .{dir_count}); + // Get free disk space (simplified - just use a placeholder) + const bytes_free: u64 = 1024 * 1024 * 1024; // 1GB placeholder + + try output_buffer.writer().print(" {d} File(s) {d:>14} bytes\n", .{ file_count, total_file_bytes }); + try output_buffer.writer().print(" {d} Dir(s) {d:>14} bytes free\n", .{ dir_count, bytes_free }); if (output_capture) |capture| { try capture.write(output_buffer.items); |