Skip to content

Commit

Permalink
self-hosted: implement getAppDataDir for windows
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewrk committed Jul 17, 2018
1 parent 97bfeac commit 3bb00ea
Show file tree
Hide file tree
Showing 2 changed files with 143 additions and 6 deletions.
64 changes: 58 additions & 6 deletions src-self-hosted/compilation.zig
Expand Up @@ -237,6 +237,7 @@ pub const Compilation = struct {
ReadOnlyFileSystem,
LinkQuotaExceeded,
EnvironmentVariableNotFound,
AppDataDirUnavailable,
};

pub const Event = union(enum) {
Expand Down Expand Up @@ -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];
}
85 changes: 85 additions & 0 deletions std/os/windows/index.zig
@@ -1,3 +1,5 @@
const std = @import("../../index.zig");
const assert = std.debug.assert;
test "import" {
_ = @import("util.zig");
}
Expand Down Expand Up @@ -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));

0 comments on commit 3bb00ea

Please sign in to comment.