summaryrefslogtreecommitdiff
path: root/src/paths.zig
blob: abda053928a0be4fe8d8c93b7f32fdf8bff7bc22 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
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) };
}