Commit a8a1b5af07

Andrew Kelley <superjoe30@gmail.com>
2018-07-18 16:07:22
fix build on windows
* move getAppDataDir and utf16leToUtf8 from self-hosted to std lib * fix std.event.Loop on windows
1 parent b7be082
src-self-hosted/compilation.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");
 }
std/event/loop.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;
std/os/get_app_data_dir.zig
@@ -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);
+}
+
std/os/index.zig
@@ -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;
 
std/unicode.zig
@@ -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"));
+    }
+}
CMakeLists.txt
@@ -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"