Skip to content

Commit a8a1b5a

Browse files
committedJul 18, 2018
fix build on windows
* move getAppDataDir and utf16leToUtf8 from self-hosted to std lib * fix std.event.Loop on windows
·
0.15.10.3.0
1 parent b7be082 commit a8a1b5a

File tree

6 files changed

+156
-141
lines changed

6 files changed

+156
-141
lines changed
 

‎CMakeLists.txt‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,7 @@ set(ZIG_STD_FILES
557557
"os/darwin_errno.zig"
558558
"os/epoch.zig"
559559
"os/file.zig"
560+
"os/get_app_data_dir.zig"
560561
"os/get_user_id.zig"
561562
"os/index.zig"
562563
"os/linux/errno.zig"

‎src-self-hosted/compilation.zig‎

Lines changed: 1 addition & 138 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ const io = std.io;
44
const mem = std.mem;
55
const Allocator = mem.Allocator;
66
const Buffer = std.Buffer;
7-
const unicode = std.unicode;
87
const llvm = @import("llvm.zig");
98
const c = @import("c.zig");
109
const builtin = @import("builtin");
@@ -952,141 +951,5 @@ async fn addFnToLinkSet(comp: *Compilation, fn_val: *Value.Fn) void {
952951
}
953952

954953
fn getZigDir(allocator: *mem.Allocator) ![]u8 {
955-
return getAppDataDir(allocator, "zig");
956-
}
957-
958-
const GetAppDataDirError = error{
959-
OutOfMemory,
960-
AppDataDirUnavailable,
961-
};
962-
963-
/// Caller owns returned memory.
964-
/// TODO move to zig std lib
965-
fn getAppDataDir(allocator: *mem.Allocator, appname: []const u8) GetAppDataDirError![]u8 {
966-
switch (builtin.os) {
967-
builtin.Os.windows => {
968-
var dir_path_ptr: [*]u16 = undefined;
969-
switch (os.windows.SHGetKnownFolderPath(
970-
&os.windows.FOLDERID_LocalAppData,
971-
os.windows.KF_FLAG_CREATE,
972-
null,
973-
&dir_path_ptr,
974-
)) {
975-
os.windows.S_OK => {
976-
defer os.windows.CoTaskMemFree(@ptrCast(*c_void, dir_path_ptr));
977-
const global_dir = try utf16leToUtf8(allocator, utf16lePtrSlice(dir_path_ptr));
978-
defer allocator.free(global_dir);
979-
return os.path.join(allocator, global_dir, appname);
980-
},
981-
os.windows.E_OUTOFMEMORY => return error.OutOfMemory,
982-
else => return error.AppDataDirUnavailable,
983-
}
984-
},
985-
// TODO for macos it should be "~/Library/Application Support/<APPNAME>"
986-
else => {
987-
const home_dir = os.getEnvVarOwned(allocator, "HOME") catch |err| switch (err) {
988-
error.OutOfMemory => return error.OutOfMemory,
989-
error.EnvironmentVariableNotFound => return error.AppDataDirUnavailable, // TODO look in /etc/passwd
990-
};
991-
defer allocator.free(home_dir);
992-
return os.path.join(allocator, home_dir, ".local", "share", appname);
993-
},
994-
}
995-
}
996-
997-
test "getAppDataDir" {
998-
const result = try getAppDataDir(std.debug.global_allocator, "zig");
999-
std.debug.warn("{}...", result);
1000-
}
1001-
1002-
// TODO: put general purpose stuff in std.unicode
1003-
fn utf16leToUtf8(allocator: *mem.Allocator, utf16le: []const u16) ![]u8 {
1004-
var result = ArrayList(u8).init(allocator);
1005-
// optimistically guess that it will all be ascii.
1006-
try result.ensureCapacity(utf16le.len);
1007-
1008-
const utf16le_as_bytes = @sliceToBytes(utf16le);
1009-
var i: usize = 0;
1010-
var out_index: usize = 0;
1011-
while (i < utf16le_as_bytes.len) : (i += 2) {
1012-
// decode
1013-
const c0: u32 = mem.readIntLE(u16, utf16le_as_bytes[i..i + 2]);
1014-
var codepoint: u32 = undefined;
1015-
if (c0 & ~u32(0x03ff) == 0xd800) {
1016-
// surrogate pair
1017-
i += 2;
1018-
if (i >= utf16le_as_bytes.len) return error.DanglingSurrogateHalf;
1019-
const c1: u32 = mem.readIntLE(u16, utf16le_as_bytes[i..i + 2]);
1020-
if (c1 & ~u32(0x03ff) != 0xdc00) return error.ExpectedSecondSurrogateHalf;
1021-
codepoint = 0x10000 + (((c0 & 0x03ff) << 10) | (c1 & 0x03ff));
1022-
} else if (c0 & ~u32(0x03ff) == 0xdc00) {
1023-
return error.UnexpectedSecondSurrogateHalf;
1024-
} else {
1025-
codepoint = c0;
1026-
}
1027-
1028-
// encode
1029-
const utf8_len = unicode.utf8CodepointSequenceLength(codepoint) catch unreachable;
1030-
try result.resize(result.len + utf8_len);
1031-
_ = unicode.utf8Encode(codepoint, result.items[out_index..]) catch unreachable;
1032-
out_index += utf8_len;
1033-
}
1034-
1035-
return result.toOwnedSlice();
1036-
}
1037-
1038-
test "utf16leToUtf8" {
1039-
var utf16le: [2]u16 = undefined;
1040-
const utf16le_as_bytes = @sliceToBytes(utf16le[0..]);
1041-
1042-
{
1043-
mem.writeInt(utf16le_as_bytes[0..], u16('A'), builtin.Endian.Little);
1044-
mem.writeInt(utf16le_as_bytes[2..], u16('a'), builtin.Endian.Little);
1045-
const utf8 = try utf16leToUtf8(std.debug.global_allocator, utf16le);
1046-
assert(mem.eql(u8, utf8, "Aa"));
1047-
}
1048-
1049-
{
1050-
mem.writeInt(utf16le_as_bytes[0..], u16(0x80), builtin.Endian.Little);
1051-
mem.writeInt(utf16le_as_bytes[2..], u16(0xffff), builtin.Endian.Little);
1052-
const utf8 = try utf16leToUtf8(std.debug.global_allocator, utf16le);
1053-
assert(mem.eql(u8, utf8, "\xc2\x80" ++ "\xef\xbf\xbf"));
1054-
}
1055-
1056-
{
1057-
// the values just outside the surrogate half range
1058-
mem.writeInt(utf16le_as_bytes[0..], u16(0xd7ff), builtin.Endian.Little);
1059-
mem.writeInt(utf16le_as_bytes[2..], u16(0xe000), builtin.Endian.Little);
1060-
const utf8 = try utf16leToUtf8(std.debug.global_allocator, utf16le);
1061-
assert(mem.eql(u8, utf8, "\xed\x9f\xbf" ++ "\xee\x80\x80"));
1062-
}
1063-
1064-
{
1065-
// smallest surrogate pair
1066-
mem.writeInt(utf16le_as_bytes[0..], u16(0xd800), builtin.Endian.Little);
1067-
mem.writeInt(utf16le_as_bytes[2..], u16(0xdc00), builtin.Endian.Little);
1068-
const utf8 = try utf16leToUtf8(std.debug.global_allocator, utf16le);
1069-
assert(mem.eql(u8, utf8, "\xf0\x90\x80\x80"));
1070-
}
1071-
1072-
{
1073-
// largest surrogate pair
1074-
mem.writeInt(utf16le_as_bytes[0..], u16(0xdbff), builtin.Endian.Little);
1075-
mem.writeInt(utf16le_as_bytes[2..], u16(0xdfff), builtin.Endian.Little);
1076-
const utf8 = try utf16leToUtf8(std.debug.global_allocator, utf16le);
1077-
assert(mem.eql(u8, utf8, "\xf4\x8f\xbf\xbf"));
1078-
}
1079-
1080-
{
1081-
mem.writeInt(utf16le_as_bytes[0..], u16(0xdbff), builtin.Endian.Little);
1082-
mem.writeInt(utf16le_as_bytes[2..], u16(0xdc00), builtin.Endian.Little);
1083-
const utf8 = try utf16leToUtf8(std.debug.global_allocator, utf16le);
1084-
assert(mem.eql(u8, utf8, "\xf4\x8f\xb0\x80"));
1085-
}
1086-
}
1087-
1088-
fn utf16lePtrSlice(ptr: [*]const u16) []const u16 {
1089-
var index: usize = 0;
1090-
while (ptr[index] != 0) : (index += 1) {}
1091-
return ptr[0..index];
954+
return os.getAppDataDir(allocator, "zig");
1092955
}

‎std/event/loop.zig‎

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -233,8 +233,6 @@ pub const Loop = struct {
233233
}
234234
},
235235
builtin.Os.windows => {
236-
self.os_data.extra_thread_count = extra_thread_count;
237-
238236
self.os_data.io_port = try std.os.windowsCreateIoCompletionPort(
239237
windows.INVALID_HANDLE_VALUE,
240238
null,
@@ -468,7 +466,7 @@ pub const Loop = struct {
468466
},
469467
builtin.Os.windows => {
470468
var i: usize = 0;
471-
while (i < self.os_data.extra_thread_count) : (i += 1) {
469+
while (i < self.extra_threads.len + 1) : (i += 1) {
472470
while (true) {
473471
const overlapped = @intToPtr(?*windows.OVERLAPPED, 0x1);
474472
std.os.windowsPostQueuedCompletionStatus(self.os_data.io_port, undefined, @ptrToInt(&self.final_resume_node), overlapped) catch continue;

‎std/os/get_app_data_dir.zig‎

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
const std = @import("../index.zig");
2+
const builtin = @import("builtin");
3+
const unicode = std.unicode;
4+
const mem = std.mem;
5+
const os = std.os;
6+
7+
pub const GetAppDataDirError = error{
8+
OutOfMemory,
9+
AppDataDirUnavailable,
10+
};
11+
12+
/// Caller owns returned memory.
13+
pub fn getAppDataDir(allocator: *mem.Allocator, appname: []const u8) GetAppDataDirError![]u8 {
14+
switch (builtin.os) {
15+
builtin.Os.windows => {
16+
var dir_path_ptr: [*]u16 = undefined;
17+
switch (os.windows.SHGetKnownFolderPath(
18+
&os.windows.FOLDERID_LocalAppData,
19+
os.windows.KF_FLAG_CREATE,
20+
null,
21+
&dir_path_ptr,
22+
)) {
23+
os.windows.S_OK => {
24+
defer os.windows.CoTaskMemFree(@ptrCast(*c_void, dir_path_ptr));
25+
const global_dir = unicode.utf16leToUtf8(allocator, utf16lePtrSlice(dir_path_ptr)) catch |err| switch (err) {
26+
error.UnexpectedSecondSurrogateHalf => return error.AppDataDirUnavailable,
27+
error.ExpectedSecondSurrogateHalf => return error.AppDataDirUnavailable,
28+
error.DanglingSurrogateHalf => return error.AppDataDirUnavailable,
29+
error.OutOfMemory => return error.OutOfMemory,
30+
};
31+
defer allocator.free(global_dir);
32+
return os.path.join(allocator, global_dir, appname);
33+
},
34+
os.windows.E_OUTOFMEMORY => return error.OutOfMemory,
35+
else => return error.AppDataDirUnavailable,
36+
}
37+
},
38+
// TODO for macos it should be "~/Library/Application Support/<APPNAME>"
39+
else => {
40+
const home_dir = os.getEnvVarOwned(allocator, "HOME") catch |err| switch (err) {
41+
error.OutOfMemory => return error.OutOfMemory,
42+
error.EnvironmentVariableNotFound => return error.AppDataDirUnavailable, // TODO look in /etc/passwd
43+
};
44+
defer allocator.free(home_dir);
45+
return os.path.join(allocator, home_dir, ".local", "share", appname);
46+
},
47+
}
48+
}
49+
50+
fn utf16lePtrSlice(ptr: [*]const u16) []const u16 {
51+
var index: usize = 0;
52+
while (ptr[index] != 0) : (index += 1) {}
53+
return ptr[0..index];
54+
}
55+
56+
test "getAppDataDir" {
57+
const result = try getAppDataDir(std.debug.global_allocator, "zig");
58+
std.debug.warn("{}...", result);
59+
}
60+

‎std/os/index.zig‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ test "std.os" {
1818
_ = @import("test.zig");
1919
_ = @import("time.zig");
2020
_ = @import("windows/index.zig");
21+
_ = @import("get_app_data_dir.zig");
2122
}
2223

2324
pub const windows = @import("windows/index.zig");
@@ -76,6 +77,9 @@ pub const WindowsWriteError = windows_util.WriteError;
7677

7778
pub const FileHandle = if (is_windows) windows.HANDLE else i32;
7879

80+
pub const getAppDataDir = @import("get_app_data_dir.zig").getAppDataDir;
81+
pub const GetAppDataDirError = @import("get_app_data_dir.zig").GetAppDataDirError;
82+
7983
const debug = std.debug;
8084
const assert = debug.assert;
8185

‎std/unicode.zig‎

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
const std = @import("./index.zig");
2+
const builtin = @import("builtin");
23
const debug = std.debug;
4+
const assert = std.debug.assert;
5+
const mem = std.mem;
36

47
/// Returns how many bytes the UTF-8 representation would require
58
/// for the given codepoint.
@@ -441,3 +444,89 @@ fn testDecode(bytes: []const u8) !u32 {
441444
debug.assert(bytes.len == length);
442445
return utf8Decode(bytes);
443446
}
447+
448+
// TODO: make this API on top of a non-allocating Utf16LeView
449+
pub fn utf16leToUtf8(allocator: *mem.Allocator, utf16le: []const u16) ![]u8 {
450+
var result = std.ArrayList(u8).init(allocator);
451+
// optimistically guess that it will all be ascii.
452+
try result.ensureCapacity(utf16le.len);
453+
454+
const utf16le_as_bytes = @sliceToBytes(utf16le);
455+
var i: usize = 0;
456+
var out_index: usize = 0;
457+
while (i < utf16le_as_bytes.len) : (i += 2) {
458+
// decode
459+
const c0: u32 = mem.readIntLE(u16, utf16le_as_bytes[i..i + 2]);
460+
var codepoint: u32 = undefined;
461+
if (c0 & ~u32(0x03ff) == 0xd800) {
462+
// surrogate pair
463+
i += 2;
464+
if (i >= utf16le_as_bytes.len) return error.DanglingSurrogateHalf;
465+
const c1: u32 = mem.readIntLE(u16, utf16le_as_bytes[i..i + 2]);
466+
if (c1 & ~u32(0x03ff) != 0xdc00) return error.ExpectedSecondSurrogateHalf;
467+
codepoint = 0x10000 + (((c0 & 0x03ff) << 10) | (c1 & 0x03ff));
468+
} else if (c0 & ~u32(0x03ff) == 0xdc00) {
469+
return error.UnexpectedSecondSurrogateHalf;
470+
} else {
471+
codepoint = c0;
472+
}
473+
474+
// encode
475+
const utf8_len = utf8CodepointSequenceLength(codepoint) catch unreachable;
476+
try result.resize(result.len + utf8_len);
477+
_ = utf8Encode(codepoint, result.items[out_index..]) catch unreachable;
478+
out_index += utf8_len;
479+
}
480+
481+
return result.toOwnedSlice();
482+
}
483+
484+
test "utf16leToUtf8" {
485+
var utf16le: [2]u16 = undefined;
486+
const utf16le_as_bytes = @sliceToBytes(utf16le[0..]);
487+
488+
{
489+
mem.writeInt(utf16le_as_bytes[0..], u16('A'), builtin.Endian.Little);
490+
mem.writeInt(utf16le_as_bytes[2..], u16('a'), builtin.Endian.Little);
491+
const utf8 = try utf16leToUtf8(std.debug.global_allocator, utf16le);
492+
assert(mem.eql(u8, utf8, "Aa"));
493+
}
494+
495+
{
496+
mem.writeInt(utf16le_as_bytes[0..], u16(0x80), builtin.Endian.Little);
497+
mem.writeInt(utf16le_as_bytes[2..], u16(0xffff), builtin.Endian.Little);
498+
const utf8 = try utf16leToUtf8(std.debug.global_allocator, utf16le);
499+
assert(mem.eql(u8, utf8, "\xc2\x80" ++ "\xef\xbf\xbf"));
500+
}
501+
502+
{
503+
// the values just outside the surrogate half range
504+
mem.writeInt(utf16le_as_bytes[0..], u16(0xd7ff), builtin.Endian.Little);
505+
mem.writeInt(utf16le_as_bytes[2..], u16(0xe000), builtin.Endian.Little);
506+
const utf8 = try utf16leToUtf8(std.debug.global_allocator, utf16le);
507+
assert(mem.eql(u8, utf8, "\xed\x9f\xbf" ++ "\xee\x80\x80"));
508+
}
509+
510+
{
511+
// smallest surrogate pair
512+
mem.writeInt(utf16le_as_bytes[0..], u16(0xd800), builtin.Endian.Little);
513+
mem.writeInt(utf16le_as_bytes[2..], u16(0xdc00), builtin.Endian.Little);
514+
const utf8 = try utf16leToUtf8(std.debug.global_allocator, utf16le);
515+
assert(mem.eql(u8, utf8, "\xf0\x90\x80\x80"));
516+
}
517+
518+
{
519+
// largest surrogate pair
520+
mem.writeInt(utf16le_as_bytes[0..], u16(0xdbff), builtin.Endian.Little);
521+
mem.writeInt(utf16le_as_bytes[2..], u16(0xdfff), builtin.Endian.Little);
522+
const utf8 = try utf16leToUtf8(std.debug.global_allocator, utf16le);
523+
assert(mem.eql(u8, utf8, "\xf4\x8f\xbf\xbf"));
524+
}
525+
526+
{
527+
mem.writeInt(utf16le_as_bytes[0..], u16(0xdbff), builtin.Endian.Little);
528+
mem.writeInt(utf16le_as_bytes[2..], u16(0xdc00), builtin.Endian.Little);
529+
const utf8 = try utf16leToUtf8(std.debug.global_allocator, utf16le);
530+
assert(mem.eql(u8, utf8, "\xf4\x8f\xb0\x80"));
531+
}
532+
}

0 commit comments

Comments
 (0)
Please sign in to comment.