authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-07-18 10:07:22-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-07-18 10:07:22-04:00
loga8a1b5af07519b49b5ba31ad6c802a7ccc8a5e23
tree4da94fe3e2b0fc4692eb368244e90696f2cbcec1
parentb7be082bd9aaba4cbf7c7c7449e481f9caa1dc24

fix build on windows

* move getAppDataDir and utf16leToUtf8 from self-hosted to std lib * fix std.event.Loop on windows

6 files changed, 156 insertions(+), 141 deletions(-)

CMakeLists.txt+1
...@@ -557,6 +557,7 @@ set(ZIG_STD_FILES...@@ -557,6 +557,7 @@ set(ZIG_STD_FILES
557 "os/darwin_errno.zig"557 "os/darwin_errno.zig"
558 "os/epoch.zig"558 "os/epoch.zig"
559 "os/file.zig"559 "os/file.zig"
560 "os/get_app_data_dir.zig"
560 "os/get_user_id.zig"561 "os/get_user_id.zig"
561 "os/index.zig"562 "os/index.zig"
562 "os/linux/errno.zig"563 "os/linux/errno.zig"
src-self-hosted/compilation.zig+1-138
...@@ -4,7 +4,6 @@ const io = std.io;...@@ -4,7 +4,6 @@ const io = std.io;
4const mem = std.mem;4const mem = std.mem;
5const Allocator = mem.Allocator;5const Allocator = mem.Allocator;
6const Buffer = std.Buffer;6const Buffer = std.Buffer;
7const unicode = std.unicode;
8const llvm = @import("llvm.zig");7const llvm = @import("llvm.zig");
9const c = @import("c.zig");8const c = @import("c.zig");
10const builtin = @import("builtin");9const builtin = @import("builtin");
...@@ -952,141 +951,5 @@ async fn addFnToLinkSet(comp: *Compilation, fn_val: *Value.Fn) void {...@@ -952,141 +951,5 @@ async fn addFnToLinkSet(comp: *Compilation, fn_val: *Value.Fn) void {
952}951}
953952
954fn getZigDir(allocator: *mem.Allocator) ![]u8 {953fn getZigDir(allocator: *mem.Allocator) ![]u8 {
955 return getAppDataDir(allocator, "zig");954 return os.getAppDataDir(allocator, "zig");
956}
957
958const GetAppDataDirError = error{
959 OutOfMemory,
960 AppDataDirUnavailable,
961};
962
963/// Caller owns returned memory.
964/// TODO move to zig std lib
965fn 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
997test "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
1003fn 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
1038test "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
1088fn utf16lePtrSlice(ptr: [*]const u16) []const u16 {
1089 var index: usize = 0;
1090 while (ptr[index] != 0) : (index += 1) {}
1091 return ptr[0..index];
1092}955}
std/event/loop.zig+1-3
...@@ -233,8 +233,6 @@ pub const Loop = struct {...@@ -233,8 +233,6 @@ pub const Loop = struct {
233 }233 }
234 },234 },
235 builtin.Os.windows => {235 builtin.Os.windows => {
236 self.os_data.extra_thread_count = extra_thread_count;
237
238 self.os_data.io_port = try std.os.windowsCreateIoCompletionPort(236 self.os_data.io_port = try std.os.windowsCreateIoCompletionPort(
239 windows.INVALID_HANDLE_VALUE,237 windows.INVALID_HANDLE_VALUE,
240 null,238 null,
...@@ -468,7 +466,7 @@ pub const Loop = struct {...@@ -468,7 +466,7 @@ pub const Loop = struct {
468 },466 },
469 builtin.Os.windows => {467 builtin.Os.windows => {
470 var i: usize = 0;468 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) {
472 while (true) {470 while (true) {
473 const overlapped = @intToPtr(?*windows.OVERLAPPED, 0x1);471 const overlapped = @intToPtr(?*windows.OVERLAPPED, 0x1);
474 std.os.windowsPostQueuedCompletionStatus(self.os_data.io_port, undefined, @ptrToInt(&self.final_resume_node), overlapped) catch continue;472 std.os.windowsPostQueuedCompletionStatus(self.os_data.io_port, undefined, @ptrToInt(&self.final_resume_node), overlapped) catch continue;
std/os/get_app_data_dir.zig created+60
...@@ -0,0 +1,60 @@
1const std = @import("../index.zig");
2const builtin = @import("builtin");
3const unicode = std.unicode;
4const mem = std.mem;
5const os = std.os;
6
7pub const GetAppDataDirError = error{
8 OutOfMemory,
9 AppDataDirUnavailable,
10};
11
12/// Caller owns returned memory.
13pub 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
50fn 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
56test "getAppDataDir" {
57 const result = try getAppDataDir(std.debug.global_allocator, "zig");
58 std.debug.warn("{}...", result);
59}
60
std/os/index.zig+4
...@@ -18,6 +18,7 @@ test "std.os" {...@@ -18,6 +18,7 @@ test "std.os" {
18 _ = @import("test.zig");18 _ = @import("test.zig");
19 _ = @import("time.zig");19 _ = @import("time.zig");
20 _ = @import("windows/index.zig");20 _ = @import("windows/index.zig");
21 _ = @import("get_app_data_dir.zig");
21}22}
2223
23pub const windows = @import("windows/index.zig");24pub const windows = @import("windows/index.zig");
...@@ -76,6 +77,9 @@ pub const WindowsWriteError = windows_util.WriteError;...@@ -76,6 +77,9 @@ pub const WindowsWriteError = windows_util.WriteError;
7677
77pub const FileHandle = if (is_windows) windows.HANDLE else i32;78pub const FileHandle = if (is_windows) windows.HANDLE else i32;
7879
80pub const getAppDataDir = @import("get_app_data_dir.zig").getAppDataDir;
81pub const GetAppDataDirError = @import("get_app_data_dir.zig").GetAppDataDirError;
82
79const debug = std.debug;83const debug = std.debug;
80const assert = debug.assert;84const assert = debug.assert;
8185
std/unicode.zig+89
...@@ -1,5 +1,8 @@...@@ -1,5 +1,8 @@
1const std = @import("./index.zig");1const std = @import("./index.zig");
2const builtin = @import("builtin");
2const debug = std.debug;3const debug = std.debug;
4const assert = std.debug.assert;
5const mem = std.mem;
36
4/// Returns how many bytes the UTF-8 representation would require7/// Returns how many bytes the UTF-8 representation would require
5/// for the given codepoint.8/// for the given codepoint.
...@@ -441,3 +444,89 @@ fn testDecode(bytes: []const u8) !u32 {...@@ -441,3 +444,89 @@ fn testDecode(bytes: []const u8) !u32 {
441 debug.assert(bytes.len == length);444 debug.assert(bytes.len == length);
442 return utf8Decode(bytes);445 return utf8Decode(bytes);
443}446}
447
448// TODO: make this API on top of a non-allocating Utf16LeView
449pub 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
484test "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}