getAppDataDir()
|
/// Caller owns returned memory.
/// TODO determine if we can remove the allocator requirement
pub fn getAppDataDir(allocator: mem.Allocator, appname: []const u8) GetAppDataDirError![]u8 {
switch (builtin.os.tag) {
.windows => {
var dir_path_ptr: [*:0]u16 = undefined;
switch (os.windows.shell32.SHGetKnownFolderPath(
&os.windows.FOLDERID_LocalAppData,
os.windows.KF_FLAG_CREATE,
null,
&dir_path_ptr,
)) {
os.windows.S_OK => {
defer os.windows.ole32.CoTaskMemFree(@as(*anyopaque, @ptrCast(dir_path_ptr)));
const global_dir = unicode.utf16leToUtf8Alloc(allocator, mem.sliceTo(dir_path_ptr, 0)) catch |err| switch (err) {
error.UnexpectedSecondSurrogateHalf => return error.AppDataDirUnavailable,
error.ExpectedSecondSurrogateHalf => return error.AppDataDirUnavailable,
error.DanglingSurrogateHalf => return error.AppDataDirUnavailable,
error.OutOfMemory => return error.OutOfMemory,
};
defer allocator.free(global_dir);
return fs.path.join(allocator, &[_][]const u8{ global_dir, appname });
},
os.windows.E_OUTOFMEMORY => return error.OutOfMemory,
else => return error.AppDataDirUnavailable,
}
},
.macos => {
const home_dir = os.getenv("HOME") orelse {
// TODO look in /etc/passwd
return error.AppDataDirUnavailable;
};
return fs.path.join(allocator, &[_][]const u8{ home_dir, "Library", "Application Support", appname });
},
.linux, .freebsd, .netbsd, .dragonfly, .openbsd, .solaris => {
if (os.getenv("XDG_DATA_HOME")) |xdg| {
return fs.path.join(allocator, &[_][]const u8{ xdg, appname });
}
|
Test:getAppDataDir
|
const home_dir = os.getenv("HOME") orelse {
// TODO look in /etc/passwd
return error.AppDataDirUnavailable;
};
return fs.path.join(allocator, &[_][]const u8{ home_dir, ".local", "share", appname });
},
.haiku => {
var dir_path_ptr: [*:0]u8 = undefined;
// TODO look into directory_which
const be_user_settings = 0xbbe;
const rc = os.system.find_directory(be_user_settings, -1, true, dir_path_ptr, 1);
const settings_dir = try allocator.dupeZ(u8, mem.sliceTo(dir_path_ptr, 0));
defer allocator.free(settings_dir);
switch (rc) {
0 => return fs.path.join(allocator, &[_][]const u8{ settings_dir, appname }),
else => return error.AppDataDirUnavailable,
}
},
else => @compileError("Unsupported OS"),
}
}
test "getAppDataDir" {
if (builtin.os.tag == .wasi) return error.SkipZigTest;
// We can't actually validate the result
const dir = getAppDataDir(std.testing.allocator, "zig") catch return;
defer std.testing.allocator.free(dir);
}
|