fix build on windows
* move getAppDataDir and utf16leToUtf8 from self-hosted to std lib * fix std.event.Loop on windowsmaster
parent
b7be082bd9
commit
a8a1b5af07
|
@ -557,6 +557,7 @@ set(ZIG_STD_FILES
|
|||
"os/darwin_errno.zig"
|
||||
"os/epoch.zig"
|
||||
"os/file.zig"
|
||||
"os/get_app_data_dir.zig"
|
||||
"os/get_user_id.zig"
|
||||
"os/index.zig"
|
||||
"os/linux/errno.zig"
|
||||
|
|
|
@ -4,7 +4,6 @@ const io = std.io;
|
|||
const mem = std.mem;
|
||||
const Allocator = mem.Allocator;
|
||||
const Buffer = std.Buffer;
|
||||
const unicode = std.unicode;
|
||||
const llvm = @import("llvm.zig");
|
||||
const c = @import("c.zig");
|
||||
const builtin = @import("builtin");
|
||||
|
@ -952,141 +951,5 @@ async fn addFnToLinkSet(comp: *Compilation, fn_val: *Value.Fn) void {
|
|||
}
|
||||
|
||||
fn getZigDir(allocator: *mem.Allocator) ![]u8 {
|
||||
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);
|
||||
}
|
||||
|
||||
// TODO: put general purpose stuff in std.unicode
|
||||
fn utf16leToUtf8(allocator: *mem.Allocator, utf16le: []const u16) ![]u8 {
|
||||
var result = ArrayList(u8).init(allocator);
|
||||
// optimistically guess that it will all be ascii.
|
||||
try result.ensureCapacity(utf16le.len);
|
||||
|
||||
const utf16le_as_bytes = @sliceToBytes(utf16le);
|
||||
var i: usize = 0;
|
||||
var out_index: usize = 0;
|
||||
while (i < utf16le_as_bytes.len) : (i += 2) {
|
||||
// decode
|
||||
const c0: u32 = mem.readIntLE(u16, utf16le_as_bytes[i..i + 2]);
|
||||
var codepoint: u32 = undefined;
|
||||
if (c0 & ~u32(0x03ff) == 0xd800) {
|
||||
// surrogate pair
|
||||
i += 2;
|
||||
if (i >= utf16le_as_bytes.len) return error.DanglingSurrogateHalf;
|
||||
const c1: u32 = mem.readIntLE(u16, utf16le_as_bytes[i..i + 2]);
|
||||
if (c1 & ~u32(0x03ff) != 0xdc00) return error.ExpectedSecondSurrogateHalf;
|
||||
codepoint = 0x10000 + (((c0 & 0x03ff) << 10) | (c1 & 0x03ff));
|
||||
} else if (c0 & ~u32(0x03ff) == 0xdc00) {
|
||||
return error.UnexpectedSecondSurrogateHalf;
|
||||
} else {
|
||||
codepoint = c0;
|
||||
}
|
||||
|
||||
// encode
|
||||
const utf8_len = unicode.utf8CodepointSequenceLength(codepoint) catch unreachable;
|
||||
try result.resize(result.len + utf8_len);
|
||||
_ = unicode.utf8Encode(codepoint, result.items[out_index..]) catch unreachable;
|
||||
out_index += utf8_len;
|
||||
}
|
||||
|
||||
return result.toOwnedSlice();
|
||||
}
|
||||
|
||||
test "utf16leToUtf8" {
|
||||
var utf16le: [2]u16 = undefined;
|
||||
const utf16le_as_bytes = @sliceToBytes(utf16le[0..]);
|
||||
|
||||
{
|
||||
mem.writeInt(utf16le_as_bytes[0..], u16('A'), builtin.Endian.Little);
|
||||
mem.writeInt(utf16le_as_bytes[2..], u16('a'), builtin.Endian.Little);
|
||||
const utf8 = try utf16leToUtf8(std.debug.global_allocator, utf16le);
|
||||
assert(mem.eql(u8, utf8, "Aa"));
|
||||
}
|
||||
|
||||
{
|
||||
mem.writeInt(utf16le_as_bytes[0..], u16(0x80), builtin.Endian.Little);
|
||||
mem.writeInt(utf16le_as_bytes[2..], u16(0xffff), builtin.Endian.Little);
|
||||
const utf8 = try utf16leToUtf8(std.debug.global_allocator, utf16le);
|
||||
assert(mem.eql(u8, utf8, "\xc2\x80" ++ "\xef\xbf\xbf"));
|
||||
}
|
||||
|
||||
{
|
||||
// the values just outside the surrogate half range
|
||||
mem.writeInt(utf16le_as_bytes[0..], u16(0xd7ff), builtin.Endian.Little);
|
||||
mem.writeInt(utf16le_as_bytes[2..], u16(0xe000), builtin.Endian.Little);
|
||||
const utf8 = try utf16leToUtf8(std.debug.global_allocator, utf16le);
|
||||
assert(mem.eql(u8, utf8, "\xed\x9f\xbf" ++ "\xee\x80\x80"));
|
||||
}
|
||||
|
||||
{
|
||||
// smallest surrogate pair
|
||||
mem.writeInt(utf16le_as_bytes[0..], u16(0xd800), builtin.Endian.Little);
|
||||
mem.writeInt(utf16le_as_bytes[2..], u16(0xdc00), builtin.Endian.Little);
|
||||
const utf8 = try utf16leToUtf8(std.debug.global_allocator, utf16le);
|
||||
assert(mem.eql(u8, utf8, "\xf0\x90\x80\x80"));
|
||||
}
|
||||
|
||||
{
|
||||
// largest surrogate pair
|
||||
mem.writeInt(utf16le_as_bytes[0..], u16(0xdbff), builtin.Endian.Little);
|
||||
mem.writeInt(utf16le_as_bytes[2..], u16(0xdfff), builtin.Endian.Little);
|
||||
const utf8 = try utf16leToUtf8(std.debug.global_allocator, utf16le);
|
||||
assert(mem.eql(u8, utf8, "\xf4\x8f\xbf\xbf"));
|
||||
}
|
||||
|
||||
{
|
||||
mem.writeInt(utf16le_as_bytes[0..], u16(0xdbff), builtin.Endian.Little);
|
||||
mem.writeInt(utf16le_as_bytes[2..], u16(0xdc00), builtin.Endian.Little);
|
||||
const utf8 = try utf16leToUtf8(std.debug.global_allocator, utf16le);
|
||||
assert(mem.eql(u8, utf8, "\xf4\x8f\xb0\x80"));
|
||||
}
|
||||
}
|
||||
|
||||
fn utf16lePtrSlice(ptr: [*]const u16) []const u16 {
|
||||
var index: usize = 0;
|
||||
while (ptr[index] != 0) : (index += 1) {}
|
||||
return ptr[0..index];
|
||||
return os.getAppDataDir(allocator, "zig");
|
||||
}
|
||||
|
|
|
@ -233,8 +233,6 @@ pub const Loop = struct {
|
|||
}
|
||||
},
|
||||
builtin.Os.windows => {
|
||||
self.os_data.extra_thread_count = extra_thread_count;
|
||||
|
||||
self.os_data.io_port = try std.os.windowsCreateIoCompletionPort(
|
||||
windows.INVALID_HANDLE_VALUE,
|
||||
null,
|
||||
|
@ -468,7 +466,7 @@ pub const Loop = struct {
|
|||
},
|
||||
builtin.Os.windows => {
|
||||
var i: usize = 0;
|
||||
while (i < self.os_data.extra_thread_count) : (i += 1) {
|
||||
while (i < self.extra_threads.len + 1) : (i += 1) {
|
||||
while (true) {
|
||||
const overlapped = @intToPtr(?*windows.OVERLAPPED, 0x1);
|
||||
std.os.windowsPostQueuedCompletionStatus(self.os_data.io_port, undefined, @ptrToInt(&self.final_resume_node), overlapped) catch continue;
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
const std = @import("../index.zig");
|
||||
const builtin = @import("builtin");
|
||||
const unicode = std.unicode;
|
||||
const mem = std.mem;
|
||||
const os = std.os;
|
||||
|
||||
pub const GetAppDataDirError = error{
|
||||
OutOfMemory,
|
||||
AppDataDirUnavailable,
|
||||
};
|
||||
|
||||
/// Caller owns returned memory.
|
||||
pub 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 = unicode.utf16leToUtf8(allocator, utf16lePtrSlice(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 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);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn utf16lePtrSlice(ptr: [*]const u16) []const u16 {
|
||||
var index: usize = 0;
|
||||
while (ptr[index] != 0) : (index += 1) {}
|
||||
return ptr[0..index];
|
||||
}
|
||||
|
||||
test "getAppDataDir" {
|
||||
const result = try getAppDataDir(std.debug.global_allocator, "zig");
|
||||
std.debug.warn("{}...", result);
|
||||
}
|
||||
|
|
@ -18,6 +18,7 @@ test "std.os" {
|
|||
_ = @import("test.zig");
|
||||
_ = @import("time.zig");
|
||||
_ = @import("windows/index.zig");
|
||||
_ = @import("get_app_data_dir.zig");
|
||||
}
|
||||
|
||||
pub const windows = @import("windows/index.zig");
|
||||
|
@ -76,6 +77,9 @@ pub const WindowsWriteError = windows_util.WriteError;
|
|||
|
||||
pub const FileHandle = if (is_windows) windows.HANDLE else i32;
|
||||
|
||||
pub const getAppDataDir = @import("get_app_data_dir.zig").getAppDataDir;
|
||||
pub const GetAppDataDirError = @import("get_app_data_dir.zig").GetAppDataDirError;
|
||||
|
||||
const debug = std.debug;
|
||||
const assert = debug.assert;
|
||||
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
const std = @import("./index.zig");
|
||||
const builtin = @import("builtin");
|
||||
const debug = std.debug;
|
||||
const assert = std.debug.assert;
|
||||
const mem = std.mem;
|
||||
|
||||
/// Returns how many bytes the UTF-8 representation would require
|
||||
/// for the given codepoint.
|
||||
|
@ -441,3 +444,89 @@ fn testDecode(bytes: []const u8) !u32 {
|
|||
debug.assert(bytes.len == length);
|
||||
return utf8Decode(bytes);
|
||||
}
|
||||
|
||||
// TODO: make this API on top of a non-allocating Utf16LeView
|
||||
pub fn utf16leToUtf8(allocator: *mem.Allocator, utf16le: []const u16) ![]u8 {
|
||||
var result = std.ArrayList(u8).init(allocator);
|
||||
// optimistically guess that it will all be ascii.
|
||||
try result.ensureCapacity(utf16le.len);
|
||||
|
||||
const utf16le_as_bytes = @sliceToBytes(utf16le);
|
||||
var i: usize = 0;
|
||||
var out_index: usize = 0;
|
||||
while (i < utf16le_as_bytes.len) : (i += 2) {
|
||||
// decode
|
||||
const c0: u32 = mem.readIntLE(u16, utf16le_as_bytes[i..i + 2]);
|
||||
var codepoint: u32 = undefined;
|
||||
if (c0 & ~u32(0x03ff) == 0xd800) {
|
||||
// surrogate pair
|
||||
i += 2;
|
||||
if (i >= utf16le_as_bytes.len) return error.DanglingSurrogateHalf;
|
||||
const c1: u32 = mem.readIntLE(u16, utf16le_as_bytes[i..i + 2]);
|
||||
if (c1 & ~u32(0x03ff) != 0xdc00) return error.ExpectedSecondSurrogateHalf;
|
||||
codepoint = 0x10000 + (((c0 & 0x03ff) << 10) | (c1 & 0x03ff));
|
||||
} else if (c0 & ~u32(0x03ff) == 0xdc00) {
|
||||
return error.UnexpectedSecondSurrogateHalf;
|
||||
} else {
|
||||
codepoint = c0;
|
||||
}
|
||||
|
||||
// encode
|
||||
const utf8_len = utf8CodepointSequenceLength(codepoint) catch unreachable;
|
||||
try result.resize(result.len + utf8_len);
|
||||
_ = utf8Encode(codepoint, result.items[out_index..]) catch unreachable;
|
||||
out_index += utf8_len;
|
||||
}
|
||||
|
||||
return result.toOwnedSlice();
|
||||
}
|
||||
|
||||
test "utf16leToUtf8" {
|
||||
var utf16le: [2]u16 = undefined;
|
||||
const utf16le_as_bytes = @sliceToBytes(utf16le[0..]);
|
||||
|
||||
{
|
||||
mem.writeInt(utf16le_as_bytes[0..], u16('A'), builtin.Endian.Little);
|
||||
mem.writeInt(utf16le_as_bytes[2..], u16('a'), builtin.Endian.Little);
|
||||
const utf8 = try utf16leToUtf8(std.debug.global_allocator, utf16le);
|
||||
assert(mem.eql(u8, utf8, "Aa"));
|
||||
}
|
||||
|
||||
{
|
||||
mem.writeInt(utf16le_as_bytes[0..], u16(0x80), builtin.Endian.Little);
|
||||
mem.writeInt(utf16le_as_bytes[2..], u16(0xffff), builtin.Endian.Little);
|
||||
const utf8 = try utf16leToUtf8(std.debug.global_allocator, utf16le);
|
||||
assert(mem.eql(u8, utf8, "\xc2\x80" ++ "\xef\xbf\xbf"));
|
||||
}
|
||||
|
||||
{
|
||||
// the values just outside the surrogate half range
|
||||
mem.writeInt(utf16le_as_bytes[0..], u16(0xd7ff), builtin.Endian.Little);
|
||||
mem.writeInt(utf16le_as_bytes[2..], u16(0xe000), builtin.Endian.Little);
|
||||
const utf8 = try utf16leToUtf8(std.debug.global_allocator, utf16le);
|
||||
assert(mem.eql(u8, utf8, "\xed\x9f\xbf" ++ "\xee\x80\x80"));
|
||||
}
|
||||
|
||||
{
|
||||
// smallest surrogate pair
|
||||
mem.writeInt(utf16le_as_bytes[0..], u16(0xd800), builtin.Endian.Little);
|
||||
mem.writeInt(utf16le_as_bytes[2..], u16(0xdc00), builtin.Endian.Little);
|
||||
const utf8 = try utf16leToUtf8(std.debug.global_allocator, utf16le);
|
||||
assert(mem.eql(u8, utf8, "\xf0\x90\x80\x80"));
|
||||
}
|
||||
|
||||
{
|
||||
// largest surrogate pair
|
||||
mem.writeInt(utf16le_as_bytes[0..], u16(0xdbff), builtin.Endian.Little);
|
||||
mem.writeInt(utf16le_as_bytes[2..], u16(0xdfff), builtin.Endian.Little);
|
||||
const utf8 = try utf16leToUtf8(std.debug.global_allocator, utf16le);
|
||||
assert(mem.eql(u8, utf8, "\xf4\x8f\xbf\xbf"));
|
||||
}
|
||||
|
||||
{
|
||||
mem.writeInt(utf16le_as_bytes[0..], u16(0xdbff), builtin.Endian.Little);
|
||||
mem.writeInt(utf16le_as_bytes[2..], u16(0xdc00), builtin.Endian.Little);
|
||||
const utf8 = try utf16leToUtf8(std.debug.global_allocator, utf16le);
|
||||
assert(mem.eql(u8, utf8, "\xf4\x8f\xb0\x80"));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue