zig/lib/std/fs/get_app_data_dir.zig
Andrew Kelley 4616af0ca4
introduce operating system version ranges as part of the target
* re-introduce `std.build.Target` which is distinct from `std.Target`.
   `std.build.Target` wraps `std.Target` so that it can be annotated as
   "the native target" or an explicitly specified target.
 * `std.Target.Os` is moved to `std.Target.Os.Tag`. The former is now a
   struct which has the tag as well as version range information.
 * `std.elf` gains some more ELF header constants.
 * `std.Target.parse` gains the ability to parse operating system
   version ranges as well as glibc version.
 * Added `std.Target.isGnuLibC()`.
 * self-hosted dynamic linker detection and glibc version detection.
   This also adds the improved logic using `/usr/bin/env` rather than
   invoking the system C compiler to find the dynamic linker when zig
   is statically linked. Related: #2084
   Note: this `/usr/bin/env` code is work-in-progress.
 * `-target-glibc` CLI option is removed in favor of the new `-target`
   syntax. Example: `-target x86_64-linux-gnu.2.27`

closes #1907
2020-02-28 14:51:53 -05:00

63 lines
2.6 KiB
Zig

const std = @import("../std.zig");
const builtin = @import("builtin");
const unicode = std.unicode;
const mem = std.mem;
const fs = std.fs;
const os = std.os;
pub const GetAppDataDirError = error{
OutOfMemory,
AppDataDirUnavailable,
};
/// 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(@ptrCast(*c_void, dir_path_ptr));
const global_dir = unicode.utf16leToUtf8Alloc(allocator, mem.toSliceConst(u16, dir_path_ptr)) 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,
}
},
.macosx => {
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 => {
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 });
},
else => @compileError("Unsupported OS"),
}
}
test "getAppDataDir" {
// We can't actually validate the result
const dir = getAppDataDir(std.testing.allocator, "zig") catch return;
defer std.testing.allocator.free(dir);
}