Commit 3bb00eac37
Changed files (2)
src-self-hosted
std
os
windows
src-self-hosted/compilation.zig
@@ -237,6 +237,7 @@ pub const Compilation = struct {
ReadOnlyFileSystem,
LinkQuotaExceeded,
EnvironmentVariableNotFound,
+ AppDataDirUnavailable,
};
pub const Event = union(enum) {
@@ -944,13 +945,64 @@ async fn addFnToLinkSet(comp: *Compilation, fn_val: *Value.Fn) void {
}
fn getZigDir(allocator: *mem.Allocator) ![]u8 {
- const home_dir = try getHomeDir(allocator);
- defer allocator.free(home_dir);
+ return getAppDataDir(allocator, "zig");
+}
+
+
+const GetAppDataDirError = error{
+ OutOfMemory,
+ AppDataDirUnavailable,
+};
+
+
+/// Caller owns returned memory.
+/// TODO move to zig std lib
+fn getAppDataDir(allocator: *mem.Allocator, appname: []const u8) GetAppDataDirError![]u8 {
+ switch (builtin.os) {
+ builtin.Os.windows => {
+ var dir_path_ptr: [*]u16 = undefined;
+ switch (os.windows.SHGetKnownFolderPath(&os.windows.FOLDERID_LocalAppData, os.windows.KF_FLAG_CREATE,
+ null, &dir_path_ptr,))
+ {
+ os.windows.S_OK => {
+ defer os.windows.CoTaskMemFree(@ptrCast(*c_void, dir_path_ptr));
+ const global_dir = try utf16leToUtf8(allocator, utf16lePtrSlice(dir_path_ptr));
+ defer allocator.free(global_dir);
+ return os.path.join(allocator, global_dir, appname);
+ },
+ os.windows.E_OUTOFMEMORY => return error.OutOfMemory,
+ else => return error.AppDataDirUnavailable,
+ }
+ },
+ // TODO for macos it should be "~/Library/Application Support/<APPNAME>"
+ else => {
+ const home_dir = os.getEnvVarOwned(allocator, "HOME") catch |err| switch (err) {
+ error.OutOfMemory => return error.OutOfMemory,
+ error.EnvironmentVariableNotFound => return error.AppDataDirUnavailable, // TODO look in /etc/passwd
+ };
+ defer allocator.free(home_dir);
+ return os.path.join(allocator, home_dir, ".local", "share", appname);
+ },
+ }
+}
+
+test "getAppDataDir" {
+ const result = try getAppDataDir(std.debug.global_allocator, "zig");
+ std.debug.warn("{}...", result);
+}
- return os.path.join(allocator, home_dir, ".zig");
+// TODO full utf-16 LE support
+fn utf16leToUtf8(allocator: *mem.Allocator, utf16le: []const u16) ![]u8 {
+ const utf8_bytes = try allocator.alloc(u8, utf16le.len);
+ for (utf16le) |codepoint, i| {
+ assert(codepoint < 127); // TODO full utf-16 LE support
+ utf8_bytes[i] = @intCast(u8, codepoint);
+ }
+ return utf8_bytes;
}
-/// TODO move to zig std lib, and make it work for other OSes
-fn getHomeDir(allocator: *mem.Allocator) ![]u8 {
- return os.getEnvVarOwned(allocator, "HOME");
+fn utf16lePtrSlice(ptr: [*]const u16) []const u16 {
+ var index: usize = 0;
+ while (ptr[index] != 0) : (index += 1) {}
+ return ptr[0..index];
}
std/os/windows/index.zig
@@ -1,3 +1,5 @@
+const std = @import("../../index.zig");
+const assert = std.debug.assert;
test "import" {
_ = @import("util.zig");
}
@@ -439,3 +441,86 @@ pub const SYSTEM_INFO = extern struct {
wProcessorLevel: WORD,
wProcessorRevision: WORD,
};
+
+pub extern "ole32.dll" stdcallcc fn CoTaskMemFree(pv: LPVOID) void;
+
+pub extern "shell32.dll" stdcallcc fn SHGetKnownFolderPath(rfid: *const KNOWNFOLDERID, dwFlags: DWORD, hToken: ?HANDLE, ppszPath: *[*]WCHAR) HRESULT;
+
+pub const HRESULT = c_long;
+
+pub const KNOWNFOLDERID = GUID;
+pub const GUID = extern struct {
+ Data1: c_ulong,
+ Data2: c_ushort,
+ Data3: c_ushort,
+ Data4: [8]u8,
+
+ pub fn parse(str: []const u8) GUID {
+ var guid: GUID = undefined;
+ var index: usize = 0;
+ assert(str[index] == '{');
+ index += 1;
+
+ guid.Data1 = std.fmt.parseUnsigned(c_ulong, str[index..index + 8], 16) catch unreachable;
+ index += 8;
+
+ assert(str[index] == '-');
+ index += 1;
+
+ guid.Data2 = std.fmt.parseUnsigned(c_ushort, str[index..index + 4], 16) catch unreachable;
+ index += 4;
+
+ assert(str[index] == '-');
+ index += 1;
+
+ guid.Data3 = std.fmt.parseUnsigned(c_ushort, str[index..index + 4], 16) catch unreachable;
+ index += 4;
+
+ assert(str[index] == '-');
+ index += 1;
+
+ guid.Data4[0] = std.fmt.parseUnsigned(u8, str[index..index + 2], 16) catch unreachable;
+ index += 2;
+ guid.Data4[1] = std.fmt.parseUnsigned(u8, str[index..index + 2], 16) catch unreachable;
+ index += 2;
+
+ assert(str[index] == '-');
+ index += 1;
+
+ var i: usize = 2;
+ while (i < guid.Data4.len) : (i += 1) {
+ guid.Data4[i] = std.fmt.parseUnsigned(u8, str[index..index + 2], 16) catch unreachable;
+ index += 2;
+ }
+
+ assert(str[index] == '}');
+ index += 1;
+ return guid;
+ }
+};
+
+pub const FOLDERID_LocalAppData = GUID.parse("{F1B32785-6FBA-4FCF-9D55-7B8E7F157091}");
+
+pub const KF_FLAG_DEFAULT = 0;
+pub const KF_FLAG_NO_APPCONTAINER_REDIRECTION = 65536;
+pub const KF_FLAG_CREATE = 32768;
+pub const KF_FLAG_DONT_VERIFY = 16384;
+pub const KF_FLAG_DONT_UNEXPAND = 8192;
+pub const KF_FLAG_NO_ALIAS = 4096;
+pub const KF_FLAG_INIT = 2048;
+pub const KF_FLAG_DEFAULT_PATH = 1024;
+pub const KF_FLAG_NOT_PARENT_RELATIVE = 512;
+pub const KF_FLAG_SIMPLE_IDLIST = 256;
+pub const KF_FLAG_ALIAS_ONLY = -2147483648;
+
+pub const S_OK = 0;
+pub const E_NOTIMPL = @bitCast(c_long, c_ulong(0x80004001));
+pub const E_NOINTERFACE = @bitCast(c_long, c_ulong(0x80004002));
+pub const E_POINTER = @bitCast(c_long, c_ulong(0x80004003));
+pub const E_ABORT = @bitCast(c_long, c_ulong(0x80004004));
+pub const E_FAIL = @bitCast(c_long, c_ulong(0x80004005));
+pub const E_UNEXPECTED = @bitCast(c_long, c_ulong(0x8000FFFF));
+pub const E_ACCESSDENIED = @bitCast(c_long, c_ulong(0x80070005));
+pub const E_HANDLE = @bitCast(c_long, c_ulong(0x80070006));
+pub const E_OUTOFMEMORY = @bitCast(c_long, c_ulong(0x8007000E));
+pub const E_INVALIDARG = @bitCast(c_long, c_ulong(0x80070057));