| ... | @@ -24,6 +24,7 @@ | ... | @@ -24,6 +24,7 @@ |
| 24 | #endif | 24 | #endif |
| 25 | | 25 | |
| 26 | #include <windows.h> | 26 | #include <windows.h> |
| | 27 | #include <shlobj.h> |
| 27 | #include <io.h> | 28 | #include <io.h> |
| 28 | #include <fcntl.h> | 29 | #include <fcntl.h> |
| 29 | | 30 | |
| ... | @@ -1393,7 +1394,7 @@ Error os_self_exe_path(Buf *out_path) { | ... | @@ -1393,7 +1394,7 @@ Error os_self_exe_path(Buf *out_path) { |
| 1393 | } | 1394 | } |
| 1394 | if (copied_amt < buf_len(out_path)) { | 1395 | if (copied_amt < buf_len(out_path)) { |
| 1395 | buf_resize(out_path, copied_amt); | 1396 | buf_resize(out_path, copied_amt); |
| 1396 | return 0; | 1397 | return ErrorNone; |
| 1397 | } | 1398 | } |
| 1398 | buf_resize(out_path, buf_len(out_path) * 2); | 1399 | buf_resize(out_path, buf_len(out_path) * 2); |
| 1399 | } | 1400 | } |
| ... | @@ -1616,10 +1617,118 @@ int os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_ArchTy | ... | @@ -1616,10 +1617,118 @@ int os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_ArchTy |
| 1616 | #endif | 1617 | #endif |
| 1617 | } | 1618 | } |
| 1618 | | 1619 | |
| 1619 | // Ported from std/os/get_app_data_dir.zig | 1620 | #if defined(ZIG_OS_WINDOWS) |
| | 1621 | // Ported from std/unicode.zig |
| | 1622 | struct Utf16LeIterator { |
| | 1623 | uint8_t *bytes; |
| | 1624 | size_t i; |
| | 1625 | }; |
| | 1626 | |
| | 1627 | // Ported from std/unicode.zig |
| | 1628 | static Utf16LeIterator Utf16LeIterator_init(WCHAR *ptr) { |
| | 1629 | return {(uint8_t*)ptr, 0}; |
| | 1630 | } |
| | 1631 | |
| | 1632 | // Ported from std/unicode.zig |
| | 1633 | static Optional<uint32_t> Utf16LeIterator_nextCodepoint(Utf16LeIterator *it) { |
| | 1634 | if (it->bytes[it->i] == 0 && it->bytes[it->i + 1] == 0) |
| | 1635 | return {}; |
| | 1636 | uint32_t c0 = ((uint32_t)it->bytes[it->i]) | (((uint32_t)it->bytes[it->i + 1]) << 8); |
| | 1637 | if (c0 & ~((uint32_t)0x03ff) == 0xd800) { |
| | 1638 | // surrogate pair |
| | 1639 | it->i += 2; |
| | 1640 | assert(it->bytes[it->i] != 0 || it->bytes[it->i + 1] != 0); |
| | 1641 | uint32_t c1 = ((uint32_t)it->bytes[it->i]) | (((uint32_t)it->bytes[it->i + 1]) << 8); |
| | 1642 | assert(c1 & ~((uint32_t)0x03ff) == 0xdc00); |
| | 1643 | it->i += 2; |
| | 1644 | return Optional<uint32_t>::some(0x10000 + (((c0 & 0x03ff) << 10) | (c1 & 0x03ff))); |
| | 1645 | } else { |
| | 1646 | assert(c0 & ~((uint32_t)0x03ff) != 0xdc00); |
| | 1647 | it->i += 2; |
| | 1648 | return Optional<uint32_t>::some(c0); |
| | 1649 | } |
| | 1650 | } |
| | 1651 | |
| | 1652 | // Ported from std/unicode.zig |
| | 1653 | static uint8_t utf8CodepointSequenceLength(uint32_t c) { |
| | 1654 | if (c < 0x80) return 1; |
| | 1655 | if (c < 0x800) return 2; |
| | 1656 | if (c < 0x10000) return 3; |
| | 1657 | if (c < 0x110000) return 4; |
| | 1658 | zig_unreachable(); |
| | 1659 | } |
| | 1660 | |
| | 1661 | // Ported from std/unicode.zig |
| | 1662 | static size_t utf8Encode(uint32_t c, Slice<uint8_t> out) { |
| | 1663 | size_t length = utf8CodepointSequenceLength(c); |
| | 1664 | assert(out.len >= length); |
| | 1665 | switch (length) { |
| | 1666 | // The pattern for each is the same |
| | 1667 | // - Increasing the initial shift by 6 each time |
| | 1668 | // - Each time after the first shorten the shifted |
| | 1669 | // value to a max of 0b111111 (63) |
| | 1670 | case 1: |
| | 1671 | out.ptr[0] = c; // Can just do 0 + codepoint for initial range |
| | 1672 | break; |
| | 1673 | case 2: |
| | 1674 | out.ptr[0] = 0b11000000 | (c >> 6); |
| | 1675 | out.ptr[1] = 0b10000000 | (c & 0b111111); |
| | 1676 | break; |
| | 1677 | case 3: |
| | 1678 | assert(!(0xd800 <= c && c <= 0xdfff)); |
| | 1679 | out.ptr[0] = 0b11100000 | (c >> 12); |
| | 1680 | out.ptr[1] = 0b10000000 | ((c >> 6) & 0b111111); |
| | 1681 | out.ptr[2] = 0b10000000 | (c & 0b111111); |
| | 1682 | break; |
| | 1683 | case 4: |
| | 1684 | out.ptr[0] = 0b11110000 | (c >> 18); |
| | 1685 | out.ptr[1] = 0b10000000 | ((c >> 12) & 0b111111); |
| | 1686 | out.ptr[2] = 0b10000000 | ((c >> 6) & 0b111111); |
| | 1687 | out.ptr[3] = 0b10000000 | (c & 0b111111); |
| | 1688 | break; |
| | 1689 | default: |
| | 1690 | zig_unreachable(); |
| | 1691 | } |
| | 1692 | return length; |
| | 1693 | } |
| | 1694 | |
| | 1695 | // Ported from std.unicode.utf16leToUtf8Alloc |
| | 1696 | static void utf16le_ptr_to_utf8(Buf *out, WCHAR *utf16le) { |
| | 1697 | // optimistically guess that it will all be ascii. |
| | 1698 | buf_resize(out, 0); |
| | 1699 | size_t out_index = 0; |
| | 1700 | Utf16LeIterator it = Utf16LeIterator_init(utf16le); |
| | 1701 | for (;;) { |
| | 1702 | Optional<uint32_t> opt_codepoint = Utf16LeIterator_nextCodepoint(&it); |
| | 1703 | if (!opt_codepoint.is_some) break; |
| | 1704 | uint32_t codepoint = opt_codepoint.value; |
| | 1705 | |
| | 1706 | size_t utf8_len = utf8CodepointSequenceLength(codepoint); |
| | 1707 | buf_resize(out, buf_len(out) + utf8_len); |
| | 1708 | utf8Encode(codepoint, {(uint8_t*)buf_ptr(out)+out_index, buf_len(out)-out_index}); |
| | 1709 | out_index += utf8_len; |
| | 1710 | } |
| | 1711 | } |
| | 1712 | #endif |
| | 1713 | |
| | 1714 | // Ported from std.os.getAppDataDir |
| 1620 | Error os_get_app_data_dir(Buf *out_path, const char *appname) { | 1715 | Error os_get_app_data_dir(Buf *out_path, const char *appname) { |
| 1621 | #if defined(ZIG_OS_WINDOWS) | 1716 | #if defined(ZIG_OS_WINDOWS) |
| 1622 | #error "Unimplemented" | 1717 | Error err; |
| | 1718 | WCHAR *dir_path_ptr; |
| | 1719 | switch (SHGetKnownFolderPath(FOLDERID_LocalAppData, KF_FLAG_CREATE, nullptr, &dir_path_ptr)) { |
| | 1720 | case S_OK: |
| | 1721 | // defer os.windows.CoTaskMemFree(@ptrCast(*c_void, dir_path_ptr)); |
| | 1722 | utf16le_ptr_to_utf8(out_path, dir_path_ptr); |
| | 1723 | CoTaskMemFree(dir_path_ptr); |
| | 1724 | buf_appendf(out_path, "\\%s", appname); |
| | 1725 | return ErrorNone; |
| | 1726 | case E_OUTOFMEMORY: |
| | 1727 | return ErrorNoMem; |
| | 1728 | default: |
| | 1729 | return ErrorUnexpected; |
| | 1730 | } |
| | 1731 | zig_unreachable(); |
| 1623 | #elif defined(ZIG_OS_DARWIN) | 1732 | #elif defined(ZIG_OS_DARWIN) |
| 1624 | const char *home_dir = getenv("HOME"); | 1733 | const char *home_dir = getenv("HOME"); |
| 1625 | if (home_dir == nullptr) { | 1734 | if (home_dir == nullptr) { |
| ... | @@ -1665,14 +1774,44 @@ Error os_self_exe_shared_libs(ZigList<Buf *> &paths) { | ... | @@ -1665,14 +1774,44 @@ Error os_self_exe_shared_libs(ZigList<Buf *> &paths) { |
| 1665 | paths.append(buf_create_from_str(name)); | 1774 | paths.append(buf_create_from_str(name)); |
| 1666 | } | 1775 | } |
| 1667 | return ErrorNone; | 1776 | return ErrorNone; |
| | 1777 | #elif defined(ZIG_OS_WINDOWS) |
| | 1778 | // zig is built statically on windows, so we can return an empty list |
| | 1779 | paths.resize(0); |
| | 1780 | return ErrorNone; |
| 1668 | #else | 1781 | #else |
| 1669 | #error "unimplemented" | 1782 | #error unimplemented |
| 1670 | #endif | 1783 | #endif |
| 1671 | } | 1784 | } |
| 1672 | | 1785 | |
| 1673 | Error os_file_open_r(Buf *full_path, OsFile *out_file) { | 1786 | Error os_file_open_r(Buf *full_path, OsFile *out_file) { |
| 1674 | #if defined(ZIG_OS_WINDOWS) | 1787 | #if defined(ZIG_OS_WINDOWS) |
| 1675 | #error "unimplemented" | 1788 | // TODO use CreateFileW |
| | 1789 | HANDLE result = CreateFileA(buf_ptr(full_path), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); |
| | 1790 | |
| | 1791 | if (result == INVALID_HANDLE_VALUE) { |
| | 1792 | DWORD err = GetLastError(); |
| | 1793 | switch (err) { |
| | 1794 | case ERROR_SHARING_VIOLATION: |
| | 1795 | return ErrorSharingViolation; |
| | 1796 | case ERROR_ALREADY_EXISTS: |
| | 1797 | return ErrorPathAlreadyExists; |
| | 1798 | case ERROR_FILE_EXISTS: |
| | 1799 | return ErrorPathAlreadyExists; |
| | 1800 | case ERROR_FILE_NOT_FOUND: |
| | 1801 | return ErrorFileNotFound; |
| | 1802 | case ERROR_PATH_NOT_FOUND: |
| | 1803 | return ErrorFileNotFound; |
| | 1804 | case ERROR_ACCESS_DENIED: |
| | 1805 | return ErrorAccess; |
| | 1806 | case ERROR_PIPE_BUSY: |
| | 1807 | return ErrorPipeBusy; |
| | 1808 | default: |
| | 1809 | return ErrorUnexpected; |
| | 1810 | } |
| | 1811 | } |
| | 1812 | |
| | 1813 | *out_file = result; |
| | 1814 | return ErrorNone; |
| 1676 | #else | 1815 | #else |
| 1677 | for (;;) { | 1816 | for (;;) { |
| 1678 | int fd = open(buf_ptr(full_path), O_RDONLY|O_CLOEXEC); | 1817 | int fd = open(buf_ptr(full_path), O_RDONLY|O_CLOEXEC); |
| ... | @@ -1702,7 +1841,36 @@ Error os_file_open_r(Buf *full_path, OsFile *out_file) { | ... | @@ -1702,7 +1841,36 @@ Error os_file_open_r(Buf *full_path, OsFile *out_file) { |
| 1702 | | 1841 | |
| 1703 | Error os_file_open_lock_rw(Buf *full_path, OsFile *out_file) { | 1842 | Error os_file_open_lock_rw(Buf *full_path, OsFile *out_file) { |
| 1704 | #if defined(ZIG_OS_WINDOWS) | 1843 | #if defined(ZIG_OS_WINDOWS) |
| 1705 | #error "unimplemented" | 1844 | for (;;) { |
| | 1845 | HANDLE result = CreateFileA(buf_ptr(full_path), GENERIC_READ | GENERIC_WRITE, |
| | 1846 | 0, nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); |
| | 1847 | |
| | 1848 | if (result == INVALID_HANDLE_VALUE) { |
| | 1849 | DWORD err = GetLastError(); |
| | 1850 | switch (err) { |
| | 1851 | case ERROR_SHARING_VIOLATION: |
| | 1852 | // TODO wait for the lock instead of sleeping |
| | 1853 | Sleep(10); |
| | 1854 | continue; |
| | 1855 | case ERROR_ALREADY_EXISTS: |
| | 1856 | return ErrorPathAlreadyExists; |
| | 1857 | case ERROR_FILE_EXISTS: |
| | 1858 | return ErrorPathAlreadyExists; |
| | 1859 | case ERROR_FILE_NOT_FOUND: |
| | 1860 | return ErrorFileNotFound; |
| | 1861 | case ERROR_PATH_NOT_FOUND: |
| | 1862 | return ErrorFileNotFound; |
| | 1863 | case ERROR_ACCESS_DENIED: |
| | 1864 | return ErrorAccess; |
| | 1865 | case ERROR_PIPE_BUSY: |
| | 1866 | return ErrorPipeBusy; |
| | 1867 | default: |
| | 1868 | return ErrorUnexpected; |
| | 1869 | } |
| | 1870 | } |
| | 1871 | *out_file = result; |
| | 1872 | return ErrorNone; |
| | 1873 | } |
| 1706 | #else | 1874 | #else |
| 1707 | int fd; | 1875 | int fd; |
| 1708 | for (;;) { | 1876 | for (;;) { |
| ... | @@ -1757,7 +1925,12 @@ Error os_file_open_lock_rw(Buf *full_path, OsFile *out_file) { | ... | @@ -1757,7 +1925,12 @@ Error os_file_open_lock_rw(Buf *full_path, OsFile *out_file) { |
| 1757 | | 1925 | |
| 1758 | Error os_file_mtime(OsFile file, OsTimeStamp *mtime) { | 1926 | Error os_file_mtime(OsFile file, OsTimeStamp *mtime) { |
| 1759 | #if defined(ZIG_OS_WINDOWS) | 1927 | #if defined(ZIG_OS_WINDOWS) |
| 1760 | #error unimplemented | 1928 | FILETIME last_write_time; |
| | 1929 | if (!GetFileTime(file, nullptr, nullptr, &last_write_time)) |
| | 1930 | return ErrorUnexpected; |
| | 1931 | mtime->sec = last_write_time.dwLowDateTime | (last_write_time.dwHighDateTime << 32); |
| | 1932 | mtime->nsec = 0; |
| | 1933 | return ErrorNone; |
| 1761 | #elif defined(ZIG_OS_LINUX) | 1934 | #elif defined(ZIG_OS_LINUX) |
| 1762 | struct stat statbuf; | 1935 | struct stat statbuf; |
| 1763 | if (fstat(file, &statbuf) == -1) | 1936 | if (fstat(file, &statbuf) == -1) |
| ... | @@ -1781,7 +1954,11 @@ Error os_file_mtime(OsFile file, OsTimeStamp *mtime) { | ... | @@ -1781,7 +1954,11 @@ Error os_file_mtime(OsFile file, OsTimeStamp *mtime) { |
| 1781 | | 1954 | |
| 1782 | Error os_file_read(OsFile file, void *ptr, size_t *len) { | 1955 | Error os_file_read(OsFile file, void *ptr, size_t *len) { |
| 1783 | #if defined(ZIG_OS_WINDOWS) | 1956 | #if defined(ZIG_OS_WINDOWS) |
| 1784 | #error unimplemented | 1957 | DWORD amt_read; |
| | 1958 | if (ReadFile(file, ptr, *len, &amt_read, nullptr) == 0) |
| | 1959 | return ErrorUnexpected; |
| | 1960 | *len = amt_read; |
| | 1961 | return ErrorNone; |
| 1785 | #else | 1962 | #else |
| 1786 | for (;;) { | 1963 | for (;;) { |
| 1787 | ssize_t rc = read(file, ptr, *len); | 1964 | ssize_t rc = read(file, ptr, *len); |
| ... | @@ -1830,10 +2007,18 @@ Error os_file_read_all(OsFile file, Buf *contents) { | ... | @@ -1830,10 +2007,18 @@ Error os_file_read_all(OsFile file, Buf *contents) { |
| 1830 | | 2007 | |
| 1831 | Error os_file_overwrite(OsFile file, Buf *contents) { | 2008 | Error os_file_overwrite(OsFile file, Buf *contents) { |
| 1832 | #if defined(ZIG_OS_WINDOWS) | 2009 | #if defined(ZIG_OS_WINDOWS) |
| 1833 | #error unimplemented | 2010 | if (SetFilePointer(file, 0, nullptr, FILE_BEGIN) == INVALID_SET_FILE_POINTER) |
| | 2011 | return ErrorFileSystem; |
| | 2012 | if (!SetEndOfFile(file)) |
| | 2013 | return ErrorFileSystem; |
| | 2014 | if (!WriteFile(file, buf_ptr(contents), buf_len(contents), nullptr, nullptr)) |
| | 2015 | return ErrorFileSystem; |
| | 2016 | return ErrorNone; |
| 1834 | #else | 2017 | #else |
| 1835 | if (lseek(file, 0, SEEK_SET) == -1) | 2018 | if (lseek(file, 0, SEEK_SET) == -1) |
| 1836 | return ErrorFileSystem; | 2019 | return ErrorFileSystem; |
| | 2020 | if (ftruncate(file, 0) == -1) |
| | 2021 | return ErrorFileSystem; |
| 1837 | for (;;) { | 2022 | for (;;) { |
| 1838 | if (write(file, buf_ptr(contents), buf_len(contents)) == -1) { | 2023 | if (write(file, buf_ptr(contents), buf_len(contents)) == -1) { |
| 1839 | switch (errno) { | 2024 | switch (errno) { |
| ... | @@ -1853,5 +2038,9 @@ Error os_file_overwrite(OsFile file, Buf *contents) { | ... | @@ -1853,5 +2038,9 @@ Error os_file_overwrite(OsFile file, Buf *contents) { |
| 1853 | } | 2038 | } |
| 1854 | | 2039 | |
| 1855 | void os_file_close(OsFile file) { | 2040 | void os_file_close(OsFile file) { |
| | 2041 | #if defined(ZIG_OS_WINDOWS) |
| | 2042 | CloseHandle(file); |
| | 2043 | #else |
| 1856 | close(file); | 2044 | close(file); |
| | 2045 | #endif |
| 1857 | } | 2046 | } |