| author | |
| committer | |
| log | 3bb00eac37c6b7be789f7b2f516fc1e44e892c8d |
| tree | fa86b4e2475a25e2cfc6f3becfdccd1c6ad9603c |
| parent | 97bfeac13f89e1b5a22fcd7d4705341b4c3e1950 |
2 files changed, 143 insertions(+), 6 deletions(-)
src-self-hosted/compilation.zig+58-6| ... | @@ -237,6 +237,7 @@ pub const Compilation = struct { | ... | @@ -237,6 +237,7 @@ pub const Compilation = struct { |
| 237 | ReadOnlyFileSystem, | 237 | ReadOnlyFileSystem, |
| 238 | LinkQuotaExceeded, | 238 | LinkQuotaExceeded, |
| 239 | EnvironmentVariableNotFound, | 239 | EnvironmentVariableNotFound, |
| 240 | AppDataDirUnavailable, | ||
| 240 | }; | 241 | }; |
| 241 | 242 | ||
| 242 | pub const Event = union(enum) { | 243 | pub const Event = union(enum) { |
| ... | @@ -944,13 +945,64 @@ async fn addFnToLinkSet(comp: *Compilation, fn_val: *Value.Fn) void { | ... | @@ -944,13 +945,64 @@ async fn addFnToLinkSet(comp: *Compilation, fn_val: *Value.Fn) void { |
| 944 | } | 945 | } |
| 945 | 946 | ||
| 946 | fn getZigDir(allocator: *mem.Allocator) ![]u8 { | 947 | fn getZigDir(allocator: *mem.Allocator) ![]u8 { |
| 947 | const home_dir = try getHomeDir(allocator); | 948 | return getAppDataDir(allocator, "zig"); |
| 948 | defer allocator.free(home_dir); | 949 | } |
| 950 | |||
| 951 | |||
| 952 | const GetAppDataDirError = error{ | ||
| 953 | OutOfMemory, | ||
| 954 | AppDataDirUnavailable, | ||
| 955 | }; | ||
| 956 | |||
| 957 | |||
| 958 | /// Caller owns returned memory. | ||
| 959 | /// TODO move to zig std lib | ||
| 960 | fn getAppDataDir(allocator: *mem.Allocator, appname: []const u8) GetAppDataDirError![]u8 { | ||
| 961 | switch (builtin.os) { | ||
| 962 | builtin.Os.windows => { | ||
| 963 | var dir_path_ptr: [*]u16 = undefined; | ||
| 964 | switch (os.windows.SHGetKnownFolderPath(&os.windows.FOLDERID_LocalAppData, os.windows.KF_FLAG_CREATE, | ||
| 965 | null, &dir_path_ptr,)) | ||
| 966 | { | ||
| 967 | os.windows.S_OK => { | ||
| 968 | defer os.windows.CoTaskMemFree(@ptrCast(*c_void, dir_path_ptr)); | ||
| 969 | const global_dir = try utf16leToUtf8(allocator, utf16lePtrSlice(dir_path_ptr)); | ||
| 970 | defer allocator.free(global_dir); | ||
| 971 | return os.path.join(allocator, global_dir, appname); | ||
| 972 | }, | ||
| 973 | os.windows.E_OUTOFMEMORY => return error.OutOfMemory, | ||
| 974 | else => return error.AppDataDirUnavailable, | ||
| 975 | } | ||
| 976 | }, | ||
| 977 | // TODO for macos it should be "~/Library/Application Support/<APPNAME>" | ||
| 978 | else => { | ||
| 979 | const home_dir = os.getEnvVarOwned(allocator, "HOME") catch |err| switch (err) { | ||
| 980 | error.OutOfMemory => return error.OutOfMemory, | ||
| 981 | error.EnvironmentVariableNotFound => return error.AppDataDirUnavailable, // TODO look in /etc/passwd | ||
| 982 | }; | ||
| 983 | defer allocator.free(home_dir); | ||
| 984 | return os.path.join(allocator, home_dir, ".local", "share", appname); | ||
| 985 | }, | ||
| 986 | } | ||
| 987 | } | ||
| 988 | |||
| 989 | test "getAppDataDir" { | ||
| 990 | const result = try getAppDataDir(std.debug.global_allocator, "zig"); | ||
| 991 | std.debug.warn("{}...", result); | ||
| 992 | } | ||
| 949 | 993 | ||
| 950 | return os.path.join(allocator, home_dir, ".zig"); | 994 | // TODO full utf-16 LE support |
| 995 | fn utf16leToUtf8(allocator: *mem.Allocator, utf16le: []const u16) ![]u8 { | ||
| 996 | const utf8_bytes = try allocator.alloc(u8, utf16le.len); | ||
| 997 | for (utf16le) |codepoint, i| { | ||
| 998 | assert(codepoint < 127); // TODO full utf-16 LE support | ||
| 999 | utf8_bytes[i] = @intCast(u8, codepoint); | ||
| 1000 | } | ||
| 1001 | return utf8_bytes; | ||
| 951 | } | 1002 | } |
| 952 | 1003 | ||
| 953 | /// TODO move to zig std lib, and make it work for other OSes | 1004 | fn utf16lePtrSlice(ptr: [*]const u16) []const u16 { |
| 954 | fn getHomeDir(allocator: *mem.Allocator) ![]u8 { | 1005 | var index: usize = 0; |
| 955 | return os.getEnvVarOwned(allocator, "HOME"); | 1006 | while (ptr[index] != 0) : (index += 1) {} |
| 1007 | return ptr[0..index]; | ||
| 956 | } | 1008 | } |
std/os/windows/index.zig+85| ... | @@ -1,3 +1,5 @@ | ... | @@ -1,3 +1,5 @@ |
| 1 | const std = @import("../../index.zig"); | ||
| 2 | const assert = std.debug.assert; | ||
| 1 | test "import" { | 3 | test "import" { |
| 2 | _ = @import("util.zig"); | 4 | _ = @import("util.zig"); |
| 3 | } | 5 | } |
| ... | @@ -439,3 +441,86 @@ pub const SYSTEM_INFO = extern struct { | ... | @@ -439,3 +441,86 @@ pub const SYSTEM_INFO = extern struct { |
| 439 | wProcessorLevel: WORD, | 441 | wProcessorLevel: WORD, |
| 440 | wProcessorRevision: WORD, | 442 | wProcessorRevision: WORD, |
| 441 | }; | 443 | }; |
| 444 | |||
| 445 | pub extern "ole32.dll" stdcallcc fn CoTaskMemFree(pv: LPVOID) void; | ||
| 446 | |||
| 447 | pub extern "shell32.dll" stdcallcc fn SHGetKnownFolderPath(rfid: *const KNOWNFOLDERID, dwFlags: DWORD, hToken: ?HANDLE, ppszPath: *[*]WCHAR) HRESULT; | ||
| 448 | |||
| 449 | pub const HRESULT = c_long; | ||
| 450 | |||
| 451 | pub const KNOWNFOLDERID = GUID; | ||
| 452 | pub const GUID = extern struct { | ||
| 453 | Data1: c_ulong, | ||
| 454 | Data2: c_ushort, | ||
| 455 | Data3: c_ushort, | ||
| 456 | Data4: [8]u8, | ||
| 457 | |||
| 458 | pub fn parse(str: []const u8) GUID { | ||
| 459 | var guid: GUID = undefined; | ||
| 460 | var index: usize = 0; | ||
| 461 | assert(str[index] == '{'); | ||
| 462 | index += 1; | ||
| 463 | |||
| 464 | guid.Data1 = std.fmt.parseUnsigned(c_ulong, str[index..index + 8], 16) catch unreachable; | ||
| 465 | index += 8; | ||
| 466 | |||
| 467 | assert(str[index] == '-'); | ||
| 468 | index += 1; | ||
| 469 | |||
| 470 | guid.Data2 = std.fmt.parseUnsigned(c_ushort, str[index..index + 4], 16) catch unreachable; | ||
| 471 | index += 4; | ||
| 472 | |||
| 473 | assert(str[index] == '-'); | ||
| 474 | index += 1; | ||
| 475 | |||
| 476 | guid.Data3 = std.fmt.parseUnsigned(c_ushort, str[index..index + 4], 16) catch unreachable; | ||
| 477 | index += 4; | ||
| 478 | |||
| 479 | assert(str[index] == '-'); | ||
| 480 | index += 1; | ||
| 481 | |||
| 482 | guid.Data4[0] = std.fmt.parseUnsigned(u8, str[index..index + 2], 16) catch unreachable; | ||
| 483 | index += 2; | ||
| 484 | guid.Data4[1] = std.fmt.parseUnsigned(u8, str[index..index + 2], 16) catch unreachable; | ||
| 485 | index += 2; | ||
| 486 | |||
| 487 | assert(str[index] == '-'); | ||
| 488 | index += 1; | ||
| 489 | |||
| 490 | var i: usize = 2; | ||
| 491 | while (i < guid.Data4.len) : (i += 1) { | ||
| 492 | guid.Data4[i] = std.fmt.parseUnsigned(u8, str[index..index + 2], 16) catch unreachable; | ||
| 493 | index += 2; | ||
| 494 | } | ||
| 495 | |||
| 496 | assert(str[index] == '}'); | ||
| 497 | index += 1; | ||
| 498 | return guid; | ||
| 499 | } | ||
| 500 | }; | ||
| 501 | |||
| 502 | pub const FOLDERID_LocalAppData = GUID.parse("{F1B32785-6FBA-4FCF-9D55-7B8E7F157091}"); | ||
| 503 | |||
| 504 | pub const KF_FLAG_DEFAULT = 0; | ||
| 505 | pub const KF_FLAG_NO_APPCONTAINER_REDIRECTION = 65536; | ||
| 506 | pub const KF_FLAG_CREATE = 32768; | ||
| 507 | pub const KF_FLAG_DONT_VERIFY = 16384; | ||
| 508 | pub const KF_FLAG_DONT_UNEXPAND = 8192; | ||
| 509 | pub const KF_FLAG_NO_ALIAS = 4096; | ||
| 510 | pub const KF_FLAG_INIT = 2048; | ||
| 511 | pub const KF_FLAG_DEFAULT_PATH = 1024; | ||
| 512 | pub const KF_FLAG_NOT_PARENT_RELATIVE = 512; | ||
| 513 | pub const KF_FLAG_SIMPLE_IDLIST = 256; | ||
| 514 | pub const KF_FLAG_ALIAS_ONLY = -2147483648; | ||
| 515 | |||
| 516 | pub const S_OK = 0; | ||
| 517 | pub const E_NOTIMPL = @bitCast(c_long, c_ulong(0x80004001)); | ||
| 518 | pub const E_NOINTERFACE = @bitCast(c_long, c_ulong(0x80004002)); | ||
| 519 | pub const E_POINTER = @bitCast(c_long, c_ulong(0x80004003)); | ||
| 520 | pub const E_ABORT = @bitCast(c_long, c_ulong(0x80004004)); | ||
| 521 | pub const E_FAIL = @bitCast(c_long, c_ulong(0x80004005)); | ||
| 522 | pub const E_UNEXPECTED = @bitCast(c_long, c_ulong(0x8000FFFF)); | ||
| 523 | pub const E_ACCESSDENIED = @bitCast(c_long, c_ulong(0x80070005)); | ||
| 524 | pub const E_HANDLE = @bitCast(c_long, c_ulong(0x80070006)); | ||
| 525 | pub const E_OUTOFMEMORY = @bitCast(c_long, c_ulong(0x8007000E)); | ||
| 526 | pub const E_INVALIDARG = @bitCast(c_long, c_ulong(0x80070057)); |