| ... | ... | @@ -3,6 +3,7 @@ const builtin = @import("builtin"); |
| 3 | 3 | |
| 4 | 4 | const std = @import("std"); |
| 5 | 5 | const Io = std.Io; |
| 6 | const Dir = std.Io.Dir; |
| 6 | 7 | const Writer = std.Io.Writer; |
| 7 | 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 | 23 | |
| 23 | 24 | /// Find path and version of Windows 10 SDK and Windows 8.1 SDK, and find path to MSVC's `lib/` directory. |
| 24 | 25 | /// Caller owns the result's fields. |
| 25 | | /// After finishing work, call `free(allocator)`. |
| 26 | | pub fn find(allocator: Allocator, arch: std.Target.Cpu.Arch) error{ OutOfMemory, NotFound, PathTooLong }!WindowsSdk { |
| 26 | /// Returns memory allocated by `gpa` |
| 27 | pub fn find(gpa: Allocator, arch: std.Target.Cpu.Arch) error{ OutOfMemory, NotFound, PathTooLong }!WindowsSdk { |
| 27 | 28 | if (builtin.os.tag != .windows) return error.NotFound; |
| 28 | 29 | |
| 29 | 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 | 33 | }; |
| 33 | 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 | 37 | error.InstallationNotFound => null, |
| 37 | 38 | error.PathTooLong => null, |
| 38 | 39 | error.VersionTooLong => null, |
| 39 | 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 | 45 | error.InstallationNotFound => null, |
| 45 | 46 | error.PathTooLong => null, |
| 46 | 47 | error.VersionTooLong => null, |
| 47 | 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 | 53 | error.MsvcLibDirNotFound => null, |
| 53 | 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 | 58 | return .{ |
| 58 | 59 | .windows10sdk = windows10sdk, |
| ... | ... | @@ -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 | 66 | if (sdk.windows10sdk) |*w10sdk| { |
| 66 | | w10sdk.free(allocator); |
| 67 | w10sdk.free(gpa); |
| 67 | 68 | } |
| 68 | 69 | if (sdk.windows81sdk) |*w81sdk| { |
| 69 | | w81sdk.free(allocator); |
| 70 | w81sdk.free(gpa); |
| 70 | 71 | } |
| 71 | 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 | 78 | /// and a version. Returns slice of version strings sorted in descending order. |
| 78 | 79 | /// Caller owns result. |
| 79 | 80 | fn iterateAndFilterByVersion( |
| 80 | | iterator: *Io.Dir.Iterator, |
| 81 | | allocator: Allocator, |
| 81 | iterator: *Dir.Iterator, |
| 82 | gpa: Allocator, |
| 82 | 83 | prefix: []const u8, |
| 83 | 84 | ) error{OutOfMemory}![][]const u8 { |
| 84 | 85 | const Version = struct { |
| ... | ... | @@ -95,11 +96,11 @@ fn iterateAndFilterByVersion( |
| 95 | 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 dirs = std.array_list.Managed([]const u8).init(allocator); |
| 99 | var versions = std.array_list.Managed(Version).init(gpa); |
| 100 | var dirs = std.array_list.Managed([]const u8).init(gpa); |
| 100 | 101 | defer { |
| 101 | 102 | versions.deinit(); |
| 102 | | for (dirs.items) |filtered_dir| allocator.free(filtered_dir); |
| 103 | for (dirs.items) |filtered_dir| gpa.free(filtered_dir); |
| 103 | 104 | dirs.deinit(); |
| 104 | 105 | } |
| 105 | 106 | |
| ... | ... | @@ -119,8 +120,8 @@ fn iterateAndFilterByVersion( |
| 119 | 120 | num.* = Version.parseNum(num_it.next() orelse break) orelse continue :iterate |
| 120 | 121 | else if (num_it.next()) |_| continue; |
| 121 | 122 | |
| 122 | | const name = try allocator.dupe(u8, suffix); |
| 123 | | errdefer allocator.free(name); |
| 123 | const name = try gpa.dupe(u8, suffix); |
| 124 | errdefer gpa.free(name); |
| 124 | 125 | if (underscore) |pos| version.build = name[pos + 1 ..]; |
| 125 | 126 | |
| 126 | 127 | try versions.append(version); |
| ... | ... | @@ -177,7 +178,7 @@ const RegistryWtf8 = struct { |
| 177 | 178 | |
| 178 | 179 | /// Get string from registry. |
| 179 | 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 | 182 | const subkey_wtf16le: [:0]const u16 = subkey_wtf16le: { |
| 182 | 183 | var subkey_wtf16le_buf: [RegistryWtf16Le.key_name_max_len]u16 = undefined; |
| 183 | 184 | const subkey_wtf16le_len: usize = std.unicode.wtf8ToWtf16Le(subkey_wtf16le_buf[0..], subkey) catch unreachable; |
| ... | ... | @@ -193,11 +194,11 @@ const RegistryWtf8 = struct { |
| 193 | 194 | }; |
| 194 | 195 | |
| 195 | 196 | const registry_wtf16le: RegistryWtf16Le = .{ .key = reg.key }; |
| 196 | | const value_wtf16le = try registry_wtf16le.getString(allocator, subkey_wtf16le, value_name_wtf16le); |
| 197 | | defer allocator.free(value_wtf16le); |
| 197 | const value_wtf16le = try registry_wtf16le.getString(gpa, subkey_wtf16le, value_name_wtf16le); |
| 198 | defer gpa.free(value_wtf16le); |
| 198 | 199 | |
| 199 | | const value_wtf8: []u8 = try std.unicode.wtf16LeToWtf8Alloc(allocator, value_wtf16le); |
| 200 | | errdefer allocator.free(value_wtf8); |
| 200 | const value_wtf8: []u8 = try std.unicode.wtf16LeToWtf8Alloc(gpa, value_wtf16le); |
| 201 | errdefer gpa.free(value_wtf8); |
| 201 | 202 | |
| 202 | 203 | return value_wtf8; |
| 203 | 204 | } |
| ... | ... | @@ -285,7 +286,7 @@ const RegistryWtf16Le = struct { |
| 285 | 286 | } |
| 286 | 287 | |
| 287 | 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 | 290 | var actual_type: windows.ULONG = undefined; |
| 290 | 291 | |
| 291 | 292 | // Calculating length to allocate |
| ... | ... | @@ -314,8 +315,8 @@ const RegistryWtf16Le = struct { |
| 314 | 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 | | errdefer allocator.free(value_wtf16le_buf); |
| 318 | const value_wtf16le_buf: []u16 = try gpa.alloc(u16, std.math.divCeil(u32, value_wtf16le_buf_size, 2) catch unreachable); |
| 319 | errdefer gpa.free(value_wtf16le_buf); |
| 319 | 320 | |
| 320 | 321 | return_code_int = windows.advapi32.RegGetValueW( |
| 321 | 322 | reg.key, |
| ... | ... | @@ -349,7 +350,7 @@ const RegistryWtf16Le = struct { |
| 349 | 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 | 354 | return value_wtf16le; |
| 354 | 355 | } |
| 355 | 356 | |
| ... | ... | @@ -417,66 +418,65 @@ pub const Installation = struct { |
| 417 | 418 | |
| 418 | 419 | /// Find path and version of Windows SDK. |
| 419 | 420 | /// Caller owns the result's fields. |
| 420 | | /// After finishing work, call `free(allocator)`. |
| 421 | 421 | fn find( |
| 422 | | allocator: Allocator, |
| 422 | gpa: Allocator, |
| 423 | 423 | roots_key: RegistryWtf8, |
| 424 | 424 | roots_subkey: []const u8, |
| 425 | 425 | prefix: []const u8, |
| 426 | 426 | version_key_name: []const u8, |
| 427 | 427 | ) error{ OutOfMemory, InstallationNotFound, PathTooLong, VersionTooLong }!Installation { |
| 428 | 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 | 430 | break :roots; |
| 431 | 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 | 436 | if (installation.isValidVersion()) return installation; |
| 437 | | installation.free(allocator); |
| 437 | installation.free(gpa); |
| 438 | 438 | } |
| 439 | 439 | return error.InstallationNotFound; |
| 440 | 440 | } |
| 441 | 441 | |
| 442 | 442 | fn findFromRoot( |
| 443 | | allocator: Allocator, |
| 443 | gpa: Allocator, |
| 444 | 444 | io: Io, |
| 445 | 445 | roots_key: RegistryWtf8, |
| 446 | 446 | roots_subkey: []const u8, |
| 447 | 447 | prefix: []const u8, |
| 448 | 448 | ) error{ OutOfMemory, InstallationNotFound, PathTooLong, VersionTooLong }!Installation { |
| 449 | 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 | 451 | error.NotAString => return error.InstallationNotFound, |
| 452 | 452 | error.ValueNameNotFound => return error.InstallationNotFound, |
| 453 | 453 | error.StringNotFound => return error.InstallationNotFound, |
| 454 | 454 | |
| 455 | 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)) { |
| 458 | | allocator.free(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 | gpa.free(path_maybe_with_trailing_slash); |
| 459 | 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 | 463 | errdefer path.deinit(); |
| 464 | 464 | |
| 465 | 465 | // String might contain trailing slash, so trim it here |
| 466 | 466 | if (path.items.len > "C:\\".len and path.getLast() == '\\') _ = path.pop(); |
| 467 | 467 | break :path try path.toOwnedSlice(); |
| 468 | 468 | }; |
| 469 | | errdefer allocator.free(path); |
| 469 | errdefer gpa.free(path); |
| 470 | 470 | |
| 471 | 471 | const version = version: { |
| 472 | | var buf: [std.fs.max_path_bytes]u8 = undefined; |
| 472 | var buf: [Dir.max_path_bytes]u8 = undefined; |
| 473 | 473 | const sdk_lib_dir_path = std.fmt.bufPrint(buf[0..], "{s}\\Lib\\", .{path}) catch |err| switch (err) { |
| 474 | 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 | 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 | 480 | .iterate = true, |
| 481 | 481 | }) catch |err| switch (err) { |
| 482 | 482 | error.NameTooLong => return error.PathTooLong, |
| ... | ... | @@ -485,21 +485,21 @@ pub const Installation = struct { |
| 485 | 485 | defer sdk_lib_dir.close(io); |
| 486 | 486 | |
| 487 | 487 | var iterator = sdk_lib_dir.iterate(); |
| 488 | | const versions = try iterateAndFilterByVersion(&iterator, allocator, prefix); |
| 488 | const versions = try iterateAndFilterByVersion(&iterator, gpa, prefix); |
| 489 | 489 | if (versions.len == 0) return error.InstallationNotFound; |
| 490 | 490 | defer { |
| 491 | | for (versions[1..]) |version| allocator.free(version); |
| 492 | | allocator.free(versions); |
| 491 | for (versions[1..]) |version| gpa.free(version); |
| 492 | gpa.free(versions); |
| 493 | 493 | } |
| 494 | 494 | break :version versions[0]; |
| 495 | 495 | }; |
| 496 | | errdefer allocator.free(version); |
| 496 | errdefer gpa.free(version); |
| 497 | 497 | |
| 498 | 498 | return .{ .path = path, .version = version }; |
| 499 | 499 | } |
| 500 | 500 | |
| 501 | 501 | fn findFromInstallationFolder( |
| 502 | | allocator: Allocator, |
| 502 | gpa: Allocator, |
| 503 | 503 | version_key_name: []const u8, |
| 504 | 504 | ) error{ OutOfMemory, InstallationNotFound, PathTooLong, VersionTooLong }!Installation { |
| 505 | 505 | var key_name_buf: [RegistryWtf16Le.key_name_max_len]u8 = undefined; |
| ... | ... | @@ -518,7 +518,7 @@ pub const Installation = struct { |
| 518 | 518 | defer key.closeKey(); |
| 519 | 519 | |
| 520 | 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 | 522 | error.NotAString => return error.InstallationNotFound, |
| 523 | 523 | error.ValueNameNotFound => return error.InstallationNotFound, |
| 524 | 524 | error.StringNotFound => return error.InstallationNotFound, |
| ... | ... | @@ -526,12 +526,12 @@ pub const Installation = struct { |
| 526 | 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)) { |
| 530 | | allocator.free(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 | gpa.free(path_maybe_with_trailing_slash); |
| 531 | 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 | 535 | errdefer path.deinit(); |
| 536 | 536 | |
| 537 | 537 | // String might contain trailing slash, so trim it here |
| ... | ... | @@ -540,12 +540,12 @@ pub const Installation = struct { |
| 540 | 540 | const path_without_trailing_slash = try path.toOwnedSlice(); |
| 541 | 541 | break :path path_without_trailing_slash; |
| 542 | 542 | }; |
| 543 | | errdefer allocator.free(path); |
| 543 | errdefer gpa.free(path); |
| 544 | 544 | |
| 545 | 545 | const version: []const u8 = version: { |
| 546 | 546 | |
| 547 | 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 | 549 | error.NotAString => return error.InstallationNotFound, |
| 550 | 550 | error.ValueNameNotFound => return error.InstallationNotFound, |
| 551 | 551 | error.StringNotFound => return error.InstallationNotFound, |
| ... | ... | @@ -553,11 +553,11 @@ pub const Installation = struct { |
| 553 | 553 | error.OutOfMemory => return error.OutOfMemory, |
| 554 | 554 | }; |
| 555 | 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 | 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 | 561 | errdefer version.deinit(); |
| 562 | 562 | |
| 563 | 563 | try version.appendSlice(".0"); |
| ... | ... | @@ -565,14 +565,14 @@ pub const Installation = struct { |
| 565 | 565 | const version_with_0 = try version.toOwnedSlice(); |
| 566 | 566 | break :version version_with_0; |
| 567 | 567 | }; |
| 568 | | errdefer allocator.free(version); |
| 568 | errdefer gpa.free(version); |
| 569 | 569 | |
| 570 | 570 | return .{ .path = path, .version = version }; |
| 571 | 571 | } |
| 572 | 572 | |
| 573 | 573 | /// Check whether this version is enumerated in registry. |
| 574 | 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 | 576 | const reg_query_as_wtf8 = std.fmt.bufPrint(buf[0..], "{s}\\{s}\\Installed Options", .{ |
| 577 | 577 | windows_kits_reg_key, |
| 578 | 578 | installation.version, |
| ... | ... | @@ -601,21 +601,21 @@ pub const Installation = struct { |
| 601 | 601 | return (reg_value == 1); |
| 602 | 602 | } |
| 603 | 603 | |
| 604 | | fn free(install: Installation, allocator: Allocator) void { |
| 605 | | allocator.free(install.path); |
| 606 | | allocator.free(install.version); |
| 604 | fn free(install: Installation, gpa: Allocator) void { |
| 605 | gpa.free(install.path); |
| 606 | gpa.free(install.version); |
| 607 | 607 | } |
| 608 | 608 | }; |
| 609 | 609 | |
| 610 | 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 | 612 | const vs_setup_key_path = "SOFTWARE\\Microsoft\\VisualStudio\\Setup"; |
| 613 | 613 | const vs_setup_key = RegistryWtf8.openKey(windows.HKEY_LOCAL_MACHINE, vs_setup_key_path, .{}) catch |err| switch (err) { |
| 614 | 614 | error.KeyNotFound => return error.PathNotFound, |
| 615 | 615 | }; |
| 616 | 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 | 619 | error.NotAString, |
| 620 | 620 | error.ValueNameNotFound, |
| 621 | 621 | error.StringNotFound, |
| ... | ... | @@ -623,24 +623,24 @@ const MsvcLibDir = struct { |
| 623 | 623 | |
| 624 | 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" }); |
| 631 | | defer allocator.free(instances_path); |
| 630 | const instances_path = try Dir.path.join(gpa, &.{ packages_path, "_Instances" }); |
| 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 | 637 | const setup_configuration_clsid = "{177f0c4a-1cd3-4de7-a32c-71dbbb9fa36d}"; |
| 638 | 638 | const setup_config_key = RegistryWtf8.openKey(windows.HKEY_CLASSES_ROOT, "CLSID\\" ++ setup_configuration_clsid, .{}) catch |err| switch (err) { |
| 639 | 639 | error.KeyNotFound => return error.PathNotFound, |
| 640 | 640 | }; |
| 641 | 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 | 644 | error.NotAString, |
| 645 | 645 | error.ValueNameNotFound, |
| 646 | 646 | error.StringNotFound, |
| ... | ... | @@ -648,11 +648,11 @@ const MsvcLibDir = struct { |
| 648 | 648 | |
| 649 | 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 | 656 | // the .dll filename |
| 657 | 657 | _ = path_it.last(); |
| 658 | 658 | const root_path = while (path_it.previous()) |dir_component| { |
| ... | ... | @@ -663,17 +663,17 @@ const MsvcLibDir = struct { |
| 663 | 663 | return error.PathNotFound; |
| 664 | 664 | }; |
| 665 | 665 | |
| 666 | | const instances_path = try std.fs.path.join(allocator, &.{ root_path, "Packages", "_Instances" }); |
| 667 | | defer allocator.free(instances_path); |
| 666 | const instances_path = try Dir.path.join(gpa, &.{ root_path, "Packages", "_Instances" }); |
| 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 | 673 | // First, try getting the packages cache path from the registry. |
| 674 | 674 | // This only seems to exist when the path is different from the default. |
| 675 | 675 | method1: { |
| 676 | | return findInstancesDirViaSetup(allocator) catch |err| switch (err) { |
| 676 | return findInstancesDirViaSetup(gpa) catch |err| switch (err) { |
| 677 | 677 | error.OutOfMemory => |e| return e, |
| 678 | 678 | error.PathNotFound => break :method1, |
| 679 | 679 | }; |
| ... | ... | @@ -681,7 +681,7 @@ const MsvcLibDir = struct { |
| 681 | 681 | // Otherwise, try to get the path from the .dll that would have been |
| 682 | 682 | // loaded via COM for SetupConfiguration. |
| 683 | 683 | method2: { |
| 684 | | return findInstancesDirViaCLSID(allocator) catch |err| switch (err) { |
| 684 | return findInstancesDirViaCLSID(gpa, io) catch |err| switch (err) { |
| 685 | 685 | error.OutOfMemory => |e| return e, |
| 686 | 686 | error.PathNotFound => break :method2, |
| 687 | 687 | }; |
| ... | ... | @@ -689,19 +689,19 @@ const MsvcLibDir = struct { |
| 689 | 689 | // If that can't be found, fall back to manually appending |
| 690 | 690 | // `Microsoft\VisualStudio\Packages\_Instances` to %PROGRAMDATA% |
| 691 | 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 | 693 | error.OutOfMemory => |e| return e, |
| 694 | 694 | error.InvalidWtf8 => unreachable, |
| 695 | 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" }); |
| 702 | | defer allocator.free(instances_path); |
| 701 | const instances_path = try Dir.path.join(gpa, &.{ program_data, "Microsoft", "VisualStudio", "Packages", "_Instances" }); |
| 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 | 706 | return error.PathNotFound; |
| 707 | 707 | } |
| ... | ... | @@ -752,17 +752,17 @@ const MsvcLibDir = struct { |
| 752 | 752 | /// |
| 753 | 753 | /// The logic in this function is intended to match what ISetupConfiguration does |
| 754 | 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 | 756 | // Typically `%PROGRAMDATA%\Microsoft\VisualStudio\Packages\_Instances` |
| 757 | 757 | // This will contain directories with names of instance IDs like 80a758ca, |
| 758 | 758 | // which will contain `state.json` files that have the version and |
| 759 | 759 | // installation directory. |
| 760 | | var instances_dir = try findInstancesDir(allocator); |
| 760 | var instances_dir = try findInstancesDir(gpa, io); |
| 761 | 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 | 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 | 767 | var latest_version: u64 = 0; |
| 768 | 768 | var instances_dir_it = instances_dir.iterateAssumeFirstIteration(); |
| ... | ... | @@ -772,13 +772,13 @@ const MsvcLibDir = struct { |
| 772 | 772 | var writer: Writer = .fixed(&state_subpath_buf); |
| 773 | 773 | |
| 774 | 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 | 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; |
| 779 | | defer allocator.free(json_contents); |
| 778 | const json_contents = instances_dir.readFileAlloc(io, writer.buffered(), gpa, .limited(std.math.maxInt(usize))) catch continue; |
| 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 | 782 | defer parsed.deinit(); |
| 783 | 783 | |
| 784 | 784 | if (parsed.value != .object) continue; |
| ... | ... | @@ -795,40 +795,40 @@ const MsvcLibDir = struct { |
| 795 | 795 | const installation_path = parsed.value.object.get("installationPath") orelse continue; |
| 796 | 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 | 799 | error.OutOfMemory => |e| return e, |
| 800 | 800 | error.PathNotFound => continue, |
| 801 | 801 | }; |
| 802 | | defer allocator.free(lib_dir_path); |
| 802 | defer gpa.free(lib_dir_path); |
| 803 | 803 | |
| 804 | 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 | 806 | latest_version = parsed_version; |
| 807 | 807 | } |
| 808 | 808 | |
| 809 | 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 | 813 | fn libDirFromInstallationPath( |
| 814 | | allocator: Allocator, |
| 814 | gpa: Allocator, |
| 815 | 815 | io: Io, |
| 816 | 816 | installation_path: []const u8, |
| 817 | 817 | arch: std.Target.Cpu.Arch, |
| 818 | 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 | 820 | errdefer lib_dir_buf.deinit(); |
| 821 | 821 | |
| 822 | 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 | 825 | try lib_dir_buf.append('\\'); |
| 826 | 826 | } |
| 827 | 827 | const installation_path_with_trailing_sep_len = lib_dir_buf.items.len; |
| 828 | 828 | |
| 829 | 829 | try lib_dir_buf.appendSlice("VC\\Auxiliary\\Build\\Microsoft.VCToolsVersion.default.txt"); |
| 830 | 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 | 832 | return error.PathNotFound; |
| 833 | 833 | }; |
| 834 | 834 | var tokenizer = std.mem.tokenizeAny(u8, default_tools_version_contents, " \r\n"); |
| ... | ... | @@ -854,64 +854,64 @@ const MsvcLibDir = struct { |
| 854 | 854 | } |
| 855 | 855 | |
| 856 | 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 | 859 | // %localappdata%\Microsoft\VisualStudio\ |
| 860 | 860 | // %appdata%\Local\Microsoft\VisualStudio\ |
| 861 | | const visualstudio_folder_path = std.fs.getAppDataDir(allocator, "Microsoft\\VisualStudio\\") catch return error.PathNotFound; |
| 862 | | defer allocator.free(visualstudio_folder_path); |
| 861 | const visualstudio_folder_path = std.fs.getAppDataDir(gpa, "Microsoft\\VisualStudio\\") catch return error.PathNotFound; |
| 862 | defer gpa.free(visualstudio_folder_path); |
| 863 | 863 | |
| 864 | 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 | 866 | // enumerate folders that contain `privateregistry.bin`, looking for all versions |
| 867 | 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 | 869 | .iterate = true, |
| 870 | 870 | }) catch return error.PathNotFound; |
| 871 | 871 | defer visualstudio_folder.close(io); |
| 872 | 872 | |
| 873 | 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 | 876 | defer { |
| 877 | | for (vs_versions) |vs_version| allocator.free(vs_version); |
| 878 | | allocator.free(vs_versions); |
| 877 | for (vs_versions) |vs_version| gpa.free(vs_version); |
| 878 | gpa.free(vs_versions); |
| 879 | 879 | } |
| 880 | 880 | var config_subkey_buf: [RegistryWtf16Le.key_name_max_len * 2]u8 = undefined; |
| 881 | 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; |
| 883 | | defer allocator.free(privateregistry_absolute_path); |
| 884 | | if (!std.fs.path.isAbsolute(privateregistry_absolute_path)) continue; |
| 882 | const privateregistry_absolute_path = Dir.path.join(gpa, &.{ visualstudio_folder_path, vs_version, "privateregistry.bin" }) catch continue; |
| 883 | defer gpa.free(privateregistry_absolute_path); |
| 884 | if (!Dir.path.isAbsolute(privateregistry_absolute_path)) continue; |
| 885 | 885 | |
| 886 | 886 | const visualstudio_registry = RegistryWtf8.loadFromPath(privateregistry_absolute_path) catch continue; |
| 887 | 887 | defer visualstudio_registry.closeKey(); |
| 888 | 888 | |
| 889 | 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 | 892 | error.OutOfMemory => return error.OutOfMemory, |
| 893 | 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 |
| 896 | | allocator.free(source_directories_value); |
| 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 | gpa.free(source_directories_value); |
| 897 | 897 | continue; |
| 898 | 898 | } |
| 899 | 899 | |
| 900 | 900 | break :source_directories source_directories_value; |
| 901 | 901 | } else return error.PathNotFound; |
| 902 | | defer allocator.free(source_directories); |
| 902 | defer gpa.free(source_directories); |
| 903 | 903 | |
| 904 | 904 | var source_directories_split = std.mem.splitScalar(u8, source_directories, ';'); |
| 905 | 905 | |
| 906 | 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)) { |
| 910 | | allocator.free(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 | gpa.free(msvc_include_dir_maybe_with_trailing_slash); |
| 911 | 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 | 915 | errdefer msvc_dir.deinit(); |
| 916 | 916 | |
| 917 | 917 | // String might contain trailing slash, so trim it here |
| ... | ... | @@ -933,7 +933,7 @@ const MsvcLibDir = struct { |
| 933 | 933 | const msvc_dir_with_arch = try msvc_dir.toOwnedSlice(); |
| 934 | 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 | 938 | if (!verifyLibDir(io, msvc_dir)) { |
| 939 | 939 | return error.PathNotFound; |
| ... | ... | @@ -942,10 +942,10 @@ const MsvcLibDir = struct { |
| 942 | 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 | 946 | var base_path: std.array_list.Managed(u8) = base_path: { |
| 947 | 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 | 949 | error.OutOfMemory => return error.OutOfMemory, |
| 950 | 950 | else => break :try_env, |
| 951 | 951 | }; |
| ... | ... | @@ -953,8 +953,8 @@ const MsvcLibDir = struct { |
| 953 | 953 | |
| 954 | 954 | if (env_map.get("VS140COMNTOOLS")) |VS140COMNTOOLS| { |
| 955 | 955 | if (VS140COMNTOOLS.len < "C:\\Common7\\Tools".len) break :try_env; |
| 956 | | if (!std.fs.path.isAbsolute(VS140COMNTOOLS)) break :try_env; |
| 957 | | var list = std.array_list.Managed(u8).init(allocator); |
| 956 | if (!Dir.path.isAbsolute(VS140COMNTOOLS)) break :try_env; |
| 957 | var list = std.array_list.Managed(u8).init(gpa); |
| 958 | 958 | errdefer list.deinit(); |
| 959 | 959 | |
| 960 | 960 | try list.appendSlice(VS140COMNTOOLS); // C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\Tools |
| ... | ... | @@ -968,17 +968,17 @@ const MsvcLibDir = struct { |
| 968 | 968 | const vs7_key = RegistryWtf8.openKey(windows.HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\VisualStudio\\SxS\\VS7", .{ .wow64_32 = true }) catch return error.PathNotFound; |
| 969 | 969 | defer vs7_key.closeKey(); |
| 970 | 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 | 972 | error.OutOfMemory => return error.OutOfMemory, |
| 973 | 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)) { |
| 977 | | allocator.free(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 | gpa.free(path_maybe_with_trailing_slash); |
| 978 | 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 | 982 | errdefer path.deinit(); |
| 983 | 983 | |
| 984 | 984 | // String might contain trailing slash, so trim it here |
| ... | ... | @@ -1007,9 +1007,9 @@ const MsvcLibDir = struct { |
| 1007 | 1007 | } |
| 1008 | 1008 | |
| 1009 | 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 | 1013 | defer dir.close(io); |
| 1014 | 1014 | |
| 1015 | 1015 | const stat = dir.statFile(io, "vcruntime.lib", .{}) catch return false; |
| ... | ... | @@ -1021,18 +1021,18 @@ const MsvcLibDir = struct { |
| 1021 | 1021 | |
| 1022 | 1022 | /// Find path to MSVC's `lib/` directory. |
| 1023 | 1023 | /// Caller owns the result. |
| 1024 | | pub fn find(allocator: 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) { |
| 1024 | pub fn find(gpa: Allocator, io: Io, arch: std.Target.Cpu.Arch) error{ OutOfMemory, MsvcLibDirNotFound }![]const u8 { |
| 1025 | const full_path = MsvcLibDir.findViaCOM(gpa, io, arch) catch |err1| switch (err1) { |
| 1026 | 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 | 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 | 1030 | error.OutOfMemory => return error.OutOfMemory, |
| 1031 | 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 | 1037 | return full_path; |
| 1038 | 1038 | } |