const std = @import("std"); const Allocator = std.mem.Allocator; const ArrayList = std.ArrayList; pub fn formatDosPath(allocator: Allocator, path: []const u8) ![]const u8 { var result = ArrayList(u8){}; defer result.deinit(allocator); // Convert path to DOS format with uppercase drive letter and backslashes var converted_path = ArrayList(u8){}; defer converted_path.deinit(allocator); for (path) |ch| { if (ch == '/') { try converted_path.append(allocator, '\\'); } else { try converted_path.append(allocator, std.ascii.toUpper(ch)); } } // Split into components and convert each to 8.3 format var it = std.mem.splitScalar(u8, converted_path.items, '\\'); var first = true; while (it.next()) |component| { if (component.len == 0) continue; if (!first) { try result.append(allocator, '\\'); } first = false; // Convert component to 8.3 format const short_name = try convertTo83(allocator, component); defer allocator.free(short_name.name); defer allocator.free(short_name.ext); try result.appendSlice(allocator, short_name.name); if (short_name.ext.len > 0) { try result.append(allocator, '.'); try result.appendSlice(allocator, short_name.ext); } } // 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){}; defer prefixed.deinit(allocator); try prefixed.appendSlice(allocator, "C:"); if (result.items.len > 0 and result.items[0] != '\\') { try prefixed.append(allocator, '\\'); } try prefixed.appendSlice(allocator, result.items); return allocator.dupe(u8, prefixed.items); } return allocator.dupe(u8, result.items); } pub fn convertTo83(allocator: Allocator, filename: []const u8) !struct { name: []const u8, ext: []const u8 } { // Handle special directories if (std.mem.eql(u8, filename, ".") or std.mem.eql(u8, filename, "..")) { return .{ .name = try allocator.dupe(u8, filename), .ext = try allocator.dupe(u8, "") }; } // Handle drive letters (like C:) if (filename.len == 2 and filename[1] == ':') { return .{ .name = try allocator.dupe(u8, filename), .ext = try allocator.dupe(u8, "") }; } // Split filename and extension var name_part: []const u8 = filename; var ext_part: []const u8 = ""; if (std.mem.lastIndexOf(u8, filename, ".")) |dot_pos| { if (dot_pos > 0) { // Don't treat leading dot as extension separator name_part = filename[0..dot_pos]; ext_part = filename[dot_pos + 1 ..]; } } // Clean name part (remove spaces and invalid chars, convert to uppercase) var clean_name = ArrayList(u8){}; defer clean_name.deinit(allocator); for (name_part) |ch| { if (std.ascii.isAlphanumeric(ch)) { try clean_name.append(allocator, std.ascii.toUpper(ch)); } else if (ch == '-' or ch == '_') { try clean_name.append(allocator, ch); } // Skip spaces and other invalid characters } // Clean extension part (max 3 chars, uppercase) var clean_ext = ArrayList(u8){}; defer clean_ext.deinit(allocator); for (ext_part) |ch| { if (clean_ext.items.len >= 3) break; if (std.ascii.isAlphanumeric(ch)) { try clean_ext.append(allocator, std.ascii.toUpper(ch)); } } var name_result = ArrayList(u8){}; defer name_result.deinit(allocator); var ext_result = ArrayList(u8){}; defer ext_result.deinit(allocator); // Build 8.3 filename if (clean_name.items.len <= 8 and clean_ext.items.len <= 3) { // Name fits in 8.3, use as-is try name_result.appendSlice(allocator, clean_name.items); try ext_result.appendSlice(allocator, clean_ext.items); } else { // Need to abbreviate with ~1 const max_name_len = if (clean_name.items.len > 6) 6 else clean_name.items.len; try name_result.appendSlice(allocator, clean_name.items[0..max_name_len]); try name_result.appendSlice(allocator, "~1"); if (clean_ext.items.len > 0) { const max_ext_len = if (clean_ext.items.len > 3) 3 else clean_ext.items.len; try ext_result.appendSlice(allocator, clean_ext.items[0..max_ext_len]); } } return .{ .name = try allocator.dupe(u8, name_result.items), .ext = try allocator.dupe(u8, ext_result.items) }; }