authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-09-12 11:33:26-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-09-12 11:33:26-04:00
log1caa48c2df63d61b8d2501b3e3ee7c85ee8d89cb
tree596273952517f58477d1aed2da85f2711448412c
parentff0b7fe29a49a5619b3c2f7fee0baccb979caf2d

windows os.cpp implementations


4 files changed, 203 insertions(+), 10 deletions(-)

src/error.cpp+2
......@@ -30,6 +30,8 @@ const char *err_str(int err) {
3030 case ErrorEndOfFile: return "end of file";
3131 case ErrorIsDir: return "is directory";
3232 case ErrorUnsupportedOperatingSystem: return "unsupported operating system";
33 case ErrorSharingViolation: return "sharing violation";
34 case ErrorPipeBusy: return "pipe busy";
3335 }
3436 return "(invalid error)";
3537}
src/error.hpp+2
......@@ -30,6 +30,8 @@ enum Error {
3030 ErrorEndOfFile,
3131 ErrorIsDir,
3232 ErrorUnsupportedOperatingSystem,
33 ErrorSharingViolation,
34 ErrorPipeBusy,
3335};
3436
3537const char *err_str(int err);
src/os.cpp+198-9
......@@ -24,6 +24,7 @@
2424#endif
2525
2626#include <windows.h>
27#include <shlobj.h>
2728#include <io.h>
2829#include <fcntl.h>
2930
......@@ -1393,7 +1394,7 @@ Error os_self_exe_path(Buf *out_path) {
13931394 }
13941395 if (copied_amt < buf_len(out_path)) {
13951396 buf_resize(out_path, copied_amt);
1396 return 0;
1397 return ErrorNone;
13971398 }
13981399 buf_resize(out_path, buf_len(out_path) * 2);
13991400 }
......@@ -1616,10 +1617,118 @@ int os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_ArchTy
16161617#endif
16171618}
16181619
1619// Ported from std/os/get_app_data_dir.zig
1620#if defined(ZIG_OS_WINDOWS)
1621// Ported from std/unicode.zig
1622struct Utf16LeIterator {
1623 uint8_t *bytes;
1624 size_t i;
1625};
1626
1627// Ported from std/unicode.zig
1628static Utf16LeIterator Utf16LeIterator_init(WCHAR *ptr) {
1629 return {(uint8_t*)ptr, 0};
1630}
1631
1632// Ported from std/unicode.zig
1633static 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
1653static 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
1662static 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
1696static 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
16201715Error os_get_app_data_dir(Buf *out_path, const char *appname) {
16211716#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();
16231732#elif defined(ZIG_OS_DARWIN)
16241733 const char *home_dir = getenv("HOME");
16251734 if (home_dir == nullptr) {
......@@ -1665,14 +1774,44 @@ Error os_self_exe_shared_libs(ZigList<Buf *> &paths) {
16651774 paths.append(buf_create_from_str(name));
16661775 }
16671776 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;
16681781#else
1669#error "unimplemented"
1782#error unimplemented
16701783#endif
16711784}
16721785
16731786Error os_file_open_r(Buf *full_path, OsFile *out_file) {
16741787#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;
16761815#else
16771816 for (;;) {
16781817 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) {
17021841
17031842Error os_file_open_lock_rw(Buf *full_path, OsFile *out_file) {
17041843#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 }
17061874#else
17071875 int fd;
17081876 for (;;) {
......@@ -1757,7 +1925,12 @@ Error os_file_open_lock_rw(Buf *full_path, OsFile *out_file) {
17571925
17581926Error os_file_mtime(OsFile file, OsTimeStamp *mtime) {
17591927#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;
17611934#elif defined(ZIG_OS_LINUX)
17621935 struct stat statbuf;
17631936 if (fstat(file, &statbuf) == -1)
......@@ -1781,7 +1954,11 @@ Error os_file_mtime(OsFile file, OsTimeStamp *mtime) {
17811954
17821955Error os_file_read(OsFile file, void *ptr, size_t *len) {
17831956#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;
17851962#else
17861963 for (;;) {
17871964 ssize_t rc = read(file, ptr, *len);
......@@ -1830,10 +2007,18 @@ Error os_file_read_all(OsFile file, Buf *contents) {
18302007
18312008Error os_file_overwrite(OsFile file, Buf *contents) {
18322009#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;
18342017#else
18352018 if (lseek(file, 0, SEEK_SET) == -1)
18362019 return ErrorFileSystem;
2020 if (ftruncate(file, 0) == -1)
2021 return ErrorFileSystem;
18372022 for (;;) {
18382023 if (write(file, buf_ptr(contents), buf_len(contents)) == -1) {
18392024 switch (errno) {
......@@ -1853,5 +2038,9 @@ Error os_file_overwrite(OsFile file, Buf *contents) {
18532038}
18542039
18552040void os_file_close(OsFile file) {
2041#if defined(ZIG_OS_WINDOWS)
2042 CloseHandle(file);
2043#else
18562044 close(file);
2045#endif
18572046}
src/os.hpp+1-1
......@@ -72,7 +72,7 @@ struct Termination {
7272};
7373
7474#if defined(ZIG_OS_WINDOWS)
75#define OsFile (void *)
75#define OsFile void *
7676#else
7777#define OsFile int
7878#endif