| ... | @@ -3,6 +3,7 @@ const builtin = @import("builtin"); | ... | @@ -3,6 +3,7 @@ const builtin = @import("builtin"); |
| 3 | | 3 | |
| 4 | const std = @import("std"); | 4 | const std = @import("std"); |
| 5 | const Io = std.Io; | 5 | const Io = std.Io; |
| | 6 | const Dir = std.Io.Dir; |
| 6 | const Writer = std.Io.Writer; | 7 | const Writer = std.Io.Writer; |
| 7 | const Allocator = std.mem.Allocator; | 8 | const Allocator = std.mem.Allocator; |
| 8 | | 9 | |
| ... | @@ -22,8 +23,8 @@ const product_version_max_length = version_major_minor_max_length + ".65535".len | ... | @@ -22,8 +23,8 @@ const product_version_max_length = version_major_minor_max_length + ".65535".len |
| 22 | | 23 | |
| 23 | /// Find path and version of Windows 10 SDK and Windows 8.1 SDK, and find path to MSVC's `lib/` directory. | 24 | /// Find path and version of Windows 10 SDK and Windows 8.1 SDK, and find path to MSVC's `lib/` directory. |
| 24 | /// Caller owns the result's fields. | 25 | /// Caller owns the result's fields. |
| 25 | /// After finishing work, call `free(allocator)`. | 26 | /// Returns memory allocated by `gpa` |
| 26 | pub fn find(allocator: Allocator, arch: std.Target.Cpu.Arch) error{ OutOfMemory, NotFound, PathTooLong }!WindowsSdk { | 27 | pub fn find(gpa: Allocator, arch: std.Target.Cpu.Arch) error{ OutOfMemory, NotFound, PathTooLong }!WindowsSdk { |
| 27 | if (builtin.os.tag != .windows) return error.NotFound; | 28 | if (builtin.os.tag != .windows) return error.NotFound; |
| 28 | | 29 | |
| 29 | //note(dimenus): If this key doesn't exist, neither the Win 8 SDK nor the Win 10 SDK is installed | 30 | //note(dimenus): If this key doesn't exist, neither the Win 8 SDK nor the Win 10 SDK is installed |
| ... | @@ -32,27 +33,27 @@ pub fn find(allocator: Allocator, arch: std.Target.Cpu.Arch) error{ OutOfMemory, | ... | @@ -32,27 +33,27 @@ pub fn find(allocator: Allocator, arch: std.Target.Cpu.Arch) error{ OutOfMemory, |
| 32 | }; | 33 | }; |
| 33 | defer roots_key.closeKey(); | 34 | defer roots_key.closeKey(); |
| 34 | | 35 | |
| 35 | const windows10sdk = Installation.find(allocator, roots_key, "KitsRoot10", "", "v10.0") catch |err| switch (err) { | 36 | const windows10sdk = Installation.find(gpa, roots_key, "KitsRoot10", "", "v10.0") catch |err| switch (err) { |
| 36 | error.InstallationNotFound => null, | 37 | error.InstallationNotFound => null, |
| 37 | error.PathTooLong => null, | 38 | error.PathTooLong => null, |
| 38 | error.VersionTooLong => null, | 39 | error.VersionTooLong => null, |
| 39 | error.OutOfMemory => return error.OutOfMemory, | 40 | error.OutOfMemory => return error.OutOfMemory, |
| 40 | }; | 41 | }; |
| 41 | errdefer if (windows10sdk) |*w| w.free(allocator); | 42 | errdefer if (windows10sdk) |*w| w.free(gpa); |
| 42 | | 43 | |
| 43 | const windows81sdk = Installation.find(allocator, roots_key, "KitsRoot81", "winver", "v8.1") catch |err| switch (err) { | 44 | const windows81sdk = Installation.find(gpa, roots_key, "KitsRoot81", "winver", "v8.1") catch |err| switch (err) { |
| 44 | error.InstallationNotFound => null, | 45 | error.InstallationNotFound => null, |
| 45 | error.PathTooLong => null, | 46 | error.PathTooLong => null, |
| 46 | error.VersionTooLong => null, | 47 | error.VersionTooLong => null, |
| 47 | error.OutOfMemory => return error.OutOfMemory, | 48 | error.OutOfMemory => return error.OutOfMemory, |
| 48 | }; | 49 | }; |
| 49 | errdefer if (windows81sdk) |*w| w.free(allocator); | 50 | errdefer if (windows81sdk) |*w| w.free(gpa); |
| 50 | | 51 | |
| 51 | const msvc_lib_dir: ?[]const u8 = MsvcLibDir.find(allocator, arch) catch |err| switch (err) { | 52 | const msvc_lib_dir: ?[]const u8 = MsvcLibDir.find(gpa, arch) catch |err| switch (err) { |
| 52 | error.MsvcLibDirNotFound => null, | 53 | error.MsvcLibDirNotFound => null, |
| 53 | error.OutOfMemory => return error.OutOfMemory, | 54 | error.OutOfMemory => return error.OutOfMemory, |
| 54 | }; | 55 | }; |
| 55 | errdefer allocator.free(msvc_lib_dir); | 56 | errdefer gpa.free(msvc_lib_dir); |
| 56 | | 57 | |
| 57 | return .{ | 58 | return .{ |
| 58 | .windows10sdk = windows10sdk, | 59 | .windows10sdk = windows10sdk, |
| ... | @@ -61,15 +62,15 @@ pub fn find(allocator: Allocator, arch: std.Target.Cpu.Arch) error{ OutOfMemory, | ... | @@ -61,15 +62,15 @@ pub fn find(allocator: Allocator, arch: std.Target.Cpu.Arch) error{ OutOfMemory, |
| 61 | }; | 62 | }; |
| 62 | } | 63 | } |
| 63 | | 64 | |
| 64 | pub fn free(sdk: WindowsSdk, allocator: Allocator) void { | 65 | pub fn free(sdk: WindowsSdk, gpa: Allocator) void { |
| 65 | if (sdk.windows10sdk) |*w10sdk| { | 66 | if (sdk.windows10sdk) |*w10sdk| { |
| 66 | w10sdk.free(allocator); | 67 | w10sdk.free(gpa); |
| 67 | } | 68 | } |
| 68 | if (sdk.windows81sdk) |*w81sdk| { | 69 | if (sdk.windows81sdk) |*w81sdk| { |
| 69 | w81sdk.free(allocator); | 70 | w81sdk.free(gpa); |
| 70 | } | 71 | } |
| 71 | if (sdk.msvc_lib_dir) |msvc_lib_dir| { | 72 | if (sdk.msvc_lib_dir) |msvc_lib_dir| { |
| 72 | allocator.free(msvc_lib_dir); | 73 | gpa.free(msvc_lib_dir); |
| 73 | } | 74 | } |
| 74 | } | 75 | } |
| 75 | | 76 | |
| ... | @@ -77,8 +78,8 @@ pub fn free(sdk: WindowsSdk, allocator: Allocator) void { | ... | @@ -77,8 +78,8 @@ pub fn free(sdk: WindowsSdk, allocator: Allocator) void { |
| 77 | /// and a version. Returns slice of version strings sorted in descending order. | 78 | /// and a version. Returns slice of version strings sorted in descending order. |
| 78 | /// Caller owns result. | 79 | /// Caller owns result. |
| 79 | fn iterateAndFilterByVersion( | 80 | fn iterateAndFilterByVersion( |
| 80 | iterator: *Io.Dir.Iterator, | 81 | iterator: *Dir.Iterator, |
| 81 | allocator: Allocator, | 82 | gpa: Allocator, |
| 82 | prefix: []const u8, | 83 | prefix: []const u8, |
| 83 | ) error{OutOfMemory}![][]const u8 { | 84 | ) error{OutOfMemory}![][]const u8 { |
| 84 | const Version = struct { | 85 | const Version = struct { |
| ... | @@ -95,11 +96,11 @@ fn iterateAndFilterByVersion( | ... | @@ -95,11 +96,11 @@ fn iterateAndFilterByVersion( |
| 95 | std.mem.order(u8, lhs.build, rhs.build); | 96 | std.mem.order(u8, lhs.build, rhs.build); |
| 96 | } | 97 | } |
| 97 | }; | 98 | }; |
| 98 | var versions = std.array_list.Managed(Version).init(allocator); | 99 | var versions = std.array_list.Managed(Version).init(gpa); |
| 99 | var dirs = std.array_list.Managed([]const u8).init(allocator); | 100 | var dirs = std.array_list.Managed([]const u8).init(gpa); |
| 100 | defer { | 101 | defer { |
| 101 | versions.deinit(); | 102 | versions.deinit(); |
| 102 | for (dirs.items) |filtered_dir| allocator.free(filtered_dir); | 103 | for (dirs.items) |filtered_dir| gpa.free(filtered_dir); |
| 103 | dirs.deinit(); | 104 | dirs.deinit(); |
| 104 | } | 105 | } |
| 105 | | 106 | |
| ... | @@ -119,8 +120,8 @@ fn iterateAndFilterByVersion( | ... | @@ -119,8 +120,8 @@ fn iterateAndFilterByVersion( |
| 119 | num.* = Version.parseNum(num_it.next() orelse break) orelse continue :iterate | 120 | num.* = Version.parseNum(num_it.next() orelse break) orelse continue :iterate |
| 120 | else if (num_it.next()) |_| continue; | 121 | else if (num_it.next()) |_| continue; |
| 121 | | 122 | |
| 122 | const name = try allocator.dupe(u8, suffix); | 123 | const name = try gpa.dupe(u8, suffix); |
| 123 | errdefer allocator.free(name); | 124 | errdefer gpa.free(name); |
| 124 | if (underscore) |pos| version.build = name[pos + 1 ..]; | 125 | if (underscore) |pos| version.build = name[pos + 1 ..]; |
| 125 | | 126 | |
| 126 | try versions.append(version); | 127 | try versions.append(version); |
| ... | @@ -177,7 +178,7 @@ const RegistryWtf8 = struct { | ... | @@ -177,7 +178,7 @@ const RegistryWtf8 = struct { |
| 177 | | 178 | |
| 178 | /// Get string from registry. | 179 | /// Get string from registry. |
| 179 | /// Caller owns result. | 180 | /// Caller owns result. |
| 180 | pub fn getString(reg: RegistryWtf8, allocator: Allocator, subkey: []const u8, value_name: []const u8) error{ OutOfMemory, ValueNameNotFound, NotAString, StringNotFound }![]u8 { | 181 | pub fn getString(reg: RegistryWtf8, gpa: Allocator, subkey: []const u8, value_name: []const u8) error{ OutOfMemory, ValueNameNotFound, NotAString, StringNotFound }![]u8 { |
| 181 | const subkey_wtf16le: [:0]const u16 = subkey_wtf16le: { | 182 | const subkey_wtf16le: [:0]const u16 = subkey_wtf16le: { |
| 182 | var subkey_wtf16le_buf: [RegistryWtf16Le.key_name_max_len]u16 = undefined; | 183 | var subkey_wtf16le_buf: [RegistryWtf16Le.key_name_max_len]u16 = undefined; |
| 183 | const subkey_wtf16le_len: usize = std.unicode.wtf8ToWtf16Le(subkey_wtf16le_buf[0..], subkey) catch unreachable; | 184 | const subkey_wtf16le_len: usize = std.unicode.wtf8ToWtf16Le(subkey_wtf16le_buf[0..], subkey) catch unreachable; |
| ... | @@ -193,11 +194,11 @@ const RegistryWtf8 = struct { | ... | @@ -193,11 +194,11 @@ const RegistryWtf8 = struct { |
| 193 | }; | 194 | }; |
| 194 | | 195 | |
| 195 | const registry_wtf16le: RegistryWtf16Le = .{ .key = reg.key }; | 196 | const registry_wtf16le: RegistryWtf16Le = .{ .key = reg.key }; |
| 196 | const value_wtf16le = try registry_wtf16le.getString(allocator, subkey_wtf16le, value_name_wtf16le); | 197 | const value_wtf16le = try registry_wtf16le.getString(gpa, subkey_wtf16le, value_name_wtf16le); |
| 197 | defer allocator.free(value_wtf16le); | 198 | defer gpa.free(value_wtf16le); |
| 198 | | 199 | |
| 199 | const value_wtf8: []u8 = try std.unicode.wtf16LeToWtf8Alloc(allocator, value_wtf16le); | 200 | const value_wtf8: []u8 = try std.unicode.wtf16LeToWtf8Alloc(gpa, value_wtf16le); |
| 200 | errdefer allocator.free(value_wtf8); | 201 | errdefer gpa.free(value_wtf8); |
| 201 | | 202 | |
| 202 | return value_wtf8; | 203 | return value_wtf8; |
| 203 | } | 204 | } |
| ... | @@ -285,7 +286,7 @@ const RegistryWtf16Le = struct { | ... | @@ -285,7 +286,7 @@ const RegistryWtf16Le = struct { |
| 285 | } | 286 | } |
| 286 | | 287 | |
| 287 | /// Get string ([:0]const u16) from registry. | 288 | /// Get string ([:0]const u16) from registry. |
| 288 | fn getString(reg: RegistryWtf16Le, allocator: Allocator, subkey_wtf16le: [:0]const u16, value_name_wtf16le: [:0]const u16) error{ OutOfMemory, ValueNameNotFound, NotAString, StringNotFound }![]const u16 { | 289 | fn getString(reg: RegistryWtf16Le, gpa: Allocator, subkey_wtf16le: [:0]const u16, value_name_wtf16le: [:0]const u16) error{ OutOfMemory, ValueNameNotFound, NotAString, StringNotFound }![]const u16 { |
| 289 | var actual_type: windows.ULONG = undefined; | 290 | var actual_type: windows.ULONG = undefined; |
| 290 | | 291 | |
| 291 | // Calculating length to allocate | 292 | // Calculating length to allocate |
| ... | @@ -314,8 +315,8 @@ const RegistryWtf16Le = struct { | ... | @@ -314,8 +315,8 @@ const RegistryWtf16Le = struct { |
| 314 | else => return error.NotAString, | 315 | else => return error.NotAString, |
| 315 | } | 316 | } |
| 316 | | 317 | |
| 317 | const value_wtf16le_buf: []u16 = try allocator.alloc(u16, std.math.divCeil(u32, value_wtf16le_buf_size, 2) catch unreachable); | 318 | const value_wtf16le_buf: []u16 = try gpa.alloc(u16, std.math.divCeil(u32, value_wtf16le_buf_size, 2) catch unreachable); |
| 318 | errdefer allocator.free(value_wtf16le_buf); | 319 | errdefer gpa.free(value_wtf16le_buf); |
| 319 | | 320 | |
| 320 | return_code_int = windows.advapi32.RegGetValueW( | 321 | return_code_int = windows.advapi32.RegGetValueW( |
| 321 | reg.key, | 322 | reg.key, |
| ... | @@ -349,7 +350,7 @@ const RegistryWtf16Le = struct { | ... | @@ -349,7 +350,7 @@ const RegistryWtf16Le = struct { |
| 349 | break :value_wtf16le std.mem.span(value_wtf16le_overestimated); | 350 | break :value_wtf16le std.mem.span(value_wtf16le_overestimated); |
| 350 | }; | 351 | }; |
| 351 | | 352 | |
| 352 | _ = allocator.resize(value_wtf16le_buf, value_wtf16le.len); | 353 | _ = gpa.resize(value_wtf16le_buf, value_wtf16le.len); |
| 353 | return value_wtf16le; | 354 | return value_wtf16le; |
| 354 | } | 355 | } |
| 355 | | 356 | |
| ... | @@ -417,66 +418,65 @@ pub const Installation = struct { | ... | @@ -417,66 +418,65 @@ pub const Installation = struct { |
| 417 | | 418 | |
| 418 | /// Find path and version of Windows SDK. | 419 | /// Find path and version of Windows SDK. |
| 419 | /// Caller owns the result's fields. | 420 | /// Caller owns the result's fields. |
| 420 | /// After finishing work, call `free(allocator)`. | | |
| 421 | fn find( | 421 | fn find( |
| 422 | allocator: Allocator, | 422 | gpa: Allocator, |
| 423 | roots_key: RegistryWtf8, | 423 | roots_key: RegistryWtf8, |
| 424 | roots_subkey: []const u8, | 424 | roots_subkey: []const u8, |
| 425 | prefix: []const u8, | 425 | prefix: []const u8, |
| 426 | version_key_name: []const u8, | 426 | version_key_name: []const u8, |
| 427 | ) error{ OutOfMemory, InstallationNotFound, PathTooLong, VersionTooLong }!Installation { | 427 | ) error{ OutOfMemory, InstallationNotFound, PathTooLong, VersionTooLong }!Installation { |
| 428 | roots: { | 428 | roots: { |
| 429 | const installation = findFromRoot(allocator, roots_key, roots_subkey, prefix) catch | 429 | const installation = findFromRoot(gpa, roots_key, roots_subkey, prefix) catch |
| 430 | break :roots; | 430 | break :roots; |
| 431 | if (installation.isValidVersion()) return installation; | 431 | if (installation.isValidVersion()) return installation; |
| 432 | installation.free(allocator); | 432 | installation.free(gpa); |
| 433 | } | 433 | } |
| 434 | { | 434 | { |
| 435 | const installation = try findFromInstallationFolder(allocator, version_key_name); | 435 | const installation = try findFromInstallationFolder(gpa, version_key_name); |
| 436 | if (installation.isValidVersion()) return installation; | 436 | if (installation.isValidVersion()) return installation; |
| 437 | installation.free(allocator); | 437 | installation.free(gpa); |
| 438 | } | 438 | } |
| 439 | return error.InstallationNotFound; | 439 | return error.InstallationNotFound; |
| 440 | } | 440 | } |
| 441 | | 441 | |
| 442 | fn findFromRoot( | 442 | fn findFromRoot( |
| 443 | allocator: Allocator, | 443 | gpa: Allocator, |
| 444 | io: Io, | 444 | io: Io, |
| 445 | roots_key: RegistryWtf8, | 445 | roots_key: RegistryWtf8, |
| 446 | roots_subkey: []const u8, | 446 | roots_subkey: []const u8, |
| 447 | prefix: []const u8, | 447 | prefix: []const u8, |
| 448 | ) error{ OutOfMemory, InstallationNotFound, PathTooLong, VersionTooLong }!Installation { | 448 | ) error{ OutOfMemory, InstallationNotFound, PathTooLong, VersionTooLong }!Installation { |
| 449 | const path = path: { | 449 | const path = path: { |
| 450 | const path_maybe_with_trailing_slash = roots_key.getString(allocator, "", roots_subkey) catch |err| switch (err) { | 450 | const path_maybe_with_trailing_slash = roots_key.getString(gpa, "", roots_subkey) catch |err| switch (err) { |
| 451 | error.NotAString => return error.InstallationNotFound, | 451 | error.NotAString => return error.InstallationNotFound, |
| 452 | error.ValueNameNotFound => return error.InstallationNotFound, | 452 | error.ValueNameNotFound => return error.InstallationNotFound, |
| 453 | error.StringNotFound => return error.InstallationNotFound, | 453 | error.StringNotFound => return error.InstallationNotFound, |
| 454 | | 454 | |
| 455 | error.OutOfMemory => return error.OutOfMemory, | 455 | error.OutOfMemory => return error.OutOfMemory, |
| 456 | }; | 456 | }; |
| 457 | if (path_maybe_with_trailing_slash.len > std.fs.max_path_bytes or !std.fs.path.isAbsolute(path_maybe_with_trailing_slash)) { | 457 | if (path_maybe_with_trailing_slash.len > Dir.max_path_bytes or !Dir.path.isAbsolute(path_maybe_with_trailing_slash)) { |
| 458 | allocator.free(path_maybe_with_trailing_slash); | 458 | gpa.free(path_maybe_with_trailing_slash); |
| 459 | return error.PathTooLong; | 459 | return error.PathTooLong; |
| 460 | } | 460 | } |
| 461 | | 461 | |
| 462 | var path = std.array_list.Managed(u8).fromOwnedSlice(allocator, path_maybe_with_trailing_slash); | 462 | var path = std.array_list.Managed(u8).fromOwnedSlice(gpa, path_maybe_with_trailing_slash); |
| 463 | errdefer path.deinit(); | 463 | errdefer path.deinit(); |
| 464 | | 464 | |
| 465 | // String might contain trailing slash, so trim it here | 465 | // String might contain trailing slash, so trim it here |
| 466 | if (path.items.len > "C:\\".len and path.getLast() == '\\') _ = path.pop(); | 466 | if (path.items.len > "C:\\".len and path.getLast() == '\\') _ = path.pop(); |
| 467 | break :path try path.toOwnedSlice(); | 467 | break :path try path.toOwnedSlice(); |
| 468 | }; | 468 | }; |
| 469 | errdefer allocator.free(path); | 469 | errdefer gpa.free(path); |
| 470 | | 470 | |
| 471 | const version = version: { | 471 | const version = version: { |
| 472 | var buf: [std.fs.max_path_bytes]u8 = undefined; | 472 | var buf: [Dir.max_path_bytes]u8 = undefined; |
| 473 | const sdk_lib_dir_path = std.fmt.bufPrint(buf[0..], "{s}\\Lib\\", .{path}) catch |err| switch (err) { | 473 | const sdk_lib_dir_path = std.fmt.bufPrint(buf[0..], "{s}\\Lib\\", .{path}) catch |err| switch (err) { |
| 474 | error.NoSpaceLeft => return error.PathTooLong, | 474 | error.NoSpaceLeft => return error.PathTooLong, |
| 475 | }; | 475 | }; |
| 476 | if (!std.fs.path.isAbsolute(sdk_lib_dir_path)) return error.InstallationNotFound; | 476 | if (!Dir.path.isAbsolute(sdk_lib_dir_path)) return error.InstallationNotFound; |
| 477 | | 477 | |
| 478 | // enumerate files in sdk path looking for latest version | 478 | // enumerate files in sdk path looking for latest version |
| 479 | var sdk_lib_dir = std.fs.openDirAbsolute(sdk_lib_dir_path, .{ | 479 | var sdk_lib_dir = Dir.openDirAbsolute(io, sdk_lib_dir_path, .{ |
| 480 | .iterate = true, | 480 | .iterate = true, |
| 481 | }) catch |err| switch (err) { | 481 | }) catch |err| switch (err) { |
| 482 | error.NameTooLong => return error.PathTooLong, | 482 | error.NameTooLong => return error.PathTooLong, |
| ... | @@ -485,21 +485,21 @@ pub const Installation = struct { | ... | @@ -485,21 +485,21 @@ pub const Installation = struct { |
| 485 | defer sdk_lib_dir.close(io); | 485 | defer sdk_lib_dir.close(io); |
| 486 | | 486 | |
| 487 | var iterator = sdk_lib_dir.iterate(); | 487 | var iterator = sdk_lib_dir.iterate(); |
| 488 | const versions = try iterateAndFilterByVersion(&iterator, allocator, prefix); | 488 | const versions = try iterateAndFilterByVersion(&iterator, gpa, prefix); |
| 489 | if (versions.len == 0) return error.InstallationNotFound; | 489 | if (versions.len == 0) return error.InstallationNotFound; |
| 490 | defer { | 490 | defer { |
| 491 | for (versions[1..]) |version| allocator.free(version); | 491 | for (versions[1..]) |version| gpa.free(version); |
| 492 | allocator.free(versions); | 492 | gpa.free(versions); |
| 493 | } | 493 | } |
| 494 | break :version versions[0]; | 494 | break :version versions[0]; |
| 495 | }; | 495 | }; |
| 496 | errdefer allocator.free(version); | 496 | errdefer gpa.free(version); |
| 497 | | 497 | |
| 498 | return .{ .path = path, .version = version }; | 498 | return .{ .path = path, .version = version }; |
| 499 | } | 499 | } |
| 500 | | 500 | |
| 501 | fn findFromInstallationFolder( | 501 | fn findFromInstallationFolder( |
| 502 | allocator: Allocator, | 502 | gpa: Allocator, |
| 503 | version_key_name: []const u8, | 503 | version_key_name: []const u8, |
| 504 | ) error{ OutOfMemory, InstallationNotFound, PathTooLong, VersionTooLong }!Installation { | 504 | ) error{ OutOfMemory, InstallationNotFound, PathTooLong, VersionTooLong }!Installation { |
| 505 | var key_name_buf: [RegistryWtf16Le.key_name_max_len]u8 = undefined; | 505 | var key_name_buf: [RegistryWtf16Le.key_name_max_len]u8 = undefined; |
| ... | @@ -518,7 +518,7 @@ pub const Installation = struct { | ... | @@ -518,7 +518,7 @@ pub const Installation = struct { |
| 518 | defer key.closeKey(); | 518 | defer key.closeKey(); |
| 519 | | 519 | |
| 520 | const path: []const u8 = path: { | 520 | const path: []const u8 = path: { |
| 521 | const path_maybe_with_trailing_slash = key.getString(allocator, "", "InstallationFolder") catch |err| switch (err) { | 521 | const path_maybe_with_trailing_slash = key.getString(gpa, "", "InstallationFolder") catch |err| switch (err) { |
| 522 | error.NotAString => return error.InstallationNotFound, | 522 | error.NotAString => return error.InstallationNotFound, |
| 523 | error.ValueNameNotFound => return error.InstallationNotFound, | 523 | error.ValueNameNotFound => return error.InstallationNotFound, |
| 524 | error.StringNotFound => return error.InstallationNotFound, | 524 | error.StringNotFound => return error.InstallationNotFound, |
| ... | @@ -526,12 +526,12 @@ pub const Installation = struct { | ... | @@ -526,12 +526,12 @@ pub const Installation = struct { |
| 526 | error.OutOfMemory => return error.OutOfMemory, | 526 | error.OutOfMemory => return error.OutOfMemory, |
| 527 | }; | 527 | }; |
| 528 | | 528 | |
| 529 | if (path_maybe_with_trailing_slash.len > std.fs.max_path_bytes or !std.fs.path.isAbsolute(path_maybe_with_trailing_slash)) { | 529 | if (path_maybe_with_trailing_slash.len > Dir.max_path_bytes or !Dir.path.isAbsolute(path_maybe_with_trailing_slash)) { |
| 530 | allocator.free(path_maybe_with_trailing_slash); | 530 | gpa.free(path_maybe_with_trailing_slash); |
| 531 | return error.PathTooLong; | 531 | return error.PathTooLong; |
| 532 | } | 532 | } |
| 533 | | 533 | |
| 534 | var path = std.array_list.Managed(u8).fromOwnedSlice(allocator, path_maybe_with_trailing_slash); | 534 | var path = std.array_list.Managed(u8).fromOwnedSlice(gpa, path_maybe_with_trailing_slash); |
| 535 | errdefer path.deinit(); | 535 | errdefer path.deinit(); |
| 536 | | 536 | |
| 537 | // String might contain trailing slash, so trim it here | 537 | // String might contain trailing slash, so trim it here |
| ... | @@ -540,12 +540,12 @@ pub const Installation = struct { | ... | @@ -540,12 +540,12 @@ pub const Installation = struct { |
| 540 | const path_without_trailing_slash = try path.toOwnedSlice(); | 540 | const path_without_trailing_slash = try path.toOwnedSlice(); |
| 541 | break :path path_without_trailing_slash; | 541 | break :path path_without_trailing_slash; |
| 542 | }; | 542 | }; |
| 543 | errdefer allocator.free(path); | 543 | errdefer gpa.free(path); |
| 544 | | 544 | |
| 545 | const version: []const u8 = version: { | 545 | const version: []const u8 = version: { |
| 546 | | 546 | |
| 547 | // note(dimenus): Microsoft doesn't include the .0 in the ProductVersion key.... | 547 | // note(dimenus): Microsoft doesn't include the .0 in the ProductVersion key.... |
| 548 | const version_without_0 = key.getString(allocator, "", "ProductVersion") catch |err| switch (err) { | 548 | const version_without_0 = key.getString(gpa, "", "ProductVersion") catch |err| switch (err) { |
| 549 | error.NotAString => return error.InstallationNotFound, | 549 | error.NotAString => return error.InstallationNotFound, |
| 550 | error.ValueNameNotFound => return error.InstallationNotFound, | 550 | error.ValueNameNotFound => return error.InstallationNotFound, |
| 551 | error.StringNotFound => return error.InstallationNotFound, | 551 | error.StringNotFound => return error.InstallationNotFound, |
| ... | @@ -553,11 +553,11 @@ pub const Installation = struct { | ... | @@ -553,11 +553,11 @@ pub const Installation = struct { |
| 553 | error.OutOfMemory => return error.OutOfMemory, | 553 | error.OutOfMemory => return error.OutOfMemory, |
| 554 | }; | 554 | }; |
| 555 | if (version_without_0.len + ".0".len > product_version_max_length) { | 555 | if (version_without_0.len + ".0".len > product_version_max_length) { |
| 556 | allocator.free(version_without_0); | 556 | gpa.free(version_without_0); |
| 557 | return error.VersionTooLong; | 557 | return error.VersionTooLong; |
| 558 | } | 558 | } |
| 559 | | 559 | |
| 560 | var version = std.array_list.Managed(u8).fromOwnedSlice(allocator, version_without_0); | 560 | var version = std.array_list.Managed(u8).fromOwnedSlice(gpa, version_without_0); |
| 561 | errdefer version.deinit(); | 561 | errdefer version.deinit(); |
| 562 | | 562 | |
| 563 | try version.appendSlice(".0"); | 563 | try version.appendSlice(".0"); |
| ... | @@ -565,14 +565,14 @@ pub const Installation = struct { | ... | @@ -565,14 +565,14 @@ pub const Installation = struct { |
| 565 | const version_with_0 = try version.toOwnedSlice(); | 565 | const version_with_0 = try version.toOwnedSlice(); |
| 566 | break :version version_with_0; | 566 | break :version version_with_0; |
| 567 | }; | 567 | }; |
| 568 | errdefer allocator.free(version); | 568 | errdefer gpa.free(version); |
| 569 | | 569 | |
| 570 | return .{ .path = path, .version = version }; | 570 | return .{ .path = path, .version = version }; |
| 571 | } | 571 | } |
| 572 | | 572 | |
| 573 | /// Check whether this version is enumerated in registry. | 573 | /// Check whether this version is enumerated in registry. |
| 574 | fn isValidVersion(installation: Installation) bool { | 574 | fn isValidVersion(installation: Installation) bool { |
| 575 | var buf: [std.fs.max_path_bytes]u8 = undefined; | 575 | var buf: [Dir.max_path_bytes]u8 = undefined; |
| 576 | const reg_query_as_wtf8 = std.fmt.bufPrint(buf[0..], "{s}\\{s}\\Installed Options", .{ | 576 | const reg_query_as_wtf8 = std.fmt.bufPrint(buf[0..], "{s}\\{s}\\Installed Options", .{ |
| 577 | windows_kits_reg_key, | 577 | windows_kits_reg_key, |
| 578 | installation.version, | 578 | installation.version, |
| ... | @@ -601,21 +601,21 @@ pub const Installation = struct { | ... | @@ -601,21 +601,21 @@ pub const Installation = struct { |
| 601 | return (reg_value == 1); | 601 | return (reg_value == 1); |
| 602 | } | 602 | } |
| 603 | | 603 | |
| 604 | fn free(install: Installation, allocator: Allocator) void { | 604 | fn free(install: Installation, gpa: Allocator) void { |
| 605 | allocator.free(install.path); | 605 | gpa.free(install.path); |
| 606 | allocator.free(install.version); | 606 | gpa.free(install.version); |
| 607 | } | 607 | } |
| 608 | }; | 608 | }; |
| 609 | | 609 | |
| 610 | const MsvcLibDir = struct { | 610 | const MsvcLibDir = struct { |
| 611 | fn findInstancesDirViaSetup(allocator: Allocator) error{ OutOfMemory, PathNotFound }!Io.Dir { | 611 | fn findInstancesDirViaSetup(gpa: Allocator, io: Io) error{ OutOfMemory, PathNotFound }!Dir { |
| 612 | const vs_setup_key_path = "SOFTWARE\\Microsoft\\VisualStudio\\Setup"; | 612 | const vs_setup_key_path = "SOFTWARE\\Microsoft\\VisualStudio\\Setup"; |
| 613 | const vs_setup_key = RegistryWtf8.openKey(windows.HKEY_LOCAL_MACHINE, vs_setup_key_path, .{}) catch |err| switch (err) { | 613 | const vs_setup_key = RegistryWtf8.openKey(windows.HKEY_LOCAL_MACHINE, vs_setup_key_path, .{}) catch |err| switch (err) { |
| 614 | error.KeyNotFound => return error.PathNotFound, | 614 | error.KeyNotFound => return error.PathNotFound, |
| 615 | }; | 615 | }; |
| 616 | defer vs_setup_key.closeKey(); | 616 | defer vs_setup_key.closeKey(); |
| 617 | | 617 | |
| 618 | const packages_path = vs_setup_key.getString(allocator, "", "CachePath") catch |err| switch (err) { | 618 | const packages_path = vs_setup_key.getString(gpa, "", "CachePath") catch |err| switch (err) { |
| 619 | error.NotAString, | 619 | error.NotAString, |
| 620 | error.ValueNameNotFound, | 620 | error.ValueNameNotFound, |
| 621 | error.StringNotFound, | 621 | error.StringNotFound, |
| ... | @@ -623,24 +623,24 @@ const MsvcLibDir = struct { | ... | @@ -623,24 +623,24 @@ const MsvcLibDir = struct { |
| 623 | | 623 | |
| 624 | error.OutOfMemory => return error.OutOfMemory, | 624 | error.OutOfMemory => return error.OutOfMemory, |
| 625 | }; | 625 | }; |
| 626 | defer allocator.free(packages_path); | 626 | defer gpa.free(packages_path); |
| 627 | | 627 | |
| 628 | if (!std.fs.path.isAbsolute(packages_path)) return error.PathNotFound; | 628 | if (!Dir.path.isAbsolute(packages_path)) return error.PathNotFound; |
| 629 | | 629 | |
| 630 | const instances_path = try std.fs.path.join(allocator, &.{ packages_path, "_Instances" }); | 630 | const instances_path = try Dir.path.join(gpa, &.{ packages_path, "_Instances" }); |
| 631 | defer allocator.free(instances_path); | 631 | defer gpa.free(instances_path); |
| 632 | | 632 | |
| 633 | return std.fs.openDirAbsolute(instances_path, .{ .iterate = true }) catch return error.PathNotFound; | 633 | return Dir.openDirAbsolute(io, instances_path, .{ .iterate = true }) catch return error.PathNotFound; |
| 634 | } | 634 | } |
| 635 | | 635 | |
| 636 | fn findInstancesDirViaCLSID(allocator: Allocator) error{ OutOfMemory, PathNotFound }!Io.Dir { | 636 | fn findInstancesDirViaCLSID(gpa: Allocator, io: Io) error{ OutOfMemory, PathNotFound }!Dir { |
| 637 | const setup_configuration_clsid = "{177f0c4a-1cd3-4de7-a32c-71dbbb9fa36d}"; | 637 | const setup_configuration_clsid = "{177f0c4a-1cd3-4de7-a32c-71dbbb9fa36d}"; |
| 638 | const setup_config_key = RegistryWtf8.openKey(windows.HKEY_CLASSES_ROOT, "CLSID\\" ++ setup_configuration_clsid, .{}) catch |err| switch (err) { | 638 | const setup_config_key = RegistryWtf8.openKey(windows.HKEY_CLASSES_ROOT, "CLSID\\" ++ setup_configuration_clsid, .{}) catch |err| switch (err) { |
| 639 | error.KeyNotFound => return error.PathNotFound, | 639 | error.KeyNotFound => return error.PathNotFound, |
| 640 | }; | 640 | }; |
| 641 | defer setup_config_key.closeKey(); | 641 | defer setup_config_key.closeKey(); |
| 642 | | 642 | |
| 643 | const dll_path = setup_config_key.getString(allocator, "InprocServer32", "") catch |err| switch (err) { | 643 | const dll_path = setup_config_key.getString(gpa, "InprocServer32", "") catch |err| switch (err) { |
| 644 | error.NotAString, | 644 | error.NotAString, |
| 645 | error.ValueNameNotFound, | 645 | error.ValueNameNotFound, |
| 646 | error.StringNotFound, | 646 | error.StringNotFound, |
| ... | @@ -648,11 +648,11 @@ const MsvcLibDir = struct { | ... | @@ -648,11 +648,11 @@ const MsvcLibDir = struct { |
| 648 | | 648 | |
| 649 | error.OutOfMemory => return error.OutOfMemory, | 649 | error.OutOfMemory => return error.OutOfMemory, |
| 650 | }; | 650 | }; |
| 651 | defer allocator.free(dll_path); | 651 | defer gpa.free(dll_path); |
| 652 | | 652 | |
| 653 | if (!std.fs.path.isAbsolute(dll_path)) return error.PathNotFound; | 653 | if (!Dir.path.isAbsolute(dll_path)) return error.PathNotFound; |
| 654 | | 654 | |
| 655 | var path_it = std.fs.path.componentIterator(dll_path); | 655 | var path_it = Dir.path.componentIterator(dll_path); |
| 656 | // the .dll filename | 656 | // the .dll filename |
| 657 | _ = path_it.last(); | 657 | _ = path_it.last(); |
| 658 | const root_path = while (path_it.previous()) |dir_component| { | 658 | const root_path = while (path_it.previous()) |dir_component| { |
| ... | @@ -663,17 +663,17 @@ const MsvcLibDir = struct { | ... | @@ -663,17 +663,17 @@ const MsvcLibDir = struct { |
| 663 | return error.PathNotFound; | 663 | return error.PathNotFound; |
| 664 | }; | 664 | }; |
| 665 | | 665 | |
| 666 | const instances_path = try std.fs.path.join(allocator, &.{ root_path, "Packages", "_Instances" }); | 666 | const instances_path = try Dir.path.join(gpa, &.{ root_path, "Packages", "_Instances" }); |
| 667 | defer allocator.free(instances_path); | 667 | defer gpa.free(instances_path); |
| 668 | | 668 | |
| 669 | return std.fs.openDirAbsolute(instances_path, .{ .iterate = true }) catch return error.PathNotFound; | 669 | return Dir.openDirAbsolute(io, instances_path, .{ .iterate = true }) catch return error.PathNotFound; |
| 670 | } | 670 | } |
| 671 | | 671 | |
| 672 | fn findInstancesDir(allocator: Allocator) error{ OutOfMemory, PathNotFound }!Io.Dir { | 672 | fn findInstancesDir(gpa: Allocator, io: Io) error{ OutOfMemory, PathNotFound }!Dir { |
| 673 | // First, try getting the packages cache path from the registry. | 673 | // First, try getting the packages cache path from the registry. |
| 674 | // This only seems to exist when the path is different from the default. | 674 | // This only seems to exist when the path is different from the default. |
| 675 | method1: { | 675 | method1: { |
| 676 | return findInstancesDirViaSetup(allocator) catch |err| switch (err) { | 676 | return findInstancesDirViaSetup(gpa) catch |err| switch (err) { |
| 677 | error.OutOfMemory => |e| return e, | 677 | error.OutOfMemory => |e| return e, |
| 678 | error.PathNotFound => break :method1, | 678 | error.PathNotFound => break :method1, |
| 679 | }; | 679 | }; |
| ... | @@ -681,7 +681,7 @@ const MsvcLibDir = struct { | ... | @@ -681,7 +681,7 @@ const MsvcLibDir = struct { |
| 681 | // Otherwise, try to get the path from the .dll that would have been | 681 | // Otherwise, try to get the path from the .dll that would have been |
| 682 | // loaded via COM for SetupConfiguration. | 682 | // loaded via COM for SetupConfiguration. |
| 683 | method2: { | 683 | method2: { |
| 684 | return findInstancesDirViaCLSID(allocator) catch |err| switch (err) { | 684 | return findInstancesDirViaCLSID(gpa, io) catch |err| switch (err) { |
| 685 | error.OutOfMemory => |e| return e, | 685 | error.OutOfMemory => |e| return e, |
| 686 | error.PathNotFound => break :method2, | 686 | error.PathNotFound => break :method2, |
| 687 | }; | 687 | }; |
| ... | @@ -689,19 +689,19 @@ const MsvcLibDir = struct { | ... | @@ -689,19 +689,19 @@ const MsvcLibDir = struct { |
| 689 | // If that can't be found, fall back to manually appending | 689 | // If that can't be found, fall back to manually appending |
| 690 | // `Microsoft\VisualStudio\Packages\_Instances` to %PROGRAMDATA% | 690 | // `Microsoft\VisualStudio\Packages\_Instances` to %PROGRAMDATA% |
| 691 | method3: { | 691 | method3: { |
| 692 | const program_data = std.process.getEnvVarOwned(allocator, "PROGRAMDATA") catch |err| switch (err) { | 692 | const program_data = std.process.getEnvVarOwned(gpa, "PROGRAMDATA") catch |err| switch (err) { |
| 693 | error.OutOfMemory => |e| return e, | 693 | error.OutOfMemory => |e| return e, |
| 694 | error.InvalidWtf8 => unreachable, | 694 | error.InvalidWtf8 => unreachable, |
| 695 | error.EnvironmentVariableNotFound => break :method3, | 695 | error.EnvironmentVariableNotFound => break :method3, |
| 696 | }; | 696 | }; |
| 697 | defer allocator.free(program_data); | 697 | defer gpa.free(program_data); |
| 698 | | 698 | |
| 699 | if (!std.fs.path.isAbsolute(program_data)) break :method3; | 699 | if (!Dir.path.isAbsolute(program_data)) break :method3; |
| 700 | | 700 | |
| 701 | const instances_path = try std.fs.path.join(allocator, &.{ program_data, "Microsoft", "VisualStudio", "Packages", "_Instances" }); | 701 | const instances_path = try Dir.path.join(gpa, &.{ program_data, "Microsoft", "VisualStudio", "Packages", "_Instances" }); |
| 702 | defer allocator.free(instances_path); | 702 | defer gpa.free(instances_path); |
| 703 | | 703 | |
| 704 | return std.fs.openDirAbsolute(instances_path, .{ .iterate = true }) catch break :method3; | 704 | return Dir.openDirAbsolute(io, instances_path, .{ .iterate = true }) catch break :method3; |
| 705 | } | 705 | } |
| 706 | return error.PathNotFound; | 706 | return error.PathNotFound; |
| 707 | } | 707 | } |
| ... | @@ -752,17 +752,17 @@ const MsvcLibDir = struct { | ... | @@ -752,17 +752,17 @@ const MsvcLibDir = struct { |
| 752 | /// | 752 | /// |
| 753 | /// The logic in this function is intended to match what ISetupConfiguration does | 753 | /// The logic in this function is intended to match what ISetupConfiguration does |
| 754 | /// under-the-hood, as verified using Procmon. | 754 | /// under-the-hood, as verified using Procmon. |
| 755 | fn findViaCOM(allocator: Allocator, io: Io, arch: std.Target.Cpu.Arch) error{ OutOfMemory, PathNotFound }![]const u8 { | 755 | fn findViaCOM(gpa: Allocator, io: Io, arch: std.Target.Cpu.Arch) error{ OutOfMemory, PathNotFound }![]const u8 { |
| 756 | // Typically `%PROGRAMDATA%\Microsoft\VisualStudio\Packages\_Instances` | 756 | // Typically `%PROGRAMDATA%\Microsoft\VisualStudio\Packages\_Instances` |
| 757 | // This will contain directories with names of instance IDs like 80a758ca, | 757 | // This will contain directories with names of instance IDs like 80a758ca, |
| 758 | // which will contain `state.json` files that have the version and | 758 | // which will contain `state.json` files that have the version and |
| 759 | // installation directory. | 759 | // installation directory. |
| 760 | var instances_dir = try findInstancesDir(allocator); | 760 | var instances_dir = try findInstancesDir(gpa, io); |
| 761 | defer instances_dir.close(io); | 761 | defer instances_dir.close(io); |
| 762 | | 762 | |
| 763 | var state_subpath_buf: [std.fs.max_name_bytes + 32]u8 = undefined; | 763 | var state_subpath_buf: [Dir.max_name_bytes + 32]u8 = undefined; |
| 764 | var latest_version_lib_dir: std.ArrayList(u8) = .empty; | 764 | var latest_version_lib_dir: std.ArrayList(u8) = .empty; |
| 765 | errdefer latest_version_lib_dir.deinit(allocator); | 765 | errdefer latest_version_lib_dir.deinit(gpa); |
| 766 | | 766 | |
| 767 | var latest_version: u64 = 0; | 767 | var latest_version: u64 = 0; |
| 768 | var instances_dir_it = instances_dir.iterateAssumeFirstIteration(); | 768 | var instances_dir_it = instances_dir.iterateAssumeFirstIteration(); |
| ... | @@ -772,13 +772,13 @@ const MsvcLibDir = struct { | ... | @@ -772,13 +772,13 @@ const MsvcLibDir = struct { |
| 772 | var writer: Writer = .fixed(&state_subpath_buf); | 772 | var writer: Writer = .fixed(&state_subpath_buf); |
| 773 | | 773 | |
| 774 | writer.writeAll(entry.name) catch unreachable; | 774 | writer.writeAll(entry.name) catch unreachable; |
| 775 | writer.writeByte(std.fs.path.sep) catch unreachable; | 775 | writer.writeByte(Dir.path.sep) catch unreachable; |
| 776 | writer.writeAll("state.json") catch unreachable; | 776 | writer.writeAll("state.json") catch unreachable; |
| 777 | | 777 | |
| 778 | const json_contents = instances_dir.readFileAlloc(io, writer.buffered(), allocator, .limited(std.math.maxInt(usize))) catch continue; | 778 | const json_contents = instances_dir.readFileAlloc(io, writer.buffered(), gpa, .limited(std.math.maxInt(usize))) catch continue; |
| 779 | defer allocator.free(json_contents); | 779 | defer gpa.free(json_contents); |
| 780 | | 780 | |
| 781 | var parsed = std.json.parseFromSlice(std.json.Value, allocator, json_contents, .{}) catch continue; | 781 | var parsed = std.json.parseFromSlice(std.json.Value, gpa, json_contents, .{}) catch continue; |
| 782 | defer parsed.deinit(); | 782 | defer parsed.deinit(); |
| 783 | | 783 | |
| 784 | if (parsed.value != .object) continue; | 784 | if (parsed.value != .object) continue; |
| ... | @@ -795,40 +795,40 @@ const MsvcLibDir = struct { | ... | @@ -795,40 +795,40 @@ const MsvcLibDir = struct { |
| 795 | const installation_path = parsed.value.object.get("installationPath") orelse continue; | 795 | const installation_path = parsed.value.object.get("installationPath") orelse continue; |
| 796 | if (installation_path != .string) continue; | 796 | if (installation_path != .string) continue; |
| 797 | | 797 | |
| 798 | const lib_dir_path = libDirFromInstallationPath(allocator, io, installation_path.string, arch) catch |err| switch (err) { | 798 | const lib_dir_path = libDirFromInstallationPath(gpa, io, installation_path.string, arch) catch |err| switch (err) { |
| 799 | error.OutOfMemory => |e| return e, | 799 | error.OutOfMemory => |e| return e, |
| 800 | error.PathNotFound => continue, | 800 | error.PathNotFound => continue, |
| 801 | }; | 801 | }; |
| 802 | defer allocator.free(lib_dir_path); | 802 | defer gpa.free(lib_dir_path); |
| 803 | | 803 | |
| 804 | latest_version_lib_dir.clearRetainingCapacity(); | 804 | latest_version_lib_dir.clearRetainingCapacity(); |
| 805 | try latest_version_lib_dir.appendSlice(allocator, lib_dir_path); | 805 | try latest_version_lib_dir.appendSlice(gpa, lib_dir_path); |
| 806 | latest_version = parsed_version; | 806 | latest_version = parsed_version; |
| 807 | } | 807 | } |
| 808 | | 808 | |
| 809 | if (latest_version_lib_dir.items.len == 0) return error.PathNotFound; | 809 | if (latest_version_lib_dir.items.len == 0) return error.PathNotFound; |
| 810 | return latest_version_lib_dir.toOwnedSlice(allocator); | 810 | return latest_version_lib_dir.toOwnedSlice(gpa); |
| 811 | } | 811 | } |
| 812 | | 812 | |
| 813 | fn libDirFromInstallationPath( | 813 | fn libDirFromInstallationPath( |
| 814 | allocator: Allocator, | 814 | gpa: Allocator, |
| 815 | io: Io, | 815 | io: Io, |
| 816 | installation_path: []const u8, | 816 | installation_path: []const u8, |
| 817 | arch: std.Target.Cpu.Arch, | 817 | arch: std.Target.Cpu.Arch, |
| 818 | ) error{ OutOfMemory, PathNotFound }![]const u8 { | 818 | ) error{ OutOfMemory, PathNotFound }![]const u8 { |
| 819 | var lib_dir_buf = try std.array_list.Managed(u8).initCapacity(allocator, installation_path.len + 64); | 819 | var lib_dir_buf = try std.array_list.Managed(u8).initCapacity(gpa, installation_path.len + 64); |
| 820 | errdefer lib_dir_buf.deinit(); | 820 | errdefer lib_dir_buf.deinit(); |
| 821 | | 821 | |
| 822 | lib_dir_buf.appendSliceAssumeCapacity(installation_path); | 822 | lib_dir_buf.appendSliceAssumeCapacity(installation_path); |
| 823 | | 823 | |
| 824 | if (!std.fs.path.isSep(lib_dir_buf.getLast())) { | 824 | if (!Dir.path.isSep(lib_dir_buf.getLast())) { |
| 825 | try lib_dir_buf.append('\\'); | 825 | try lib_dir_buf.append('\\'); |
| 826 | } | 826 | } |
| 827 | const installation_path_with_trailing_sep_len = lib_dir_buf.items.len; | 827 | const installation_path_with_trailing_sep_len = lib_dir_buf.items.len; |
| 828 | | 828 | |
| 829 | try lib_dir_buf.appendSlice("VC\\Auxiliary\\Build\\Microsoft.VCToolsVersion.default.txt"); | 829 | try lib_dir_buf.appendSlice("VC\\Auxiliary\\Build\\Microsoft.VCToolsVersion.default.txt"); |
| 830 | var default_tools_version_buf: [512]u8 = undefined; | 830 | var default_tools_version_buf: [512]u8 = undefined; |
| 831 | const default_tools_version_contents = Io.Dir.cwd().readFile(lib_dir_buf.items, &default_tools_version_buf) catch { | 831 | const default_tools_version_contents = Dir.cwd().readFile(lib_dir_buf.items, &default_tools_version_buf) catch { |
| 832 | return error.PathNotFound; | 832 | return error.PathNotFound; |
| 833 | }; | 833 | }; |
| 834 | var tokenizer = std.mem.tokenizeAny(u8, default_tools_version_contents, " \r\n"); | 834 | var tokenizer = std.mem.tokenizeAny(u8, default_tools_version_contents, " \r\n"); |
| ... | @@ -854,64 +854,64 @@ const MsvcLibDir = struct { | ... | @@ -854,64 +854,64 @@ const MsvcLibDir = struct { |
| 854 | } | 854 | } |
| 855 | | 855 | |
| 856 | // https://learn.microsoft.com/en-us/visualstudio/install/tools-for-managing-visual-studio-instances?view=vs-2022#editing-the-registry-for-a-visual-studio-instance | 856 | // https://learn.microsoft.com/en-us/visualstudio/install/tools-for-managing-visual-studio-instances?view=vs-2022#editing-the-registry-for-a-visual-studio-instance |
| 857 | fn findViaRegistry(allocator: Allocator, io: Io, arch: std.Target.Cpu.Arch) error{ OutOfMemory, PathNotFound }![]const u8 { | 857 | fn findViaRegistry(gpa: Allocator, io: Io, arch: std.Target.Cpu.Arch) error{ OutOfMemory, PathNotFound }![]const u8 { |
| 858 | | 858 | |
| 859 | // %localappdata%\Microsoft\VisualStudio\ | 859 | // %localappdata%\Microsoft\VisualStudio\ |
| 860 | // %appdata%\Local\Microsoft\VisualStudio\ | 860 | // %appdata%\Local\Microsoft\VisualStudio\ |
| 861 | const visualstudio_folder_path = std.fs.getAppDataDir(allocator, "Microsoft\\VisualStudio\\") catch return error.PathNotFound; | 861 | const visualstudio_folder_path = std.fs.getAppDataDir(gpa, "Microsoft\\VisualStudio\\") catch return error.PathNotFound; |
| 862 | defer allocator.free(visualstudio_folder_path); | 862 | defer gpa.free(visualstudio_folder_path); |
| 863 | | 863 | |
| 864 | const vs_versions: []const []const u8 = vs_versions: { | 864 | const vs_versions: []const []const u8 = vs_versions: { |
| 865 | if (!std.fs.path.isAbsolute(visualstudio_folder_path)) return error.PathNotFound; | 865 | if (!Dir.path.isAbsolute(visualstudio_folder_path)) return error.PathNotFound; |
| 866 | // enumerate folders that contain `privateregistry.bin`, looking for all versions | 866 | // enumerate folders that contain `privateregistry.bin`, looking for all versions |
| 867 | // f.i. %localappdata%\Microsoft\VisualStudio\17.0_9e9cbb98\ | 867 | // f.i. %localappdata%\Microsoft\VisualStudio\17.0_9e9cbb98\ |
| 868 | var visualstudio_folder = std.fs.openDirAbsolute(visualstudio_folder_path, .{ | 868 | var visualstudio_folder = Dir.openDirAbsolute(io, visualstudio_folder_path, .{ |
| 869 | .iterate = true, | 869 | .iterate = true, |
| 870 | }) catch return error.PathNotFound; | 870 | }) catch return error.PathNotFound; |
| 871 | defer visualstudio_folder.close(io); | 871 | defer visualstudio_folder.close(io); |
| 872 | | 872 | |
| 873 | var iterator = visualstudio_folder.iterate(); | 873 | var iterator = visualstudio_folder.iterate(); |
| 874 | break :vs_versions try iterateAndFilterByVersion(&iterator, allocator, ""); | 874 | break :vs_versions try iterateAndFilterByVersion(&iterator, gpa, ""); |
| 875 | }; | 875 | }; |
| 876 | defer { | 876 | defer { |
| 877 | for (vs_versions) |vs_version| allocator.free(vs_version); | 877 | for (vs_versions) |vs_version| gpa.free(vs_version); |
| 878 | allocator.free(vs_versions); | 878 | gpa.free(vs_versions); |
| 879 | } | 879 | } |
| 880 | var config_subkey_buf: [RegistryWtf16Le.key_name_max_len * 2]u8 = undefined; | 880 | var config_subkey_buf: [RegistryWtf16Le.key_name_max_len * 2]u8 = undefined; |
| 881 | const source_directories: []const u8 = source_directories: for (vs_versions) |vs_version| { | 881 | const source_directories: []const u8 = source_directories: for (vs_versions) |vs_version| { |
| 882 | const privateregistry_absolute_path = std.fs.path.join(allocator, &.{ visualstudio_folder_path, vs_version, "privateregistry.bin" }) catch continue; | 882 | const privateregistry_absolute_path = Dir.path.join(gpa, &.{ visualstudio_folder_path, vs_version, "privateregistry.bin" }) catch continue; |
| 883 | defer allocator.free(privateregistry_absolute_path); | 883 | defer gpa.free(privateregistry_absolute_path); |
| 884 | if (!std.fs.path.isAbsolute(privateregistry_absolute_path)) continue; | 884 | if (!Dir.path.isAbsolute(privateregistry_absolute_path)) continue; |
| 885 | | 885 | |
| 886 | const visualstudio_registry = RegistryWtf8.loadFromPath(privateregistry_absolute_path) catch continue; | 886 | const visualstudio_registry = RegistryWtf8.loadFromPath(privateregistry_absolute_path) catch continue; |
| 887 | defer visualstudio_registry.closeKey(); | 887 | defer visualstudio_registry.closeKey(); |
| 888 | | 888 | |
| 889 | const config_subkey = std.fmt.bufPrint(config_subkey_buf[0..], "Software\\Microsoft\\VisualStudio\\{s}_Config", .{vs_version}) catch unreachable; | 889 | const config_subkey = std.fmt.bufPrint(config_subkey_buf[0..], "Software\\Microsoft\\VisualStudio\\{s}_Config", .{vs_version}) catch unreachable; |
| 890 | | 890 | |
| 891 | const source_directories_value = visualstudio_registry.getString(allocator, config_subkey, "Source Directories") catch |err| switch (err) { | 891 | const source_directories_value = visualstudio_registry.getString(gpa, config_subkey, "Source Directories") catch |err| switch (err) { |
| 892 | error.OutOfMemory => return error.OutOfMemory, | 892 | error.OutOfMemory => return error.OutOfMemory, |
| 893 | else => continue, | 893 | else => continue, |
| 894 | }; | 894 | }; |
| 895 | if (source_directories_value.len > (std.fs.max_path_bytes * 30)) { // note(bratishkaerik): guessing from the fact that on my computer it has 15 paths and at least some of them are not of max length | 895 | if (source_directories_value.len > (Dir.max_path_bytes * 30)) { // note(bratishkaerik): guessing from the fact that on my computer it has 15 paths and at least some of them are not of max length |
| 896 | allocator.free(source_directories_value); | 896 | gpa.free(source_directories_value); |
| 897 | continue; | 897 | continue; |
| 898 | } | 898 | } |
| 899 | | 899 | |
| 900 | break :source_directories source_directories_value; | 900 | break :source_directories source_directories_value; |
| 901 | } else return error.PathNotFound; | 901 | } else return error.PathNotFound; |
| 902 | defer allocator.free(source_directories); | 902 | defer gpa.free(source_directories); |
| 903 | | 903 | |
| 904 | var source_directories_split = std.mem.splitScalar(u8, source_directories, ';'); | 904 | var source_directories_split = std.mem.splitScalar(u8, source_directories, ';'); |
| 905 | | 905 | |
| 906 | const msvc_dir: []const u8 = msvc_dir: { | 906 | const msvc_dir: []const u8 = msvc_dir: { |
| 907 | const msvc_include_dir_maybe_with_trailing_slash = try allocator.dupe(u8, source_directories_split.first()); | 907 | const msvc_include_dir_maybe_with_trailing_slash = try gpa.dupe(u8, source_directories_split.first()); |
| 908 | | 908 | |
| 909 | if (msvc_include_dir_maybe_with_trailing_slash.len > std.fs.max_path_bytes or !std.fs.path.isAbsolute(msvc_include_dir_maybe_with_trailing_slash)) { | 909 | if (msvc_include_dir_maybe_with_trailing_slash.len > Dir.max_path_bytes or !Dir.path.isAbsolute(msvc_include_dir_maybe_with_trailing_slash)) { |
| 910 | allocator.free(msvc_include_dir_maybe_with_trailing_slash); | 910 | gpa.free(msvc_include_dir_maybe_with_trailing_slash); |
| 911 | return error.PathNotFound; | 911 | return error.PathNotFound; |
| 912 | } | 912 | } |
| 913 | | 913 | |
| 914 | var msvc_dir = std.array_list.Managed(u8).fromOwnedSlice(allocator, msvc_include_dir_maybe_with_trailing_slash); | 914 | var msvc_dir = std.array_list.Managed(u8).fromOwnedSlice(gpa, msvc_include_dir_maybe_with_trailing_slash); |
| 915 | errdefer msvc_dir.deinit(); | 915 | errdefer msvc_dir.deinit(); |
| 916 | | 916 | |
| 917 | // String might contain trailing slash, so trim it here | 917 | // String might contain trailing slash, so trim it here |
| ... | @@ -933,7 +933,7 @@ const MsvcLibDir = struct { | ... | @@ -933,7 +933,7 @@ const MsvcLibDir = struct { |
| 933 | const msvc_dir_with_arch = try msvc_dir.toOwnedSlice(); | 933 | const msvc_dir_with_arch = try msvc_dir.toOwnedSlice(); |
| 934 | break :msvc_dir msvc_dir_with_arch; | 934 | break :msvc_dir msvc_dir_with_arch; |
| 935 | }; | 935 | }; |
| 936 | errdefer allocator.free(msvc_dir); | 936 | errdefer gpa.free(msvc_dir); |
| 937 | | 937 | |
| 938 | if (!verifyLibDir(io, msvc_dir)) { | 938 | if (!verifyLibDir(io, msvc_dir)) { |
| 939 | return error.PathNotFound; | 939 | return error.PathNotFound; |
| ... | @@ -942,10 +942,10 @@ const MsvcLibDir = struct { | ... | @@ -942,10 +942,10 @@ const MsvcLibDir = struct { |
| 942 | return msvc_dir; | 942 | return msvc_dir; |
| 943 | } | 943 | } |
| 944 | | 944 | |
| 945 | fn findViaVs7Key(allocator: Allocator, io: Io, arch: std.Target.Cpu.Arch) error{ OutOfMemory, PathNotFound }![]const u8 { | 945 | fn findViaVs7Key(gpa: Allocator, io: Io, arch: std.Target.Cpu.Arch) error{ OutOfMemory, PathNotFound }![]const u8 { |
| 946 | var base_path: std.array_list.Managed(u8) = base_path: { | 946 | var base_path: std.array_list.Managed(u8) = base_path: { |
| 947 | try_env: { | 947 | try_env: { |
| 948 | var env_map = std.process.getEnvMap(allocator) catch |err| switch (err) { | 948 | var env_map = std.process.getEnvMap(gpa) catch |err| switch (err) { |
| 949 | error.OutOfMemory => return error.OutOfMemory, | 949 | error.OutOfMemory => return error.OutOfMemory, |
| 950 | else => break :try_env, | 950 | else => break :try_env, |
| 951 | }; | 951 | }; |
| ... | @@ -953,8 +953,8 @@ const MsvcLibDir = struct { | ... | @@ -953,8 +953,8 @@ const MsvcLibDir = struct { |
| 953 | | 953 | |
| 954 | if (env_map.get("VS140COMNTOOLS")) |VS140COMNTOOLS| { | 954 | if (env_map.get("VS140COMNTOOLS")) |VS140COMNTOOLS| { |
| 955 | if (VS140COMNTOOLS.len < "C:\\Common7\\Tools".len) break :try_env; | 955 | if (VS140COMNTOOLS.len < "C:\\Common7\\Tools".len) break :try_env; |
| 956 | if (!std.fs.path.isAbsolute(VS140COMNTOOLS)) break :try_env; | 956 | if (!Dir.path.isAbsolute(VS140COMNTOOLS)) break :try_env; |
| 957 | var list = std.array_list.Managed(u8).init(allocator); | 957 | var list = std.array_list.Managed(u8).init(gpa); |
| 958 | errdefer list.deinit(); | 958 | errdefer list.deinit(); |
| 959 | | 959 | |
| 960 | try list.appendSlice(VS140COMNTOOLS); // C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\Tools | 960 | try list.appendSlice(VS140COMNTOOLS); // C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\Tools |
| ... | @@ -968,17 +968,17 @@ const MsvcLibDir = struct { | ... | @@ -968,17 +968,17 @@ const MsvcLibDir = struct { |
| 968 | const vs7_key = RegistryWtf8.openKey(windows.HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\VisualStudio\\SxS\\VS7", .{ .wow64_32 = true }) catch return error.PathNotFound; | 968 | const vs7_key = RegistryWtf8.openKey(windows.HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\VisualStudio\\SxS\\VS7", .{ .wow64_32 = true }) catch return error.PathNotFound; |
| 969 | defer vs7_key.closeKey(); | 969 | defer vs7_key.closeKey(); |
| 970 | try_vs7_key: { | 970 | try_vs7_key: { |
| 971 | const path_maybe_with_trailing_slash = vs7_key.getString(allocator, "", "14.0") catch |err| switch (err) { | 971 | const path_maybe_with_trailing_slash = vs7_key.getString(gpa, "", "14.0") catch |err| switch (err) { |
| 972 | error.OutOfMemory => return error.OutOfMemory, | 972 | error.OutOfMemory => return error.OutOfMemory, |
| 973 | else => break :try_vs7_key, | 973 | else => break :try_vs7_key, |
| 974 | }; | 974 | }; |
| 975 | | 975 | |
| 976 | if (path_maybe_with_trailing_slash.len > std.fs.max_path_bytes or !std.fs.path.isAbsolute(path_maybe_with_trailing_slash)) { | 976 | if (path_maybe_with_trailing_slash.len > Dir.max_path_bytes or !Dir.path.isAbsolute(path_maybe_with_trailing_slash)) { |
| 977 | allocator.free(path_maybe_with_trailing_slash); | 977 | gpa.free(path_maybe_with_trailing_slash); |
| 978 | break :try_vs7_key; | 978 | break :try_vs7_key; |
| 979 | } | 979 | } |
| 980 | | 980 | |
| 981 | var path = std.array_list.Managed(u8).fromOwnedSlice(allocator, path_maybe_with_trailing_slash); | 981 | var path = std.array_list.Managed(u8).fromOwnedSlice(gpa, path_maybe_with_trailing_slash); |
| 982 | errdefer path.deinit(); | 982 | errdefer path.deinit(); |
| 983 | | 983 | |
| 984 | // String might contain trailing slash, so trim it here | 984 | // String might contain trailing slash, so trim it here |
| ... | @@ -1007,9 +1007,9 @@ const MsvcLibDir = struct { | ... | @@ -1007,9 +1007,9 @@ const MsvcLibDir = struct { |
| 1007 | } | 1007 | } |
| 1008 | | 1008 | |
| 1009 | fn verifyLibDir(io: Io, lib_dir_path: []const u8) bool { | 1009 | fn verifyLibDir(io: Io, lib_dir_path: []const u8) bool { |
| 1010 | std.debug.assert(std.fs.path.isAbsolute(lib_dir_path)); // should be already handled in `findVia*` | 1010 | std.debug.assert(Dir.path.isAbsolute(lib_dir_path)); // should be already handled in `findVia*` |
| 1011 | | 1011 | |
| 1012 | var dir = std.fs.openDirAbsolute(lib_dir_path, .{}) catch return false; | 1012 | var dir = Dir.openDirAbsolute(io, lib_dir_path, .{}) catch return false; |
| 1013 | defer dir.close(io); | 1013 | defer dir.close(io); |
| 1014 | | 1014 | |
| 1015 | const stat = dir.statFile(io, "vcruntime.lib", .{}) catch return false; | 1015 | const stat = dir.statFile(io, "vcruntime.lib", .{}) catch return false; |
| ... | @@ -1021,18 +1021,18 @@ const MsvcLibDir = struct { | ... | @@ -1021,18 +1021,18 @@ const MsvcLibDir = struct { |
| 1021 | | 1021 | |
| 1022 | /// Find path to MSVC's `lib/` directory. | 1022 | /// Find path to MSVC's `lib/` directory. |
| 1023 | /// Caller owns the result. | 1023 | /// Caller owns the result. |
| 1024 | pub fn find(allocator: Allocator, io: Io, arch: std.Target.Cpu.Arch) error{ OutOfMemory, MsvcLibDirNotFound }![]const u8 { | 1024 | pub fn find(gpa: Allocator, io: Io, arch: std.Target.Cpu.Arch) error{ OutOfMemory, MsvcLibDirNotFound }![]const u8 { |
| 1025 | const full_path = MsvcLibDir.findViaCOM(allocator, io, arch) catch |err1| switch (err1) { | 1025 | const full_path = MsvcLibDir.findViaCOM(gpa, io, arch) catch |err1| switch (err1) { |
| 1026 | error.OutOfMemory => return error.OutOfMemory, | 1026 | error.OutOfMemory => return error.OutOfMemory, |
| 1027 | error.PathNotFound => MsvcLibDir.findViaRegistry(allocator, io, arch) catch |err2| switch (err2) { | 1027 | error.PathNotFound => MsvcLibDir.findViaRegistry(gpa, io, arch) catch |err2| switch (err2) { |
| 1028 | error.OutOfMemory => return error.OutOfMemory, | 1028 | error.OutOfMemory => return error.OutOfMemory, |
| 1029 | error.PathNotFound => MsvcLibDir.findViaVs7Key(allocator, io, arch) catch |err3| switch (err3) { | 1029 | error.PathNotFound => MsvcLibDir.findViaVs7Key(gpa, io, arch) catch |err3| switch (err3) { |
| 1030 | error.OutOfMemory => return error.OutOfMemory, | 1030 | error.OutOfMemory => return error.OutOfMemory, |
| 1031 | error.PathNotFound => return error.MsvcLibDirNotFound, | 1031 | error.PathNotFound => return error.MsvcLibDirNotFound, |
| 1032 | }, | 1032 | }, |
| 1033 | }, | 1033 | }, |
| 1034 | }; | 1034 | }; |
| 1035 | errdefer allocator.free(full_path); | 1035 | errdefer gpa.free(full_path); |
| 1036 | | 1036 | |
| 1037 | return full_path; | 1037 | return full_path; |
| 1038 | } | 1038 | } |