authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-07-17 00:01:36-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-07-17 00:01:36-04:00
log3bb00eac37c6b7be789f7b2f516fc1e44e892c8d
treefa86b4e2475a25e2cfc6f3becfdccd1c6ad9603c
parent97bfeac13f89e1b5a22fcd7d4705341b4c3e1950

self-hosted: implement getAppDataDir for windows


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 };
241242
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}
945946
946fn getZigDir(allocator: *mem.Allocator) ![]u8 {947fn 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
952const GetAppDataDirError = error{
953 OutOfMemory,
954 AppDataDirUnavailable,
955};
956
957
958/// Caller owns returned memory.
959/// TODO move to zig std lib
960fn 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
989test "getAppDataDir" {
990 const result = try getAppDataDir(std.debug.global_allocator, "zig");
991 std.debug.warn("{}...", result);
992}
949993
950 return os.path.join(allocator, home_dir, ".zig");994// TODO full utf-16 LE support
995fn 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}
9521003
953/// TODO move to zig std lib, and make it work for other OSes1004fn utf16lePtrSlice(ptr: [*]const u16) []const u16 {
954fn 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 @@
1const std = @import("../../index.zig");
2const assert = std.debug.assert;
1test "import" {3test "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
445pub extern "ole32.dll" stdcallcc fn CoTaskMemFree(pv: LPVOID) void;
446
447pub extern "shell32.dll" stdcallcc fn SHGetKnownFolderPath(rfid: *const KNOWNFOLDERID, dwFlags: DWORD, hToken: ?HANDLE, ppszPath: *[*]WCHAR) HRESULT;
448
449pub const HRESULT = c_long;
450
451pub const KNOWNFOLDERID = GUID;
452pub 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
502pub const FOLDERID_LocalAppData = GUID.parse("{F1B32785-6FBA-4FCF-9D55-7B8E7F157091}");
503
504pub const KF_FLAG_DEFAULT = 0;
505pub const KF_FLAG_NO_APPCONTAINER_REDIRECTION = 65536;
506pub const KF_FLAG_CREATE = 32768;
507pub const KF_FLAG_DONT_VERIFY = 16384;
508pub const KF_FLAG_DONT_UNEXPAND = 8192;
509pub const KF_FLAG_NO_ALIAS = 4096;
510pub const KF_FLAG_INIT = 2048;
511pub const KF_FLAG_DEFAULT_PATH = 1024;
512pub const KF_FLAG_NOT_PARENT_RELATIVE = 512;
513pub const KF_FLAG_SIMPLE_IDLIST = 256;
514pub const KF_FLAG_ALIAS_ONLY = -2147483648;
515
516pub const S_OK = 0;
517pub const E_NOTIMPL = @bitCast(c_long, c_ulong(0x80004001));
518pub const E_NOINTERFACE = @bitCast(c_long, c_ulong(0x80004002));
519pub const E_POINTER = @bitCast(c_long, c_ulong(0x80004003));
520pub const E_ABORT = @bitCast(c_long, c_ulong(0x80004004));
521pub const E_FAIL = @bitCast(c_long, c_ulong(0x80004005));
522pub const E_UNEXPECTED = @bitCast(c_long, c_ulong(0x8000FFFF));
523pub const E_ACCESSDENIED = @bitCast(c_long, c_ulong(0x80070005));
524pub const E_HANDLE = @bitCast(c_long, c_ulong(0x80070006));
525pub const E_OUTOFMEMORY = @bitCast(c_long, c_ulong(0x8007000E));
526pub const E_INVALIDARG = @bitCast(c_long, c_ulong(0x80070057));